138fd1498Szrj /* simple-object.c -- simple routines to read and write object files.
238fd1498Szrj    Copyright (C) 2010-2018 Free Software Foundation, Inc.
338fd1498Szrj    Written by Ian Lance Taylor, Google.
438fd1498Szrj 
538fd1498Szrj This program is free software; you can redistribute it and/or modify it
638fd1498Szrj under the terms of the GNU General Public License as published by the
738fd1498Szrj Free Software Foundation; either version 2, or (at your option) any
838fd1498Szrj later version.
938fd1498Szrj 
1038fd1498Szrj This program is distributed in the hope that it will be useful,
1138fd1498Szrj but WITHOUT ANY WARRANTY; without even the implied warranty of
1238fd1498Szrj MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1338fd1498Szrj GNU General Public License for more details.
1438fd1498Szrj 
1538fd1498Szrj You should have received a copy of the GNU General Public License
1638fd1498Szrj along with this program; if not, write to the Free Software
1738fd1498Szrj Foundation, 51 Franklin Street - Fifth Floor,
1838fd1498Szrj Boston, MA 02110-1301, USA.  */
1938fd1498Szrj 
2038fd1498Szrj #include "config.h"
2138fd1498Szrj #include "libiberty.h"
2238fd1498Szrj #include "simple-object.h"
2338fd1498Szrj 
2438fd1498Szrj #include <errno.h>
2538fd1498Szrj #include <fcntl.h>
2638fd1498Szrj 
2738fd1498Szrj #ifdef HAVE_STDLIB_H
2838fd1498Szrj #include <stdlib.h>
2938fd1498Szrj #endif
3038fd1498Szrj 
3138fd1498Szrj #ifdef HAVE_STDINT_H
3238fd1498Szrj #include <stdint.h>
3338fd1498Szrj #endif
3438fd1498Szrj 
3538fd1498Szrj #ifdef HAVE_STRING_H
3638fd1498Szrj #include <string.h>
3738fd1498Szrj #endif
3838fd1498Szrj 
3938fd1498Szrj #ifdef HAVE_INTTYPES_H
4038fd1498Szrj #include <inttypes.h>
4138fd1498Szrj #endif
4238fd1498Szrj 
4338fd1498Szrj #ifndef SEEK_SET
4438fd1498Szrj #define SEEK_SET 0
4538fd1498Szrj #endif
4638fd1498Szrj 
47*58e805e6Szrj #ifndef O_BINARY
48*58e805e6Szrj #define O_BINARY 0
49*58e805e6Szrj #endif
50*58e805e6Szrj 
5138fd1498Szrj #include "simple-object-common.h"
5238fd1498Szrj 
5338fd1498Szrj /* The known object file formats.  */
5438fd1498Szrj 
5538fd1498Szrj static const struct simple_object_functions * const format_functions[] =
5638fd1498Szrj {
5738fd1498Szrj   &simple_object_elf_functions,
5838fd1498Szrj   &simple_object_mach_o_functions,
5938fd1498Szrj   &simple_object_coff_functions,
6038fd1498Szrj   &simple_object_xcoff_functions
6138fd1498Szrj };
6238fd1498Szrj 
6338fd1498Szrj /* Read data from a file using the simple_object error reporting
6438fd1498Szrj    conventions.  */
6538fd1498Szrj 
6638fd1498Szrj int
simple_object_internal_read(int descriptor,off_t offset,unsigned char * buffer,size_t size,const char ** errmsg,int * err)6738fd1498Szrj simple_object_internal_read (int descriptor, off_t offset,
6838fd1498Szrj 			     unsigned char *buffer, size_t size,
6938fd1498Szrj 			     const char **errmsg, int *err)
7038fd1498Szrj {
7138fd1498Szrj   if (lseek (descriptor, offset, SEEK_SET) < 0)
7238fd1498Szrj     {
7338fd1498Szrj       *errmsg = "lseek";
7438fd1498Szrj       *err = errno;
7538fd1498Szrj       return 0;
7638fd1498Szrj     }
7738fd1498Szrj 
7838fd1498Szrj   do
7938fd1498Szrj     {
8038fd1498Szrj       ssize_t got = read (descriptor, buffer, size);
8138fd1498Szrj       if (got == 0)
8238fd1498Szrj 	break;
8338fd1498Szrj       else if (got > 0)
8438fd1498Szrj 	{
8538fd1498Szrj 	  buffer += got;
8638fd1498Szrj 	  size -= got;
8738fd1498Szrj 	}
8838fd1498Szrj       else if (errno != EINTR)
8938fd1498Szrj 	{
9038fd1498Szrj 	  *errmsg = "read";
9138fd1498Szrj 	  *err = errno;
9238fd1498Szrj 	  return 0;
9338fd1498Szrj 	}
9438fd1498Szrj     }
9538fd1498Szrj   while (size > 0);
9638fd1498Szrj 
9738fd1498Szrj   if (size > 0)
9838fd1498Szrj     {
9938fd1498Szrj       *errmsg = "file too short";
10038fd1498Szrj       *err = 0;
10138fd1498Szrj       return 0;
10238fd1498Szrj     }
10338fd1498Szrj 
10438fd1498Szrj   return 1;
10538fd1498Szrj }
10638fd1498Szrj 
10738fd1498Szrj /* Write data to a file using the simple_object error reporting
10838fd1498Szrj    conventions.  */
10938fd1498Szrj 
11038fd1498Szrj int
simple_object_internal_write(int descriptor,off_t offset,const unsigned char * buffer,size_t size,const char ** errmsg,int * err)11138fd1498Szrj simple_object_internal_write (int descriptor, off_t offset,
11238fd1498Szrj 			      const unsigned char *buffer, size_t size,
11338fd1498Szrj 			      const char **errmsg, int *err)
11438fd1498Szrj {
11538fd1498Szrj   if (lseek (descriptor, offset, SEEK_SET) < 0)
11638fd1498Szrj     {
11738fd1498Szrj       *errmsg = "lseek";
11838fd1498Szrj       *err = errno;
11938fd1498Szrj       return 0;
12038fd1498Szrj     }
12138fd1498Szrj 
12238fd1498Szrj   do
12338fd1498Szrj     {
12438fd1498Szrj       ssize_t wrote = write (descriptor, buffer, size);
12538fd1498Szrj       if (wrote == 0)
12638fd1498Szrj 	break;
12738fd1498Szrj       else if (wrote > 0)
12838fd1498Szrj 	{
12938fd1498Szrj 	  buffer += wrote;
13038fd1498Szrj 	  size -= wrote;
13138fd1498Szrj 	}
13238fd1498Szrj       else if (errno != EINTR)
13338fd1498Szrj 	{
13438fd1498Szrj 	  *errmsg = "write";
13538fd1498Szrj 	  *err = errno;
13638fd1498Szrj 	  return 0;
13738fd1498Szrj 	}
13838fd1498Szrj     }
13938fd1498Szrj   while (size > 0);
14038fd1498Szrj 
14138fd1498Szrj   if (size > 0)
14238fd1498Szrj     {
14338fd1498Szrj       *errmsg = "short write";
14438fd1498Szrj       *err = 0;
14538fd1498Szrj       return 0;
14638fd1498Szrj     }
14738fd1498Szrj 
14838fd1498Szrj   return 1;
14938fd1498Szrj }
15038fd1498Szrj 
15138fd1498Szrj /* Open for read.  */
15238fd1498Szrj 
15338fd1498Szrj simple_object_read *
simple_object_start_read(int descriptor,off_t offset,const char * segment_name,const char ** errmsg,int * err)15438fd1498Szrj simple_object_start_read (int descriptor, off_t offset,
15538fd1498Szrj 			  const char *segment_name, const char **errmsg,
15638fd1498Szrj 			  int *err)
15738fd1498Szrj {
15838fd1498Szrj   unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN];
15938fd1498Szrj   size_t len, i;
16038fd1498Szrj 
16138fd1498Szrj   if (!simple_object_internal_read (descriptor, offset, header,
16238fd1498Szrj 				    SIMPLE_OBJECT_MATCH_HEADER_LEN,
16338fd1498Szrj 				    errmsg, err))
16438fd1498Szrj     return NULL;
16538fd1498Szrj 
16638fd1498Szrj   len = sizeof (format_functions) / sizeof (format_functions[0]);
16738fd1498Szrj   for (i = 0; i < len; ++i)
16838fd1498Szrj     {
16938fd1498Szrj       void *data;
17038fd1498Szrj 
17138fd1498Szrj       data = format_functions[i]->match (header, descriptor, offset,
17238fd1498Szrj 					 segment_name, errmsg, err);
17338fd1498Szrj       if (data != NULL)
17438fd1498Szrj 	{
17538fd1498Szrj 	  simple_object_read *ret;
17638fd1498Szrj 
17738fd1498Szrj 	  ret = XNEW (simple_object_read);
17838fd1498Szrj 	  ret->descriptor = descriptor;
17938fd1498Szrj 	  ret->offset = offset;
18038fd1498Szrj 	  ret->functions = format_functions[i];
18138fd1498Szrj 	  ret->data = data;
18238fd1498Szrj 	  return ret;
18338fd1498Szrj 	}
18438fd1498Szrj     }
18538fd1498Szrj 
18638fd1498Szrj   *errmsg = "file not recognized";
18738fd1498Szrj   *err = 0;
18838fd1498Szrj   return NULL;
18938fd1498Szrj }
19038fd1498Szrj 
19138fd1498Szrj /* Find all sections.  */
19238fd1498Szrj 
19338fd1498Szrj const char *
simple_object_find_sections(simple_object_read * sobj,int (* pfn)(void *,const char *,off_t,off_t),void * data,int * err)19438fd1498Szrj simple_object_find_sections (simple_object_read *sobj,
19538fd1498Szrj 			     int (*pfn) (void *, const char *, off_t, off_t),
19638fd1498Szrj 			     void *data,
19738fd1498Szrj 			     int *err)
19838fd1498Szrj {
19938fd1498Szrj   return sobj->functions->find_sections (sobj, pfn, data, err);
20038fd1498Szrj }
20138fd1498Szrj 
20238fd1498Szrj /* Internal data passed to find_one_section.  */
20338fd1498Szrj 
20438fd1498Szrj struct find_one_section_data
20538fd1498Szrj {
20638fd1498Szrj   /* The section we are looking for.  */
20738fd1498Szrj   const char *name;
20838fd1498Szrj   /* Where to store the section offset.  */
20938fd1498Szrj   off_t *offset;
21038fd1498Szrj   /* Where to store the section length.  */
21138fd1498Szrj   off_t *length;
21238fd1498Szrj   /* Set if the name is found.  */
21338fd1498Szrj   int found;
21438fd1498Szrj };
21538fd1498Szrj 
21638fd1498Szrj /* Internal function passed to find_sections.  */
21738fd1498Szrj 
21838fd1498Szrj static int
find_one_section(void * data,const char * name,off_t offset,off_t length)21938fd1498Szrj find_one_section (void *data, const char *name, off_t offset, off_t length)
22038fd1498Szrj {
22138fd1498Szrj   struct find_one_section_data *fosd = (struct find_one_section_data *) data;
22238fd1498Szrj 
22338fd1498Szrj   if (strcmp (name, fosd->name) != 0)
22438fd1498Szrj     return 1;
22538fd1498Szrj 
22638fd1498Szrj   *fosd->offset = offset;
22738fd1498Szrj   *fosd->length = length;
22838fd1498Szrj   fosd->found = 1;
22938fd1498Szrj 
23038fd1498Szrj   /* Stop iteration.  */
23138fd1498Szrj   return 0;
23238fd1498Szrj }
23338fd1498Szrj 
23438fd1498Szrj /* Find a section.  */
23538fd1498Szrj 
23638fd1498Szrj int
simple_object_find_section(simple_object_read * sobj,const char * name,off_t * offset,off_t * length,const char ** errmsg,int * err)23738fd1498Szrj simple_object_find_section (simple_object_read *sobj, const char *name,
23838fd1498Szrj 			    off_t *offset, off_t *length,
23938fd1498Szrj 			    const char **errmsg, int *err)
24038fd1498Szrj {
24138fd1498Szrj   struct find_one_section_data fosd;
24238fd1498Szrj 
24338fd1498Szrj   fosd.name = name;
24438fd1498Szrj   fosd.offset = offset;
24538fd1498Szrj   fosd.length = length;
24638fd1498Szrj   fosd.found = 0;
24738fd1498Szrj 
24838fd1498Szrj   *errmsg = simple_object_find_sections (sobj, find_one_section,
24938fd1498Szrj 					 (void *) &fosd, err);
25038fd1498Szrj   if (*errmsg != NULL)
25138fd1498Szrj     return 0;
25238fd1498Szrj   if (!fosd.found)
25338fd1498Szrj     return 0;
25438fd1498Szrj   return 1;
25538fd1498Szrj }
25638fd1498Szrj 
25738fd1498Szrj /* Callback to identify and rename LTO debug sections by name.
25838fd1498Szrj    Returns 1 if NAME is a LTO debug section, 0 if not.  */
25938fd1498Szrj 
26038fd1498Szrj static char *
handle_lto_debug_sections(const char * name)26138fd1498Szrj handle_lto_debug_sections (const char *name)
26238fd1498Szrj {
26338fd1498Szrj   char *newname = XCNEWVEC (char, strlen (name) + 1);
26438fd1498Szrj 
26538fd1498Szrj   /* ???  So we can't use .gnu.lto_ prefixed sections as the assembler
26638fd1498Szrj      complains about bogus section flags.  Which means we need to arrange
26738fd1498Szrj      for that to be fixed or .gnu.debuglto_ marked as SHF_EXCLUDE (to make
26838fd1498Szrj      fat lto object tooling work for the fat part).  */
26938fd1498Szrj   /* Also include corresponding reloc sections.  */
27038fd1498Szrj   if (strncmp (name, ".rela", sizeof (".rela") - 1) == 0)
27138fd1498Szrj     {
27238fd1498Szrj       strncpy (newname, name, sizeof (".rela") - 1);
27338fd1498Szrj       name += sizeof (".rela") - 1;
27438fd1498Szrj     }
27538fd1498Szrj   else if (strncmp (name, ".rel", sizeof (".rel") - 1) == 0)
27638fd1498Szrj     {
27738fd1498Szrj       strncpy (newname, name, sizeof (".rel") - 1);
27838fd1498Szrj       name += sizeof (".rel") - 1;
27938fd1498Szrj     }
28038fd1498Szrj   /* ???  For now this handles both .gnu.lto_ and .gnu.debuglto_ prefixed
28138fd1498Szrj      sections.  */
28238fd1498Szrj   /* Copy LTO debug sections and rename them to their non-LTO name.  */
28338fd1498Szrj   if (strncmp (name, ".gnu.debuglto_", sizeof (".gnu.debuglto_") - 1) == 0)
28438fd1498Szrj     return strcat (newname, name + sizeof (".gnu.debuglto_") - 1);
28538fd1498Szrj   else if (strncmp (name, ".gnu.lto_.debug_",
28638fd1498Szrj 		    sizeof (".gnu.lto_.debug_") -1) == 0)
28738fd1498Szrj     return strcat (newname, name + sizeof (".gnu.lto_") - 1);
28838fd1498Szrj   /* Copy over .note.GNU-stack section under the same name if present.  */
28938fd1498Szrj   else if (strcmp (name, ".note.GNU-stack") == 0)
29038fd1498Szrj     return strcpy (newname, name);
29138fd1498Szrj   /* Copy over .comment section under the same name if present.  Solaris
29238fd1498Szrj      ld uses them to relax its checking of ELF gABI access rules for
29338fd1498Szrj      COMDAT sections in objects produced by GCC.  */
29438fd1498Szrj   else if (strcmp (name, ".comment") == 0)
29538fd1498Szrj     return strcpy (newname, name);
29638fd1498Szrj   return NULL;
29738fd1498Szrj }
29838fd1498Szrj 
29938fd1498Szrj /* Copy LTO debug sections.  */
30038fd1498Szrj 
30138fd1498Szrj const char *
simple_object_copy_lto_debug_sections(simple_object_read * sobj,const char * dest,int * err)30238fd1498Szrj simple_object_copy_lto_debug_sections (simple_object_read *sobj,
30338fd1498Szrj 				       const char *dest, int *err)
30438fd1498Szrj {
30538fd1498Szrj   const char *errmsg;
30638fd1498Szrj   simple_object_write *dest_sobj;
30738fd1498Szrj   simple_object_attributes *attrs;
30838fd1498Szrj   int outfd;
30938fd1498Szrj 
31038fd1498Szrj   if (! sobj->functions->copy_lto_debug_sections)
31138fd1498Szrj     {
31238fd1498Szrj       *err = EINVAL;
31338fd1498Szrj       return "simple_object_copy_lto_debug_sections not implemented";
31438fd1498Szrj     }
31538fd1498Szrj 
31638fd1498Szrj   attrs = simple_object_fetch_attributes (sobj, &errmsg, err);
31738fd1498Szrj   if (! attrs)
31838fd1498Szrj     return errmsg;
31938fd1498Szrj   dest_sobj = simple_object_start_write (attrs, NULL, &errmsg, err);
32038fd1498Szrj   simple_object_release_attributes (attrs);
32138fd1498Szrj   if (! dest_sobj)
32238fd1498Szrj     return errmsg;
32338fd1498Szrj 
32438fd1498Szrj   errmsg = sobj->functions->copy_lto_debug_sections (sobj, dest_sobj,
32538fd1498Szrj 						     handle_lto_debug_sections,
32638fd1498Szrj 						     err);
32738fd1498Szrj   if (errmsg)
32838fd1498Szrj     {
32938fd1498Szrj       simple_object_release_write (dest_sobj);
33038fd1498Szrj       return errmsg;
33138fd1498Szrj     }
33238fd1498Szrj 
333*58e805e6Szrj   outfd = open (dest, O_CREAT|O_WRONLY|O_TRUNC|O_BINARY, 00777);
33438fd1498Szrj   if (outfd == -1)
33538fd1498Szrj     {
33638fd1498Szrj       *err = errno;
33738fd1498Szrj       simple_object_release_write (dest_sobj);
33838fd1498Szrj       return "open failed";
33938fd1498Szrj     }
34038fd1498Szrj 
34138fd1498Szrj   errmsg = simple_object_write_to_file (dest_sobj, outfd, err);
34238fd1498Szrj   close (outfd);
34338fd1498Szrj   if (errmsg)
34438fd1498Szrj     {
34538fd1498Szrj       simple_object_release_write (dest_sobj);
34638fd1498Szrj       return errmsg;
34738fd1498Szrj     }
34838fd1498Szrj 
34938fd1498Szrj   simple_object_release_write (dest_sobj);
35038fd1498Szrj   return NULL;
35138fd1498Szrj }
35238fd1498Szrj 
35338fd1498Szrj /* Fetch attributes.  */
35438fd1498Szrj 
35538fd1498Szrj simple_object_attributes *
simple_object_fetch_attributes(simple_object_read * sobj,const char ** errmsg,int * err)35638fd1498Szrj simple_object_fetch_attributes (simple_object_read *sobj, const char **errmsg,
35738fd1498Szrj 				int *err)
35838fd1498Szrj {
35938fd1498Szrj   void *data;
36038fd1498Szrj   simple_object_attributes *ret;
36138fd1498Szrj 
36238fd1498Szrj   data = sobj->functions->fetch_attributes (sobj, errmsg, err);
36338fd1498Szrj   if (data == NULL)
36438fd1498Szrj     return NULL;
36538fd1498Szrj   ret = XNEW (simple_object_attributes);
36638fd1498Szrj   ret->functions = sobj->functions;
36738fd1498Szrj   ret->data = data;
36838fd1498Szrj   return ret;
36938fd1498Szrj }
37038fd1498Szrj 
37138fd1498Szrj /* Release an simple_object_read.  */
37238fd1498Szrj 
37338fd1498Szrj void
simple_object_release_read(simple_object_read * sobj)37438fd1498Szrj simple_object_release_read (simple_object_read *sobj)
37538fd1498Szrj {
37638fd1498Szrj   sobj->functions->release_read (sobj->data);
37738fd1498Szrj   XDELETE (sobj);
37838fd1498Szrj }
37938fd1498Szrj 
38038fd1498Szrj /* Merge attributes.  */
38138fd1498Szrj 
38238fd1498Szrj const char *
simple_object_attributes_merge(simple_object_attributes * to,simple_object_attributes * from,int * err)38338fd1498Szrj simple_object_attributes_merge (simple_object_attributes *to,
38438fd1498Szrj 				simple_object_attributes *from,
38538fd1498Szrj 				int *err)
38638fd1498Szrj {
38738fd1498Szrj   if (to->functions != from->functions)
38838fd1498Szrj     {
38938fd1498Szrj       *err = 0;
39038fd1498Szrj       return "different object file format";
39138fd1498Szrj     }
39238fd1498Szrj   return to->functions->attributes_merge (to->data, from->data, err);
39338fd1498Szrj }
39438fd1498Szrj 
39538fd1498Szrj /* Release an attributes structure.  */
39638fd1498Szrj 
39738fd1498Szrj void
simple_object_release_attributes(simple_object_attributes * attrs)39838fd1498Szrj simple_object_release_attributes (simple_object_attributes *attrs)
39938fd1498Szrj {
40038fd1498Szrj   attrs->functions->release_attributes (attrs->data);
40138fd1498Szrj   XDELETE (attrs);
40238fd1498Szrj }
40338fd1498Szrj 
40438fd1498Szrj /* Start creating an object file.  */
40538fd1498Szrj 
40638fd1498Szrj simple_object_write *
simple_object_start_write(simple_object_attributes * attrs,const char * segment_name,const char ** errmsg,int * err)40738fd1498Szrj simple_object_start_write (simple_object_attributes *attrs,
40838fd1498Szrj 			   const char *segment_name, const char **errmsg,
40938fd1498Szrj 			   int *err)
41038fd1498Szrj {
41138fd1498Szrj   void *data;
41238fd1498Szrj   simple_object_write *ret;
41338fd1498Szrj 
41438fd1498Szrj   data = attrs->functions->start_write (attrs->data, errmsg, err);
41538fd1498Szrj   if (data == NULL)
41638fd1498Szrj     return NULL;
41738fd1498Szrj   ret = XNEW (simple_object_write);
41838fd1498Szrj   ret->functions = attrs->functions;
41938fd1498Szrj   ret->segment_name = segment_name ? xstrdup (segment_name) : NULL;
42038fd1498Szrj   ret->sections = NULL;
42138fd1498Szrj   ret->last_section = NULL;
42238fd1498Szrj   ret->data = data;
42338fd1498Szrj   return ret;
42438fd1498Szrj }
42538fd1498Szrj 
42638fd1498Szrj /* Start creating a section.  */
42738fd1498Szrj 
42838fd1498Szrj 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)42938fd1498Szrj simple_object_write_create_section (simple_object_write *sobj, const char *name,
43038fd1498Szrj 				    unsigned int align,
43138fd1498Szrj 				    const char **errmsg ATTRIBUTE_UNUSED,
43238fd1498Szrj 				    int *err ATTRIBUTE_UNUSED)
43338fd1498Szrj {
43438fd1498Szrj   simple_object_write_section *ret;
43538fd1498Szrj 
43638fd1498Szrj   ret = XNEW (simple_object_write_section);
43738fd1498Szrj   ret->next = NULL;
43838fd1498Szrj   ret->name = xstrdup (name);
43938fd1498Szrj   ret->align = align;
44038fd1498Szrj   ret->buffers = NULL;
44138fd1498Szrj   ret->last_buffer = NULL;
44238fd1498Szrj 
44338fd1498Szrj   if (sobj->last_section == NULL)
44438fd1498Szrj     {
44538fd1498Szrj       sobj->sections = ret;
44638fd1498Szrj       sobj->last_section = ret;
44738fd1498Szrj     }
44838fd1498Szrj   else
44938fd1498Szrj     {
45038fd1498Szrj       sobj->last_section->next = ret;
45138fd1498Szrj       sobj->last_section = ret;
45238fd1498Szrj     }
45338fd1498Szrj 
45438fd1498Szrj   return ret;
45538fd1498Szrj }
45638fd1498Szrj 
45738fd1498Szrj /* Add data to a section.  */
45838fd1498Szrj 
45938fd1498Szrj 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)46038fd1498Szrj simple_object_write_add_data (simple_object_write *sobj ATTRIBUTE_UNUSED,
46138fd1498Szrj 			      simple_object_write_section *section,
46238fd1498Szrj 			      const void *buffer,
46338fd1498Szrj 			      size_t size, int copy,
46438fd1498Szrj 			      int *err ATTRIBUTE_UNUSED)
46538fd1498Szrj {
46638fd1498Szrj   struct simple_object_write_section_buffer *wsb;
46738fd1498Szrj 
46838fd1498Szrj   wsb = XNEW (struct simple_object_write_section_buffer);
46938fd1498Szrj   wsb->next = NULL;
47038fd1498Szrj   wsb->size = size;
47138fd1498Szrj 
47238fd1498Szrj   if (!copy)
47338fd1498Szrj     {
47438fd1498Szrj       wsb->buffer = buffer;
47538fd1498Szrj       wsb->free_buffer = NULL;
47638fd1498Szrj     }
47738fd1498Szrj   else
47838fd1498Szrj     {
47938fd1498Szrj       wsb->free_buffer = (void *) XNEWVEC (char, size);
48038fd1498Szrj       memcpy (wsb->free_buffer, buffer, size);
48138fd1498Szrj       wsb->buffer = wsb->free_buffer;
48238fd1498Szrj     }
48338fd1498Szrj 
48438fd1498Szrj   if (section->last_buffer == NULL)
48538fd1498Szrj     {
48638fd1498Szrj       section->buffers = wsb;
48738fd1498Szrj       section->last_buffer = wsb;
48838fd1498Szrj     }
48938fd1498Szrj   else
49038fd1498Szrj     {
49138fd1498Szrj       section->last_buffer->next = wsb;
49238fd1498Szrj       section->last_buffer = wsb;
49338fd1498Szrj     }
49438fd1498Szrj 
49538fd1498Szrj   return NULL;
49638fd1498Szrj }
49738fd1498Szrj 
49838fd1498Szrj /* Write the complete object file.  */
49938fd1498Szrj 
50038fd1498Szrj const char *
simple_object_write_to_file(simple_object_write * sobj,int descriptor,int * err)50138fd1498Szrj simple_object_write_to_file (simple_object_write *sobj, int descriptor,
50238fd1498Szrj 			     int *err)
50338fd1498Szrj {
50438fd1498Szrj   return sobj->functions->write_to_file (sobj, descriptor, err);
50538fd1498Szrj }
50638fd1498Szrj 
50738fd1498Szrj /* Release an simple_object_write.  */
50838fd1498Szrj 
50938fd1498Szrj void
simple_object_release_write(simple_object_write * sobj)51038fd1498Szrj simple_object_release_write (simple_object_write *sobj)
51138fd1498Szrj {
51238fd1498Szrj   simple_object_write_section *section;
51338fd1498Szrj 
51438fd1498Szrj   free (sobj->segment_name);
51538fd1498Szrj 
51638fd1498Szrj   section = sobj->sections;
51738fd1498Szrj   while (section != NULL)
51838fd1498Szrj     {
51938fd1498Szrj       struct simple_object_write_section_buffer *buffer;
52038fd1498Szrj       simple_object_write_section *next_section;
52138fd1498Szrj 
52238fd1498Szrj       buffer = section->buffers;
52338fd1498Szrj       while (buffer != NULL)
52438fd1498Szrj 	{
52538fd1498Szrj 	  struct simple_object_write_section_buffer *next_buffer;
52638fd1498Szrj 
52738fd1498Szrj 	  if (buffer->free_buffer != NULL)
52838fd1498Szrj 	    XDELETEVEC (buffer->free_buffer);
52938fd1498Szrj 	  next_buffer = buffer->next;
53038fd1498Szrj 	  XDELETE (buffer);
53138fd1498Szrj 	  buffer = next_buffer;
53238fd1498Szrj 	}
53338fd1498Szrj 
53438fd1498Szrj       next_section = section->next;
53538fd1498Szrj       free (section->name);
53638fd1498Szrj       XDELETE (section);
53738fd1498Szrj       section = next_section;
53838fd1498Szrj     }
53938fd1498Szrj 
54038fd1498Szrj   sobj->functions->release_write (sobj->data);
54138fd1498Szrj   XDELETE (sobj);
54238fd1498Szrj }
543