198b9484cSchristos /* simple-object.c -- simple routines to read and write object files. 2*7e120ff0Schristos Copyright (C) 2010-2024 Free Software Foundation, Inc. 398b9484cSchristos Written by Ian Lance Taylor, Google. 498b9484cSchristos 598b9484cSchristos This program is free software; you can redistribute it and/or modify it 698b9484cSchristos under the terms of the GNU General Public License as published by the 798b9484cSchristos Free Software Foundation; either version 2, or (at your option) any 898b9484cSchristos later version. 998b9484cSchristos 1098b9484cSchristos This program is distributed in the hope that it will be useful, 1198b9484cSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of 1298b9484cSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1398b9484cSchristos GNU General Public License for more details. 1498b9484cSchristos 1598b9484cSchristos You should have received a copy of the GNU General Public License 1698b9484cSchristos along with this program; if not, write to the Free Software 1798b9484cSchristos Foundation, 51 Franklin Street - Fifth Floor, 1898b9484cSchristos Boston, MA 02110-1301, USA. */ 1998b9484cSchristos 2098b9484cSchristos #include "config.h" 2198b9484cSchristos #include "libiberty.h" 2298b9484cSchristos #include "simple-object.h" 2398b9484cSchristos 2498b9484cSchristos #include <errno.h> 254559860eSchristos #include <fcntl.h> 2698b9484cSchristos 2798b9484cSchristos #ifdef HAVE_STDLIB_H 2898b9484cSchristos #include <stdlib.h> 2998b9484cSchristos #endif 3098b9484cSchristos 3198b9484cSchristos #ifdef HAVE_STDINT_H 3298b9484cSchristos #include <stdint.h> 3398b9484cSchristos #endif 3498b9484cSchristos 3598b9484cSchristos #ifdef HAVE_STRING_H 3698b9484cSchristos #include <string.h> 3798b9484cSchristos #endif 3898b9484cSchristos 3998b9484cSchristos #ifdef HAVE_INTTYPES_H 4098b9484cSchristos #include <inttypes.h> 4198b9484cSchristos #endif 4298b9484cSchristos 4398b9484cSchristos #ifndef SEEK_SET 4498b9484cSchristos #define SEEK_SET 0 4598b9484cSchristos #endif 4698b9484cSchristos 478dffb485Schristos #ifndef O_BINARY 488dffb485Schristos #define O_BINARY 0 498dffb485Schristos #endif 508dffb485Schristos 5198b9484cSchristos #include "simple-object-common.h" 5298b9484cSchristos 5398b9484cSchristos /* The known object file formats. */ 5498b9484cSchristos 5598b9484cSchristos static const struct simple_object_functions * const format_functions[] = 5698b9484cSchristos { 5798b9484cSchristos &simple_object_elf_functions, 5898b9484cSchristos &simple_object_mach_o_functions, 59a2e2270fSchristos &simple_object_coff_functions, 60a2e2270fSchristos &simple_object_xcoff_functions 6198b9484cSchristos }; 6298b9484cSchristos 6398b9484cSchristos /* Read data from a file using the simple_object error reporting 6498b9484cSchristos conventions. */ 6598b9484cSchristos 6698b9484cSchristos int 6798b9484cSchristos simple_object_internal_read (int descriptor, off_t offset, 6898b9484cSchristos unsigned char *buffer, size_t size, 6998b9484cSchristos const char **errmsg, int *err) 7098b9484cSchristos { 7198b9484cSchristos if (lseek (descriptor, offset, SEEK_SET) < 0) 7298b9484cSchristos { 7398b9484cSchristos *errmsg = "lseek"; 7498b9484cSchristos *err = errno; 7598b9484cSchristos return 0; 7698b9484cSchristos } 7798b9484cSchristos 78837edd6bSchristos do 79837edd6bSchristos { 80837edd6bSchristos ssize_t got = read (descriptor, buffer, size); 81837edd6bSchristos if (got == 0) 82837edd6bSchristos break; 83837edd6bSchristos else if (got > 0) 84837edd6bSchristos { 85837edd6bSchristos buffer += got; 86837edd6bSchristos size -= got; 87837edd6bSchristos } 88837edd6bSchristos else if (errno != EINTR) 8998b9484cSchristos { 9098b9484cSchristos *errmsg = "read"; 9198b9484cSchristos *err = errno; 9298b9484cSchristos return 0; 9398b9484cSchristos } 94837edd6bSchristos } 95837edd6bSchristos while (size > 0); 9698b9484cSchristos 97837edd6bSchristos if (size > 0) 9898b9484cSchristos { 9998b9484cSchristos *errmsg = "file too short"; 10098b9484cSchristos *err = 0; 10198b9484cSchristos return 0; 10298b9484cSchristos } 10398b9484cSchristos 10498b9484cSchristos return 1; 10598b9484cSchristos } 10698b9484cSchristos 10798b9484cSchristos /* Write data to a file using the simple_object error reporting 10898b9484cSchristos conventions. */ 10998b9484cSchristos 11098b9484cSchristos int 11198b9484cSchristos simple_object_internal_write (int descriptor, off_t offset, 11298b9484cSchristos const unsigned char *buffer, size_t size, 11398b9484cSchristos const char **errmsg, int *err) 11498b9484cSchristos { 11598b9484cSchristos if (lseek (descriptor, offset, SEEK_SET) < 0) 11698b9484cSchristos { 11798b9484cSchristos *errmsg = "lseek"; 11898b9484cSchristos *err = errno; 11998b9484cSchristos return 0; 12098b9484cSchristos } 12198b9484cSchristos 122837edd6bSchristos do 123837edd6bSchristos { 124837edd6bSchristos ssize_t wrote = write (descriptor, buffer, size); 125837edd6bSchristos if (wrote == 0) 126837edd6bSchristos break; 127837edd6bSchristos else if (wrote > 0) 128837edd6bSchristos { 129837edd6bSchristos buffer += wrote; 130837edd6bSchristos size -= wrote; 131837edd6bSchristos } 132837edd6bSchristos else if (errno != EINTR) 13398b9484cSchristos { 13498b9484cSchristos *errmsg = "write"; 13598b9484cSchristos *err = errno; 13698b9484cSchristos return 0; 13798b9484cSchristos } 138837edd6bSchristos } 139837edd6bSchristos while (size > 0); 14098b9484cSchristos 141837edd6bSchristos if (size > 0) 14298b9484cSchristos { 14398b9484cSchristos *errmsg = "short write"; 14498b9484cSchristos *err = 0; 14598b9484cSchristos return 0; 14698b9484cSchristos } 14798b9484cSchristos 14898b9484cSchristos return 1; 14998b9484cSchristos } 15098b9484cSchristos 15198b9484cSchristos /* Open for read. */ 15298b9484cSchristos 15398b9484cSchristos simple_object_read * 15498b9484cSchristos simple_object_start_read (int descriptor, off_t offset, 15598b9484cSchristos const char *segment_name, const char **errmsg, 15698b9484cSchristos int *err) 15798b9484cSchristos { 15898b9484cSchristos unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN]; 15998b9484cSchristos size_t len, i; 16098b9484cSchristos 16198b9484cSchristos if (!simple_object_internal_read (descriptor, offset, header, 16298b9484cSchristos SIMPLE_OBJECT_MATCH_HEADER_LEN, 16398b9484cSchristos errmsg, err)) 16498b9484cSchristos return NULL; 16598b9484cSchristos 16698b9484cSchristos len = sizeof (format_functions) / sizeof (format_functions[0]); 16798b9484cSchristos for (i = 0; i < len; ++i) 16898b9484cSchristos { 16998b9484cSchristos void *data; 17098b9484cSchristos 17198b9484cSchristos data = format_functions[i]->match (header, descriptor, offset, 17298b9484cSchristos segment_name, errmsg, err); 17398b9484cSchristos if (data != NULL) 17498b9484cSchristos { 17598b9484cSchristos simple_object_read *ret; 17698b9484cSchristos 17798b9484cSchristos ret = XNEW (simple_object_read); 17898b9484cSchristos ret->descriptor = descriptor; 17998b9484cSchristos ret->offset = offset; 18098b9484cSchristos ret->functions = format_functions[i]; 18198b9484cSchristos ret->data = data; 18298b9484cSchristos return ret; 18398b9484cSchristos } 18498b9484cSchristos } 18598b9484cSchristos 18698b9484cSchristos *errmsg = "file not recognized"; 18798b9484cSchristos *err = 0; 18898b9484cSchristos return NULL; 18998b9484cSchristos } 19098b9484cSchristos 19198b9484cSchristos /* Find all sections. */ 19298b9484cSchristos 19398b9484cSchristos const char * 19498b9484cSchristos simple_object_find_sections (simple_object_read *sobj, 19598b9484cSchristos int (*pfn) (void *, const char *, off_t, off_t), 19698b9484cSchristos void *data, 19798b9484cSchristos int *err) 19898b9484cSchristos { 19998b9484cSchristos return sobj->functions->find_sections (sobj, pfn, data, err); 20098b9484cSchristos } 20198b9484cSchristos 20298b9484cSchristos /* Internal data passed to find_one_section. */ 20398b9484cSchristos 20498b9484cSchristos struct find_one_section_data 20598b9484cSchristos { 20698b9484cSchristos /* The section we are looking for. */ 20798b9484cSchristos const char *name; 20898b9484cSchristos /* Where to store the section offset. */ 20998b9484cSchristos off_t *offset; 21098b9484cSchristos /* Where to store the section length. */ 21198b9484cSchristos off_t *length; 21298b9484cSchristos /* Set if the name is found. */ 21398b9484cSchristos int found; 21498b9484cSchristos }; 21598b9484cSchristos 21698b9484cSchristos /* Internal function passed to find_sections. */ 21798b9484cSchristos 21898b9484cSchristos static int 21998b9484cSchristos find_one_section (void *data, const char *name, off_t offset, off_t length) 22098b9484cSchristos { 22198b9484cSchristos struct find_one_section_data *fosd = (struct find_one_section_data *) data; 22298b9484cSchristos 22398b9484cSchristos if (strcmp (name, fosd->name) != 0) 22498b9484cSchristos return 1; 22598b9484cSchristos 22698b9484cSchristos *fosd->offset = offset; 22798b9484cSchristos *fosd->length = length; 22898b9484cSchristos fosd->found = 1; 22998b9484cSchristos 23098b9484cSchristos /* Stop iteration. */ 23198b9484cSchristos return 0; 23298b9484cSchristos } 23398b9484cSchristos 23498b9484cSchristos /* Find a section. */ 23598b9484cSchristos 23698b9484cSchristos int 23798b9484cSchristos simple_object_find_section (simple_object_read *sobj, const char *name, 23898b9484cSchristos off_t *offset, off_t *length, 23998b9484cSchristos const char **errmsg, int *err) 24098b9484cSchristos { 24198b9484cSchristos struct find_one_section_data fosd; 24298b9484cSchristos 24398b9484cSchristos fosd.name = name; 24498b9484cSchristos fosd.offset = offset; 24598b9484cSchristos fosd.length = length; 24698b9484cSchristos fosd.found = 0; 24798b9484cSchristos 24898b9484cSchristos *errmsg = simple_object_find_sections (sobj, find_one_section, 24998b9484cSchristos (void *) &fosd, err); 25098b9484cSchristos if (*errmsg != NULL) 25198b9484cSchristos return 0; 25298b9484cSchristos if (!fosd.found) 25398b9484cSchristos return 0; 25498b9484cSchristos return 1; 25598b9484cSchristos } 25698b9484cSchristos 2574559860eSchristos /* Callback to identify and rename LTO debug sections by name. 2584559860eSchristos Returns non-NULL if NAME is a LTO debug section, NULL if not. 2594559860eSchristos If RENAME is true it will rename LTO debug sections to non-LTO 2604559860eSchristos ones. */ 2614559860eSchristos 2624559860eSchristos static char * 2634559860eSchristos handle_lto_debug_sections (const char *name, int rename) 2644559860eSchristos { 2654559860eSchristos char *newname = rename ? XCNEWVEC (char, strlen (name) + 1) 2664559860eSchristos : xstrdup (name); 2674559860eSchristos 2684559860eSchristos /* ??? So we can't use .gnu.lto_ prefixed sections as the assembler 2694559860eSchristos complains about bogus section flags. Which means we need to arrange 2704559860eSchristos for that to be fixed or .gnu.debuglto_ marked as SHF_EXCLUDE (to make 2714559860eSchristos fat lto object tooling work for the fat part). */ 2724559860eSchristos /* Also include corresponding reloc sections. */ 2734559860eSchristos if (strncmp (name, ".rela", sizeof (".rela") - 1) == 0) 2744559860eSchristos { 2754559860eSchristos if (rename) 2764559860eSchristos strncpy (newname, name, sizeof (".rela") - 1); 2774559860eSchristos name += sizeof (".rela") - 1; 2784559860eSchristos } 2794559860eSchristos else if (strncmp (name, ".rel", sizeof (".rel") - 1) == 0) 2804559860eSchristos { 2814559860eSchristos if (rename) 2824559860eSchristos strncpy (newname, name, sizeof (".rel") - 1); 2834559860eSchristos name += sizeof (".rel") - 1; 2844559860eSchristos } 2854559860eSchristos /* ??? For now this handles both .gnu.lto_ and .gnu.debuglto_ prefixed 2864559860eSchristos sections. */ 2874559860eSchristos /* Copy LTO debug sections and rename them to their non-LTO name. */ 2884559860eSchristos if (strncmp (name, ".gnu.debuglto_", sizeof (".gnu.debuglto_") - 1) == 0) 2894559860eSchristos return rename ? strcat (newname, name + sizeof (".gnu.debuglto_") - 1) : newname; 2904559860eSchristos else if (strncmp (name, ".gnu.lto_.debug_", 2914559860eSchristos sizeof (".gnu.lto_.debug_") -1) == 0) 2924559860eSchristos return rename ? strcat (newname, name + sizeof (".gnu.lto_") - 1) : newname; 2934559860eSchristos /* Copy over .note.GNU-stack section under the same name if present. */ 2944559860eSchristos else if (strcmp (name, ".note.GNU-stack") == 0) 2954559860eSchristos return strcpy (newname, name); 2968dffb485Schristos /* Copy over .note.gnu.property section under the same name if present. */ 2978dffb485Schristos else if (strcmp (name, ".note.gnu.property") == 0) 2988dffb485Schristos return strcpy (newname, name); 2994559860eSchristos /* Copy over .comment section under the same name if present. Solaris 3004559860eSchristos ld uses them to relax its checking of ELF gABI access rules for 3014559860eSchristos COMDAT sections in objects produced by GCC. */ 3024559860eSchristos else if (strcmp (name, ".comment") == 0) 3034559860eSchristos return strcpy (newname, name); 3048dffb485Schristos /* Copy over .GCC.command.line section under the same name if present. */ 3058dffb485Schristos else if (strcmp (name, ".GCC.command.line") == 0) 3068dffb485Schristos return strcpy (newname, name); 3074b169a6bSchristos /* Copy over .ctf section under the same name if present. */ 3084b169a6bSchristos else if (strcmp (name, ".ctf") == 0) 3094b169a6bSchristos return strcpy (newname, name); 3104b169a6bSchristos /* Copy over .BTF section under the same name if present. */ 3114b169a6bSchristos else if (strcmp (name, ".BTF") == 0) 3124b169a6bSchristos return strcpy (newname, name); 3134559860eSchristos free (newname); 3144559860eSchristos return NULL; 3154559860eSchristos } 3164559860eSchristos 3174559860eSchristos /* Wrapper for handle_lto_debug_sections. */ 3184559860eSchristos 3194559860eSchristos static char * 3204559860eSchristos handle_lto_debug_sections_rename (const char *name) 3214559860eSchristos { 3224559860eSchristos return handle_lto_debug_sections (name, 1); 3234559860eSchristos } 3244559860eSchristos 3254559860eSchristos /* Wrapper for handle_lto_debug_sections. */ 3264559860eSchristos 3274559860eSchristos static char * 3284559860eSchristos handle_lto_debug_sections_norename (const char *name) 3294559860eSchristos { 3304559860eSchristos return handle_lto_debug_sections (name, 0); 3314559860eSchristos } 3324559860eSchristos 3334559860eSchristos /* Copy LTO debug sections. */ 3344559860eSchristos 3354559860eSchristos const char * 3364559860eSchristos simple_object_copy_lto_debug_sections (simple_object_read *sobj, 3374559860eSchristos const char *dest, int *err, int rename) 3384559860eSchristos { 3394559860eSchristos const char *errmsg; 3404559860eSchristos simple_object_write *dest_sobj; 3414559860eSchristos simple_object_attributes *attrs; 3424559860eSchristos int outfd; 3434559860eSchristos 3444559860eSchristos if (! sobj->functions->copy_lto_debug_sections) 3454559860eSchristos { 3464559860eSchristos *err = EINVAL; 3474559860eSchristos return "simple_object_copy_lto_debug_sections not implemented"; 3484559860eSchristos } 3494559860eSchristos 3504559860eSchristos attrs = simple_object_fetch_attributes (sobj, &errmsg, err); 3514559860eSchristos if (! attrs) 3524559860eSchristos return errmsg; 3534559860eSchristos dest_sobj = simple_object_start_write (attrs, NULL, &errmsg, err); 3544559860eSchristos simple_object_release_attributes (attrs); 3554559860eSchristos if (! dest_sobj) 3564559860eSchristos return errmsg; 3574559860eSchristos 3584559860eSchristos errmsg = sobj->functions->copy_lto_debug_sections 3594559860eSchristos (sobj, dest_sobj, 3604559860eSchristos rename ? handle_lto_debug_sections_rename 3614559860eSchristos : handle_lto_debug_sections_norename, err); 3624559860eSchristos if (errmsg) 3634559860eSchristos { 3644559860eSchristos simple_object_release_write (dest_sobj); 3654559860eSchristos return errmsg; 3664559860eSchristos } 3674559860eSchristos 3688dffb485Schristos outfd = open (dest, O_CREAT|O_WRONLY|O_TRUNC|O_BINARY, 00777); 3694559860eSchristos if (outfd == -1) 3704559860eSchristos { 3714559860eSchristos *err = errno; 3724559860eSchristos simple_object_release_write (dest_sobj); 3734559860eSchristos return "open failed"; 3744559860eSchristos } 3754559860eSchristos 3764559860eSchristos errmsg = simple_object_write_to_file (dest_sobj, outfd, err); 3774559860eSchristos close (outfd); 3784559860eSchristos if (errmsg) 3794559860eSchristos { 3804559860eSchristos simple_object_release_write (dest_sobj); 3814559860eSchristos return errmsg; 3824559860eSchristos } 3834559860eSchristos 3844559860eSchristos simple_object_release_write (dest_sobj); 3854559860eSchristos return NULL; 3864559860eSchristos } 3874559860eSchristos 38898b9484cSchristos /* Fetch attributes. */ 38998b9484cSchristos 39098b9484cSchristos simple_object_attributes * 39198b9484cSchristos simple_object_fetch_attributes (simple_object_read *sobj, const char **errmsg, 39298b9484cSchristos int *err) 39398b9484cSchristos { 39498b9484cSchristos void *data; 39598b9484cSchristos simple_object_attributes *ret; 39698b9484cSchristos 39798b9484cSchristos data = sobj->functions->fetch_attributes (sobj, errmsg, err); 39898b9484cSchristos if (data == NULL) 39998b9484cSchristos return NULL; 40098b9484cSchristos ret = XNEW (simple_object_attributes); 40198b9484cSchristos ret->functions = sobj->functions; 40298b9484cSchristos ret->data = data; 40398b9484cSchristos return ret; 40498b9484cSchristos } 40598b9484cSchristos 40698b9484cSchristos /* Release an simple_object_read. */ 40798b9484cSchristos 40898b9484cSchristos void 40998b9484cSchristos simple_object_release_read (simple_object_read *sobj) 41098b9484cSchristos { 41198b9484cSchristos sobj->functions->release_read (sobj->data); 41298b9484cSchristos XDELETE (sobj); 41398b9484cSchristos } 41498b9484cSchristos 41598b9484cSchristos /* Merge attributes. */ 41698b9484cSchristos 41798b9484cSchristos const char * 41898b9484cSchristos simple_object_attributes_merge (simple_object_attributes *to, 41998b9484cSchristos simple_object_attributes *from, 42098b9484cSchristos int *err) 42198b9484cSchristos { 42298b9484cSchristos if (to->functions != from->functions) 42398b9484cSchristos { 42498b9484cSchristos *err = 0; 42598b9484cSchristos return "different object file format"; 42698b9484cSchristos } 42798b9484cSchristos return to->functions->attributes_merge (to->data, from->data, err); 42898b9484cSchristos } 42998b9484cSchristos 43098b9484cSchristos /* Release an attributes structure. */ 43198b9484cSchristos 43298b9484cSchristos void 43398b9484cSchristos simple_object_release_attributes (simple_object_attributes *attrs) 43498b9484cSchristos { 43598b9484cSchristos attrs->functions->release_attributes (attrs->data); 43698b9484cSchristos XDELETE (attrs); 43798b9484cSchristos } 43898b9484cSchristos 43998b9484cSchristos /* Start creating an object file. */ 44098b9484cSchristos 44198b9484cSchristos simple_object_write * 44298b9484cSchristos simple_object_start_write (simple_object_attributes *attrs, 44398b9484cSchristos const char *segment_name, const char **errmsg, 44498b9484cSchristos int *err) 44598b9484cSchristos { 44698b9484cSchristos void *data; 44798b9484cSchristos simple_object_write *ret; 44898b9484cSchristos 44998b9484cSchristos data = attrs->functions->start_write (attrs->data, errmsg, err); 45098b9484cSchristos if (data == NULL) 45198b9484cSchristos return NULL; 45298b9484cSchristos ret = XNEW (simple_object_write); 45398b9484cSchristos ret->functions = attrs->functions; 4544559860eSchristos ret->segment_name = segment_name ? xstrdup (segment_name) : NULL; 45598b9484cSchristos ret->sections = NULL; 45698b9484cSchristos ret->last_section = NULL; 45798b9484cSchristos ret->data = data; 45898b9484cSchristos return ret; 45998b9484cSchristos } 46098b9484cSchristos 46198b9484cSchristos /* Start creating a section. */ 46298b9484cSchristos 46398b9484cSchristos simple_object_write_section * 46498b9484cSchristos simple_object_write_create_section (simple_object_write *sobj, const char *name, 46598b9484cSchristos unsigned int align, 46698b9484cSchristos const char **errmsg ATTRIBUTE_UNUSED, 46798b9484cSchristos int *err ATTRIBUTE_UNUSED) 46898b9484cSchristos { 46998b9484cSchristos simple_object_write_section *ret; 47098b9484cSchristos 47198b9484cSchristos ret = XNEW (simple_object_write_section); 47298b9484cSchristos ret->next = NULL; 47398b9484cSchristos ret->name = xstrdup (name); 47498b9484cSchristos ret->align = align; 47598b9484cSchristos ret->buffers = NULL; 47698b9484cSchristos ret->last_buffer = NULL; 47798b9484cSchristos 47898b9484cSchristos if (sobj->last_section == NULL) 47998b9484cSchristos { 48098b9484cSchristos sobj->sections = ret; 48198b9484cSchristos sobj->last_section = ret; 48298b9484cSchristos } 48398b9484cSchristos else 48498b9484cSchristos { 48598b9484cSchristos sobj->last_section->next = ret; 48698b9484cSchristos sobj->last_section = ret; 48798b9484cSchristos } 48898b9484cSchristos 48998b9484cSchristos return ret; 49098b9484cSchristos } 49198b9484cSchristos 49298b9484cSchristos /* Add data to a section. */ 49398b9484cSchristos 49498b9484cSchristos const char * 49598b9484cSchristos simple_object_write_add_data (simple_object_write *sobj ATTRIBUTE_UNUSED, 49698b9484cSchristos simple_object_write_section *section, 49798b9484cSchristos const void *buffer, 49898b9484cSchristos size_t size, int copy, 49998b9484cSchristos int *err ATTRIBUTE_UNUSED) 50098b9484cSchristos { 50198b9484cSchristos struct simple_object_write_section_buffer *wsb; 50298b9484cSchristos 50398b9484cSchristos wsb = XNEW (struct simple_object_write_section_buffer); 50498b9484cSchristos wsb->next = NULL; 50598b9484cSchristos wsb->size = size; 50698b9484cSchristos 50798b9484cSchristos if (!copy) 50898b9484cSchristos { 50998b9484cSchristos wsb->buffer = buffer; 51098b9484cSchristos wsb->free_buffer = NULL; 51198b9484cSchristos } 51298b9484cSchristos else 51398b9484cSchristos { 51498b9484cSchristos wsb->free_buffer = (void *) XNEWVEC (char, size); 51598b9484cSchristos memcpy (wsb->free_buffer, buffer, size); 51698b9484cSchristos wsb->buffer = wsb->free_buffer; 51798b9484cSchristos } 51898b9484cSchristos 51998b9484cSchristos if (section->last_buffer == NULL) 52098b9484cSchristos { 52198b9484cSchristos section->buffers = wsb; 52298b9484cSchristos section->last_buffer = wsb; 52398b9484cSchristos } 52498b9484cSchristos else 52598b9484cSchristos { 52698b9484cSchristos section->last_buffer->next = wsb; 52798b9484cSchristos section->last_buffer = wsb; 52898b9484cSchristos } 52998b9484cSchristos 53098b9484cSchristos return NULL; 53198b9484cSchristos } 53298b9484cSchristos 53398b9484cSchristos /* Write the complete object file. */ 53498b9484cSchristos 53598b9484cSchristos const char * 53698b9484cSchristos simple_object_write_to_file (simple_object_write *sobj, int descriptor, 53798b9484cSchristos int *err) 53898b9484cSchristos { 53998b9484cSchristos return sobj->functions->write_to_file (sobj, descriptor, err); 54098b9484cSchristos } 54198b9484cSchristos 54298b9484cSchristos /* Release an simple_object_write. */ 54398b9484cSchristos 54498b9484cSchristos void 54598b9484cSchristos simple_object_release_write (simple_object_write *sobj) 54698b9484cSchristos { 54798b9484cSchristos simple_object_write_section *section; 54898b9484cSchristos 54998b9484cSchristos free (sobj->segment_name); 55098b9484cSchristos 55198b9484cSchristos section = sobj->sections; 55298b9484cSchristos while (section != NULL) 55398b9484cSchristos { 55498b9484cSchristos struct simple_object_write_section_buffer *buffer; 55598b9484cSchristos simple_object_write_section *next_section; 55698b9484cSchristos 55798b9484cSchristos buffer = section->buffers; 55898b9484cSchristos while (buffer != NULL) 55998b9484cSchristos { 56098b9484cSchristos struct simple_object_write_section_buffer *next_buffer; 56198b9484cSchristos 56298b9484cSchristos if (buffer->free_buffer != NULL) 56398b9484cSchristos XDELETEVEC (buffer->free_buffer); 56498b9484cSchristos next_buffer = buffer->next; 56598b9484cSchristos XDELETE (buffer); 56698b9484cSchristos buffer = next_buffer; 56798b9484cSchristos } 56898b9484cSchristos 56998b9484cSchristos next_section = section->next; 57098b9484cSchristos free (section->name); 57198b9484cSchristos XDELETE (section); 57298b9484cSchristos section = next_section; 57398b9484cSchristos } 57498b9484cSchristos 57598b9484cSchristos sobj->functions->release_write (sobj->data); 57698b9484cSchristos XDELETE (sobj); 57798b9484cSchristos } 578