xref: /netbsd-src/external/gpl3/binutils.old/dist/libiberty/simple-object.c (revision e992f068c547fd6e84b3f104dc2340adcc955732)
116dce513Schristos /* simple-object.c -- simple routines to read and write object files.
2*e992f068Schristos    Copyright (C) 2010-2022 Free Software Foundation, Inc.
316dce513Schristos    Written by Ian Lance Taylor, Google.
416dce513Schristos 
516dce513Schristos This program is free software; you can redistribute it and/or modify it
616dce513Schristos under the terms of the GNU General Public License as published by the
716dce513Schristos Free Software Foundation; either version 2, or (at your option) any
816dce513Schristos later version.
916dce513Schristos 
1016dce513Schristos This program is distributed in the hope that it will be useful,
1116dce513Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
1216dce513Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1316dce513Schristos GNU General Public License for more details.
1416dce513Schristos 
1516dce513Schristos You should have received a copy of the GNU General Public License
1616dce513Schristos along with this program; if not, write to the Free Software
1716dce513Schristos Foundation, 51 Franklin Street - Fifth Floor,
1816dce513Schristos Boston, MA 02110-1301, USA.  */
1916dce513Schristos 
2016dce513Schristos #include "config.h"
2116dce513Schristos #include "libiberty.h"
2216dce513Schristos #include "simple-object.h"
2316dce513Schristos 
2416dce513Schristos #include <errno.h>
25ede78133Schristos #include <fcntl.h>
2616dce513Schristos 
2716dce513Schristos #ifdef HAVE_STDLIB_H
2816dce513Schristos #include <stdlib.h>
2916dce513Schristos #endif
3016dce513Schristos 
3116dce513Schristos #ifdef HAVE_STDINT_H
3216dce513Schristos #include <stdint.h>
3316dce513Schristos #endif
3416dce513Schristos 
3516dce513Schristos #ifdef HAVE_STRING_H
3616dce513Schristos #include <string.h>
3716dce513Schristos #endif
3816dce513Schristos 
3916dce513Schristos #ifdef HAVE_INTTYPES_H
4016dce513Schristos #include <inttypes.h>
4116dce513Schristos #endif
4216dce513Schristos 
4316dce513Schristos #ifndef SEEK_SET
4416dce513Schristos #define SEEK_SET 0
4516dce513Schristos #endif
4616dce513Schristos 
47012573ebSchristos #ifndef O_BINARY
48012573ebSchristos #define O_BINARY 0
49012573ebSchristos #endif
50012573ebSchristos 
5116dce513Schristos #include "simple-object-common.h"
5216dce513Schristos 
5316dce513Schristos /* The known object file formats.  */
5416dce513Schristos 
5516dce513Schristos static const struct simple_object_functions * const format_functions[] =
5616dce513Schristos {
5716dce513Schristos   &simple_object_elf_functions,
5816dce513Schristos   &simple_object_mach_o_functions,
5916dce513Schristos   &simple_object_coff_functions,
6016dce513Schristos   &simple_object_xcoff_functions
6116dce513Schristos };
6216dce513Schristos 
6316dce513Schristos /* Read data from a file using the simple_object error reporting
6416dce513Schristos    conventions.  */
6516dce513Schristos 
6616dce513Schristos int
simple_object_internal_read(int descriptor,off_t offset,unsigned char * buffer,size_t size,const char ** errmsg,int * err)6716dce513Schristos simple_object_internal_read (int descriptor, off_t offset,
6816dce513Schristos 			     unsigned char *buffer, size_t size,
6916dce513Schristos 			     const char **errmsg, int *err)
7016dce513Schristos {
7116dce513Schristos   if (lseek (descriptor, offset, SEEK_SET) < 0)
7216dce513Schristos     {
7316dce513Schristos       *errmsg = "lseek";
7416dce513Schristos       *err = errno;
7516dce513Schristos       return 0;
7616dce513Schristos     }
7716dce513Schristos 
7816dce513Schristos   do
7916dce513Schristos     {
8016dce513Schristos       ssize_t got = read (descriptor, buffer, size);
8116dce513Schristos       if (got == 0)
8216dce513Schristos 	break;
8316dce513Schristos       else if (got > 0)
8416dce513Schristos 	{
8516dce513Schristos 	  buffer += got;
8616dce513Schristos 	  size -= got;
8716dce513Schristos 	}
8816dce513Schristos       else if (errno != EINTR)
8916dce513Schristos 	{
9016dce513Schristos 	  *errmsg = "read";
9116dce513Schristos 	  *err = errno;
9216dce513Schristos 	  return 0;
9316dce513Schristos 	}
9416dce513Schristos     }
9516dce513Schristos   while (size > 0);
9616dce513Schristos 
9716dce513Schristos   if (size > 0)
9816dce513Schristos     {
9916dce513Schristos       *errmsg = "file too short";
10016dce513Schristos       *err = 0;
10116dce513Schristos       return 0;
10216dce513Schristos     }
10316dce513Schristos 
10416dce513Schristos   return 1;
10516dce513Schristos }
10616dce513Schristos 
10716dce513Schristos /* Write data to a file using the simple_object error reporting
10816dce513Schristos    conventions.  */
10916dce513Schristos 
11016dce513Schristos int
simple_object_internal_write(int descriptor,off_t offset,const unsigned char * buffer,size_t size,const char ** errmsg,int * err)11116dce513Schristos simple_object_internal_write (int descriptor, off_t offset,
11216dce513Schristos 			      const unsigned char *buffer, size_t size,
11316dce513Schristos 			      const char **errmsg, int *err)
11416dce513Schristos {
11516dce513Schristos   if (lseek (descriptor, offset, SEEK_SET) < 0)
11616dce513Schristos     {
11716dce513Schristos       *errmsg = "lseek";
11816dce513Schristos       *err = errno;
11916dce513Schristos       return 0;
12016dce513Schristos     }
12116dce513Schristos 
12216dce513Schristos   do
12316dce513Schristos     {
12416dce513Schristos       ssize_t wrote = write (descriptor, buffer, size);
12516dce513Schristos       if (wrote == 0)
12616dce513Schristos 	break;
12716dce513Schristos       else if (wrote > 0)
12816dce513Schristos 	{
12916dce513Schristos 	  buffer += wrote;
13016dce513Schristos 	  size -= wrote;
13116dce513Schristos 	}
13216dce513Schristos       else if (errno != EINTR)
13316dce513Schristos 	{
13416dce513Schristos 	  *errmsg = "write";
13516dce513Schristos 	  *err = errno;
13616dce513Schristos 	  return 0;
13716dce513Schristos 	}
13816dce513Schristos     }
13916dce513Schristos   while (size > 0);
14016dce513Schristos 
14116dce513Schristos   if (size > 0)
14216dce513Schristos     {
14316dce513Schristos       *errmsg = "short write";
14416dce513Schristos       *err = 0;
14516dce513Schristos       return 0;
14616dce513Schristos     }
14716dce513Schristos 
14816dce513Schristos   return 1;
14916dce513Schristos }
15016dce513Schristos 
15116dce513Schristos /* Open for read.  */
15216dce513Schristos 
15316dce513Schristos simple_object_read *
simple_object_start_read(int descriptor,off_t offset,const char * segment_name,const char ** errmsg,int * err)15416dce513Schristos simple_object_start_read (int descriptor, off_t offset,
15516dce513Schristos 			  const char *segment_name, const char **errmsg,
15616dce513Schristos 			  int *err)
15716dce513Schristos {
15816dce513Schristos   unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN];
15916dce513Schristos   size_t len, i;
16016dce513Schristos 
16116dce513Schristos   if (!simple_object_internal_read (descriptor, offset, header,
16216dce513Schristos 				    SIMPLE_OBJECT_MATCH_HEADER_LEN,
16316dce513Schristos 				    errmsg, err))
16416dce513Schristos     return NULL;
16516dce513Schristos 
16616dce513Schristos   len = sizeof (format_functions) / sizeof (format_functions[0]);
16716dce513Schristos   for (i = 0; i < len; ++i)
16816dce513Schristos     {
16916dce513Schristos       void *data;
17016dce513Schristos 
17116dce513Schristos       data = format_functions[i]->match (header, descriptor, offset,
17216dce513Schristos 					 segment_name, errmsg, err);
17316dce513Schristos       if (data != NULL)
17416dce513Schristos 	{
17516dce513Schristos 	  simple_object_read *ret;
17616dce513Schristos 
17716dce513Schristos 	  ret = XNEW (simple_object_read);
17816dce513Schristos 	  ret->descriptor = descriptor;
17916dce513Schristos 	  ret->offset = offset;
18016dce513Schristos 	  ret->functions = format_functions[i];
18116dce513Schristos 	  ret->data = data;
18216dce513Schristos 	  return ret;
18316dce513Schristos 	}
18416dce513Schristos     }
18516dce513Schristos 
18616dce513Schristos   *errmsg = "file not recognized";
18716dce513Schristos   *err = 0;
18816dce513Schristos   return NULL;
18916dce513Schristos }
19016dce513Schristos 
19116dce513Schristos /* Find all sections.  */
19216dce513Schristos 
19316dce513Schristos const char *
simple_object_find_sections(simple_object_read * sobj,int (* pfn)(void *,const char *,off_t,off_t),void * data,int * err)19416dce513Schristos simple_object_find_sections (simple_object_read *sobj,
19516dce513Schristos 			     int (*pfn) (void *, const char *, off_t, off_t),
19616dce513Schristos 			     void *data,
19716dce513Schristos 			     int *err)
19816dce513Schristos {
19916dce513Schristos   return sobj->functions->find_sections (sobj, pfn, data, err);
20016dce513Schristos }
20116dce513Schristos 
20216dce513Schristos /* Internal data passed to find_one_section.  */
20316dce513Schristos 
20416dce513Schristos struct find_one_section_data
20516dce513Schristos {
20616dce513Schristos   /* The section we are looking for.  */
20716dce513Schristos   const char *name;
20816dce513Schristos   /* Where to store the section offset.  */
20916dce513Schristos   off_t *offset;
21016dce513Schristos   /* Where to store the section length.  */
21116dce513Schristos   off_t *length;
21216dce513Schristos   /* Set if the name is found.  */
21316dce513Schristos   int found;
21416dce513Schristos };
21516dce513Schristos 
21616dce513Schristos /* Internal function passed to find_sections.  */
21716dce513Schristos 
21816dce513Schristos static int
find_one_section(void * data,const char * name,off_t offset,off_t length)21916dce513Schristos find_one_section (void *data, const char *name, off_t offset, off_t length)
22016dce513Schristos {
22116dce513Schristos   struct find_one_section_data *fosd = (struct find_one_section_data *) data;
22216dce513Schristos 
22316dce513Schristos   if (strcmp (name, fosd->name) != 0)
22416dce513Schristos     return 1;
22516dce513Schristos 
22616dce513Schristos   *fosd->offset = offset;
22716dce513Schristos   *fosd->length = length;
22816dce513Schristos   fosd->found = 1;
22916dce513Schristos 
23016dce513Schristos   /* Stop iteration.  */
23116dce513Schristos   return 0;
23216dce513Schristos }
23316dce513Schristos 
23416dce513Schristos /* Find a section.  */
23516dce513Schristos 
23616dce513Schristos int
simple_object_find_section(simple_object_read * sobj,const char * name,off_t * offset,off_t * length,const char ** errmsg,int * err)23716dce513Schristos simple_object_find_section (simple_object_read *sobj, const char *name,
23816dce513Schristos 			    off_t *offset, off_t *length,
23916dce513Schristos 			    const char **errmsg, int *err)
24016dce513Schristos {
24116dce513Schristos   struct find_one_section_data fosd;
24216dce513Schristos 
24316dce513Schristos   fosd.name = name;
24416dce513Schristos   fosd.offset = offset;
24516dce513Schristos   fosd.length = length;
24616dce513Schristos   fosd.found = 0;
24716dce513Schristos 
24816dce513Schristos   *errmsg = simple_object_find_sections (sobj, find_one_section,
24916dce513Schristos 					 (void *) &fosd, err);
25016dce513Schristos   if (*errmsg != NULL)
25116dce513Schristos     return 0;
25216dce513Schristos   if (!fosd.found)
25316dce513Schristos     return 0;
25416dce513Schristos   return 1;
25516dce513Schristos }
25616dce513Schristos 
257ede78133Schristos /* Callback to identify and rename LTO debug sections by name.
258ede78133Schristos    Returns non-NULL if NAME is a LTO debug section, NULL if not.
259ede78133Schristos    If RENAME is true it will rename LTO debug sections to non-LTO
260ede78133Schristos    ones.  */
261ede78133Schristos 
262ede78133Schristos static char *
handle_lto_debug_sections(const char * name,int rename)263ede78133Schristos handle_lto_debug_sections (const char *name, int rename)
264ede78133Schristos {
265ede78133Schristos   char *newname = rename ? XCNEWVEC (char, strlen (name) + 1)
266ede78133Schristos 	  	         : xstrdup (name);
267ede78133Schristos 
268ede78133Schristos   /* ???  So we can't use .gnu.lto_ prefixed sections as the assembler
269ede78133Schristos      complains about bogus section flags.  Which means we need to arrange
270ede78133Schristos      for that to be fixed or .gnu.debuglto_ marked as SHF_EXCLUDE (to make
271ede78133Schristos      fat lto object tooling work for the fat part).  */
272ede78133Schristos   /* Also include corresponding reloc sections.  */
273ede78133Schristos   if (strncmp (name, ".rela", sizeof (".rela") - 1) == 0)
274ede78133Schristos     {
275ede78133Schristos       if (rename)
276ede78133Schristos         strncpy (newname, name, sizeof (".rela") - 1);
277ede78133Schristos       name += sizeof (".rela") - 1;
278ede78133Schristos     }
279ede78133Schristos   else if (strncmp (name, ".rel", sizeof (".rel") - 1) == 0)
280ede78133Schristos     {
281ede78133Schristos       if (rename)
282ede78133Schristos         strncpy (newname, name, sizeof (".rel") - 1);
283ede78133Schristos       name += sizeof (".rel") - 1;
284ede78133Schristos     }
285ede78133Schristos   /* ???  For now this handles both .gnu.lto_ and .gnu.debuglto_ prefixed
286ede78133Schristos      sections.  */
287ede78133Schristos   /* Copy LTO debug sections and rename them to their non-LTO name.  */
288ede78133Schristos   if (strncmp (name, ".gnu.debuglto_", sizeof (".gnu.debuglto_") - 1) == 0)
289ede78133Schristos     return rename ? strcat (newname, name + sizeof (".gnu.debuglto_") - 1) : newname;
290ede78133Schristos   else if (strncmp (name, ".gnu.lto_.debug_",
291ede78133Schristos 		    sizeof (".gnu.lto_.debug_") -1) == 0)
292ede78133Schristos     return rename ? strcat (newname, name + sizeof (".gnu.lto_") - 1) : newname;
293ede78133Schristos   /* Copy over .note.GNU-stack section under the same name if present.  */
294ede78133Schristos   else if (strcmp (name, ".note.GNU-stack") == 0)
295ede78133Schristos     return strcpy (newname, name);
296*e992f068Schristos   /* Copy over .note.gnu.property section under the same name if present.  */
297*e992f068Schristos   else if (strcmp (name, ".note.gnu.property") == 0)
298*e992f068Schristos     return strcpy (newname, name);
299ede78133Schristos   /* Copy over .comment section under the same name if present.  Solaris
300ede78133Schristos      ld uses them to relax its checking of ELF gABI access rules for
301ede78133Schristos      COMDAT sections in objects produced by GCC.  */
302ede78133Schristos   else if (strcmp (name, ".comment") == 0)
303ede78133Schristos     return strcpy (newname, name);
304*e992f068Schristos   /* Copy over .GCC.command.line section under the same name if present.  */
305*e992f068Schristos   else if (strcmp (name, ".GCC.command.line") == 0)
306*e992f068Schristos     return strcpy (newname, name);
307*e992f068Schristos   /* Copy over .ctf section under the same name if present.  */
308*e992f068Schristos   else if (strcmp (name, ".ctf") == 0)
309*e992f068Schristos     return strcpy (newname, name);
310*e992f068Schristos   /* Copy over .BTF section under the same name if present.  */
311*e992f068Schristos   else if (strcmp (name, ".BTF") == 0)
312*e992f068Schristos     return strcpy (newname, name);
313ede78133Schristos   free (newname);
314ede78133Schristos   return NULL;
315ede78133Schristos }
316ede78133Schristos 
317ede78133Schristos /* Wrapper for handle_lto_debug_sections.  */
318ede78133Schristos 
319ede78133Schristos static char *
handle_lto_debug_sections_rename(const char * name)320ede78133Schristos handle_lto_debug_sections_rename (const char *name)
321ede78133Schristos {
322ede78133Schristos   return handle_lto_debug_sections (name, 1);
323ede78133Schristos }
324ede78133Schristos 
325ede78133Schristos /* Wrapper for handle_lto_debug_sections.  */
326ede78133Schristos 
327ede78133Schristos static char *
handle_lto_debug_sections_norename(const char * name)328ede78133Schristos handle_lto_debug_sections_norename (const char *name)
329ede78133Schristos {
330ede78133Schristos   return handle_lto_debug_sections (name, 0);
331ede78133Schristos }
332ede78133Schristos 
333ede78133Schristos /* Copy LTO debug sections.  */
334ede78133Schristos 
335ede78133Schristos const char *
simple_object_copy_lto_debug_sections(simple_object_read * sobj,const char * dest,int * err,int rename)336ede78133Schristos simple_object_copy_lto_debug_sections (simple_object_read *sobj,
337ede78133Schristos 				       const char *dest, int *err, int rename)
338ede78133Schristos {
339ede78133Schristos   const char *errmsg;
340ede78133Schristos   simple_object_write *dest_sobj;
341ede78133Schristos   simple_object_attributes *attrs;
342ede78133Schristos   int outfd;
343ede78133Schristos 
344ede78133Schristos   if (! sobj->functions->copy_lto_debug_sections)
345ede78133Schristos     {
346ede78133Schristos       *err = EINVAL;
347ede78133Schristos       return "simple_object_copy_lto_debug_sections not implemented";
348ede78133Schristos     }
349ede78133Schristos 
350ede78133Schristos   attrs = simple_object_fetch_attributes (sobj, &errmsg, err);
351ede78133Schristos   if (! attrs)
352ede78133Schristos     return errmsg;
353ede78133Schristos   dest_sobj = simple_object_start_write (attrs, NULL, &errmsg, err);
354ede78133Schristos   simple_object_release_attributes (attrs);
355ede78133Schristos   if (! dest_sobj)
356ede78133Schristos     return errmsg;
357ede78133Schristos 
358ede78133Schristos   errmsg = sobj->functions->copy_lto_debug_sections
359ede78133Schristos 	 	 (sobj, dest_sobj,
360ede78133Schristos 		  rename ? handle_lto_debug_sections_rename
361ede78133Schristos 			 : handle_lto_debug_sections_norename,  err);
362ede78133Schristos   if (errmsg)
363ede78133Schristos     {
364ede78133Schristos       simple_object_release_write (dest_sobj);
365ede78133Schristos       return errmsg;
366ede78133Schristos     }
367ede78133Schristos 
368012573ebSchristos   outfd = open (dest, O_CREAT|O_WRONLY|O_TRUNC|O_BINARY, 00777);
369ede78133Schristos   if (outfd == -1)
370ede78133Schristos     {
371ede78133Schristos       *err = errno;
372ede78133Schristos       simple_object_release_write (dest_sobj);
373ede78133Schristos       return "open failed";
374ede78133Schristos     }
375ede78133Schristos 
376ede78133Schristos   errmsg = simple_object_write_to_file (dest_sobj, outfd, err);
377ede78133Schristos   close (outfd);
378ede78133Schristos   if (errmsg)
379ede78133Schristos     {
380ede78133Schristos       simple_object_release_write (dest_sobj);
381ede78133Schristos       return errmsg;
382ede78133Schristos     }
383ede78133Schristos 
384ede78133Schristos   simple_object_release_write (dest_sobj);
385ede78133Schristos   return NULL;
386ede78133Schristos }
387ede78133Schristos 
38816dce513Schristos /* Fetch attributes.  */
38916dce513Schristos 
39016dce513Schristos simple_object_attributes *
simple_object_fetch_attributes(simple_object_read * sobj,const char ** errmsg,int * err)39116dce513Schristos simple_object_fetch_attributes (simple_object_read *sobj, const char **errmsg,
39216dce513Schristos 				int *err)
39316dce513Schristos {
39416dce513Schristos   void *data;
39516dce513Schristos   simple_object_attributes *ret;
39616dce513Schristos 
39716dce513Schristos   data = sobj->functions->fetch_attributes (sobj, errmsg, err);
39816dce513Schristos   if (data == NULL)
39916dce513Schristos     return NULL;
40016dce513Schristos   ret = XNEW (simple_object_attributes);
40116dce513Schristos   ret->functions = sobj->functions;
40216dce513Schristos   ret->data = data;
40316dce513Schristos   return ret;
40416dce513Schristos }
40516dce513Schristos 
40616dce513Schristos /* Release an simple_object_read.  */
40716dce513Schristos 
40816dce513Schristos void
simple_object_release_read(simple_object_read * sobj)40916dce513Schristos simple_object_release_read (simple_object_read *sobj)
41016dce513Schristos {
41116dce513Schristos   sobj->functions->release_read (sobj->data);
41216dce513Schristos   XDELETE (sobj);
41316dce513Schristos }
41416dce513Schristos 
41516dce513Schristos /* Merge attributes.  */
41616dce513Schristos 
41716dce513Schristos const char *
simple_object_attributes_merge(simple_object_attributes * to,simple_object_attributes * from,int * err)41816dce513Schristos simple_object_attributes_merge (simple_object_attributes *to,
41916dce513Schristos 				simple_object_attributes *from,
42016dce513Schristos 				int *err)
42116dce513Schristos {
42216dce513Schristos   if (to->functions != from->functions)
42316dce513Schristos     {
42416dce513Schristos       *err = 0;
42516dce513Schristos       return "different object file format";
42616dce513Schristos     }
42716dce513Schristos   return to->functions->attributes_merge (to->data, from->data, err);
42816dce513Schristos }
42916dce513Schristos 
43016dce513Schristos /* Release an attributes structure.  */
43116dce513Schristos 
43216dce513Schristos void
simple_object_release_attributes(simple_object_attributes * attrs)43316dce513Schristos simple_object_release_attributes (simple_object_attributes *attrs)
43416dce513Schristos {
43516dce513Schristos   attrs->functions->release_attributes (attrs->data);
43616dce513Schristos   XDELETE (attrs);
43716dce513Schristos }
43816dce513Schristos 
43916dce513Schristos /* Start creating an object file.  */
44016dce513Schristos 
44116dce513Schristos simple_object_write *
simple_object_start_write(simple_object_attributes * attrs,const char * segment_name,const char ** errmsg,int * err)44216dce513Schristos simple_object_start_write (simple_object_attributes *attrs,
44316dce513Schristos 			   const char *segment_name, const char **errmsg,
44416dce513Schristos 			   int *err)
44516dce513Schristos {
44616dce513Schristos   void *data;
44716dce513Schristos   simple_object_write *ret;
44816dce513Schristos 
44916dce513Schristos   data = attrs->functions->start_write (attrs->data, errmsg, err);
45016dce513Schristos   if (data == NULL)
45116dce513Schristos     return NULL;
45216dce513Schristos   ret = XNEW (simple_object_write);
45316dce513Schristos   ret->functions = attrs->functions;
454ede78133Schristos   ret->segment_name = segment_name ? xstrdup (segment_name) : NULL;
45516dce513Schristos   ret->sections = NULL;
45616dce513Schristos   ret->last_section = NULL;
45716dce513Schristos   ret->data = data;
45816dce513Schristos   return ret;
45916dce513Schristos }
46016dce513Schristos 
46116dce513Schristos /* Start creating a section.  */
46216dce513Schristos 
46316dce513Schristos simple_object_write_section *
simple_object_write_create_section(simple_object_write * sobj,const char * name,unsigned int align,const char ** errmsg ATTRIBUTE_UNUSED,int * err ATTRIBUTE_UNUSED)46416dce513Schristos simple_object_write_create_section (simple_object_write *sobj, const char *name,
46516dce513Schristos 				    unsigned int align,
46616dce513Schristos 				    const char **errmsg ATTRIBUTE_UNUSED,
46716dce513Schristos 				    int *err ATTRIBUTE_UNUSED)
46816dce513Schristos {
46916dce513Schristos   simple_object_write_section *ret;
47016dce513Schristos 
47116dce513Schristos   ret = XNEW (simple_object_write_section);
47216dce513Schristos   ret->next = NULL;
47316dce513Schristos   ret->name = xstrdup (name);
47416dce513Schristos   ret->align = align;
47516dce513Schristos   ret->buffers = NULL;
47616dce513Schristos   ret->last_buffer = NULL;
47716dce513Schristos 
47816dce513Schristos   if (sobj->last_section == NULL)
47916dce513Schristos     {
48016dce513Schristos       sobj->sections = ret;
48116dce513Schristos       sobj->last_section = ret;
48216dce513Schristos     }
48316dce513Schristos   else
48416dce513Schristos     {
48516dce513Schristos       sobj->last_section->next = ret;
48616dce513Schristos       sobj->last_section = ret;
48716dce513Schristos     }
48816dce513Schristos 
48916dce513Schristos   return ret;
49016dce513Schristos }
49116dce513Schristos 
49216dce513Schristos /* Add data to a section.  */
49316dce513Schristos 
49416dce513Schristos const char *
simple_object_write_add_data(simple_object_write * sobj ATTRIBUTE_UNUSED,simple_object_write_section * section,const void * buffer,size_t size,int copy,int * err ATTRIBUTE_UNUSED)49516dce513Schristos simple_object_write_add_data (simple_object_write *sobj ATTRIBUTE_UNUSED,
49616dce513Schristos 			      simple_object_write_section *section,
49716dce513Schristos 			      const void *buffer,
49816dce513Schristos 			      size_t size, int copy,
49916dce513Schristos 			      int *err ATTRIBUTE_UNUSED)
50016dce513Schristos {
50116dce513Schristos   struct simple_object_write_section_buffer *wsb;
50216dce513Schristos 
50316dce513Schristos   wsb = XNEW (struct simple_object_write_section_buffer);
50416dce513Schristos   wsb->next = NULL;
50516dce513Schristos   wsb->size = size;
50616dce513Schristos 
50716dce513Schristos   if (!copy)
50816dce513Schristos     {
50916dce513Schristos       wsb->buffer = buffer;
51016dce513Schristos       wsb->free_buffer = NULL;
51116dce513Schristos     }
51216dce513Schristos   else
51316dce513Schristos     {
51416dce513Schristos       wsb->free_buffer = (void *) XNEWVEC (char, size);
51516dce513Schristos       memcpy (wsb->free_buffer, buffer, size);
51616dce513Schristos       wsb->buffer = wsb->free_buffer;
51716dce513Schristos     }
51816dce513Schristos 
51916dce513Schristos   if (section->last_buffer == NULL)
52016dce513Schristos     {
52116dce513Schristos       section->buffers = wsb;
52216dce513Schristos       section->last_buffer = wsb;
52316dce513Schristos     }
52416dce513Schristos   else
52516dce513Schristos     {
52616dce513Schristos       section->last_buffer->next = wsb;
52716dce513Schristos       section->last_buffer = wsb;
52816dce513Schristos     }
52916dce513Schristos 
53016dce513Schristos   return NULL;
53116dce513Schristos }
53216dce513Schristos 
53316dce513Schristos /* Write the complete object file.  */
53416dce513Schristos 
53516dce513Schristos const char *
simple_object_write_to_file(simple_object_write * sobj,int descriptor,int * err)53616dce513Schristos simple_object_write_to_file (simple_object_write *sobj, int descriptor,
53716dce513Schristos 			     int *err)
53816dce513Schristos {
53916dce513Schristos   return sobj->functions->write_to_file (sobj, descriptor, err);
54016dce513Schristos }
54116dce513Schristos 
54216dce513Schristos /* Release an simple_object_write.  */
54316dce513Schristos 
54416dce513Schristos void
simple_object_release_write(simple_object_write * sobj)54516dce513Schristos simple_object_release_write (simple_object_write *sobj)
54616dce513Schristos {
54716dce513Schristos   simple_object_write_section *section;
54816dce513Schristos 
54916dce513Schristos   free (sobj->segment_name);
55016dce513Schristos 
55116dce513Schristos   section = sobj->sections;
55216dce513Schristos   while (section != NULL)
55316dce513Schristos     {
55416dce513Schristos       struct simple_object_write_section_buffer *buffer;
55516dce513Schristos       simple_object_write_section *next_section;
55616dce513Schristos 
55716dce513Schristos       buffer = section->buffers;
55816dce513Schristos       while (buffer != NULL)
55916dce513Schristos 	{
56016dce513Schristos 	  struct simple_object_write_section_buffer *next_buffer;
56116dce513Schristos 
56216dce513Schristos 	  if (buffer->free_buffer != NULL)
56316dce513Schristos 	    XDELETEVEC (buffer->free_buffer);
56416dce513Schristos 	  next_buffer = buffer->next;
56516dce513Schristos 	  XDELETE (buffer);
56616dce513Schristos 	  buffer = next_buffer;
56716dce513Schristos 	}
56816dce513Schristos 
56916dce513Schristos       next_section = section->next;
57016dce513Schristos       free (section->name);
57116dce513Schristos       XDELETE (section);
57216dce513Schristos       section = next_section;
57316dce513Schristos     }
57416dce513Schristos 
57516dce513Schristos   sobj->functions->release_write (sobj->data);
57616dce513Schristos   XDELETE (sobj);
57716dce513Schristos }
578