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