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