1 /* simple-object.c -- simple routines to read and write object files.
2 Copyright (C) 2010-2018 Free Software Foundation, Inc.
3 Written by Ian Lance Taylor, Google.
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 2, or (at your option) any
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, 51 Franklin Street - Fifth Floor,
18 Boston, MA 02110-1301, USA. */
21 #include "libiberty.h"
22 #include "simple-object.h"
39 #ifdef HAVE_INTTYPES_H
47 #include "simple-object-common.h"
49 /* The known object file formats. */
51 static const struct simple_object_functions
* const format_functions
[] =
53 &simple_object_elf_functions
,
54 &simple_object_mach_o_functions
,
55 &simple_object_coff_functions
,
56 &simple_object_xcoff_functions
59 /* Read data from a file using the simple_object error reporting
63 simple_object_internal_read (int descriptor
, off_t offset
,
64 unsigned char *buffer
, size_t size
,
65 const char **errmsg
, int *err
)
67 if (lseek (descriptor
, offset
, SEEK_SET
) < 0)
76 ssize_t got
= read (descriptor
, buffer
, size
);
84 else if (errno
!= EINTR
)
95 *errmsg
= "file too short";
103 /* Write data to a file using the simple_object error reporting
107 simple_object_internal_write (int descriptor
, off_t offset
,
108 const unsigned char *buffer
, size_t size
,
109 const char **errmsg
, int *err
)
111 if (lseek (descriptor
, offset
, SEEK_SET
) < 0)
120 ssize_t wrote
= write (descriptor
, buffer
, size
);
128 else if (errno
!= EINTR
)
139 *errmsg
= "short write";
150 simple_object_start_read (int descriptor
, off_t offset
,
151 const char *segment_name
, const char **errmsg
,
154 unsigned char header
[SIMPLE_OBJECT_MATCH_HEADER_LEN
];
157 if (!simple_object_internal_read (descriptor
, offset
, header
,
158 SIMPLE_OBJECT_MATCH_HEADER_LEN
,
162 len
= sizeof (format_functions
) / sizeof (format_functions
[0]);
163 for (i
= 0; i
< len
; ++i
)
167 data
= format_functions
[i
]->match (header
, descriptor
, offset
,
168 segment_name
, errmsg
, err
);
171 simple_object_read
*ret
;
173 ret
= XNEW (simple_object_read
);
174 ret
->descriptor
= descriptor
;
175 ret
->offset
= offset
;
176 ret
->functions
= format_functions
[i
];
182 *errmsg
= "file not recognized";
187 /* Find all sections. */
190 simple_object_find_sections (simple_object_read
*sobj
,
191 int (*pfn
) (void *, const char *, off_t
, off_t
),
195 return sobj
->functions
->find_sections (sobj
, pfn
, data
, err
);
198 /* Internal data passed to find_one_section. */
200 struct find_one_section_data
202 /* The section we are looking for. */
204 /* Where to store the section offset. */
206 /* Where to store the section length. */
208 /* Set if the name is found. */
212 /* Internal function passed to find_sections. */
215 find_one_section (void *data
, const char *name
, off_t offset
, off_t length
)
217 struct find_one_section_data
*fosd
= (struct find_one_section_data
*) data
;
219 if (strcmp (name
, fosd
->name
) != 0)
222 *fosd
->offset
= offset
;
223 *fosd
->length
= length
;
226 /* Stop iteration. */
230 /* Find a section. */
233 simple_object_find_section (simple_object_read
*sobj
, const char *name
,
234 off_t
*offset
, off_t
*length
,
235 const char **errmsg
, int *err
)
237 struct find_one_section_data fosd
;
240 fosd
.offset
= offset
;
241 fosd
.length
= length
;
244 *errmsg
= simple_object_find_sections (sobj
, find_one_section
,
245 (void *) &fosd
, err
);
253 /* Callback to identify and rename LTO debug sections by name.
254 Returns 1 if NAME is a LTO debug section, 0 if not. */
257 handle_lto_debug_sections (const char *name
)
259 char *newname
= XCNEWVEC (char, strlen (name
) + 1);
261 /* ??? So we can't use .gnu.lto_ prefixed sections as the assembler
262 complains about bogus section flags. Which means we need to arrange
263 for that to be fixed or .gnu.debuglto_ marked as SHF_EXCLUDE (to make
264 fat lto object tooling work for the fat part). */
265 /* Also include corresponding reloc sections. */
266 if (strncmp (name
, ".rela", sizeof (".rela") - 1) == 0)
268 strncpy (newname
, name
, sizeof (".rela") - 1);
269 name
+= sizeof (".rela") - 1;
271 else if (strncmp (name
, ".rel", sizeof (".rel") - 1) == 0)
273 strncpy (newname
, name
, sizeof (".rel") - 1);
274 name
+= sizeof (".rel") - 1;
276 /* ??? For now this handles both .gnu.lto_ and .gnu.debuglto_ prefixed
278 /* Copy LTO debug sections and rename them to their non-LTO name. */
279 if (strncmp (name
, ".gnu.debuglto_", sizeof (".gnu.debuglto_") - 1) == 0)
280 return strcat (newname
, name
+ sizeof (".gnu.debuglto_") - 1);
281 else if (strncmp (name
, ".gnu.lto_.debug_",
282 sizeof (".gnu.lto_.debug_") -1) == 0)
283 return strcat (newname
, name
+ sizeof (".gnu.lto_") - 1);
284 /* Copy over .note.GNU-stack section under the same name if present. */
285 else if (strcmp (name
, ".note.GNU-stack") == 0)
286 return strcpy (newname
, name
);
287 /* Copy over .comment section under the same name if present. Solaris
288 ld uses them to relax its checking of ELF gABI access rules for
289 COMDAT sections in objects produced by GCC. */
290 else if (strcmp (name
, ".comment") == 0)
291 return strcpy (newname
, name
);
295 /* Copy LTO debug sections. */
298 simple_object_copy_lto_debug_sections (simple_object_read
*sobj
,
299 const char *dest
, int *err
)
302 simple_object_write
*dest_sobj
;
303 simple_object_attributes
*attrs
;
306 if (! sobj
->functions
->copy_lto_debug_sections
)
309 return "simple_object_copy_lto_debug_sections not implemented";
312 attrs
= simple_object_fetch_attributes (sobj
, &errmsg
, err
);
315 dest_sobj
= simple_object_start_write (attrs
, NULL
, &errmsg
, err
);
316 simple_object_release_attributes (attrs
);
320 errmsg
= sobj
->functions
->copy_lto_debug_sections (sobj
, dest_sobj
,
321 handle_lto_debug_sections
,
325 simple_object_release_write (dest_sobj
);
329 outfd
= creat (dest
, 00777);
333 simple_object_release_write (dest_sobj
);
334 return "open failed";
337 errmsg
= simple_object_write_to_file (dest_sobj
, outfd
, err
);
341 simple_object_release_write (dest_sobj
);
345 simple_object_release_write (dest_sobj
);
349 /* Fetch attributes. */
351 simple_object_attributes
*
352 simple_object_fetch_attributes (simple_object_read
*sobj
, const char **errmsg
,
356 simple_object_attributes
*ret
;
358 data
= sobj
->functions
->fetch_attributes (sobj
, errmsg
, err
);
361 ret
= XNEW (simple_object_attributes
);
362 ret
->functions
= sobj
->functions
;
367 /* Release an simple_object_read. */
370 simple_object_release_read (simple_object_read
*sobj
)
372 sobj
->functions
->release_read (sobj
->data
);
376 /* Merge attributes. */
379 simple_object_attributes_merge (simple_object_attributes
*to
,
380 simple_object_attributes
*from
,
383 if (to
->functions
!= from
->functions
)
386 return "different object file format";
388 return to
->functions
->attributes_merge (to
->data
, from
->data
, err
);
391 /* Release an attributes structure. */
394 simple_object_release_attributes (simple_object_attributes
*attrs
)
396 attrs
->functions
->release_attributes (attrs
->data
);
400 /* Start creating an object file. */
402 simple_object_write
*
403 simple_object_start_write (simple_object_attributes
*attrs
,
404 const char *segment_name
, const char **errmsg
,
408 simple_object_write
*ret
;
410 data
= attrs
->functions
->start_write (attrs
->data
, errmsg
, err
);
413 ret
= XNEW (simple_object_write
);
414 ret
->functions
= attrs
->functions
;
415 ret
->segment_name
= segment_name
? xstrdup (segment_name
) : NULL
;
416 ret
->sections
= NULL
;
417 ret
->last_section
= NULL
;
422 /* Start creating a section. */
424 simple_object_write_section
*
425 simple_object_write_create_section (simple_object_write
*sobj
, const char *name
,
427 const char **errmsg ATTRIBUTE_UNUSED
,
428 int *err ATTRIBUTE_UNUSED
)
430 simple_object_write_section
*ret
;
432 ret
= XNEW (simple_object_write_section
);
434 ret
->name
= xstrdup (name
);
437 ret
->last_buffer
= NULL
;
439 if (sobj
->last_section
== NULL
)
441 sobj
->sections
= ret
;
442 sobj
->last_section
= ret
;
446 sobj
->last_section
->next
= ret
;
447 sobj
->last_section
= ret
;
453 /* Add data to a section. */
456 simple_object_write_add_data (simple_object_write
*sobj ATTRIBUTE_UNUSED
,
457 simple_object_write_section
*section
,
459 size_t size
, int copy
,
460 int *err ATTRIBUTE_UNUSED
)
462 struct simple_object_write_section_buffer
*wsb
;
464 wsb
= XNEW (struct simple_object_write_section_buffer
);
470 wsb
->buffer
= buffer
;
471 wsb
->free_buffer
= NULL
;
475 wsb
->free_buffer
= (void *) XNEWVEC (char, size
);
476 memcpy (wsb
->free_buffer
, buffer
, size
);
477 wsb
->buffer
= wsb
->free_buffer
;
480 if (section
->last_buffer
== NULL
)
482 section
->buffers
= wsb
;
483 section
->last_buffer
= wsb
;
487 section
->last_buffer
->next
= wsb
;
488 section
->last_buffer
= wsb
;
494 /* Write the complete object file. */
497 simple_object_write_to_file (simple_object_write
*sobj
, int descriptor
,
500 return sobj
->functions
->write_to_file (sobj
, descriptor
, err
);
503 /* Release an simple_object_write. */
506 simple_object_release_write (simple_object_write
*sobj
)
508 simple_object_write_section
*section
;
510 free (sobj
->segment_name
);
512 section
= sobj
->sections
;
513 while (section
!= NULL
)
515 struct simple_object_write_section_buffer
*buffer
;
516 simple_object_write_section
*next_section
;
518 buffer
= section
->buffers
;
519 while (buffer
!= NULL
)
521 struct simple_object_write_section_buffer
*next_buffer
;
523 if (buffer
->free_buffer
!= NULL
)
524 XDELETEVEC (buffer
->free_buffer
);
525 next_buffer
= buffer
->next
;
527 buffer
= next_buffer
;
530 next_section
= section
->next
;
531 free (section
->name
);
533 section
= next_section
;
536 sobj
->functions
->release_write (sobj
->data
);