/contrib/toolchain/binutils/Makefile |
---|
15,7 → 15,7 |
LDFLAGS = -nostdlib -shared -s --image-base 0 -T ../newlib/dll.lds -e _DllStartup |
LDFLAGS+= --out-implib |
SUBDIRS = libiberty |
SUBDIRS = libiberty bfd |
# targets |
/contrib/toolchain/binutils/bfd/Makefile |
---|
0,0 → 1,44 |
CFLAGS_OPT = -U_Win32 -U_WIN32 -U__MINGW32__ -UWIN32 -U_MSC_VER -O2 |
CFLAGS_OPT+= -fomit-frame-pointer -fno-ident -mno-ms-bitfields |
CFLAGS_OPT+= -W -Wall -Wstrict-prototypes -Wmissing-prototypes -Wshadow -Wno-format -Werror |
CFLAGS = -c $(CFLAGS_OPT) |
INCLUDES= -I. -I../include -I$(SDK_DIR)/sources/newlib/libc/include -I$(SDK_DIR)/sources/zlib |
DEFINES= -DHAVE_CONFIG_H -DHAVE_i386pe_vec -DHAVE_i386pei_vec -DHAVE_bfd_elf32_i386_vec -DHAVE_bfd_elf32_little_generic_vec |
DEFINES+= -DHAVE_bfd_elf32_big_generic_vec -DBINDIR="/home/autobuild/tools/win32/bin" |
SRCS = \ |
archive.c archures.c bfd.c bfdio.c \ |
binary.c cache.c coffgen.c cofflink.c \ |
compress.c corefile.c cpu-i386.c \ |
dwarf1.c dwarf2.c elf.c elf32.c \ |
elf32-gen.c elf32-i386.c elf-attrs.c \ |
elf-eh-frame.c elf-ifunc.c elflink.c \ |
elf-nacl.c elf-strtab.c elf-vxworks.c \ |
format.c hash.c ihex.c init.c libbfd.c \ |
linker.c merge.c opncls.c pe-i386.c \ |
peigen.c reloc.c section.c simple.c \ |
srec.c stabs.c stab-syms.c syms.c \ |
targets.c tekhex.c verilog.c |
OBJS = $(patsubst %.cpp, %.o, $(patsubst %.c, %.o, $(SRCS))) |
# targets |
all: libbfd.a |
libbfd.a : $(OBJS) MAkefile |
$(AR) crs libbfd.a $(OBJS) |
# mv -f libbfd.a $(SDK_DIR)/lib |
%.o : %.c Makefile |
$(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o $@ $< |
dwarf2.o : dwarf2.c Makefile |
$(CC) $(CFLAGS) $(DEFINES) -DDEBUGDIR=\"/home/autobuild/tools/win32/lib/debug\" $(INCLUDES) -o $@ $< |
/contrib/toolchain/binutils/bfd/archive.c |
---|
0,0 → 1,2755 |
/* BFD back-end for archive files (libraries). |
Copyright 1990-2013 Free Software Foundation, Inc. |
Written by Cygnus Support. Mostly Gumby Henkel-Wallace's fault. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ |
/* |
@setfilename archive-info |
SECTION |
Archives |
DESCRIPTION |
An archive (or library) is just another BFD. It has a symbol |
table, although there's not much a user program will do with it. |
The big difference between an archive BFD and an ordinary BFD |
is that the archive doesn't have sections. Instead it has a |
chain of BFDs that are considered its contents. These BFDs can |
be manipulated like any other. The BFDs contained in an |
archive opened for reading will all be opened for reading. You |
may put either input or output BFDs into an archive opened for |
output; they will be handled correctly when the archive is closed. |
Use <<bfd_openr_next_archived_file>> to step through |
the contents of an archive opened for input. You don't |
have to read the entire archive if you don't want |
to! Read it until you find what you want. |
A BFD returned by <<bfd_openr_next_archived_file>> can be |
closed manually with <<bfd_close>>. If you do not close it, |
then a second iteration through the members of an archive may |
return the same BFD. If you close the archive BFD, then all |
the member BFDs will automatically be closed as well. |
Archive contents of output BFDs are chained through the |
<<archive_next>> pointer in a BFD. The first one is findable |
through the <<archive_head>> slot of the archive. Set it with |
<<bfd_set_archive_head>> (q.v.). A given BFD may be in only |
one open output archive at a time. |
As expected, the BFD archive code is more general than the |
archive code of any given environment. BFD archives may |
contain files of different formats (e.g., a.out and coff) and |
even different architectures. You may even place archives |
recursively into archives! |
This can cause unexpected confusion, since some archive |
formats are more expressive than others. For instance, Intel |
COFF archives can preserve long filenames; SunOS a.out archives |
cannot. If you move a file from the first to the second |
format and back again, the filename may be truncated. |
Likewise, different a.out environments have different |
conventions as to how they truncate filenames, whether they |
preserve directory names in filenames, etc. When |
interoperating with native tools, be sure your files are |
homogeneous. |
Beware: most of these formats do not react well to the |
presence of spaces in filenames. We do the best we can, but |
can't always handle this case due to restrictions in the format of |
archives. Many Unix utilities are braindead in regards to |
spaces and such in filenames anyway, so this shouldn't be much |
of a restriction. |
Archives are supported in BFD in <<archive.c>>. |
SUBSECTION |
Archive functions |
*/ |
/* Assumes: |
o - all archive elements start on an even boundary, newline padded; |
o - all arch headers are char *; |
o - all arch headers are the same size (across architectures). |
*/ |
/* Some formats provide a way to cram a long filename into the short |
(16 chars) space provided by a BSD archive. The trick is: make a |
special "file" in the front of the archive, sort of like the SYMDEF |
entry. If the filename is too long to fit, put it in the extended |
name table, and use its index as the filename. To prevent |
confusion prepend the index with a space. This means you can't |
have filenames that start with a space, but then again, many Unix |
utilities can't handle that anyway. |
This scheme unfortunately requires that you stand on your head in |
order to write an archive since you need to put a magic file at the |
front, and need to touch every entry to do so. C'est la vie. |
We support two variants of this idea: |
The SVR4 format (extended name table is named "//"), |
and an extended pseudo-BSD variant (extended name table is named |
"ARFILENAMES/"). The origin of the latter format is uncertain. |
BSD 4.4 uses a third scheme: It writes a long filename |
directly after the header. This allows 'ar q' to work. |
*/ |
/* Summary of archive member names: |
Symbol table (must be first): |
"__.SYMDEF " - Symbol table, Berkeley style, produced by ranlib. |
"/ " - Symbol table, system 5 style. |
Long name table (must be before regular file members): |
"// " - Long name table, System 5 R4 style. |
"ARFILENAMES/ " - Long name table, non-standard extended BSD (not BSD 4.4). |
Regular file members with short names: |
"filename.o/ " - Regular file, System 5 style (embedded spaces ok). |
"filename.o " - Regular file, Berkeley style (no embedded spaces). |
Regular files with long names (or embedded spaces, for BSD variants): |
"/18 " - SVR4 style, name at offset 18 in name table. |
"#1/23 " - Long name (or embedded spaces) 23 characters long, |
BSD 4.4 style, full name follows header. |
" 18 " - Long name 18 characters long, extended pseudo-BSD. |
*/ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libiberty.h" |
#include "libbfd.h" |
#include "aout/ar.h" |
#include "aout/ranlib.h" |
#include "safe-ctype.h" |
#include "hashtab.h" |
#include "filenames.h" |
#ifndef errno |
extern int errno; |
#endif |
/* We keep a cache of archive filepointers to archive elements to |
speed up searching the archive by filepos. We only add an entry to |
the cache when we actually read one. We also don't sort the cache; |
it's generally short enough to search linearly. |
Note that the pointers here point to the front of the ar_hdr, not |
to the front of the contents! */ |
struct ar_cache |
{ |
file_ptr ptr; |
bfd *arbfd; |
}; |
#define ar_padchar(abfd) ((abfd)->xvec->ar_pad_char) |
#define ar_maxnamelen(abfd) ((abfd)->xvec->ar_max_namelen) |
#define arch_eltdata(bfd) ((struct areltdata *) ((bfd)->arelt_data)) |
#define arch_hdr(bfd) ((struct ar_hdr *) arch_eltdata (bfd)->arch_header) |
/* True iff NAME designated a BSD 4.4 extended name. */ |
#define is_bsd44_extended_name(NAME) \ |
(NAME[0] == '#' && NAME[1] == '1' && NAME[2] == '/' && ISDIGIT (NAME[3])) |
void |
_bfd_ar_spacepad (char *p, size_t n, const char *fmt, long val) |
{ |
static char buf[20]; |
size_t len; |
snprintf (buf, sizeof (buf), fmt, val); |
len = strlen (buf); |
if (len < n) |
{ |
memcpy (p, buf, len); |
memset (p + len, ' ', n - len); |
} |
else |
memcpy (p, buf, n); |
} |
bfd_boolean |
_bfd_ar_sizepad (char *p, size_t n, bfd_size_type size) |
{ |
static char buf[21]; |
size_t len; |
snprintf (buf, sizeof (buf), "%-10" BFD_VMA_FMT "u", size); |
len = strlen (buf); |
if (len > n) |
{ |
bfd_set_error (bfd_error_file_too_big); |
return FALSE; |
} |
if (len < n) |
{ |
memcpy (p, buf, len); |
memset (p + len, ' ', n - len); |
} |
else |
memcpy (p, buf, n); |
return TRUE; |
} |
bfd_boolean |
_bfd_generic_mkarchive (bfd *abfd) |
{ |
bfd_size_type amt = sizeof (struct artdata); |
abfd->tdata.aout_ar_data = (struct artdata *) bfd_zalloc (abfd, amt); |
if (bfd_ardata (abfd) == NULL) |
return FALSE; |
/* Already cleared by bfd_zalloc above. |
bfd_ardata (abfd)->cache = NULL; |
bfd_ardata (abfd)->archive_head = NULL; |
bfd_ardata (abfd)->symdefs = NULL; |
bfd_ardata (abfd)->extended_names = NULL; |
bfd_ardata (abfd)->extended_names_size = 0; |
bfd_ardata (abfd)->tdata = NULL; */ |
return TRUE; |
} |
/* |
FUNCTION |
bfd_get_next_mapent |
SYNOPSIS |
symindex bfd_get_next_mapent |
(bfd *abfd, symindex previous, carsym **sym); |
DESCRIPTION |
Step through archive @var{abfd}'s symbol table (if it |
has one). Successively update @var{sym} with the next symbol's |
information, returning that symbol's (internal) index into the |
symbol table. |
Supply <<BFD_NO_MORE_SYMBOLS>> as the @var{previous} entry to get |
the first one; returns <<BFD_NO_MORE_SYMBOLS>> when you've already |
got the last one. |
A <<carsym>> is a canonical archive symbol. The only |
user-visible element is its name, a null-terminated string. |
*/ |
symindex |
bfd_get_next_mapent (bfd *abfd, symindex prev, carsym **entry) |
{ |
if (!bfd_has_map (abfd)) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return BFD_NO_MORE_SYMBOLS; |
} |
if (prev == BFD_NO_MORE_SYMBOLS) |
prev = 0; |
else |
++prev; |
if (prev >= bfd_ardata (abfd)->symdef_count) |
return BFD_NO_MORE_SYMBOLS; |
*entry = (bfd_ardata (abfd)->symdefs + prev); |
return prev; |
} |
/* To be called by backends only. */ |
bfd * |
_bfd_create_empty_archive_element_shell (bfd *obfd) |
{ |
return _bfd_new_bfd_contained_in (obfd); |
} |
/* |
FUNCTION |
bfd_set_archive_head |
SYNOPSIS |
bfd_boolean bfd_set_archive_head (bfd *output, bfd *new_head); |
DESCRIPTION |
Set the head of the chain of |
BFDs contained in the archive @var{output} to @var{new_head}. |
*/ |
bfd_boolean |
bfd_set_archive_head (bfd *output_archive, bfd *new_head) |
{ |
output_archive->archive_head = new_head; |
return TRUE; |
} |
bfd * |
_bfd_look_for_bfd_in_cache (bfd *arch_bfd, file_ptr filepos) |
{ |
htab_t hash_table = bfd_ardata (arch_bfd)->cache; |
struct ar_cache m; |
m.ptr = filepos; |
if (hash_table) |
{ |
struct ar_cache *entry = (struct ar_cache *) htab_find (hash_table, &m); |
if (!entry) |
return NULL; |
else |
return entry->arbfd; |
} |
else |
return NULL; |
} |
static hashval_t |
hash_file_ptr (const void * p) |
{ |
return (hashval_t) (((struct ar_cache *) p)->ptr); |
} |
/* Returns non-zero if P1 and P2 are equal. */ |
static int |
eq_file_ptr (const void * p1, const void * p2) |
{ |
struct ar_cache *arc1 = (struct ar_cache *) p1; |
struct ar_cache *arc2 = (struct ar_cache *) p2; |
return arc1->ptr == arc2->ptr; |
} |
/* The calloc function doesn't always take size_t (e.g. on VMS) |
so wrap it to avoid a compile time warning. */ |
static void * |
_bfd_calloc_wrapper (size_t a, size_t b) |
{ |
return calloc (a, b); |
} |
/* Kind of stupid to call cons for each one, but we don't do too many. */ |
bfd_boolean |
_bfd_add_bfd_to_archive_cache (bfd *arch_bfd, file_ptr filepos, bfd *new_elt) |
{ |
struct ar_cache *cache; |
htab_t hash_table = bfd_ardata (arch_bfd)->cache; |
/* If the hash table hasn't been created, create it. */ |
if (hash_table == NULL) |
{ |
hash_table = htab_create_alloc (16, hash_file_ptr, eq_file_ptr, |
NULL, _bfd_calloc_wrapper, free); |
if (hash_table == NULL) |
return FALSE; |
bfd_ardata (arch_bfd)->cache = hash_table; |
} |
/* Insert new_elt into the hash table by filepos. */ |
cache = (struct ar_cache *) bfd_zalloc (arch_bfd, sizeof (struct ar_cache)); |
cache->ptr = filepos; |
cache->arbfd = new_elt; |
*htab_find_slot (hash_table, (const void *) cache, INSERT) = cache; |
/* Provide a means of accessing this from child. */ |
arch_eltdata (new_elt)->parent_cache = hash_table; |
arch_eltdata (new_elt)->key = filepos; |
return TRUE; |
} |
static bfd * |
_bfd_find_nested_archive (bfd *arch_bfd, const char *filename) |
{ |
bfd *abfd; |
const char *target; |
/* PR 15140: Don't allow a nested archive pointing to itself. */ |
if (filename_cmp (filename, arch_bfd->filename) == 0) |
{ |
bfd_set_error (bfd_error_malformed_archive); |
return NULL; |
} |
for (abfd = arch_bfd->nested_archives; |
abfd != NULL; |
abfd = abfd->archive_next) |
{ |
if (filename_cmp (filename, abfd->filename) == 0) |
return abfd; |
} |
target = NULL; |
if (!arch_bfd->target_defaulted) |
target = arch_bfd->xvec->name; |
abfd = bfd_openr (filename, target); |
if (abfd) |
{ |
abfd->archive_next = arch_bfd->nested_archives; |
arch_bfd->nested_archives = abfd; |
} |
return abfd; |
} |
/* The name begins with space. Hence the rest of the name is an index into |
the string table. */ |
static char * |
get_extended_arelt_filename (bfd *arch, const char *name, file_ptr *originp) |
{ |
unsigned long table_index = 0; |
const char *endp; |
/* Should extract string so that I can guarantee not to overflow into |
the next region, but I'm too lazy. */ |
errno = 0; |
/* Skip first char, which is '/' in SVR4 or ' ' in some other variants. */ |
table_index = strtol (name + 1, (char **) &endp, 10); |
if (errno != 0 || table_index >= bfd_ardata (arch)->extended_names_size) |
{ |
bfd_set_error (bfd_error_malformed_archive); |
return NULL; |
} |
/* In a thin archive, a member of an archive-within-an-archive |
will have the offset in the inner archive encoded here. */ |
if (bfd_is_thin_archive (arch) && endp != NULL && *endp == ':') |
{ |
file_ptr origin = strtol (endp + 1, NULL, 10); |
if (errno != 0) |
{ |
bfd_set_error (bfd_error_malformed_archive); |
return NULL; |
} |
*originp = origin; |
} |
else |
*originp = 0; |
return bfd_ardata (arch)->extended_names + table_index; |
} |
/* This functions reads an arch header and returns an areltdata pointer, or |
NULL on error. |
Presumes the file pointer is already in the right place (ie pointing |
to the ar_hdr in the file). Moves the file pointer; on success it |
should be pointing to the front of the file contents; on failure it |
could have been moved arbitrarily. */ |
void * |
_bfd_generic_read_ar_hdr (bfd *abfd) |
{ |
return _bfd_generic_read_ar_hdr_mag (abfd, NULL); |
} |
/* Alpha ECOFF uses an optional different ARFMAG value, so we have a |
variant of _bfd_generic_read_ar_hdr which accepts a magic string. */ |
void * |
_bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag) |
{ |
struct ar_hdr hdr; |
char *hdrp = (char *) &hdr; |
bfd_size_type parsed_size; |
struct areltdata *ared; |
char *filename = NULL; |
bfd_size_type namelen = 0; |
bfd_size_type allocsize = sizeof (struct areltdata) + sizeof (struct ar_hdr); |
char *allocptr = 0; |
file_ptr origin = 0; |
unsigned int extra_size = 0; |
char fmag_save; |
int scan; |
if (bfd_bread (hdrp, sizeof (struct ar_hdr), abfd) != sizeof (struct ar_hdr)) |
{ |
if (bfd_get_error () != bfd_error_system_call) |
bfd_set_error (bfd_error_no_more_archived_files); |
return NULL; |
} |
if (strncmp (hdr.ar_fmag, ARFMAG, 2) != 0 |
&& (mag == NULL |
|| strncmp (hdr.ar_fmag, mag, 2) != 0)) |
{ |
bfd_set_error (bfd_error_malformed_archive); |
return NULL; |
} |
errno = 0; |
fmag_save = hdr.ar_fmag[0]; |
hdr.ar_fmag[0] = 0; |
scan = sscanf (hdr.ar_size, "%" BFD_VMA_FMT "u", &parsed_size); |
hdr.ar_fmag[0] = fmag_save; |
if (scan != 1) |
{ |
bfd_set_error (bfd_error_malformed_archive); |
return NULL; |
} |
/* Extract the filename from the archive - there are two ways to |
specify an extended name table, either the first char of the |
name is a space, or it's a slash. */ |
if ((hdr.ar_name[0] == '/' |
|| (hdr.ar_name[0] == ' ' |
&& memchr (hdr.ar_name, '/', ar_maxnamelen (abfd)) == NULL)) |
&& bfd_ardata (abfd)->extended_names != NULL) |
{ |
filename = get_extended_arelt_filename (abfd, hdr.ar_name, &origin); |
if (filename == NULL) |
return NULL; |
} |
/* BSD4.4-style long filename. */ |
else if (is_bsd44_extended_name (hdr.ar_name)) |
{ |
/* BSD-4.4 extended name */ |
namelen = atoi (&hdr.ar_name[3]); |
allocsize += namelen + 1; |
parsed_size -= namelen; |
extra_size = namelen; |
allocptr = (char *) bfd_zmalloc (allocsize); |
if (allocptr == NULL) |
return NULL; |
filename = (allocptr |
+ sizeof (struct areltdata) |
+ sizeof (struct ar_hdr)); |
if (bfd_bread (filename, namelen, abfd) != namelen) |
{ |
free (allocptr); |
if (bfd_get_error () != bfd_error_system_call) |
bfd_set_error (bfd_error_no_more_archived_files); |
return NULL; |
} |
filename[namelen] = '\0'; |
} |
else |
{ |
/* We judge the end of the name by looking for '/' or ' '. |
Note: The SYSV format (terminated by '/') allows embedded |
spaces, so only look for ' ' if we don't find '/'. */ |
char *e; |
e = (char *) memchr (hdr.ar_name, '\0', ar_maxnamelen (abfd)); |
if (e == NULL) |
{ |
e = (char *) memchr (hdr.ar_name, '/', ar_maxnamelen (abfd)); |
if (e == NULL) |
e = (char *) memchr (hdr.ar_name, ' ', ar_maxnamelen (abfd)); |
} |
if (e != NULL) |
namelen = e - hdr.ar_name; |
else |
{ |
/* If we didn't find a termination character, then the name |
must be the entire field. */ |
namelen = ar_maxnamelen (abfd); |
} |
allocsize += namelen + 1; |
} |
if (!allocptr) |
{ |
allocptr = (char *) bfd_zmalloc (allocsize); |
if (allocptr == NULL) |
return NULL; |
} |
ared = (struct areltdata *) allocptr; |
ared->arch_header = allocptr + sizeof (struct areltdata); |
memcpy (ared->arch_header, &hdr, sizeof (struct ar_hdr)); |
ared->parsed_size = parsed_size; |
ared->extra_size = extra_size; |
ared->origin = origin; |
if (filename != NULL) |
ared->filename = filename; |
else |
{ |
ared->filename = allocptr + (sizeof (struct areltdata) + |
sizeof (struct ar_hdr)); |
if (namelen) |
memcpy (ared->filename, hdr.ar_name, namelen); |
ared->filename[namelen] = '\0'; |
} |
return ared; |
} |
/* Append the relative pathname for a member of the thin archive |
to the pathname of the directory containing the archive. */ |
char * |
_bfd_append_relative_path (bfd *arch, char *elt_name) |
{ |
const char *arch_name = arch->filename; |
const char *base_name = lbasename (arch_name); |
size_t prefix_len; |
char *filename; |
if (base_name == arch_name) |
return elt_name; |
prefix_len = base_name - arch_name; |
filename = (char *) bfd_alloc (arch, prefix_len + strlen (elt_name) + 1); |
if (filename == NULL) |
return NULL; |
strncpy (filename, arch_name, prefix_len); |
strcpy (filename + prefix_len, elt_name); |
return filename; |
} |
/* This is an internal function; it's mainly used when indexing |
through the archive symbol table, but also used to get the next |
element, since it handles the bookkeeping so nicely for us. */ |
bfd * |
_bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos) |
{ |
struct areltdata *new_areldata; |
bfd *n_nfd; |
char *filename; |
n_nfd = _bfd_look_for_bfd_in_cache (archive, filepos); |
if (n_nfd) |
return n_nfd; |
if (0 > bfd_seek (archive, filepos, SEEK_SET)) |
return NULL; |
if ((new_areldata = (struct areltdata *) _bfd_read_ar_hdr (archive)) == NULL) |
return NULL; |
filename = new_areldata->filename; |
if (bfd_is_thin_archive (archive)) |
{ |
const char *target; |
/* This is a proxy entry for an external file. */ |
if (! IS_ABSOLUTE_PATH (filename)) |
{ |
filename = _bfd_append_relative_path (archive, filename); |
if (filename == NULL) |
{ |
free (new_areldata); |
return NULL; |
} |
} |
if (new_areldata->origin > 0) |
{ |
/* This proxy entry refers to an element of a nested archive. |
Locate the member of that archive and return a bfd for it. */ |
bfd *ext_arch = _bfd_find_nested_archive (archive, filename); |
if (ext_arch == NULL |
|| ! bfd_check_format (ext_arch, bfd_archive)) |
{ |
free (new_areldata); |
return NULL; |
} |
n_nfd = _bfd_get_elt_at_filepos (ext_arch, new_areldata->origin); |
if (n_nfd == NULL) |
{ |
free (new_areldata); |
return NULL; |
} |
n_nfd->proxy_origin = bfd_tell (archive); |
return n_nfd; |
} |
/* It's not an element of a nested archive; |
open the external file as a bfd. */ |
target = NULL; |
if (!archive->target_defaulted) |
target = archive->xvec->name; |
n_nfd = bfd_openr (filename, target); |
if (n_nfd == NULL) |
bfd_set_error (bfd_error_malformed_archive); |
} |
else |
{ |
n_nfd = _bfd_create_empty_archive_element_shell (archive); |
} |
if (n_nfd == NULL) |
{ |
free (new_areldata); |
return NULL; |
} |
n_nfd->proxy_origin = bfd_tell (archive); |
if (bfd_is_thin_archive (archive)) |
{ |
n_nfd->origin = 0; |
} |
else |
{ |
n_nfd->origin = n_nfd->proxy_origin; |
n_nfd->filename = filename; |
} |
n_nfd->arelt_data = new_areldata; |
/* Copy BFD_COMPRESS and BFD_DECOMPRESS flags. */ |
n_nfd->flags |= archive->flags & (BFD_COMPRESS | BFD_DECOMPRESS); |
if (_bfd_add_bfd_to_archive_cache (archive, filepos, n_nfd)) |
return n_nfd; |
free (new_areldata); |
n_nfd->arelt_data = NULL; |
return NULL; |
} |
/* Return the BFD which is referenced by the symbol in ABFD indexed by |
SYM_INDEX. SYM_INDEX should have been returned by bfd_get_next_mapent. */ |
bfd * |
_bfd_generic_get_elt_at_index (bfd *abfd, symindex sym_index) |
{ |
carsym *entry; |
entry = bfd_ardata (abfd)->symdefs + sym_index; |
return _bfd_get_elt_at_filepos (abfd, entry->file_offset); |
} |
/* |
FUNCTION |
bfd_openr_next_archived_file |
SYNOPSIS |
bfd *bfd_openr_next_archived_file (bfd *archive, bfd *previous); |
DESCRIPTION |
Provided a BFD, @var{archive}, containing an archive and NULL, open |
an input BFD on the first contained element and returns that. |
Subsequent calls should pass |
the archive and the previous return value to return a created |
BFD to the next contained element. NULL is returned when there |
are no more. |
*/ |
bfd * |
bfd_openr_next_archived_file (bfd *archive, bfd *last_file) |
{ |
if ((bfd_get_format (archive) != bfd_archive) |
|| (archive->direction == write_direction)) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return NULL; |
} |
return BFD_SEND (archive, |
openr_next_archived_file, (archive, last_file)); |
} |
bfd * |
bfd_generic_openr_next_archived_file (bfd *archive, bfd *last_file) |
{ |
file_ptr filestart; |
if (!last_file) |
filestart = bfd_ardata (archive)->first_file_filepos; |
else |
{ |
bfd_size_type size = arelt_size (last_file); |
filestart = last_file->proxy_origin; |
if (! bfd_is_thin_archive (archive)) |
filestart += size; |
/* Pad to an even boundary... |
Note that last_file->origin can be odd in the case of |
BSD-4.4-style element with a long odd size. */ |
filestart += filestart % 2; |
} |
return _bfd_get_elt_at_filepos (archive, filestart); |
} |
const bfd_target * |
bfd_generic_archive_p (bfd *abfd) |
{ |
struct artdata *tdata_hold; |
char armag[SARMAG + 1]; |
bfd_size_type amt; |
if (bfd_bread (armag, SARMAG, abfd) != SARMAG) |
{ |
if (bfd_get_error () != bfd_error_system_call) |
bfd_set_error (bfd_error_wrong_format); |
return NULL; |
} |
bfd_is_thin_archive (abfd) = (strncmp (armag, ARMAGT, SARMAG) == 0); |
if (strncmp (armag, ARMAG, SARMAG) != 0 |
&& strncmp (armag, ARMAGB, SARMAG) != 0 |
&& ! bfd_is_thin_archive (abfd)) |
return NULL; |
tdata_hold = bfd_ardata (abfd); |
amt = sizeof (struct artdata); |
bfd_ardata (abfd) = (struct artdata *) bfd_zalloc (abfd, amt); |
if (bfd_ardata (abfd) == NULL) |
{ |
bfd_ardata (abfd) = tdata_hold; |
return NULL; |
} |
bfd_ardata (abfd)->first_file_filepos = SARMAG; |
/* Cleared by bfd_zalloc above. |
bfd_ardata (abfd)->cache = NULL; |
bfd_ardata (abfd)->archive_head = NULL; |
bfd_ardata (abfd)->symdefs = NULL; |
bfd_ardata (abfd)->extended_names = NULL; |
bfd_ardata (abfd)->extended_names_size = 0; |
bfd_ardata (abfd)->tdata = NULL; */ |
if (!BFD_SEND (abfd, _bfd_slurp_armap, (abfd)) |
|| !BFD_SEND (abfd, _bfd_slurp_extended_name_table, (abfd))) |
{ |
if (bfd_get_error () != bfd_error_system_call) |
bfd_set_error (bfd_error_wrong_format); |
bfd_release (abfd, bfd_ardata (abfd)); |
bfd_ardata (abfd) = tdata_hold; |
return NULL; |
} |
if (abfd->target_defaulted && bfd_has_map (abfd)) |
{ |
bfd *first; |
/* This archive has a map, so we may presume that the contents |
are object files. Make sure that if the first file in the |
archive can be recognized as an object file, it is for this |
target. If not, assume that this is the wrong format. If |
the first file is not an object file, somebody is doing |
something weird, and we permit it so that ar -t will work. |
This is done because any normal format will recognize any |
normal archive, regardless of the format of the object files. |
We do accept an empty archive. */ |
first = bfd_openr_next_archived_file (abfd, NULL); |
if (first != NULL) |
{ |
first->target_defaulted = FALSE; |
if (bfd_check_format (first, bfd_object) |
&& first->xvec != abfd->xvec) |
bfd_set_error (bfd_error_wrong_object_format); |
/* And we ought to close `first' here too. */ |
} |
} |
return abfd->xvec; |
} |
/* Some constants for a 32 bit BSD archive structure. We do not |
support 64 bit archives presently; so far as I know, none actually |
exist. Supporting them would require changing these constants, and |
changing some H_GET_32 to H_GET_64. */ |
/* The size of an external symdef structure. */ |
#define BSD_SYMDEF_SIZE 8 |
/* The offset from the start of a symdef structure to the file offset. */ |
#define BSD_SYMDEF_OFFSET_SIZE 4 |
/* The size of the symdef count. */ |
#define BSD_SYMDEF_COUNT_SIZE 4 |
/* The size of the string count. */ |
#define BSD_STRING_COUNT_SIZE 4 |
/* Read a BSD-style archive symbol table. Returns FALSE on error, |
TRUE otherwise. */ |
static bfd_boolean |
do_slurp_bsd_armap (bfd *abfd) |
{ |
struct areltdata *mapdata; |
unsigned int counter; |
bfd_byte *raw_armap, *rbase; |
struct artdata *ardata = bfd_ardata (abfd); |
char *stringbase; |
bfd_size_type parsed_size, amt; |
carsym *set; |
mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd); |
if (mapdata == NULL) |
return FALSE; |
parsed_size = mapdata->parsed_size; |
free (mapdata); |
raw_armap = (bfd_byte *) bfd_zalloc (abfd, parsed_size); |
if (raw_armap == NULL) |
return FALSE; |
if (bfd_bread (raw_armap, parsed_size, abfd) != parsed_size) |
{ |
if (bfd_get_error () != bfd_error_system_call) |
bfd_set_error (bfd_error_malformed_archive); |
byebye: |
bfd_release (abfd, raw_armap); |
return FALSE; |
} |
ardata->symdef_count = H_GET_32 (abfd, raw_armap) / BSD_SYMDEF_SIZE; |
if (ardata->symdef_count * BSD_SYMDEF_SIZE > |
parsed_size - BSD_SYMDEF_COUNT_SIZE) |
{ |
/* Probably we're using the wrong byte ordering. */ |
bfd_set_error (bfd_error_wrong_format); |
goto byebye; |
} |
ardata->cache = 0; |
rbase = raw_armap + BSD_SYMDEF_COUNT_SIZE; |
stringbase = ((char *) rbase |
+ ardata->symdef_count * BSD_SYMDEF_SIZE |
+ BSD_STRING_COUNT_SIZE); |
amt = ardata->symdef_count * sizeof (carsym); |
ardata->symdefs = (struct carsym *) bfd_alloc (abfd, amt); |
if (!ardata->symdefs) |
return FALSE; |
for (counter = 0, set = ardata->symdefs; |
counter < ardata->symdef_count; |
counter++, set++, rbase += BSD_SYMDEF_SIZE) |
{ |
set->name = H_GET_32 (abfd, rbase) + stringbase; |
set->file_offset = H_GET_32 (abfd, rbase + BSD_SYMDEF_OFFSET_SIZE); |
} |
ardata->first_file_filepos = bfd_tell (abfd); |
/* Pad to an even boundary if you have to. */ |
ardata->first_file_filepos += (ardata->first_file_filepos) % 2; |
/* FIXME, we should provide some way to free raw_ardata when |
we are done using the strings from it. For now, it seems |
to be allocated on an objalloc anyway... */ |
bfd_has_map (abfd) = TRUE; |
return TRUE; |
} |
/* Read a COFF archive symbol table. Returns FALSE on error, TRUE |
otherwise. */ |
static bfd_boolean |
do_slurp_coff_armap (bfd *abfd) |
{ |
struct areltdata *mapdata; |
int *raw_armap, *rawptr; |
struct artdata *ardata = bfd_ardata (abfd); |
char *stringbase; |
bfd_size_type stringsize; |
bfd_size_type parsed_size; |
carsym *carsyms; |
bfd_size_type nsymz; /* Number of symbols in armap. */ |
bfd_vma (*swap) (const void *); |
char int_buf[sizeof (long)]; |
bfd_size_type carsym_size, ptrsize; |
unsigned int i; |
mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd); |
if (mapdata == NULL) |
return FALSE; |
parsed_size = mapdata->parsed_size; |
free (mapdata); |
if (bfd_bread (int_buf, 4, abfd) != 4) |
{ |
if (bfd_get_error () != bfd_error_system_call) |
bfd_set_error (bfd_error_malformed_archive); |
return FALSE; |
} |
/* It seems that all numeric information in a coff archive is always |
in big endian format, nomatter the host or target. */ |
swap = bfd_getb32; |
nsymz = bfd_getb32 (int_buf); |
stringsize = parsed_size - (4 * nsymz) - 4; |
/* ... except that some archive formats are broken, and it may be our |
fault - the i960 little endian coff sometimes has big and sometimes |
little, because our tools changed. Here's a horrible hack to clean |
up the crap. */ |
if (stringsize > 0xfffff |
&& bfd_get_arch (abfd) == bfd_arch_i960 |
&& bfd_get_flavour (abfd) == bfd_target_coff_flavour) |
{ |
/* This looks dangerous, let's do it the other way around. */ |
nsymz = bfd_getl32 (int_buf); |
stringsize = parsed_size - (4 * nsymz) - 4; |
swap = bfd_getl32; |
} |
/* The coff armap must be read sequentially. So we construct a |
bsd-style one in core all at once, for simplicity. */ |
if (nsymz > ~ (bfd_size_type) 0 / sizeof (carsym)) |
return FALSE; |
carsym_size = (nsymz * sizeof (carsym)); |
ptrsize = (4 * nsymz); |
if (carsym_size + stringsize + 1 <= carsym_size) |
return FALSE; |
ardata->symdefs = (struct carsym *) bfd_zalloc (abfd, |
carsym_size + stringsize + 1); |
if (ardata->symdefs == NULL) |
return FALSE; |
carsyms = ardata->symdefs; |
stringbase = ((char *) ardata->symdefs) + carsym_size; |
/* Allocate and read in the raw offsets. */ |
raw_armap = (int *) bfd_alloc (abfd, ptrsize); |
if (raw_armap == NULL) |
goto release_symdefs; |
if (bfd_bread (raw_armap, ptrsize, abfd) != ptrsize |
|| (bfd_bread (stringbase, stringsize, abfd) != stringsize)) |
{ |
if (bfd_get_error () != bfd_error_system_call) |
bfd_set_error (bfd_error_malformed_archive); |
goto release_raw_armap; |
} |
/* OK, build the carsyms. */ |
for (i = 0; i < nsymz; i++) |
{ |
rawptr = raw_armap + i; |
carsyms->file_offset = swap ((bfd_byte *) rawptr); |
carsyms->name = stringbase; |
stringbase += strlen (stringbase) + 1; |
carsyms++; |
} |
*stringbase = 0; |
ardata->symdef_count = nsymz; |
ardata->first_file_filepos = bfd_tell (abfd); |
/* Pad to an even boundary if you have to. */ |
ardata->first_file_filepos += (ardata->first_file_filepos) % 2; |
bfd_has_map (abfd) = TRUE; |
bfd_release (abfd, raw_armap); |
/* Check for a second archive header (as used by PE). */ |
{ |
struct areltdata *tmp; |
bfd_seek (abfd, ardata->first_file_filepos, SEEK_SET); |
tmp = (struct areltdata *) _bfd_read_ar_hdr (abfd); |
if (tmp != NULL) |
{ |
if (tmp->arch_header[0] == '/' |
&& tmp->arch_header[1] == ' ') |
{ |
ardata->first_file_filepos += |
(tmp->parsed_size + sizeof (struct ar_hdr) + 1) & ~(unsigned) 1; |
} |
free (tmp); |
} |
} |
return TRUE; |
release_raw_armap: |
bfd_release (abfd, raw_armap); |
release_symdefs: |
bfd_release (abfd, (ardata)->symdefs); |
return FALSE; |
} |
/* This routine can handle either coff-style or bsd-style armaps |
(archive symbol table). Returns FALSE on error, TRUE otherwise */ |
bfd_boolean |
bfd_slurp_armap (bfd *abfd) |
{ |
char nextname[17]; |
int i = bfd_bread (nextname, 16, abfd); |
if (i == 0) |
return TRUE; |
if (i != 16) |
return FALSE; |
if (bfd_seek (abfd, (file_ptr) -16, SEEK_CUR) != 0) |
return FALSE; |
if (CONST_STRNEQ (nextname, "__.SYMDEF ") |
|| CONST_STRNEQ (nextname, "__.SYMDEF/ ")) /* Old Linux archives. */ |
return do_slurp_bsd_armap (abfd); |
else if (CONST_STRNEQ (nextname, "/ ")) |
return do_slurp_coff_armap (abfd); |
else if (CONST_STRNEQ (nextname, "/SYM64/ ")) |
{ |
/* 64bit ELF (Irix 6) archive. */ |
#ifdef BFD64 |
extern bfd_boolean bfd_elf64_archive_slurp_armap (bfd *); |
return bfd_elf64_archive_slurp_armap (abfd); |
#else |
bfd_set_error (bfd_error_wrong_format); |
return FALSE; |
#endif |
} |
else if (CONST_STRNEQ (nextname, "#1/20 ")) |
{ |
/* Mach-O has a special name for armap when the map is sorted by name. |
However because this name has a space it is slightly more difficult |
to check it. */ |
struct ar_hdr hdr; |
char extname[21]; |
if (bfd_bread (&hdr, sizeof (hdr), abfd) != sizeof (hdr)) |
return FALSE; |
/* Read the extended name. We know its length. */ |
if (bfd_bread (extname, 20, abfd) != 20) |
return FALSE; |
if (bfd_seek (abfd, -(file_ptr) (sizeof (hdr) + 20), SEEK_CUR) != 0) |
return FALSE; |
if (CONST_STRNEQ (extname, "__.SYMDEF SORTED") |
|| CONST_STRNEQ (extname, "__.SYMDEF")) |
return do_slurp_bsd_armap (abfd); |
} |
bfd_has_map (abfd) = FALSE; |
return TRUE; |
} |
/* Returns FALSE on error, TRUE otherwise. */ |
/* Flavor 2 of a bsd armap, similar to bfd_slurp_bsd_armap except the |
header is in a slightly different order and the map name is '/'. |
This flavour is used by hp300hpux. */ |
#define HPUX_SYMDEF_COUNT_SIZE 2 |
bfd_boolean |
bfd_slurp_bsd_armap_f2 (bfd *abfd) |
{ |
struct areltdata *mapdata; |
char nextname[17]; |
unsigned int counter; |
bfd_byte *raw_armap, *rbase; |
struct artdata *ardata = bfd_ardata (abfd); |
char *stringbase; |
unsigned int stringsize; |
unsigned int left; |
bfd_size_type amt; |
carsym *set; |
int i = bfd_bread (nextname, 16, abfd); |
if (i == 0) |
return TRUE; |
if (i != 16) |
return FALSE; |
/* The archive has at least 16 bytes in it. */ |
if (bfd_seek (abfd, (file_ptr) -16, SEEK_CUR) != 0) |
return FALSE; |
if (CONST_STRNEQ (nextname, "__.SYMDEF ") |
|| CONST_STRNEQ (nextname, "__.SYMDEF/ ")) /* Old Linux archives. */ |
return do_slurp_bsd_armap (abfd); |
if (! CONST_STRNEQ (nextname, "/ ")) |
{ |
bfd_has_map (abfd) = FALSE; |
return TRUE; |
} |
mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd); |
if (mapdata == NULL) |
return FALSE; |
if (mapdata->parsed_size < HPUX_SYMDEF_COUNT_SIZE + BSD_STRING_COUNT_SIZE) |
{ |
free (mapdata); |
wrong_format: |
bfd_set_error (bfd_error_wrong_format); |
byebye: |
return FALSE; |
} |
left = mapdata->parsed_size - HPUX_SYMDEF_COUNT_SIZE - BSD_STRING_COUNT_SIZE; |
amt = mapdata->parsed_size; |
free (mapdata); |
raw_armap = (bfd_byte *) bfd_zalloc (abfd, amt); |
if (raw_armap == NULL) |
goto byebye; |
if (bfd_bread (raw_armap, amt, abfd) != amt) |
{ |
if (bfd_get_error () != bfd_error_system_call) |
bfd_set_error (bfd_error_malformed_archive); |
goto byebye; |
} |
ardata->symdef_count = H_GET_16 (abfd, raw_armap); |
ardata->cache = 0; |
stringsize = H_GET_32 (abfd, raw_armap + HPUX_SYMDEF_COUNT_SIZE); |
if (stringsize > left) |
goto wrong_format; |
left -= stringsize; |
/* Skip sym count and string sz. */ |
stringbase = ((char *) raw_armap |
+ HPUX_SYMDEF_COUNT_SIZE |
+ BSD_STRING_COUNT_SIZE); |
rbase = (bfd_byte *) stringbase + stringsize; |
amt = ardata->symdef_count * BSD_SYMDEF_SIZE; |
if (amt > left) |
goto wrong_format; |
ardata->symdefs = (struct carsym *) bfd_alloc (abfd, amt); |
if (!ardata->symdefs) |
return FALSE; |
for (counter = 0, set = ardata->symdefs; |
counter < ardata->symdef_count; |
counter++, set++, rbase += BSD_SYMDEF_SIZE) |
{ |
set->name = H_GET_32 (abfd, rbase) + stringbase; |
set->file_offset = H_GET_32 (abfd, rbase + BSD_SYMDEF_OFFSET_SIZE); |
} |
ardata->first_file_filepos = bfd_tell (abfd); |
/* Pad to an even boundary if you have to. */ |
ardata->first_file_filepos += (ardata->first_file_filepos) % 2; |
/* FIXME, we should provide some way to free raw_ardata when |
we are done using the strings from it. For now, it seems |
to be allocated on an objalloc anyway... */ |
bfd_has_map (abfd) = TRUE; |
return TRUE; |
} |
/** Extended name table. |
Normally archives support only 14-character filenames. |
Intel has extended the format: longer names are stored in a special |
element (the first in the archive, or second if there is an armap); |
the name in the ar_hdr is replaced by <space><index into filename |
element>. Index is the P.R. of an int (decimal). Data General have |
extended the format by using the prefix // for the special element. */ |
/* Returns FALSE on error, TRUE otherwise. */ |
bfd_boolean |
_bfd_slurp_extended_name_table (bfd *abfd) |
{ |
char nextname[17]; |
struct areltdata *namedata; |
bfd_size_type amt; |
/* FIXME: Formatting sucks here, and in case of failure of BFD_READ, |
we probably don't want to return TRUE. */ |
if (bfd_seek (abfd, bfd_ardata (abfd)->first_file_filepos, SEEK_SET) != 0) |
return FALSE; |
if (bfd_bread (nextname, 16, abfd) == 16) |
{ |
if (bfd_seek (abfd, (file_ptr) -16, SEEK_CUR) != 0) |
return FALSE; |
if (! CONST_STRNEQ (nextname, "ARFILENAMES/ ") |
&& ! CONST_STRNEQ (nextname, "// ")) |
{ |
bfd_ardata (abfd)->extended_names = NULL; |
bfd_ardata (abfd)->extended_names_size = 0; |
return TRUE; |
} |
namedata = (struct areltdata *) _bfd_read_ar_hdr (abfd); |
if (namedata == NULL) |
return FALSE; |
amt = namedata->parsed_size; |
if (amt + 1 == 0) |
goto byebye; |
bfd_ardata (abfd)->extended_names_size = amt; |
bfd_ardata (abfd)->extended_names = (char *) bfd_zalloc (abfd, amt + 1); |
if (bfd_ardata (abfd)->extended_names == NULL) |
{ |
byebye: |
free (namedata); |
return FALSE; |
} |
if (bfd_bread (bfd_ardata (abfd)->extended_names, amt, abfd) != amt) |
{ |
if (bfd_get_error () != bfd_error_system_call) |
bfd_set_error (bfd_error_malformed_archive); |
bfd_release (abfd, (bfd_ardata (abfd)->extended_names)); |
bfd_ardata (abfd)->extended_names = NULL; |
goto byebye; |
} |
/* Since the archive is supposed to be printable if it contains |
text, the entries in the list are newline-padded, not null |
padded. In SVR4-style archives, the names also have a |
trailing '/'. DOS/NT created archive often have \ in them |
We'll fix all problems here.. */ |
{ |
char *ext_names = bfd_ardata (abfd)->extended_names; |
char *temp = ext_names; |
char *limit = temp + namedata->parsed_size; |
for (; temp < limit; ++temp) |
{ |
if (*temp == ARFMAG[1]) |
temp[temp > ext_names && temp[-1] == '/' ? -1 : 0] = '\0'; |
if (*temp == '\\') |
*temp = '/'; |
} |
*limit = '\0'; |
} |
/* Pad to an even boundary if you have to. */ |
bfd_ardata (abfd)->first_file_filepos = bfd_tell (abfd); |
bfd_ardata (abfd)->first_file_filepos += |
(bfd_ardata (abfd)->first_file_filepos) % 2; |
free (namedata); |
} |
return TRUE; |
} |
#ifdef VMS |
/* Return a copy of the stuff in the filename between any :]> and a |
semicolon. */ |
static const char * |
normalize (bfd *abfd, const char *file) |
{ |
const char *first; |
const char *last; |
char *copy; |
first = file + strlen (file) - 1; |
last = first + 1; |
while (first != file) |
{ |
if (*first == ';') |
last = first; |
if (*first == ':' || *first == ']' || *first == '>') |
{ |
first++; |
break; |
} |
first--; |
} |
copy = bfd_alloc (abfd, last - first + 1); |
if (copy == NULL) |
return NULL; |
memcpy (copy, first, last - first); |
copy[last - first] = 0; |
return copy; |
} |
#else |
static const char * |
normalize (bfd *abfd ATTRIBUTE_UNUSED, const char *file) |
{ |
return lbasename (file); |
} |
#endif |
/* Adjust a relative path name based on the reference path. |
For example: |
Relative path Reference path Result |
------------- -------------- ------ |
bar.o lib.a bar.o |
foo/bar.o lib.a foo/bar.o |
bar.o foo/lib.a ../bar.o |
foo/bar.o baz/lib.a ../foo/bar.o |
bar.o ../lib.a <parent of current dir>/bar.o |
; ../bar.o ../lib.a bar.o |
; ../bar.o lib.a ../bar.o |
foo/bar.o ../lib.a <parent of current dir>/foo/bar.o |
bar.o ../../lib.a <grandparent>/<parent>/bar.o |
bar.o foo/baz/lib.a ../../bar.o |
Note - the semicolons above are there to prevent the BFD chew |
utility from interpreting those lines as prototypes to put into |
the autogenerated bfd.h header... |
Note - the string is returned in a static buffer. */ |
static const char * |
adjust_relative_path (const char * path, const char * ref_path) |
{ |
static char *pathbuf = NULL; |
static unsigned int pathbuf_len = 0; |
const char *pathp; |
const char *refp; |
char * lpath; |
char * rpath; |
unsigned int len; |
unsigned int dir_up = 0; |
unsigned int dir_down = 0; |
char *newp; |
char * pwd = getpwd (); |
const char * down; |
/* Remove symlinks, '.' and '..' from the paths, if possible. */ |
lpath = lrealpath (path); |
pathp = lpath == NULL ? path : lpath; |
rpath = lrealpath (ref_path); |
refp = rpath == NULL ? ref_path : rpath; |
/* Remove common leading path elements. */ |
for (;;) |
{ |
const char *e1 = pathp; |
const char *e2 = refp; |
while (*e1 && ! IS_DIR_SEPARATOR (*e1)) |
++e1; |
while (*e2 && ! IS_DIR_SEPARATOR (*e2)) |
++e2; |
if (*e1 == '\0' || *e2 == '\0' || e1 - pathp != e2 - refp |
|| filename_ncmp (pathp, refp, e1 - pathp) != 0) |
break; |
pathp = e1 + 1; |
refp = e2 + 1; |
} |
len = strlen (pathp) + 1; |
/* For each leading path element in the reference path, |
insert "../" into the path. */ |
for (; *refp; ++refp) |
if (IS_DIR_SEPARATOR (*refp)) |
{ |
/* PR 12710: If the path element is "../" then instead of |
inserting "../" we need to insert the name of the directory |
at the current level. */ |
if (refp > ref_path + 1 |
&& refp[-1] == '.' |
&& refp[-2] == '.') |
dir_down ++; |
else |
dir_up ++; |
} |
/* If the lrealpath calls above succeeded then we should never |
see dir_up and dir_down both being non-zero. */ |
len += 3 * dir_up; |
if (dir_down) |
{ |
down = pwd + strlen (pwd) - 1; |
while (dir_down && down > pwd) |
{ |
if (IS_DIR_SEPARATOR (*down)) |
--dir_down; |
} |
BFD_ASSERT (dir_down == 0); |
len += strlen (down) + 1; |
} |
else |
down = NULL; |
if (len > pathbuf_len) |
{ |
if (pathbuf != NULL) |
free (pathbuf); |
pathbuf_len = 0; |
pathbuf = (char *) bfd_malloc (len); |
if (pathbuf == NULL) |
goto out; |
pathbuf_len = len; |
} |
newp = pathbuf; |
while (dir_up-- > 0) |
{ |
/* FIXME: Support Windows style path separators as well. */ |
strcpy (newp, "../"); |
newp += 3; |
} |
if (down) |
sprintf (newp, "%s/%s", down, pathp); |
else |
strcpy (newp, pathp); |
out: |
free (lpath); |
free (rpath); |
return pathbuf; |
} |
/* Build a BFD style extended name table. */ |
bfd_boolean |
_bfd_archive_bsd_construct_extended_name_table (bfd *abfd, |
char **tabloc, |
bfd_size_type *tablen, |
const char **name) |
{ |
*name = "ARFILENAMES/"; |
return _bfd_construct_extended_name_table (abfd, FALSE, tabloc, tablen); |
} |
/* Build an SVR4 style extended name table. */ |
bfd_boolean |
_bfd_archive_coff_construct_extended_name_table (bfd *abfd, |
char **tabloc, |
bfd_size_type *tablen, |
const char **name) |
{ |
*name = "//"; |
return _bfd_construct_extended_name_table (abfd, TRUE, tabloc, tablen); |
} |
/* Follows archive_head and produces an extended name table if |
necessary. Returns (in tabloc) a pointer to an extended name |
table, and in tablen the length of the table. If it makes an entry |
it clobbers the filename so that the element may be written without |
further massage. Returns TRUE if it ran successfully, FALSE if |
something went wrong. A successful return may still involve a |
zero-length tablen! */ |
bfd_boolean |
_bfd_construct_extended_name_table (bfd *abfd, |
bfd_boolean trailing_slash, |
char **tabloc, |
bfd_size_type *tablen) |
{ |
unsigned int maxname = ar_maxnamelen (abfd); |
bfd_size_type total_namelen = 0; |
bfd *current; |
char *strptr; |
const char *last_filename; |
long last_stroff; |
*tablen = 0; |
last_filename = NULL; |
/* Figure out how long the table should be. */ |
for (current = abfd->archive_head; |
current != NULL; |
current = current->archive_next) |
{ |
const char *normal; |
unsigned int thislen; |
if (bfd_is_thin_archive (abfd)) |
{ |
const char *filename = current->filename; |
/* If the element being added is a member of another archive |
(i.e., we are flattening), use the containing archive's name. */ |
if (current->my_archive |
&& ! bfd_is_thin_archive (current->my_archive)) |
filename = current->my_archive->filename; |
/* If the path is the same as the previous path seen, |
reuse it. This can happen when flattening a thin |
archive that contains other archives. */ |
if (last_filename && filename_cmp (last_filename, filename) == 0) |
continue; |
last_filename = filename; |
/* If the path is relative, adjust it relative to |
the containing archive. */ |
if (! IS_ABSOLUTE_PATH (filename) |
&& ! IS_ABSOLUTE_PATH (abfd->filename)) |
normal = adjust_relative_path (filename, abfd->filename); |
else |
normal = filename; |
/* In a thin archive, always store the full pathname |
in the extended name table. */ |
total_namelen += strlen (normal) + 1; |
if (trailing_slash) |
/* Leave room for trailing slash. */ |
++total_namelen; |
continue; |
} |
normal = normalize (current, current->filename); |
if (normal == NULL) |
return FALSE; |
thislen = strlen (normal); |
if (thislen > maxname |
&& (bfd_get_file_flags (abfd) & BFD_TRADITIONAL_FORMAT) != 0) |
thislen = maxname; |
if (thislen > maxname) |
{ |
/* Add one to leave room for \n. */ |
total_namelen += thislen + 1; |
if (trailing_slash) |
{ |
/* Leave room for trailing slash. */ |
++total_namelen; |
} |
} |
else |
{ |
struct ar_hdr *hdr = arch_hdr (current); |
if (filename_ncmp (normal, hdr->ar_name, thislen) != 0 |
|| (thislen < sizeof hdr->ar_name |
&& hdr->ar_name[thislen] != ar_padchar (current))) |
{ |
/* Must have been using extended format even though it |
didn't need to. Fix it to use normal format. */ |
memcpy (hdr->ar_name, normal, thislen); |
if (thislen < maxname |
|| (thislen == maxname && thislen < sizeof hdr->ar_name)) |
hdr->ar_name[thislen] = ar_padchar (current); |
} |
} |
} |
if (total_namelen == 0) |
return TRUE; |
*tabloc = (char *) bfd_zalloc (abfd, total_namelen); |
if (*tabloc == NULL) |
return FALSE; |
*tablen = total_namelen; |
strptr = *tabloc; |
last_filename = NULL; |
last_stroff = 0; |
for (current = abfd->archive_head; |
current != NULL; |
current = current->archive_next) |
{ |
const char *normal; |
unsigned int thislen; |
long stroff; |
const char *filename = current->filename; |
if (bfd_is_thin_archive (abfd)) |
{ |
/* If the element being added is a member of another archive |
(i.e., we are flattening), use the containing archive's name. */ |
if (current->my_archive |
&& ! bfd_is_thin_archive (current->my_archive)) |
filename = current->my_archive->filename; |
/* If the path is the same as the previous path seen, |
reuse it. This can happen when flattening a thin |
archive that contains other archives. |
If the path is relative, adjust it relative to |
the containing archive. */ |
if (last_filename && filename_cmp (last_filename, filename) == 0) |
normal = last_filename; |
else if (! IS_ABSOLUTE_PATH (filename) |
&& ! IS_ABSOLUTE_PATH (abfd->filename)) |
normal = adjust_relative_path (filename, abfd->filename); |
else |
normal = filename; |
} |
else |
{ |
normal = normalize (current, filename); |
if (normal == NULL) |
return FALSE; |
} |
thislen = strlen (normal); |
if (thislen > maxname || bfd_is_thin_archive (abfd)) |
{ |
/* Works for now; may need to be re-engineered if we |
encounter an oddball archive format and want to |
generalise this hack. */ |
struct ar_hdr *hdr = arch_hdr (current); |
if (normal == last_filename) |
stroff = last_stroff; |
else |
{ |
strcpy (strptr, normal); |
if (! trailing_slash) |
strptr[thislen] = ARFMAG[1]; |
else |
{ |
strptr[thislen] = '/'; |
strptr[thislen + 1] = ARFMAG[1]; |
} |
stroff = strptr - *tabloc; |
last_stroff = stroff; |
} |
hdr->ar_name[0] = ar_padchar (current); |
if (bfd_is_thin_archive (abfd) && current->origin > 0) |
{ |
int len = snprintf (hdr->ar_name + 1, maxname - 1, "%-ld:", |
stroff); |
_bfd_ar_spacepad (hdr->ar_name + 1 + len, maxname - 1 - len, |
"%-ld", |
current->origin - sizeof (struct ar_hdr)); |
} |
else |
_bfd_ar_spacepad (hdr->ar_name + 1, maxname - 1, "%-ld", stroff); |
if (normal != last_filename) |
{ |
strptr += thislen + 1; |
if (trailing_slash) |
++strptr; |
last_filename = filename; |
} |
} |
} |
return TRUE; |
} |
/* Do not construct an extended name table but transforms name field into |
its extended form. */ |
bfd_boolean |
_bfd_archive_bsd44_construct_extended_name_table (bfd *abfd, |
char **tabloc, |
bfd_size_type *tablen, |
const char **name) |
{ |
unsigned int maxname = ar_maxnamelen (abfd); |
bfd *current; |
*tablen = 0; |
*tabloc = NULL; |
*name = NULL; |
for (current = abfd->archive_head; |
current != NULL; |
current = current->archive_next) |
{ |
const char *normal = normalize (current, current->filename); |
int has_space = 0; |
unsigned int len; |
if (normal == NULL) |
return FALSE; |
for (len = 0; normal[len]; len++) |
if (normal[len] == ' ') |
has_space = 1; |
if (len > maxname || has_space) |
{ |
struct ar_hdr *hdr = arch_hdr (current); |
len = (len + 3) & ~3; |
arch_eltdata (current)->extra_size = len; |
_bfd_ar_spacepad (hdr->ar_name, maxname, "#1/%lu", len); |
} |
} |
return TRUE; |
} |
/* Write an archive header. */ |
bfd_boolean |
_bfd_generic_write_ar_hdr (bfd *archive, bfd *abfd) |
{ |
struct ar_hdr *hdr = arch_hdr (abfd); |
if (bfd_bwrite (hdr, sizeof (*hdr), archive) != sizeof (*hdr)) |
return FALSE; |
return TRUE; |
} |
/* Write an archive header using BSD4.4 convention. */ |
bfd_boolean |
_bfd_bsd44_write_ar_hdr (bfd *archive, bfd *abfd) |
{ |
struct ar_hdr *hdr = arch_hdr (abfd); |
if (is_bsd44_extended_name (hdr->ar_name)) |
{ |
/* This is a BSD 4.4 extended name. */ |
const char *fullname = normalize (abfd, abfd->filename); |
unsigned int len = strlen (fullname); |
unsigned int padded_len = (len + 3) & ~3; |
BFD_ASSERT (padded_len == arch_eltdata (abfd)->extra_size); |
if (!_bfd_ar_sizepad (hdr->ar_size, sizeof (hdr->ar_size), |
arch_eltdata (abfd)->parsed_size + padded_len)) |
return FALSE; |
if (bfd_bwrite (hdr, sizeof (*hdr), archive) != sizeof (*hdr)) |
return FALSE; |
if (bfd_bwrite (fullname, len, archive) != len) |
return FALSE; |
if (len & 3) |
{ |
static const char pad[3] = { 0, 0, 0 }; |
len = 4 - (len & 3); |
if (bfd_bwrite (pad, len, archive) != len) |
return FALSE; |
} |
} |
else |
{ |
if (bfd_bwrite (hdr, sizeof (*hdr), archive) != sizeof (*hdr)) |
return FALSE; |
} |
return TRUE; |
} |
/* A couple of functions for creating ar_hdrs. */ |
#ifdef HPUX_LARGE_AR_IDS |
/* Function to encode large UID/GID values according to HP. */ |
static void |
hpux_uid_gid_encode (char str[6], long int id) |
{ |
int cnt; |
str[5] = '@' + (id & 3); |
id >>= 2; |
for (cnt = 4; cnt >= 0; --cnt, id >>= 6) |
str[cnt] = ' ' + (id & 0x3f); |
} |
#endif /* HPUX_LARGE_AR_IDS */ |
#ifndef HAVE_GETUID |
#define getuid() 0 |
#endif |
#ifndef HAVE_GETGID |
#define getgid() 0 |
#endif |
/* Takes a filename, returns an arelt_data for it, or NULL if it can't |
make one. The filename must refer to a filename in the filesystem. |
The filename field of the ar_hdr will NOT be initialized. If member |
is set, and it's an in-memory bfd, we fake it. */ |
static struct areltdata * |
bfd_ar_hdr_from_filesystem (bfd *abfd, const char *filename, bfd *member) |
{ |
struct stat status; |
struct areltdata *ared; |
struct ar_hdr *hdr; |
bfd_size_type amt; |
if (member && (member->flags & BFD_IN_MEMORY) != 0) |
{ |
/* Assume we just "made" the member, and fake it. */ |
struct bfd_in_memory *bim = (struct bfd_in_memory *) member->iostream; |
time (&status.st_mtime); |
status.st_uid = getuid (); |
status.st_gid = getgid (); |
status.st_mode = 0644; |
status.st_size = bim->size; |
} |
else if (stat (filename, &status) != 0) |
{ |
bfd_set_error (bfd_error_system_call); |
return NULL; |
} |
/* If the caller requested that the BFD generate deterministic output, |
fake values for modification time, UID, GID, and file mode. */ |
if ((abfd->flags & BFD_DETERMINISTIC_OUTPUT) != 0) |
{ |
status.st_mtime = 0; |
status.st_uid = 0; |
status.st_gid = 0; |
status.st_mode = 0644; |
} |
amt = sizeof (struct ar_hdr) + sizeof (struct areltdata); |
ared = (struct areltdata *) bfd_zmalloc (amt); |
if (ared == NULL) |
return NULL; |
hdr = (struct ar_hdr *) (((char *) ared) + sizeof (struct areltdata)); |
/* ar headers are space padded, not null padded! */ |
memset (hdr, ' ', sizeof (struct ar_hdr)); |
_bfd_ar_spacepad (hdr->ar_date, sizeof (hdr->ar_date), "%-12ld", |
status.st_mtime); |
#ifdef HPUX_LARGE_AR_IDS |
/* HP has a very "special" way to handle UID/GID's with numeric values |
> 99999. */ |
if (status.st_uid > 99999) |
hpux_uid_gid_encode (hdr->ar_uid, (long) status.st_uid); |
else |
#endif |
_bfd_ar_spacepad (hdr->ar_uid, sizeof (hdr->ar_uid), "%ld", |
status.st_uid); |
#ifdef HPUX_LARGE_AR_IDS |
/* HP has a very "special" way to handle UID/GID's with numeric values |
> 99999. */ |
if (status.st_gid > 99999) |
hpux_uid_gid_encode (hdr->ar_gid, (long) status.st_gid); |
else |
#endif |
_bfd_ar_spacepad (hdr->ar_gid, sizeof (hdr->ar_gid), "%ld", |
status.st_gid); |
_bfd_ar_spacepad (hdr->ar_mode, sizeof (hdr->ar_mode), "%-8lo", |
status.st_mode); |
if (!_bfd_ar_sizepad (hdr->ar_size, sizeof (hdr->ar_size), status.st_size)) |
{ |
free (ared); |
return NULL; |
} |
memcpy (hdr->ar_fmag, ARFMAG, 2); |
ared->parsed_size = status.st_size; |
ared->arch_header = (char *) hdr; |
return ared; |
} |
/* Analogous to stat call. */ |
int |
bfd_generic_stat_arch_elt (bfd *abfd, struct stat *buf) |
{ |
struct ar_hdr *hdr; |
char *aloser; |
if (abfd->arelt_data == NULL) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return -1; |
} |
hdr = arch_hdr (abfd); |
#define foo(arelt, stelt, size) \ |
buf->stelt = strtol (hdr->arelt, &aloser, size); \ |
if (aloser == hdr->arelt) \ |
return -1; |
/* Some platforms support special notations for large IDs. */ |
#ifdef HPUX_LARGE_AR_IDS |
# define foo2(arelt, stelt, size) \ |
if (hdr->arelt[5] == ' ') \ |
{ \ |
foo (arelt, stelt, size); \ |
} \ |
else \ |
{ \ |
int cnt; \ |
for (buf->stelt = cnt = 0; cnt < 5; ++cnt) \ |
{ \ |
if (hdr->arelt[cnt] < ' ' || hdr->arelt[cnt] > ' ' + 0x3f) \ |
return -1; \ |
buf->stelt <<= 6; \ |
buf->stelt += hdr->arelt[cnt] - ' '; \ |
} \ |
if (hdr->arelt[5] < '@' || hdr->arelt[5] > '@' + 3) \ |
return -1; \ |
buf->stelt <<= 2; \ |
buf->stelt += hdr->arelt[5] - '@'; \ |
} |
#else |
# define foo2(arelt, stelt, size) foo (arelt, stelt, size) |
#endif |
foo (ar_date, st_mtime, 10); |
foo2 (ar_uid, st_uid, 10); |
foo2 (ar_gid, st_gid, 10); |
foo (ar_mode, st_mode, 8); |
buf->st_size = arch_eltdata (abfd)->parsed_size; |
return 0; |
} |
void |
bfd_dont_truncate_arname (bfd *abfd, const char *pathname, char *arhdr) |
{ |
/* FIXME: This interacts unpleasantly with ar's quick-append option. |
Fortunately ic960 users will never use that option. Fixing this |
is very hard; fortunately I know how to do it and will do so once |
intel's release is out the door. */ |
struct ar_hdr *hdr = (struct ar_hdr *) arhdr; |
size_t length; |
const char *filename; |
size_t maxlen = ar_maxnamelen (abfd); |
if ((bfd_get_file_flags (abfd) & BFD_TRADITIONAL_FORMAT) != 0) |
{ |
bfd_bsd_truncate_arname (abfd, pathname, arhdr); |
return; |
} |
filename = normalize (abfd, pathname); |
if (filename == NULL) |
{ |
/* FIXME */ |
abort (); |
} |
length = strlen (filename); |
if (length <= maxlen) |
memcpy (hdr->ar_name, filename, length); |
/* Add the padding character if there is room for it. */ |
if (length < maxlen |
|| (length == maxlen && length < sizeof hdr->ar_name)) |
(hdr->ar_name)[length] = ar_padchar (abfd); |
} |
void |
bfd_bsd_truncate_arname (bfd *abfd, const char *pathname, char *arhdr) |
{ |
struct ar_hdr *hdr = (struct ar_hdr *) arhdr; |
size_t length; |
const char *filename = lbasename (pathname); |
size_t maxlen = ar_maxnamelen (abfd); |
length = strlen (filename); |
if (length <= maxlen) |
memcpy (hdr->ar_name, filename, length); |
else |
{ |
/* pathname: meet procrustes */ |
memcpy (hdr->ar_name, filename, maxlen); |
length = maxlen; |
} |
if (length < maxlen) |
(hdr->ar_name)[length] = ar_padchar (abfd); |
} |
/* Store name into ar header. Truncates the name to fit. |
1> strip pathname to be just the basename. |
2> if it's short enuf to fit, stuff it in. |
3> If it doesn't end with .o, truncate it to fit |
4> truncate it before the .o, append .o, stuff THAT in. */ |
/* This is what gnu ar does. It's better but incompatible with the |
bsd ar. */ |
void |
bfd_gnu_truncate_arname (bfd *abfd, const char *pathname, char *arhdr) |
{ |
struct ar_hdr *hdr = (struct ar_hdr *) arhdr; |
size_t length; |
const char *filename = lbasename (pathname); |
size_t maxlen = ar_maxnamelen (abfd); |
length = strlen (filename); |
if (length <= maxlen) |
memcpy (hdr->ar_name, filename, length); |
else |
{ |
/* pathname: meet procrustes. */ |
memcpy (hdr->ar_name, filename, maxlen); |
if ((filename[length - 2] == '.') && (filename[length - 1] == 'o')) |
{ |
hdr->ar_name[maxlen - 2] = '.'; |
hdr->ar_name[maxlen - 1] = 'o'; |
} |
length = maxlen; |
} |
if (length < 16) |
(hdr->ar_name)[length] = ar_padchar (abfd); |
} |
/* The BFD is open for write and has its format set to bfd_archive. */ |
bfd_boolean |
_bfd_write_archive_contents (bfd *arch) |
{ |
bfd *current; |
char *etable = NULL; |
bfd_size_type elength = 0; |
const char *ename = NULL; |
bfd_boolean makemap = bfd_has_map (arch); |
/* If no .o's, don't bother to make a map. */ |
bfd_boolean hasobjects = FALSE; |
bfd_size_type wrote; |
int tries; |
char *armag; |
/* Verify the viability of all entries; if any of them live in the |
filesystem (as opposed to living in an archive open for input) |
then construct a fresh ar_hdr for them. */ |
for (current = arch->archive_head; |
current != NULL; |
current = current->archive_next) |
{ |
/* This check is checking the bfds for the objects we're reading |
from (which are usually either an object file or archive on |
disk), not the archive entries we're writing to. We don't |
actually create bfds for the archive members, we just copy |
them byte-wise when we write out the archive. */ |
if (bfd_write_p (current)) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
goto input_err; |
} |
if (!current->arelt_data) |
{ |
current->arelt_data = |
bfd_ar_hdr_from_filesystem (arch, current->filename, current); |
if (!current->arelt_data) |
goto input_err; |
/* Put in the file name. */ |
BFD_SEND (arch, _bfd_truncate_arname, |
(arch, current->filename, (char *) arch_hdr (current))); |
} |
if (makemap && ! hasobjects) |
{ /* Don't bother if we won't make a map! */ |
if ((bfd_check_format (current, bfd_object))) |
hasobjects = TRUE; |
} |
} |
if (!BFD_SEND (arch, _bfd_construct_extended_name_table, |
(arch, &etable, &elength, &ename))) |
return FALSE; |
if (bfd_seek (arch, (file_ptr) 0, SEEK_SET) != 0) |
return FALSE; |
armag = ARMAG; |
if (bfd_is_thin_archive (arch)) |
armag = ARMAGT; |
wrote = bfd_bwrite (armag, SARMAG, arch); |
if (wrote != SARMAG) |
return FALSE; |
if (makemap && hasobjects) |
{ |
if (! _bfd_compute_and_write_armap (arch, (unsigned int) elength)) |
return FALSE; |
} |
if (elength != 0) |
{ |
struct ar_hdr hdr; |
memset (&hdr, ' ', sizeof (struct ar_hdr)); |
memcpy (hdr.ar_name, ename, strlen (ename)); |
/* Round size up to even number in archive header. */ |
if (!_bfd_ar_sizepad (hdr.ar_size, sizeof (hdr.ar_size), |
(elength + 1) & ~(bfd_size_type) 1)) |
return FALSE; |
memcpy (hdr.ar_fmag, ARFMAG, 2); |
if ((bfd_bwrite (&hdr, sizeof (struct ar_hdr), arch) |
!= sizeof (struct ar_hdr)) |
|| bfd_bwrite (etable, elength, arch) != elength) |
return FALSE; |
if ((elength % 2) == 1) |
{ |
if (bfd_bwrite (&ARFMAG[1], 1, arch) != 1) |
return FALSE; |
} |
} |
for (current = arch->archive_head; |
current != NULL; |
current = current->archive_next) |
{ |
char buffer[DEFAULT_BUFFERSIZE]; |
bfd_size_type remaining = arelt_size (current); |
/* Write ar header. */ |
if (!_bfd_write_ar_hdr (arch, current)) |
return FALSE; |
if (bfd_is_thin_archive (arch)) |
continue; |
if (bfd_seek (current, (file_ptr) 0, SEEK_SET) != 0) |
goto input_err; |
while (remaining) |
{ |
unsigned int amt = DEFAULT_BUFFERSIZE; |
if (amt > remaining) |
amt = remaining; |
errno = 0; |
if (bfd_bread (buffer, amt, current) != amt) |
{ |
if (bfd_get_error () != bfd_error_system_call) |
bfd_set_error (bfd_error_file_truncated); |
goto input_err; |
} |
if (bfd_bwrite (buffer, amt, arch) != amt) |
return FALSE; |
remaining -= amt; |
} |
if ((arelt_size (current) % 2) == 1) |
{ |
if (bfd_bwrite (&ARFMAG[1], 1, arch) != 1) |
return FALSE; |
} |
} |
if (makemap && hasobjects) |
{ |
/* Verify the timestamp in the archive file. If it would not be |
accepted by the linker, rewrite it until it would be. If |
anything odd happens, break out and just return. (The |
Berkeley linker checks the timestamp and refuses to read the |
table-of-contents if it is >60 seconds less than the file's |
modified-time. That painful hack requires this painful hack. */ |
tries = 1; |
do |
{ |
if (bfd_update_armap_timestamp (arch)) |
break; |
(*_bfd_error_handler) |
(_("Warning: writing archive was slow: rewriting timestamp\n")); |
} |
while (++tries < 6); |
} |
return TRUE; |
input_err: |
bfd_set_error (bfd_error_on_input, current, bfd_get_error ()); |
return FALSE; |
} |
/* Note that the namidx for the first symbol is 0. */ |
bfd_boolean |
_bfd_compute_and_write_armap (bfd *arch, unsigned int elength) |
{ |
char *first_name = NULL; |
bfd *current; |
file_ptr elt_no = 0; |
struct orl *map = NULL; |
unsigned int orl_max = 1024; /* Fine initial default. */ |
unsigned int orl_count = 0; |
int stridx = 0; |
asymbol **syms = NULL; |
long syms_max = 0; |
bfd_boolean ret; |
bfd_size_type amt; |
/* Dunno if this is the best place for this info... */ |
if (elength != 0) |
elength += sizeof (struct ar_hdr); |
elength += elength % 2; |
amt = orl_max * sizeof (struct orl); |
map = (struct orl *) bfd_malloc (amt); |
if (map == NULL) |
goto error_return; |
/* We put the symbol names on the arch objalloc, and then discard |
them when done. */ |
first_name = (char *) bfd_alloc (arch, 1); |
if (first_name == NULL) |
goto error_return; |
/* Drop all the files called __.SYMDEF, we're going to make our own. */ |
while (arch->archive_head |
&& strcmp (arch->archive_head->filename, "__.SYMDEF") == 0) |
arch->archive_head = arch->archive_head->archive_next; |
/* Map over each element. */ |
for (current = arch->archive_head; |
current != NULL; |
current = current->archive_next, elt_no++) |
{ |
if (bfd_check_format (current, bfd_object) |
&& (bfd_get_file_flags (current) & HAS_SYMS) != 0) |
{ |
long storage; |
long symcount; |
long src_count; |
storage = bfd_get_symtab_upper_bound (current); |
if (storage < 0) |
goto error_return; |
if (storage != 0) |
{ |
if (storage > syms_max) |
{ |
if (syms_max > 0) |
free (syms); |
syms_max = storage; |
syms = (asymbol **) bfd_malloc (syms_max); |
if (syms == NULL) |
goto error_return; |
} |
symcount = bfd_canonicalize_symtab (current, syms); |
if (symcount < 0) |
goto error_return; |
/* Now map over all the symbols, picking out the ones we |
want. */ |
for (src_count = 0; src_count < symcount; src_count++) |
{ |
flagword flags = (syms[src_count])->flags; |
asection *sec = syms[src_count]->section; |
if (((flags & (BSF_GLOBAL |
| BSF_WEAK |
| BSF_INDIRECT |
| BSF_GNU_UNIQUE)) != 0 |
|| bfd_is_com_section (sec)) |
&& ! bfd_is_und_section (sec)) |
{ |
bfd_size_type namelen; |
struct orl *new_map; |
/* This symbol will go into the archive header. */ |
if (orl_count == orl_max) |
{ |
orl_max *= 2; |
amt = orl_max * sizeof (struct orl); |
new_map = (struct orl *) bfd_realloc (map, amt); |
if (new_map == NULL) |
goto error_return; |
map = new_map; |
} |
namelen = strlen (syms[src_count]->name); |
amt = sizeof (char *); |
map[orl_count].name = (char **) bfd_alloc (arch, amt); |
if (map[orl_count].name == NULL) |
goto error_return; |
*(map[orl_count].name) = (char *) bfd_alloc (arch, |
namelen + 1); |
if (*(map[orl_count].name) == NULL) |
goto error_return; |
strcpy (*(map[orl_count].name), syms[src_count]->name); |
map[orl_count].u.abfd = current; |
map[orl_count].namidx = stridx; |
stridx += namelen + 1; |
++orl_count; |
} |
} |
} |
/* Now ask the BFD to free up any cached information, so we |
don't fill all of memory with symbol tables. */ |
if (! bfd_free_cached_info (current)) |
goto error_return; |
} |
} |
/* OK, now we have collected all the data, let's write them out. */ |
ret = BFD_SEND (arch, write_armap, |
(arch, elength, map, orl_count, stridx)); |
if (syms_max > 0) |
free (syms); |
if (map != NULL) |
free (map); |
if (first_name != NULL) |
bfd_release (arch, first_name); |
return ret; |
error_return: |
if (syms_max > 0) |
free (syms); |
if (map != NULL) |
free (map); |
if (first_name != NULL) |
bfd_release (arch, first_name); |
return FALSE; |
} |
bfd_boolean |
bsd_write_armap (bfd *arch, |
unsigned int elength, |
struct orl *map, |
unsigned int orl_count, |
int stridx) |
{ |
int padit = stridx & 1; |
unsigned int ranlibsize = orl_count * BSD_SYMDEF_SIZE; |
unsigned int stringsize = stridx + padit; |
/* Include 8 bytes to store ranlibsize and stringsize in output. */ |
unsigned int mapsize = ranlibsize + stringsize + 8; |
file_ptr firstreal; |
bfd *current = arch->archive_head; |
bfd *last_elt = current; /* Last element arch seen. */ |
bfd_byte temp[4]; |
unsigned int count; |
struct ar_hdr hdr; |
long uid, gid; |
firstreal = mapsize + elength + sizeof (struct ar_hdr) + SARMAG; |
/* If deterministic, we use 0 as the timestamp in the map. |
Some linkers may require that the archive filesystem modification |
time is less than (or near to) the archive map timestamp. Those |
linkers should not be used with deterministic mode. (GNU ld and |
Gold do not have this restriction.) */ |
bfd_ardata (arch)->armap_timestamp = 0; |
uid = 0; |
gid = 0; |
if ((arch->flags & BFD_DETERMINISTIC_OUTPUT) == 0) |
{ |
struct stat statbuf; |
if (stat (arch->filename, &statbuf) == 0) |
bfd_ardata (arch)->armap_timestamp = (statbuf.st_mtime |
+ ARMAP_TIME_OFFSET); |
uid = getuid(); |
gid = getgid(); |
} |
memset (&hdr, ' ', sizeof (struct ar_hdr)); |
memcpy (hdr.ar_name, RANLIBMAG, strlen (RANLIBMAG)); |
bfd_ardata (arch)->armap_datepos = (SARMAG |
+ offsetof (struct ar_hdr, ar_date[0])); |
_bfd_ar_spacepad (hdr.ar_date, sizeof (hdr.ar_date), "%ld", |
bfd_ardata (arch)->armap_timestamp); |
_bfd_ar_spacepad (hdr.ar_uid, sizeof (hdr.ar_uid), "%ld", uid); |
_bfd_ar_spacepad (hdr.ar_gid, sizeof (hdr.ar_gid), "%ld", gid); |
if (!_bfd_ar_sizepad (hdr.ar_size, sizeof (hdr.ar_size), mapsize)) |
return FALSE; |
memcpy (hdr.ar_fmag, ARFMAG, 2); |
if (bfd_bwrite (&hdr, sizeof (struct ar_hdr), arch) |
!= sizeof (struct ar_hdr)) |
return FALSE; |
H_PUT_32 (arch, ranlibsize, temp); |
if (bfd_bwrite (temp, sizeof (temp), arch) != sizeof (temp)) |
return FALSE; |
for (count = 0; count < orl_count; count++) |
{ |
unsigned int offset; |
bfd_byte buf[BSD_SYMDEF_SIZE]; |
if (map[count].u.abfd != last_elt) |
{ |
do |
{ |
struct areltdata *ared = arch_eltdata (current); |
firstreal += (ared->parsed_size + ared->extra_size |
+ sizeof (struct ar_hdr)); |
firstreal += firstreal % 2; |
current = current->archive_next; |
} |
while (current != map[count].u.abfd); |
} |
/* The archive file format only has 4 bytes to store the offset |
of the member. Check to make sure that firstreal has not grown |
too big. */ |
offset = (unsigned int) firstreal; |
if (firstreal != (file_ptr) offset) |
{ |
bfd_set_error (bfd_error_file_truncated); |
return FALSE; |
} |
last_elt = current; |
H_PUT_32 (arch, map[count].namidx, buf); |
H_PUT_32 (arch, firstreal, buf + BSD_SYMDEF_OFFSET_SIZE); |
if (bfd_bwrite (buf, BSD_SYMDEF_SIZE, arch) |
!= BSD_SYMDEF_SIZE) |
return FALSE; |
} |
/* Now write the strings themselves. */ |
H_PUT_32 (arch, stringsize, temp); |
if (bfd_bwrite (temp, sizeof (temp), arch) != sizeof (temp)) |
return FALSE; |
for (count = 0; count < orl_count; count++) |
{ |
size_t len = strlen (*map[count].name) + 1; |
if (bfd_bwrite (*map[count].name, len, arch) != len) |
return FALSE; |
} |
/* The spec sez this should be a newline. But in order to be |
bug-compatible for sun's ar we use a null. */ |
if (padit) |
{ |
if (bfd_bwrite ("", 1, arch) != 1) |
return FALSE; |
} |
return TRUE; |
} |
/* At the end of archive file handling, update the timestamp in the |
file, so the linker will accept it. |
Return TRUE if the timestamp was OK, or an unusual problem happened. |
Return FALSE if we updated the timestamp. */ |
bfd_boolean |
_bfd_archive_bsd_update_armap_timestamp (bfd *arch) |
{ |
struct stat archstat; |
struct ar_hdr hdr; |
/* If creating deterministic archives, just leave the timestamp as-is. */ |
if ((arch->flags & BFD_DETERMINISTIC_OUTPUT) != 0) |
return TRUE; |
/* Flush writes, get last-write timestamp from file, and compare it |
to the timestamp IN the file. */ |
bfd_flush (arch); |
if (bfd_stat (arch, &archstat) == -1) |
{ |
bfd_perror (_("Reading archive file mod timestamp")); |
/* Can't read mod time for some reason. */ |
return TRUE; |
} |
if (((long) archstat.st_mtime) <= bfd_ardata (arch)->armap_timestamp) |
/* OK by the linker's rules. */ |
return TRUE; |
/* Update the timestamp. */ |
bfd_ardata (arch)->armap_timestamp = archstat.st_mtime + ARMAP_TIME_OFFSET; |
/* Prepare an ASCII version suitable for writing. */ |
memset (hdr.ar_date, ' ', sizeof (hdr.ar_date)); |
_bfd_ar_spacepad (hdr.ar_date, sizeof (hdr.ar_date), "%ld", |
bfd_ardata (arch)->armap_timestamp); |
/* Write it into the file. */ |
bfd_ardata (arch)->armap_datepos = (SARMAG |
+ offsetof (struct ar_hdr, ar_date[0])); |
if (bfd_seek (arch, bfd_ardata (arch)->armap_datepos, SEEK_SET) != 0 |
|| (bfd_bwrite (hdr.ar_date, sizeof (hdr.ar_date), arch) |
!= sizeof (hdr.ar_date))) |
{ |
bfd_perror (_("Writing updated armap timestamp")); |
/* Some error while writing. */ |
return TRUE; |
} |
/* We updated the timestamp successfully. */ |
return FALSE; |
} |
/* A coff armap looks like : |
lARMAG |
struct ar_hdr with name = '/' |
number of symbols |
offset of file for symbol 0 |
offset of file for symbol 1 |
offset of file for symbol n-1 |
symbol name 0 |
symbol name 1 |
symbol name n-1 */ |
bfd_boolean |
coff_write_armap (bfd *arch, |
unsigned int elength, |
struct orl *map, |
unsigned int symbol_count, |
int stridx) |
{ |
/* The size of the ranlib is the number of exported symbols in the |
archive * the number of bytes in an int, + an int for the count. */ |
unsigned int ranlibsize = (symbol_count * 4) + 4; |
unsigned int stringsize = stridx; |
unsigned int mapsize = stringsize + ranlibsize; |
file_ptr archive_member_file_ptr; |
bfd *current = arch->archive_head; |
unsigned int count; |
struct ar_hdr hdr; |
int padit = mapsize & 1; |
if (padit) |
mapsize++; |
/* Work out where the first object file will go in the archive. */ |
archive_member_file_ptr = (mapsize |
+ elength |
+ sizeof (struct ar_hdr) |
+ SARMAG); |
memset (&hdr, ' ', sizeof (struct ar_hdr)); |
hdr.ar_name[0] = '/'; |
if (!_bfd_ar_sizepad (hdr.ar_size, sizeof (hdr.ar_size), mapsize)) |
return FALSE; |
_bfd_ar_spacepad (hdr.ar_date, sizeof (hdr.ar_date), "%ld", |
((arch->flags & BFD_DETERMINISTIC_OUTPUT) == 0 |
? time (NULL) : 0)); |
/* This, at least, is what Intel coff sets the values to. */ |
_bfd_ar_spacepad (hdr.ar_uid, sizeof (hdr.ar_uid), "%ld", 0); |
_bfd_ar_spacepad (hdr.ar_gid, sizeof (hdr.ar_gid), "%ld", 0); |
_bfd_ar_spacepad (hdr.ar_mode, sizeof (hdr.ar_mode), "%-7lo", 0); |
memcpy (hdr.ar_fmag, ARFMAG, 2); |
/* Write the ar header for this item and the number of symbols. */ |
if (bfd_bwrite (&hdr, sizeof (struct ar_hdr), arch) |
!= sizeof (struct ar_hdr)) |
return FALSE; |
if (!bfd_write_bigendian_4byte_int (arch, symbol_count)) |
return FALSE; |
/* Two passes, first write the file offsets for each symbol - |
remembering that each offset is on a two byte boundary. */ |
/* Write out the file offset for the file associated with each |
symbol, and remember to keep the offsets padded out. */ |
current = arch->archive_head; |
count = 0; |
while (current != NULL && count < symbol_count) |
{ |
/* For each symbol which is used defined in this object, write |
out the object file's address in the archive. */ |
while (count < symbol_count && map[count].u.abfd == current) |
{ |
unsigned int offset = (unsigned int) archive_member_file_ptr; |
/* Catch an attempt to grow an archive past its 4Gb limit. */ |
if (archive_member_file_ptr != (file_ptr) offset) |
{ |
bfd_set_error (bfd_error_file_truncated); |
return FALSE; |
} |
if (!bfd_write_bigendian_4byte_int (arch, offset)) |
return FALSE; |
count++; |
} |
archive_member_file_ptr += sizeof (struct ar_hdr); |
if (! bfd_is_thin_archive (arch)) |
{ |
/* Add size of this archive entry. */ |
archive_member_file_ptr += arelt_size (current); |
/* Remember about the even alignment. */ |
archive_member_file_ptr += archive_member_file_ptr % 2; |
} |
current = current->archive_next; |
} |
/* Now write the strings themselves. */ |
for (count = 0; count < symbol_count; count++) |
{ |
size_t len = strlen (*map[count].name) + 1; |
if (bfd_bwrite (*map[count].name, len, arch) != len) |
return FALSE; |
} |
/* The spec sez this should be a newline. But in order to be |
bug-compatible for arc960 we use a null. */ |
if (padit) |
{ |
if (bfd_bwrite ("", 1, arch) != 1) |
return FALSE; |
} |
return TRUE; |
} |
static int |
archive_close_worker (void **slot, void *inf ATTRIBUTE_UNUSED) |
{ |
struct ar_cache *ent = (struct ar_cache *) *slot; |
bfd_close_all_done (ent->arbfd); |
return 1; |
} |
bfd_boolean |
_bfd_archive_close_and_cleanup (bfd *abfd) |
{ |
if (bfd_read_p (abfd) && abfd->format == bfd_archive) |
{ |
bfd *nbfd; |
bfd *next; |
htab_t htab; |
/* Close nested archives (if this bfd is a thin archive). */ |
for (nbfd = abfd->nested_archives; nbfd; nbfd = next) |
{ |
next = nbfd->archive_next; |
bfd_close (nbfd); |
} |
htab = bfd_ardata (abfd)->cache; |
if (htab) |
{ |
htab_traverse_noresize (htab, archive_close_worker, NULL); |
htab_delete (htab); |
bfd_ardata (abfd)->cache = NULL; |
} |
} |
if (arch_eltdata (abfd) != NULL) |
{ |
struct areltdata *ared = arch_eltdata (abfd); |
htab_t htab = (htab_t) ared->parent_cache; |
if (htab) |
{ |
struct ar_cache ent; |
void **slot; |
ent.ptr = ared->key; |
slot = htab_find_slot (htab, &ent, NO_INSERT); |
if (slot != NULL) |
{ |
BFD_ASSERT (((struct ar_cache *) *slot)->arbfd == abfd); |
htab_clear_slot (htab, slot); |
} |
} |
} |
return TRUE; |
} |
/contrib/toolchain/binutils/bfd/archures.c |
---|
0,0 → 1,1387 |
/* BFD library support routines for architectures. |
Copyright 1990-2013 Free Software Foundation, Inc. |
Hacked by John Gilmore and Steve Chamberlain of Cygnus Support. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
#include "safe-ctype.h" |
/* |
SECTION |
Architectures |
BFD keeps one atom in a BFD describing the |
architecture of the data attached to the BFD: a pointer to a |
<<bfd_arch_info_type>>. |
Pointers to structures can be requested independently of a BFD |
so that an architecture's information can be interrogated |
without access to an open BFD. |
The architecture information is provided by each architecture package. |
The set of default architectures is selected by the macro |
<<SELECT_ARCHITECTURES>>. This is normally set up in the |
@file{config/@var{target}.mt} file of your choice. If the name is not |
defined, then all the architectures supported are included. |
When BFD starts up, all the architectures are called with an |
initialize method. It is up to the architecture back end to |
insert as many items into the list of architectures as it wants to; |
generally this would be one for each machine and one for the |
default case (an item with a machine field of 0). |
BFD's idea of an architecture is implemented in @file{archures.c}. |
*/ |
/* |
SUBSECTION |
bfd_architecture |
DESCRIPTION |
This enum gives the object file's CPU architecture, in a |
global sense---i.e., what processor family does it belong to? |
Another field indicates which processor within |
the family is in use. The machine gives a number which |
distinguishes different versions of the architecture, |
containing, for example, 2 and 3 for Intel i960 KA and i960 KB, |
and 68020 and 68030 for Motorola 68020 and 68030. |
.enum bfd_architecture |
.{ |
. bfd_arch_unknown, {* File arch not known. *} |
. bfd_arch_obscure, {* Arch known, not one of these. *} |
. bfd_arch_m68k, {* Motorola 68xxx *} |
.#define bfd_mach_m68000 1 |
.#define bfd_mach_m68008 2 |
.#define bfd_mach_m68010 3 |
.#define bfd_mach_m68020 4 |
.#define bfd_mach_m68030 5 |
.#define bfd_mach_m68040 6 |
.#define bfd_mach_m68060 7 |
.#define bfd_mach_cpu32 8 |
.#define bfd_mach_fido 9 |
.#define bfd_mach_mcf_isa_a_nodiv 10 |
.#define bfd_mach_mcf_isa_a 11 |
.#define bfd_mach_mcf_isa_a_mac 12 |
.#define bfd_mach_mcf_isa_a_emac 13 |
.#define bfd_mach_mcf_isa_aplus 14 |
.#define bfd_mach_mcf_isa_aplus_mac 15 |
.#define bfd_mach_mcf_isa_aplus_emac 16 |
.#define bfd_mach_mcf_isa_b_nousp 17 |
.#define bfd_mach_mcf_isa_b_nousp_mac 18 |
.#define bfd_mach_mcf_isa_b_nousp_emac 19 |
.#define bfd_mach_mcf_isa_b 20 |
.#define bfd_mach_mcf_isa_b_mac 21 |
.#define bfd_mach_mcf_isa_b_emac 22 |
.#define bfd_mach_mcf_isa_b_float 23 |
.#define bfd_mach_mcf_isa_b_float_mac 24 |
.#define bfd_mach_mcf_isa_b_float_emac 25 |
.#define bfd_mach_mcf_isa_c 26 |
.#define bfd_mach_mcf_isa_c_mac 27 |
.#define bfd_mach_mcf_isa_c_emac 28 |
.#define bfd_mach_mcf_isa_c_nodiv 29 |
.#define bfd_mach_mcf_isa_c_nodiv_mac 30 |
.#define bfd_mach_mcf_isa_c_nodiv_emac 31 |
. bfd_arch_vax, {* DEC Vax *} |
. bfd_arch_i960, {* Intel 960 *} |
. {* The order of the following is important. |
. lower number indicates a machine type that |
. only accepts a subset of the instructions |
. available to machines with higher numbers. |
. The exception is the "ca", which is |
. incompatible with all other machines except |
. "core". *} |
. |
.#define bfd_mach_i960_core 1 |
.#define bfd_mach_i960_ka_sa 2 |
.#define bfd_mach_i960_kb_sb 3 |
.#define bfd_mach_i960_mc 4 |
.#define bfd_mach_i960_xa 5 |
.#define bfd_mach_i960_ca 6 |
.#define bfd_mach_i960_jx 7 |
.#define bfd_mach_i960_hx 8 |
. |
. bfd_arch_or32, {* OpenRISC 32 *} |
. |
. bfd_arch_sparc, {* SPARC *} |
.#define bfd_mach_sparc 1 |
.{* The difference between v8plus and v9 is that v9 is a true 64 bit env. *} |
.#define bfd_mach_sparc_sparclet 2 |
.#define bfd_mach_sparc_sparclite 3 |
.#define bfd_mach_sparc_v8plus 4 |
.#define bfd_mach_sparc_v8plusa 5 {* with ultrasparc add'ns. *} |
.#define bfd_mach_sparc_sparclite_le 6 |
.#define bfd_mach_sparc_v9 7 |
.#define bfd_mach_sparc_v9a 8 {* with ultrasparc add'ns. *} |
.#define bfd_mach_sparc_v8plusb 9 {* with cheetah add'ns. *} |
.#define bfd_mach_sparc_v9b 10 {* with cheetah add'ns. *} |
.{* Nonzero if MACH has the v9 instruction set. *} |
.#define bfd_mach_sparc_v9_p(mach) \ |
. ((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9b \ |
. && (mach) != bfd_mach_sparc_sparclite_le) |
.{* Nonzero if MACH is a 64 bit sparc architecture. *} |
.#define bfd_mach_sparc_64bit_p(mach) \ |
. ((mach) >= bfd_mach_sparc_v9 && (mach) != bfd_mach_sparc_v8plusb) |
. bfd_arch_spu, {* PowerPC SPU *} |
.#define bfd_mach_spu 256 |
. bfd_arch_mips, {* MIPS Rxxxx *} |
.#define bfd_mach_mips3000 3000 |
.#define bfd_mach_mips3900 3900 |
.#define bfd_mach_mips4000 4000 |
.#define bfd_mach_mips4010 4010 |
.#define bfd_mach_mips4100 4100 |
.#define bfd_mach_mips4111 4111 |
.#define bfd_mach_mips4120 4120 |
.#define bfd_mach_mips4300 4300 |
.#define bfd_mach_mips4400 4400 |
.#define bfd_mach_mips4600 4600 |
.#define bfd_mach_mips4650 4650 |
.#define bfd_mach_mips5000 5000 |
.#define bfd_mach_mips5400 5400 |
.#define bfd_mach_mips5500 5500 |
.#define bfd_mach_mips5900 5900 |
.#define bfd_mach_mips6000 6000 |
.#define bfd_mach_mips7000 7000 |
.#define bfd_mach_mips8000 8000 |
.#define bfd_mach_mips9000 9000 |
.#define bfd_mach_mips10000 10000 |
.#define bfd_mach_mips12000 12000 |
.#define bfd_mach_mips14000 14000 |
.#define bfd_mach_mips16000 16000 |
.#define bfd_mach_mips16 16 |
.#define bfd_mach_mips5 5 |
.#define bfd_mach_mips_loongson_2e 3001 |
.#define bfd_mach_mips_loongson_2f 3002 |
.#define bfd_mach_mips_loongson_3a 3003 |
.#define bfd_mach_mips_sb1 12310201 {* octal 'SB', 01 *} |
.#define bfd_mach_mips_octeon 6501 |
.#define bfd_mach_mips_octeonp 6601 |
.#define bfd_mach_mips_octeon2 6502 |
.#define bfd_mach_mips_xlr 887682 {* decimal 'XLR' *} |
.#define bfd_mach_mipsisa32 32 |
.#define bfd_mach_mipsisa32r2 33 |
.#define bfd_mach_mipsisa64 64 |
.#define bfd_mach_mipsisa64r2 65 |
.#define bfd_mach_mips_micromips 96 |
. bfd_arch_i386, {* Intel 386 *} |
.#define bfd_mach_i386_intel_syntax (1 << 0) |
.#define bfd_mach_i386_i8086 (1 << 1) |
.#define bfd_mach_i386_i386 (1 << 2) |
.#define bfd_mach_x86_64 (1 << 3) |
.#define bfd_mach_x64_32 (1 << 4) |
.#define bfd_mach_i386_i386_intel_syntax (bfd_mach_i386_i386 | bfd_mach_i386_intel_syntax) |
.#define bfd_mach_x86_64_intel_syntax (bfd_mach_x86_64 | bfd_mach_i386_intel_syntax) |
.#define bfd_mach_x64_32_intel_syntax (bfd_mach_x64_32 | bfd_mach_i386_intel_syntax) |
. bfd_arch_l1om, {* Intel L1OM *} |
.#define bfd_mach_l1om (1 << 5) |
.#define bfd_mach_l1om_intel_syntax (bfd_mach_l1om | bfd_mach_i386_intel_syntax) |
. bfd_arch_k1om, {* Intel K1OM *} |
.#define bfd_mach_k1om (1 << 6) |
.#define bfd_mach_k1om_intel_syntax (bfd_mach_k1om | bfd_mach_i386_intel_syntax) |
.#define bfd_mach_i386_nacl (1 << 7) |
.#define bfd_mach_i386_i386_nacl (bfd_mach_i386_i386 | bfd_mach_i386_nacl) |
.#define bfd_mach_x86_64_nacl (bfd_mach_x86_64 | bfd_mach_i386_nacl) |
.#define bfd_mach_x64_32_nacl (bfd_mach_x64_32 | bfd_mach_i386_nacl) |
. bfd_arch_we32k, {* AT&T WE32xxx *} |
. bfd_arch_tahoe, {* CCI/Harris Tahoe *} |
. bfd_arch_i860, {* Intel 860 *} |
. bfd_arch_i370, {* IBM 360/370 Mainframes *} |
. bfd_arch_romp, {* IBM ROMP PC/RT *} |
. bfd_arch_convex, {* Convex *} |
. bfd_arch_m88k, {* Motorola 88xxx *} |
. bfd_arch_m98k, {* Motorola 98xxx *} |
. bfd_arch_pyramid, {* Pyramid Technology *} |
. bfd_arch_h8300, {* Renesas H8/300 (formerly Hitachi H8/300) *} |
.#define bfd_mach_h8300 1 |
.#define bfd_mach_h8300h 2 |
.#define bfd_mach_h8300s 3 |
.#define bfd_mach_h8300hn 4 |
.#define bfd_mach_h8300sn 5 |
.#define bfd_mach_h8300sx 6 |
.#define bfd_mach_h8300sxn 7 |
. bfd_arch_pdp11, {* DEC PDP-11 *} |
. bfd_arch_plugin, |
. bfd_arch_powerpc, {* PowerPC *} |
.#define bfd_mach_ppc 32 |
.#define bfd_mach_ppc64 64 |
.#define bfd_mach_ppc_403 403 |
.#define bfd_mach_ppc_403gc 4030 |
.#define bfd_mach_ppc_405 405 |
.#define bfd_mach_ppc_505 505 |
.#define bfd_mach_ppc_601 601 |
.#define bfd_mach_ppc_602 602 |
.#define bfd_mach_ppc_603 603 |
.#define bfd_mach_ppc_ec603e 6031 |
.#define bfd_mach_ppc_604 604 |
.#define bfd_mach_ppc_620 620 |
.#define bfd_mach_ppc_630 630 |
.#define bfd_mach_ppc_750 750 |
.#define bfd_mach_ppc_860 860 |
.#define bfd_mach_ppc_a35 35 |
.#define bfd_mach_ppc_rs64ii 642 |
.#define bfd_mach_ppc_rs64iii 643 |
.#define bfd_mach_ppc_7400 7400 |
.#define bfd_mach_ppc_e500 500 |
.#define bfd_mach_ppc_e500mc 5001 |
.#define bfd_mach_ppc_e500mc64 5005 |
.#define bfd_mach_ppc_e5500 5006 |
.#define bfd_mach_ppc_e6500 5007 |
.#define bfd_mach_ppc_titan 83 |
.#define bfd_mach_ppc_vle 84 |
. bfd_arch_rs6000, {* IBM RS/6000 *} |
.#define bfd_mach_rs6k 6000 |
.#define bfd_mach_rs6k_rs1 6001 |
.#define bfd_mach_rs6k_rsc 6003 |
.#define bfd_mach_rs6k_rs2 6002 |
. bfd_arch_hppa, {* HP PA RISC *} |
.#define bfd_mach_hppa10 10 |
.#define bfd_mach_hppa11 11 |
.#define bfd_mach_hppa20 20 |
.#define bfd_mach_hppa20w 25 |
. bfd_arch_d10v, {* Mitsubishi D10V *} |
.#define bfd_mach_d10v 1 |
.#define bfd_mach_d10v_ts2 2 |
.#define bfd_mach_d10v_ts3 3 |
. bfd_arch_d30v, {* Mitsubishi D30V *} |
. bfd_arch_dlx, {* DLX *} |
. bfd_arch_m68hc11, {* Motorola 68HC11 *} |
. bfd_arch_m68hc12, {* Motorola 68HC12 *} |
.#define bfd_mach_m6812_default 0 |
.#define bfd_mach_m6812 1 |
.#define bfd_mach_m6812s 2 |
. bfd_arch_m9s12x, {* Freescale S12X *} |
. bfd_arch_m9s12xg, {* Freescale XGATE *} |
. bfd_arch_z8k, {* Zilog Z8000 *} |
.#define bfd_mach_z8001 1 |
.#define bfd_mach_z8002 2 |
. bfd_arch_h8500, {* Renesas H8/500 (formerly Hitachi H8/500) *} |
. bfd_arch_sh, {* Renesas / SuperH SH (formerly Hitachi SH) *} |
.#define bfd_mach_sh 1 |
.#define bfd_mach_sh2 0x20 |
.#define bfd_mach_sh_dsp 0x2d |
.#define bfd_mach_sh2a 0x2a |
.#define bfd_mach_sh2a_nofpu 0x2b |
.#define bfd_mach_sh2a_nofpu_or_sh4_nommu_nofpu 0x2a1 |
.#define bfd_mach_sh2a_nofpu_or_sh3_nommu 0x2a2 |
.#define bfd_mach_sh2a_or_sh4 0x2a3 |
.#define bfd_mach_sh2a_or_sh3e 0x2a4 |
.#define bfd_mach_sh2e 0x2e |
.#define bfd_mach_sh3 0x30 |
.#define bfd_mach_sh3_nommu 0x31 |
.#define bfd_mach_sh3_dsp 0x3d |
.#define bfd_mach_sh3e 0x3e |
.#define bfd_mach_sh4 0x40 |
.#define bfd_mach_sh4_nofpu 0x41 |
.#define bfd_mach_sh4_nommu_nofpu 0x42 |
.#define bfd_mach_sh4a 0x4a |
.#define bfd_mach_sh4a_nofpu 0x4b |
.#define bfd_mach_sh4al_dsp 0x4d |
.#define bfd_mach_sh5 0x50 |
. bfd_arch_alpha, {* Dec Alpha *} |
.#define bfd_mach_alpha_ev4 0x10 |
.#define bfd_mach_alpha_ev5 0x20 |
.#define bfd_mach_alpha_ev6 0x30 |
. bfd_arch_arm, {* Advanced Risc Machines ARM. *} |
.#define bfd_mach_arm_unknown 0 |
.#define bfd_mach_arm_2 1 |
.#define bfd_mach_arm_2a 2 |
.#define bfd_mach_arm_3 3 |
.#define bfd_mach_arm_3M 4 |
.#define bfd_mach_arm_4 5 |
.#define bfd_mach_arm_4T 6 |
.#define bfd_mach_arm_5 7 |
.#define bfd_mach_arm_5T 8 |
.#define bfd_mach_arm_5TE 9 |
.#define bfd_mach_arm_XScale 10 |
.#define bfd_mach_arm_ep9312 11 |
.#define bfd_mach_arm_iWMMXt 12 |
.#define bfd_mach_arm_iWMMXt2 13 |
. bfd_arch_ns32k, {* National Semiconductors ns32000 *} |
. bfd_arch_w65, {* WDC 65816 *} |
. bfd_arch_tic30, {* Texas Instruments TMS320C30 *} |
. bfd_arch_tic4x, {* Texas Instruments TMS320C3X/4X *} |
.#define bfd_mach_tic3x 30 |
.#define bfd_mach_tic4x 40 |
. bfd_arch_tic54x, {* Texas Instruments TMS320C54X *} |
. bfd_arch_tic6x, {* Texas Instruments TMS320C6X *} |
. bfd_arch_tic80, {* TI TMS320c80 (MVP) *} |
. bfd_arch_v850, {* NEC V850 *} |
. bfd_arch_v850_rh850,{* NEC V850 (using RH850 ABI) *} |
.#define bfd_mach_v850 1 |
.#define bfd_mach_v850e 'E' |
.#define bfd_mach_v850e1 '1' |
.#define bfd_mach_v850e2 0x4532 |
.#define bfd_mach_v850e2v3 0x45325633 |
.#define bfd_mach_v850e3v5 0x45335635 {* ('E'|'3'|'V'|'5') *} |
. bfd_arch_arc, {* ARC Cores *} |
.#define bfd_mach_arc_5 5 |
.#define bfd_mach_arc_6 6 |
.#define bfd_mach_arc_7 7 |
.#define bfd_mach_arc_8 8 |
. bfd_arch_m32c, {* Renesas M16C/M32C. *} |
.#define bfd_mach_m16c 0x75 |
.#define bfd_mach_m32c 0x78 |
. bfd_arch_m32r, {* Renesas M32R (formerly Mitsubishi M32R/D) *} |
.#define bfd_mach_m32r 1 {* For backwards compatibility. *} |
.#define bfd_mach_m32rx 'x' |
.#define bfd_mach_m32r2 '2' |
. bfd_arch_mn10200, {* Matsushita MN10200 *} |
. bfd_arch_mn10300, {* Matsushita MN10300 *} |
.#define bfd_mach_mn10300 300 |
.#define bfd_mach_am33 330 |
.#define bfd_mach_am33_2 332 |
. bfd_arch_fr30, |
.#define bfd_mach_fr30 0x46523330 |
. bfd_arch_frv, |
.#define bfd_mach_frv 1 |
.#define bfd_mach_frvsimple 2 |
.#define bfd_mach_fr300 300 |
.#define bfd_mach_fr400 400 |
.#define bfd_mach_fr450 450 |
.#define bfd_mach_frvtomcat 499 {* fr500 prototype *} |
.#define bfd_mach_fr500 500 |
.#define bfd_mach_fr550 550 |
. bfd_arch_moxie, {* The moxie processor *} |
.#define bfd_mach_moxie 1 |
. bfd_arch_mcore, |
. bfd_arch_mep, |
.#define bfd_mach_mep 1 |
.#define bfd_mach_mep_h1 0x6831 |
.#define bfd_mach_mep_c5 0x6335 |
. bfd_arch_metag, |
.#define bfd_mach_metag 1 |
. bfd_arch_ia64, {* HP/Intel ia64 *} |
.#define bfd_mach_ia64_elf64 64 |
.#define bfd_mach_ia64_elf32 32 |
. bfd_arch_ip2k, {* Ubicom IP2K microcontrollers. *} |
.#define bfd_mach_ip2022 1 |
.#define bfd_mach_ip2022ext 2 |
. bfd_arch_iq2000, {* Vitesse IQ2000. *} |
.#define bfd_mach_iq2000 1 |
.#define bfd_mach_iq10 2 |
. bfd_arch_epiphany, {* Adapteva EPIPHANY *} |
.#define bfd_mach_epiphany16 1 |
.#define bfd_mach_epiphany32 2 |
. bfd_arch_mt, |
.#define bfd_mach_ms1 1 |
.#define bfd_mach_mrisc2 2 |
.#define bfd_mach_ms2 3 |
. bfd_arch_pj, |
. bfd_arch_avr, {* Atmel AVR microcontrollers. *} |
.#define bfd_mach_avr1 1 |
.#define bfd_mach_avr2 2 |
.#define bfd_mach_avr25 25 |
.#define bfd_mach_avr3 3 |
.#define bfd_mach_avr31 31 |
.#define bfd_mach_avr35 35 |
.#define bfd_mach_avr4 4 |
.#define bfd_mach_avr5 5 |
.#define bfd_mach_avr51 51 |
.#define bfd_mach_avr6 6 |
.#define bfd_mach_avrxmega1 101 |
.#define bfd_mach_avrxmega2 102 |
.#define bfd_mach_avrxmega3 103 |
.#define bfd_mach_avrxmega4 104 |
.#define bfd_mach_avrxmega5 105 |
.#define bfd_mach_avrxmega6 106 |
.#define bfd_mach_avrxmega7 107 |
. bfd_arch_bfin, {* ADI Blackfin *} |
.#define bfd_mach_bfin 1 |
. bfd_arch_cr16, {* National Semiconductor CompactRISC (ie CR16). *} |
.#define bfd_mach_cr16 1 |
. bfd_arch_cr16c, {* National Semiconductor CompactRISC. *} |
.#define bfd_mach_cr16c 1 |
. bfd_arch_crx, {* National Semiconductor CRX. *} |
.#define bfd_mach_crx 1 |
. bfd_arch_cris, {* Axis CRIS *} |
.#define bfd_mach_cris_v0_v10 255 |
.#define bfd_mach_cris_v32 32 |
.#define bfd_mach_cris_v10_v32 1032 |
. bfd_arch_rl78, |
.#define bfd_mach_rl78 0x75 |
. bfd_arch_rx, {* Renesas RX. *} |
.#define bfd_mach_rx 0x75 |
. bfd_arch_s390, {* IBM s390 *} |
.#define bfd_mach_s390_31 31 |
.#define bfd_mach_s390_64 64 |
. bfd_arch_score, {* Sunplus score *} |
.#define bfd_mach_score3 3 |
.#define bfd_mach_score7 7 |
. bfd_arch_openrisc, {* OpenRISC *} |
. bfd_arch_mmix, {* Donald Knuth's educational processor. *} |
. bfd_arch_xstormy16, |
.#define bfd_mach_xstormy16 1 |
. bfd_arch_msp430, {* Texas Instruments MSP430 architecture. *} |
.#define bfd_mach_msp11 11 |
.#define bfd_mach_msp110 110 |
.#define bfd_mach_msp12 12 |
.#define bfd_mach_msp13 13 |
.#define bfd_mach_msp14 14 |
.#define bfd_mach_msp15 15 |
.#define bfd_mach_msp16 16 |
.#define bfd_mach_msp20 20 |
.#define bfd_mach_msp21 21 |
.#define bfd_mach_msp22 22 |
.#define bfd_mach_msp23 23 |
.#define bfd_mach_msp24 24 |
.#define bfd_mach_msp26 26 |
.#define bfd_mach_msp31 31 |
.#define bfd_mach_msp32 32 |
.#define bfd_mach_msp33 33 |
.#define bfd_mach_msp41 41 |
.#define bfd_mach_msp42 42 |
.#define bfd_mach_msp43 43 |
.#define bfd_mach_msp44 44 |
.#define bfd_mach_msp430x 45 |
.#define bfd_mach_msp46 46 |
.#define bfd_mach_msp47 47 |
.#define bfd_mach_msp54 54 |
. bfd_arch_xc16x, {* Infineon's XC16X Series. *} |
.#define bfd_mach_xc16x 1 |
.#define bfd_mach_xc16xl 2 |
.#define bfd_mach_xc16xs 3 |
. bfd_arch_xgate, {* Freescale XGATE *} |
.#define bfd_mach_xgate 1 |
. bfd_arch_xtensa, {* Tensilica's Xtensa cores. *} |
.#define bfd_mach_xtensa 1 |
. bfd_arch_z80, |
.#define bfd_mach_z80strict 1 {* No undocumented opcodes. *} |
.#define bfd_mach_z80 3 {* With ixl, ixh, iyl, and iyh. *} |
.#define bfd_mach_z80full 7 {* All undocumented instructions. *} |
.#define bfd_mach_r800 11 {* R800: successor with multiplication. *} |
. bfd_arch_lm32, {* Lattice Mico32 *} |
.#define bfd_mach_lm32 1 |
. bfd_arch_microblaze,{* Xilinx MicroBlaze. *} |
. bfd_arch_tilepro, {* Tilera TILEPro *} |
. bfd_arch_tilegx, {* Tilera TILE-Gx *} |
.#define bfd_mach_tilepro 1 |
.#define bfd_mach_tilegx 1 |
.#define bfd_mach_tilegx32 2 |
. bfd_arch_aarch64, {* AArch64 *} |
.#define bfd_mach_aarch64 0 |
.#define bfd_mach_aarch64_ilp32 32 |
. bfd_arch_nios2, |
.#define bfd_mach_nios2 0 |
. bfd_arch_last |
. }; |
*/ |
/* |
SUBSECTION |
bfd_arch_info |
DESCRIPTION |
This structure contains information on architectures for use |
within BFD. |
. |
.typedef struct bfd_arch_info |
.{ |
. int bits_per_word; |
. int bits_per_address; |
. int bits_per_byte; |
. enum bfd_architecture arch; |
. unsigned long mach; |
. const char *arch_name; |
. const char *printable_name; |
. unsigned int section_align_power; |
. {* TRUE if this is the default machine for the architecture. |
. The default arch should be the first entry for an arch so that |
. all the entries for that arch can be accessed via <<next>>. *} |
. bfd_boolean the_default; |
. const struct bfd_arch_info * (*compatible) |
. (const struct bfd_arch_info *a, const struct bfd_arch_info *b); |
. |
. bfd_boolean (*scan) (const struct bfd_arch_info *, const char *); |
. |
. {* Allocate via bfd_malloc and return a fill buffer of size COUNT. If |
. IS_BIGENDIAN is TRUE, the order of bytes is big endian. If CODE is |
. TRUE, the buffer contains code. *} |
. void *(*fill) (bfd_size_type count, bfd_boolean is_bigendian, |
. bfd_boolean code); |
. |
. const struct bfd_arch_info *next; |
.} |
.bfd_arch_info_type; |
. |
*/ |
extern const bfd_arch_info_type bfd_aarch64_arch; |
extern const bfd_arch_info_type bfd_alpha_arch; |
extern const bfd_arch_info_type bfd_arc_arch; |
extern const bfd_arch_info_type bfd_arm_arch; |
extern const bfd_arch_info_type bfd_avr_arch; |
extern const bfd_arch_info_type bfd_bfin_arch; |
extern const bfd_arch_info_type bfd_cr16_arch; |
extern const bfd_arch_info_type bfd_cr16c_arch; |
extern const bfd_arch_info_type bfd_cris_arch; |
extern const bfd_arch_info_type bfd_crx_arch; |
extern const bfd_arch_info_type bfd_d10v_arch; |
extern const bfd_arch_info_type bfd_d30v_arch; |
extern const bfd_arch_info_type bfd_dlx_arch; |
extern const bfd_arch_info_type bfd_epiphany_arch; |
extern const bfd_arch_info_type bfd_fr30_arch; |
extern const bfd_arch_info_type bfd_frv_arch; |
extern const bfd_arch_info_type bfd_h8300_arch; |
extern const bfd_arch_info_type bfd_h8500_arch; |
extern const bfd_arch_info_type bfd_hppa_arch; |
extern const bfd_arch_info_type bfd_i370_arch; |
extern const bfd_arch_info_type bfd_i386_arch; |
extern const bfd_arch_info_type bfd_i860_arch; |
extern const bfd_arch_info_type bfd_i960_arch; |
extern const bfd_arch_info_type bfd_ia64_arch; |
extern const bfd_arch_info_type bfd_ip2k_arch; |
extern const bfd_arch_info_type bfd_iq2000_arch; |
extern const bfd_arch_info_type bfd_k1om_arch; |
extern const bfd_arch_info_type bfd_l1om_arch; |
extern const bfd_arch_info_type bfd_lm32_arch; |
extern const bfd_arch_info_type bfd_m32c_arch; |
extern const bfd_arch_info_type bfd_m32r_arch; |
extern const bfd_arch_info_type bfd_m68hc11_arch; |
extern const bfd_arch_info_type bfd_m68hc12_arch; |
extern const bfd_arch_info_type bfd_m9s12x_arch; |
extern const bfd_arch_info_type bfd_m9s12xg_arch; |
extern const bfd_arch_info_type bfd_m68k_arch; |
extern const bfd_arch_info_type bfd_m88k_arch; |
extern const bfd_arch_info_type bfd_mcore_arch; |
extern const bfd_arch_info_type bfd_mep_arch; |
extern const bfd_arch_info_type bfd_metag_arch; |
extern const bfd_arch_info_type bfd_mips_arch; |
extern const bfd_arch_info_type bfd_microblaze_arch; |
extern const bfd_arch_info_type bfd_mmix_arch; |
extern const bfd_arch_info_type bfd_mn10200_arch; |
extern const bfd_arch_info_type bfd_mn10300_arch; |
extern const bfd_arch_info_type bfd_moxie_arch; |
extern const bfd_arch_info_type bfd_msp430_arch; |
extern const bfd_arch_info_type bfd_mt_arch; |
extern const bfd_arch_info_type bfd_nios2_arch; |
extern const bfd_arch_info_type bfd_ns32k_arch; |
extern const bfd_arch_info_type bfd_openrisc_arch; |
extern const bfd_arch_info_type bfd_or32_arch; |
extern const bfd_arch_info_type bfd_pdp11_arch; |
extern const bfd_arch_info_type bfd_pj_arch; |
extern const bfd_arch_info_type bfd_plugin_arch; |
extern const bfd_arch_info_type bfd_powerpc_archs[]; |
#define bfd_powerpc_arch bfd_powerpc_archs[0] |
extern const bfd_arch_info_type bfd_rs6000_arch; |
extern const bfd_arch_info_type bfd_rl78_arch; |
extern const bfd_arch_info_type bfd_rx_arch; |
extern const bfd_arch_info_type bfd_s390_arch; |
extern const bfd_arch_info_type bfd_score_arch; |
extern const bfd_arch_info_type bfd_sh_arch; |
extern const bfd_arch_info_type bfd_sparc_arch; |
extern const bfd_arch_info_type bfd_spu_arch; |
extern const bfd_arch_info_type bfd_tic30_arch; |
extern const bfd_arch_info_type bfd_tic4x_arch; |
extern const bfd_arch_info_type bfd_tic54x_arch; |
extern const bfd_arch_info_type bfd_tic6x_arch; |
extern const bfd_arch_info_type bfd_tic80_arch; |
extern const bfd_arch_info_type bfd_tilegx_arch; |
extern const bfd_arch_info_type bfd_tilepro_arch; |
extern const bfd_arch_info_type bfd_v850_arch; |
extern const bfd_arch_info_type bfd_v850_rh850_arch; |
extern const bfd_arch_info_type bfd_vax_arch; |
extern const bfd_arch_info_type bfd_w65_arch; |
extern const bfd_arch_info_type bfd_we32k_arch; |
extern const bfd_arch_info_type bfd_xstormy16_arch; |
extern const bfd_arch_info_type bfd_xtensa_arch; |
extern const bfd_arch_info_type bfd_xc16x_arch; |
extern const bfd_arch_info_type bfd_xgate_arch; |
extern const bfd_arch_info_type bfd_z80_arch; |
extern const bfd_arch_info_type bfd_z8k_arch; |
static const bfd_arch_info_type * const bfd_archures_list[] = |
{ |
#ifdef SELECT_ARCHITECTURES |
SELECT_ARCHITECTURES, |
#else |
&bfd_aarch64_arch, |
&bfd_alpha_arch, |
&bfd_arc_arch, |
&bfd_arm_arch, |
&bfd_avr_arch, |
&bfd_bfin_arch, |
&bfd_cr16_arch, |
&bfd_cr16c_arch, |
&bfd_cris_arch, |
&bfd_crx_arch, |
&bfd_d10v_arch, |
&bfd_d30v_arch, |
&bfd_dlx_arch, |
&bfd_epiphany_arch, |
&bfd_fr30_arch, |
&bfd_frv_arch, |
&bfd_h8300_arch, |
&bfd_h8500_arch, |
&bfd_hppa_arch, |
&bfd_i370_arch, |
&bfd_i386_arch, |
&bfd_i860_arch, |
&bfd_i960_arch, |
&bfd_ia64_arch, |
&bfd_ip2k_arch, |
&bfd_iq2000_arch, |
&bfd_k1om_arch, |
&bfd_l1om_arch, |
&bfd_lm32_arch, |
&bfd_m32c_arch, |
&bfd_m32r_arch, |
&bfd_m68hc11_arch, |
&bfd_m68hc12_arch, |
&bfd_m9s12x_arch, |
&bfd_m9s12xg_arch, |
&bfd_m68k_arch, |
&bfd_m88k_arch, |
&bfd_mcore_arch, |
&bfd_mep_arch, |
&bfd_metag_arch, |
&bfd_microblaze_arch, |
&bfd_mips_arch, |
&bfd_mmix_arch, |
&bfd_mn10200_arch, |
&bfd_mn10300_arch, |
&bfd_moxie_arch, |
&bfd_msp430_arch, |
&bfd_mt_arch, |
&bfd_nios2_arch, |
&bfd_ns32k_arch, |
&bfd_openrisc_arch, |
&bfd_or32_arch, |
&bfd_pdp11_arch, |
&bfd_powerpc_arch, |
&bfd_rs6000_arch, |
&bfd_rl78_arch, |
&bfd_rx_arch, |
&bfd_s390_arch, |
&bfd_score_arch, |
&bfd_sh_arch, |
&bfd_sparc_arch, |
&bfd_spu_arch, |
&bfd_tic30_arch, |
&bfd_tic4x_arch, |
&bfd_tic54x_arch, |
&bfd_tic6x_arch, |
&bfd_tic80_arch, |
&bfd_tilegx_arch, |
&bfd_tilepro_arch, |
&bfd_v850_arch, |
&bfd_v850_rh850_arch, |
&bfd_vax_arch, |
&bfd_w65_arch, |
&bfd_we32k_arch, |
&bfd_xstormy16_arch, |
&bfd_xtensa_arch, |
&bfd_xc16x_arch, |
&bfd_xgate_arch, |
&bfd_z80_arch, |
&bfd_z8k_arch, |
#endif |
0 |
}; |
/* |
FUNCTION |
bfd_printable_name |
SYNOPSIS |
const char *bfd_printable_name (bfd *abfd); |
DESCRIPTION |
Return a printable string representing the architecture and machine |
from the pointer to the architecture info structure. |
*/ |
const char * |
bfd_printable_name (bfd *abfd) |
{ |
return abfd->arch_info->printable_name; |
} |
/* |
FUNCTION |
bfd_scan_arch |
SYNOPSIS |
const bfd_arch_info_type *bfd_scan_arch (const char *string); |
DESCRIPTION |
Figure out if BFD supports any cpu which could be described with |
the name @var{string}. Return a pointer to an <<arch_info>> |
structure if a machine is found, otherwise NULL. |
*/ |
const bfd_arch_info_type * |
bfd_scan_arch (const char *string) |
{ |
const bfd_arch_info_type * const *app, *ap; |
/* Look through all the installed architectures. */ |
for (app = bfd_archures_list; *app != NULL; app++) |
{ |
for (ap = *app; ap != NULL; ap = ap->next) |
{ |
if (ap->scan (ap, string)) |
return ap; |
} |
} |
return NULL; |
} |
/* |
FUNCTION |
bfd_arch_list |
SYNOPSIS |
const char **bfd_arch_list (void); |
DESCRIPTION |
Return a freshly malloced NULL-terminated vector of the names |
of all the valid BFD architectures. Do not modify the names. |
*/ |
const char ** |
bfd_arch_list (void) |
{ |
int vec_length = 0; |
const char **name_ptr; |
const char **name_list; |
const bfd_arch_info_type * const *app; |
bfd_size_type amt; |
/* Determine the number of architectures. */ |
vec_length = 0; |
for (app = bfd_archures_list; *app != NULL; app++) |
{ |
const bfd_arch_info_type *ap; |
for (ap = *app; ap != NULL; ap = ap->next) |
{ |
vec_length++; |
} |
} |
amt = (vec_length + 1) * sizeof (char **); |
name_list = (const char **) bfd_malloc (amt); |
if (name_list == NULL) |
return NULL; |
/* Point the list at each of the names. */ |
name_ptr = name_list; |
for (app = bfd_archures_list; *app != NULL; app++) |
{ |
const bfd_arch_info_type *ap; |
for (ap = *app; ap != NULL; ap = ap->next) |
{ |
*name_ptr = ap->printable_name; |
name_ptr++; |
} |
} |
*name_ptr = NULL; |
return name_list; |
} |
/* |
FUNCTION |
bfd_arch_get_compatible |
SYNOPSIS |
const bfd_arch_info_type *bfd_arch_get_compatible |
(const bfd *abfd, const bfd *bbfd, bfd_boolean accept_unknowns); |
DESCRIPTION |
Determine whether two BFDs' architectures and machine types |
are compatible. Calculates the lowest common denominator |
between the two architectures and machine types implied by |
the BFDs and returns a pointer to an <<arch_info>> structure |
describing the compatible machine. |
*/ |
const bfd_arch_info_type * |
bfd_arch_get_compatible (const bfd *abfd, |
const bfd *bbfd, |
bfd_boolean accept_unknowns) |
{ |
const bfd *ubfd, *kbfd; |
/* Look for an unknown architecture. */ |
if (abfd->arch_info->arch == bfd_arch_unknown) |
ubfd = abfd, kbfd = bbfd; |
else if (bbfd->arch_info->arch == bfd_arch_unknown) |
ubfd = bbfd, kbfd = abfd; |
else |
/* Otherwise architecture-specific code has to decide. */ |
return abfd->arch_info->compatible (abfd->arch_info, bbfd->arch_info); |
/* We can allow an unknown architecture if accept_unknowns |
is true, or if the target is the "binary" format, which |
has an unknown architecture. Since the binary format can |
only be set by explicit request from the user, it is safe |
to assume that they know what they are doing. */ |
if (accept_unknowns |
|| strcmp (bfd_get_target (ubfd), "binary") == 0) |
return kbfd->arch_info; |
return NULL; |
} |
/* |
INTERNAL_DEFINITION |
bfd_default_arch_struct |
DESCRIPTION |
The <<bfd_default_arch_struct>> is an item of |
<<bfd_arch_info_type>> which has been initialized to a fairly |
generic state. A BFD starts life by pointing to this |
structure, until the correct back end has determined the real |
architecture of the file. |
.extern const bfd_arch_info_type bfd_default_arch_struct; |
*/ |
const bfd_arch_info_type bfd_default_arch_struct = { |
32, 32, 8, bfd_arch_unknown, 0, "unknown", "unknown", 2, TRUE, |
bfd_default_compatible, |
bfd_default_scan, |
bfd_arch_default_fill, |
0, |
}; |
/* |
FUNCTION |
bfd_set_arch_info |
SYNOPSIS |
void bfd_set_arch_info (bfd *abfd, const bfd_arch_info_type *arg); |
DESCRIPTION |
Set the architecture info of @var{abfd} to @var{arg}. |
*/ |
void |
bfd_set_arch_info (bfd *abfd, const bfd_arch_info_type *arg) |
{ |
abfd->arch_info = arg; |
} |
/* |
INTERNAL_FUNCTION |
bfd_default_set_arch_mach |
SYNOPSIS |
bfd_boolean bfd_default_set_arch_mach |
(bfd *abfd, enum bfd_architecture arch, unsigned long mach); |
DESCRIPTION |
Set the architecture and machine type in BFD @var{abfd} |
to @var{arch} and @var{mach}. Find the correct |
pointer to a structure and insert it into the <<arch_info>> |
pointer. |
*/ |
bfd_boolean |
bfd_default_set_arch_mach (bfd *abfd, |
enum bfd_architecture arch, |
unsigned long mach) |
{ |
abfd->arch_info = bfd_lookup_arch (arch, mach); |
if (abfd->arch_info != NULL) |
return TRUE; |
abfd->arch_info = &bfd_default_arch_struct; |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
/* |
FUNCTION |
bfd_get_arch |
SYNOPSIS |
enum bfd_architecture bfd_get_arch (bfd *abfd); |
DESCRIPTION |
Return the enumerated type which describes the BFD @var{abfd}'s |
architecture. |
*/ |
enum bfd_architecture |
bfd_get_arch (bfd *abfd) |
{ |
return abfd->arch_info->arch; |
} |
/* |
FUNCTION |
bfd_get_mach |
SYNOPSIS |
unsigned long bfd_get_mach (bfd *abfd); |
DESCRIPTION |
Return the long type which describes the BFD @var{abfd}'s |
machine. |
*/ |
unsigned long |
bfd_get_mach (bfd *abfd) |
{ |
return abfd->arch_info->mach; |
} |
/* |
FUNCTION |
bfd_arch_bits_per_byte |
SYNOPSIS |
unsigned int bfd_arch_bits_per_byte (bfd *abfd); |
DESCRIPTION |
Return the number of bits in one of the BFD @var{abfd}'s |
architecture's bytes. |
*/ |
unsigned int |
bfd_arch_bits_per_byte (bfd *abfd) |
{ |
return abfd->arch_info->bits_per_byte; |
} |
/* |
FUNCTION |
bfd_arch_bits_per_address |
SYNOPSIS |
unsigned int bfd_arch_bits_per_address (bfd *abfd); |
DESCRIPTION |
Return the number of bits in one of the BFD @var{abfd}'s |
architecture's addresses. |
*/ |
unsigned int |
bfd_arch_bits_per_address (bfd *abfd) |
{ |
return abfd->arch_info->bits_per_address; |
} |
/* |
INTERNAL_FUNCTION |
bfd_default_compatible |
SYNOPSIS |
const bfd_arch_info_type *bfd_default_compatible |
(const bfd_arch_info_type *a, const bfd_arch_info_type *b); |
DESCRIPTION |
The default function for testing for compatibility. |
*/ |
const bfd_arch_info_type * |
bfd_default_compatible (const bfd_arch_info_type *a, |
const bfd_arch_info_type *b) |
{ |
if (a->arch != b->arch) |
return NULL; |
if (a->bits_per_word != b->bits_per_word) |
return NULL; |
if (a->mach > b->mach) |
return a; |
if (b->mach > a->mach) |
return b; |
return a; |
} |
/* |
INTERNAL_FUNCTION |
bfd_default_scan |
SYNOPSIS |
bfd_boolean bfd_default_scan |
(const struct bfd_arch_info *info, const char *string); |
DESCRIPTION |
The default function for working out whether this is an |
architecture hit and a machine hit. |
*/ |
bfd_boolean |
bfd_default_scan (const bfd_arch_info_type *info, const char *string) |
{ |
const char *ptr_src; |
const char *ptr_tst; |
unsigned long number; |
enum bfd_architecture arch; |
const char *printable_name_colon; |
/* Exact match of the architecture name (ARCH_NAME) and also the |
default architecture? */ |
if (strcasecmp (string, info->arch_name) == 0 |
&& info->the_default) |
return TRUE; |
/* Exact match of the machine name (PRINTABLE_NAME)? */ |
if (strcasecmp (string, info->printable_name) == 0) |
return TRUE; |
/* Given that printable_name contains no colon, attempt to match: |
ARCH_NAME [ ":" ] PRINTABLE_NAME? */ |
printable_name_colon = strchr (info->printable_name, ':'); |
if (printable_name_colon == NULL) |
{ |
size_t strlen_arch_name = strlen (info->arch_name); |
if (strncasecmp (string, info->arch_name, strlen_arch_name) == 0) |
{ |
if (string[strlen_arch_name] == ':') |
{ |
if (strcasecmp (string + strlen_arch_name + 1, |
info->printable_name) == 0) |
return TRUE; |
} |
else |
{ |
if (strcasecmp (string + strlen_arch_name, |
info->printable_name) == 0) |
return TRUE; |
} |
} |
} |
/* Given that PRINTABLE_NAME has the form: <arch> ":" <mach>; |
Attempt to match: <arch> <mach>? */ |
if (printable_name_colon != NULL) |
{ |
size_t colon_index = printable_name_colon - info->printable_name; |
if (strncasecmp (string, info->printable_name, colon_index) == 0 |
&& strcasecmp (string + colon_index, |
info->printable_name + colon_index + 1) == 0) |
return TRUE; |
} |
/* Given that PRINTABLE_NAME has the form: <arch> ":" <mach>; Do not |
attempt to match just <mach>, it could be ambiguous. This test |
is left until later. */ |
/* NOTE: The below is retained for compatibility only. Please do |
not add to this code. */ |
/* See how much of the supplied string matches with the |
architecture, eg the string m68k:68020 would match the 68k entry |
up to the :, then we get left with the machine number. */ |
for (ptr_src = string, ptr_tst = info->arch_name; |
*ptr_src && *ptr_tst; |
ptr_src++, ptr_tst++) |
{ |
if (*ptr_src != *ptr_tst) |
break; |
} |
/* Chewed up as much of the architecture as will match, skip any |
colons. */ |
if (*ptr_src == ':') |
ptr_src++; |
if (*ptr_src == 0) |
{ |
/* Nothing more, then only keep this one if it is the default |
machine for this architecture. */ |
return info->the_default; |
} |
number = 0; |
while (ISDIGIT (*ptr_src)) |
{ |
number = number * 10 + *ptr_src - '0'; |
ptr_src++; |
} |
/* NOTE: The below is retained for compatibility only. |
PLEASE DO NOT ADD TO THIS CODE. */ |
switch (number) |
{ |
/* FIXME: These are needed to parse IEEE objects. */ |
/* The following seven case's are here only for compatibility with |
older binutils (at least IEEE objects from binutils 2.9.1 require |
them). */ |
case bfd_mach_m68000: |
case bfd_mach_m68010: |
case bfd_mach_m68020: |
case bfd_mach_m68030: |
case bfd_mach_m68040: |
case bfd_mach_m68060: |
case bfd_mach_cpu32: |
arch = bfd_arch_m68k; |
break; |
case 68000: |
arch = bfd_arch_m68k; |
number = bfd_mach_m68000; |
break; |
case 68010: |
arch = bfd_arch_m68k; |
number = bfd_mach_m68010; |
break; |
case 68020: |
arch = bfd_arch_m68k; |
number = bfd_mach_m68020; |
break; |
case 68030: |
arch = bfd_arch_m68k; |
number = bfd_mach_m68030; |
break; |
case 68040: |
arch = bfd_arch_m68k; |
number = bfd_mach_m68040; |
break; |
case 68060: |
arch = bfd_arch_m68k; |
number = bfd_mach_m68060; |
break; |
case 68332: |
arch = bfd_arch_m68k; |
number = bfd_mach_cpu32; |
break; |
case 5200: |
arch = bfd_arch_m68k; |
number = bfd_mach_mcf_isa_a_nodiv; |
break; |
case 5206: |
arch = bfd_arch_m68k; |
number = bfd_mach_mcf_isa_a_mac; |
break; |
case 5307: |
arch = bfd_arch_m68k; |
number = bfd_mach_mcf_isa_a_mac; |
break; |
case 5407: |
arch = bfd_arch_m68k; |
number = bfd_mach_mcf_isa_b_nousp_mac; |
break; |
case 5282: |
arch = bfd_arch_m68k; |
number = bfd_mach_mcf_isa_aplus_emac; |
break; |
case 32000: |
arch = bfd_arch_we32k; |
break; |
case 3000: |
arch = bfd_arch_mips; |
number = bfd_mach_mips3000; |
break; |
case 4000: |
arch = bfd_arch_mips; |
number = bfd_mach_mips4000; |
break; |
case 6000: |
arch = bfd_arch_rs6000; |
break; |
case 7410: |
arch = bfd_arch_sh; |
number = bfd_mach_sh_dsp; |
break; |
case 7708: |
arch = bfd_arch_sh; |
number = bfd_mach_sh3; |
break; |
case 7729: |
arch = bfd_arch_sh; |
number = bfd_mach_sh3_dsp; |
break; |
case 7750: |
arch = bfd_arch_sh; |
number = bfd_mach_sh4; |
break; |
default: |
return FALSE; |
} |
if (arch != info->arch) |
return FALSE; |
if (number != info->mach) |
return FALSE; |
return TRUE; |
} |
/* |
FUNCTION |
bfd_get_arch_info |
SYNOPSIS |
const bfd_arch_info_type *bfd_get_arch_info (bfd *abfd); |
DESCRIPTION |
Return the architecture info struct in @var{abfd}. |
*/ |
const bfd_arch_info_type * |
bfd_get_arch_info (bfd *abfd) |
{ |
return abfd->arch_info; |
} |
/* |
FUNCTION |
bfd_lookup_arch |
SYNOPSIS |
const bfd_arch_info_type *bfd_lookup_arch |
(enum bfd_architecture arch, unsigned long machine); |
DESCRIPTION |
Look for the architecture info structure which matches the |
arguments @var{arch} and @var{machine}. A machine of 0 matches the |
machine/architecture structure which marks itself as the |
default. |
*/ |
const bfd_arch_info_type * |
bfd_lookup_arch (enum bfd_architecture arch, unsigned long machine) |
{ |
const bfd_arch_info_type * const *app, *ap; |
for (app = bfd_archures_list; *app != NULL; app++) |
{ |
for (ap = *app; ap != NULL; ap = ap->next) |
{ |
if (ap->arch == arch |
&& (ap->mach == machine |
|| (machine == 0 && ap->the_default))) |
return ap; |
} |
} |
return NULL; |
} |
/* |
FUNCTION |
bfd_printable_arch_mach |
SYNOPSIS |
const char *bfd_printable_arch_mach |
(enum bfd_architecture arch, unsigned long machine); |
DESCRIPTION |
Return a printable string representing the architecture and |
machine type. |
This routine is depreciated. |
*/ |
const char * |
bfd_printable_arch_mach (enum bfd_architecture arch, unsigned long machine) |
{ |
const bfd_arch_info_type *ap = bfd_lookup_arch (arch, machine); |
if (ap) |
return ap->printable_name; |
return "UNKNOWN!"; |
} |
/* |
FUNCTION |
bfd_octets_per_byte |
SYNOPSIS |
unsigned int bfd_octets_per_byte (bfd *abfd); |
DESCRIPTION |
Return the number of octets (8-bit quantities) per target byte |
(minimum addressable unit). In most cases, this will be one, but some |
DSP targets have 16, 32, or even 48 bits per byte. |
*/ |
unsigned int |
bfd_octets_per_byte (bfd *abfd) |
{ |
return bfd_arch_mach_octets_per_byte (bfd_get_arch (abfd), |
bfd_get_mach (abfd)); |
} |
/* |
FUNCTION |
bfd_arch_mach_octets_per_byte |
SYNOPSIS |
unsigned int bfd_arch_mach_octets_per_byte |
(enum bfd_architecture arch, unsigned long machine); |
DESCRIPTION |
See bfd_octets_per_byte. |
This routine is provided for those cases where a bfd * is not |
available |
*/ |
unsigned int |
bfd_arch_mach_octets_per_byte (enum bfd_architecture arch, |
unsigned long mach) |
{ |
const bfd_arch_info_type *ap = bfd_lookup_arch (arch, mach); |
if (ap) |
return ap->bits_per_byte / 8; |
return 1; |
} |
/* |
INTERNAL_FUNCTION |
bfd_arch_default_fill |
SYNOPSIS |
void *bfd_arch_default_fill (bfd_size_type count, |
bfd_boolean is_bigendian, |
bfd_boolean code); |
DESCRIPTION |
Allocate via bfd_malloc and return a fill buffer of size COUNT. |
If IS_BIGENDIAN is TRUE, the order of bytes is big endian. If |
CODE is TRUE, the buffer contains code. |
*/ |
void * |
bfd_arch_default_fill (bfd_size_type count, |
bfd_boolean is_bigendian ATTRIBUTE_UNUSED, |
bfd_boolean code ATTRIBUTE_UNUSED) |
{ |
void *fill = bfd_malloc (count); |
if (fill != NULL) |
memset (fill, 0, count); |
return fill; |
} |
/contrib/toolchain/binutils/bfd/bfd-in3.h |
---|
0,0 → 1,6971 |
/* DO NOT EDIT! -*- buffer-read-only: t -*- This file is automatically |
generated from "bfd-in.h", "init.c", "opncls.c", "libbfd.c", |
"bfdio.c", "bfdwin.c", "section.c", "archures.c", "reloc.c", |
"syms.c", "bfd.c", "archive.c", "corefile.c", "targets.c", "format.c", |
"linker.c", "simple.c" and "compress.c". |
Run "make headers" in your build bfd/ to regenerate. */ |
/* Main header file for the bfd library -- portable access to object files. |
Copyright 1990-2013 Free Software Foundation, Inc. |
Contributed by Cygnus Support. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ |
#ifndef __BFD_H_SEEN__ |
#define __BFD_H_SEEN__ |
/* PR 14072: Ensure that config.h is included first. */ |
#if !defined PACKAGE && !defined PACKAGE_VERSION |
#error config.h must be included before this header |
#endif |
#ifdef __cplusplus |
extern "C" { |
#endif |
#include "ansidecl.h" |
#include "symcat.h" |
#include <sys/stat.h> |
#if defined (__STDC__) || defined (ALMOST_STDC) || defined (HAVE_STRINGIZE) |
#ifndef SABER |
/* This hack is to avoid a problem with some strict ANSI C preprocessors. |
The problem is, "32_" is not a valid preprocessing token, and we don't |
want extra underscores (e.g., "nlm_32_"). The XCONCAT2 macro will |
cause the inner CONCAT2 macros to be evaluated first, producing |
still-valid pp-tokens. Then the final concatenation can be done. */ |
#undef CONCAT4 |
#define CONCAT4(a,b,c,d) XCONCAT2(CONCAT2(a,b),CONCAT2(c,d)) |
#endif |
#endif |
/* This is a utility macro to handle the situation where the code |
wants to place a constant string into the code, followed by a |
comma and then the length of the string. Doing this by hand |
is error prone, so using this macro is safer. */ |
#define STRING_COMMA_LEN(STR) (STR), (sizeof (STR) - 1) |
/* Unfortunately it is not possible to use the STRING_COMMA_LEN macro |
to create the arguments to another macro, since the preprocessor |
will mis-count the number of arguments to the outer macro (by not |
evaluating STRING_COMMA_LEN and so missing the comma). This is a |
problem for example when trying to use STRING_COMMA_LEN to build |
the arguments to the strncmp() macro. Hence this alternative |
definition of strncmp is provided here. |
Note - these macros do NOT work if STR2 is not a constant string. */ |
#define CONST_STRNEQ(STR1,STR2) (strncmp ((STR1), (STR2), sizeof (STR2) - 1) == 0) |
/* strcpy() can have a similar problem, but since we know we are |
copying a constant string, we can use memcpy which will be faster |
since there is no need to check for a NUL byte inside STR. We |
can also save time if we do not need to copy the terminating NUL. */ |
#define LITMEMCPY(DEST,STR2) memcpy ((DEST), (STR2), sizeof (STR2) - 1) |
#define LITSTRCPY(DEST,STR2) memcpy ((DEST), (STR2), sizeof (STR2)) |
#define BFD_SUPPORTS_PLUGINS 0 |
/* The word size used by BFD on the host. This may be 64 with a 32 |
bit target if the host is 64 bit, or if other 64 bit targets have |
been selected with --enable-targets, or if --enable-64-bit-bfd. */ |
#define BFD_ARCH_SIZE 32 |
/* The word size of the default bfd target. */ |
#define BFD_DEFAULT_TARGET_SIZE 32 |
#define BFD_HOST_64BIT_LONG 0 |
#define BFD_HOST_64BIT_LONG_LONG 1 |
#if 1 |
#define BFD_HOST_64_BIT long long |
#define BFD_HOST_U_64_BIT unsigned long long |
typedef BFD_HOST_64_BIT bfd_int64_t; |
typedef BFD_HOST_U_64_BIT bfd_uint64_t; |
#endif |
#if BFD_ARCH_SIZE >= 64 |
#define BFD64 |
#endif |
#ifndef INLINE |
#if __GNUC__ >= 2 |
#define INLINE __inline__ |
#else |
#define INLINE |
#endif |
#endif |
/* Declaring a type wide enough to hold a host long and a host pointer. */ |
#define BFD_HOSTPTR_T unsigned long |
typedef BFD_HOSTPTR_T bfd_hostptr_t; |
/* Forward declaration. */ |
typedef struct bfd bfd; |
/* Boolean type used in bfd. Too many systems define their own |
versions of "boolean" for us to safely typedef a "boolean" of |
our own. Using an enum for "bfd_boolean" has its own set of |
problems, with strange looking casts required to avoid warnings |
on some older compilers. Thus we just use an int. |
General rule: Functions which are bfd_boolean return TRUE on |
success and FALSE on failure (unless they're a predicate). */ |
typedef int bfd_boolean; |
#undef FALSE |
#undef TRUE |
#define FALSE 0 |
#define TRUE 1 |
#ifdef BFD64 |
#ifndef BFD_HOST_64_BIT |
#error No 64 bit integer type available |
#endif /* ! defined (BFD_HOST_64_BIT) */ |
typedef BFD_HOST_U_64_BIT bfd_vma; |
typedef BFD_HOST_64_BIT bfd_signed_vma; |
typedef BFD_HOST_U_64_BIT bfd_size_type; |
typedef BFD_HOST_U_64_BIT symvalue; |
#if BFD_HOST_64BIT_LONG |
#define BFD_VMA_FMT "l" |
#elif defined (__MSVCRT__) |
#define BFD_VMA_FMT "I64" |
#else |
#define BFD_VMA_FMT "ll" |
#endif |
#ifndef fprintf_vma |
#define sprintf_vma(s,x) sprintf (s, "%016" BFD_VMA_FMT "x", x) |
#define fprintf_vma(f,x) fprintf (f, "%016" BFD_VMA_FMT "x", x) |
#endif |
#else /* not BFD64 */ |
/* Represent a target address. Also used as a generic unsigned type |
which is guaranteed to be big enough to hold any arithmetic types |
we need to deal with. */ |
typedef unsigned long bfd_vma; |
/* A generic signed type which is guaranteed to be big enough to hold any |
arithmetic types we need to deal with. Can be assumed to be compatible |
with bfd_vma in the same way that signed and unsigned ints are compatible |
(as parameters, in assignment, etc). */ |
typedef long bfd_signed_vma; |
typedef unsigned long symvalue; |
typedef unsigned long bfd_size_type; |
/* Print a bfd_vma x on stream s. */ |
#define BFD_VMA_FMT "l" |
#define fprintf_vma(s,x) fprintf (s, "%08" BFD_VMA_FMT "x", x) |
#define sprintf_vma(s,x) sprintf (s, "%08" BFD_VMA_FMT "x", x) |
#endif /* not BFD64 */ |
#define HALF_BFD_SIZE_TYPE \ |
(((bfd_size_type) 1) << (8 * sizeof (bfd_size_type) / 2)) |
#ifndef BFD_HOST_64_BIT |
/* Fall back on a 32 bit type. The idea is to make these types always |
available for function return types, but in the case that |
BFD_HOST_64_BIT is undefined such a function should abort or |
otherwise signal an error. */ |
typedef bfd_signed_vma bfd_int64_t; |
typedef bfd_vma bfd_uint64_t; |
#endif |
/* An offset into a file. BFD always uses the largest possible offset |
based on the build time availability of fseek, fseeko, or fseeko64. */ |
typedef BFD_HOST_64_BIT file_ptr; |
typedef unsigned BFD_HOST_64_BIT ufile_ptr; |
extern void bfd_sprintf_vma (bfd *, char *, bfd_vma); |
extern void bfd_fprintf_vma (bfd *, void *, bfd_vma); |
#define printf_vma(x) fprintf_vma(stdout,x) |
#define bfd_printf_vma(abfd,x) bfd_fprintf_vma (abfd,stdout,x) |
typedef unsigned int flagword; /* 32 bits of flags */ |
typedef unsigned char bfd_byte; |
/* File formats. */ |
typedef enum bfd_format |
{ |
bfd_unknown = 0, /* File format is unknown. */ |
bfd_object, /* Linker/assembler/compiler output. */ |
bfd_archive, /* Object archive file. */ |
bfd_core, /* Core dump. */ |
bfd_type_end /* Marks the end; don't use it! */ |
} |
bfd_format; |
/* Symbols and relocation. */ |
/* A count of carsyms (canonical archive symbols). */ |
typedef unsigned long symindex; |
/* How to perform a relocation. */ |
typedef const struct reloc_howto_struct reloc_howto_type; |
#define BFD_NO_MORE_SYMBOLS ((symindex) ~0) |
/* General purpose part of a symbol X; |
target specific parts are in libcoff.h, libaout.h, etc. */ |
#define bfd_get_section(x) ((x)->section) |
#define bfd_get_output_section(x) ((x)->section->output_section) |
#define bfd_set_section(x,y) ((x)->section) = (y) |
#define bfd_asymbol_base(x) ((x)->section->vma) |
#define bfd_asymbol_value(x) (bfd_asymbol_base(x) + (x)->value) |
#define bfd_asymbol_name(x) ((x)->name) |
/*Perhaps future: #define bfd_asymbol_bfd(x) ((x)->section->owner)*/ |
#define bfd_asymbol_bfd(x) ((x)->the_bfd) |
#define bfd_asymbol_flavour(x) \ |
(((x)->flags & BSF_SYNTHETIC) != 0 \ |
? bfd_target_unknown_flavour \ |
: bfd_asymbol_bfd (x)->xvec->flavour) |
/* A canonical archive symbol. */ |
/* This is a type pun with struct ranlib on purpose! */ |
typedef struct carsym |
{ |
char *name; |
file_ptr file_offset; /* Look here to find the file. */ |
} |
carsym; /* To make these you call a carsymogen. */ |
/* Used in generating armaps (archive tables of contents). |
Perhaps just a forward definition would do? */ |
struct orl /* Output ranlib. */ |
{ |
char **name; /* Symbol name. */ |
union |
{ |
file_ptr pos; |
bfd *abfd; |
} u; /* bfd* or file position. */ |
int namidx; /* Index into string table. */ |
}; |
/* Linenumber stuff. */ |
typedef struct lineno_cache_entry |
{ |
unsigned int line_number; /* Linenumber from start of function. */ |
union |
{ |
struct bfd_symbol *sym; /* Function name. */ |
bfd_vma offset; /* Offset into section. */ |
} u; |
} |
alent; |
/* Object and core file sections. */ |
#define align_power(addr, align) \ |
(((addr) + ((bfd_vma) 1 << (align)) - 1) & ((bfd_vma) -1 << (align))) |
typedef struct bfd_section *sec_ptr; |
#define bfd_get_section_name(bfd, ptr) ((void) bfd, (ptr)->name) |
#define bfd_get_section_vma(bfd, ptr) ((void) bfd, (ptr)->vma) |
#define bfd_get_section_lma(bfd, ptr) ((void) bfd, (ptr)->lma) |
#define bfd_get_section_alignment(bfd, ptr) ((void) bfd, \ |
(ptr)->alignment_power) |
#define bfd_section_name(bfd, ptr) ((ptr)->name) |
#define bfd_section_size(bfd, ptr) ((ptr)->size) |
#define bfd_get_section_size(ptr) ((ptr)->size) |
#define bfd_section_vma(bfd, ptr) ((ptr)->vma) |
#define bfd_section_lma(bfd, ptr) ((ptr)->lma) |
#define bfd_section_alignment(bfd, ptr) ((ptr)->alignment_power) |
#define bfd_get_section_flags(bfd, ptr) ((void) bfd, (ptr)->flags) |
#define bfd_get_section_userdata(bfd, ptr) ((void) bfd, (ptr)->userdata) |
#define bfd_is_com_section(ptr) (((ptr)->flags & SEC_IS_COMMON) != 0) |
#define bfd_set_section_vma(bfd, ptr, val) (((ptr)->vma = (ptr)->lma = (val)), ((ptr)->user_set_vma = TRUE), TRUE) |
#define bfd_set_section_alignment(bfd, ptr, val) (((ptr)->alignment_power = (val)),TRUE) |
#define bfd_set_section_userdata(bfd, ptr, val) (((ptr)->userdata = (val)),TRUE) |
/* Find the address one past the end of SEC. */ |
#define bfd_get_section_limit(bfd, sec) \ |
(((bfd)->direction != write_direction && (sec)->rawsize != 0 \ |
? (sec)->rawsize : (sec)->size) / bfd_octets_per_byte (bfd)) |
/* Return TRUE if input section SEC has been discarded. */ |
#define discarded_section(sec) \ |
(!bfd_is_abs_section (sec) \ |
&& bfd_is_abs_section ((sec)->output_section) \ |
&& (sec)->sec_info_type != SEC_INFO_TYPE_MERGE \ |
&& (sec)->sec_info_type != SEC_INFO_TYPE_JUST_SYMS) |
typedef enum bfd_print_symbol |
{ |
bfd_print_symbol_name, |
bfd_print_symbol_more, |
bfd_print_symbol_all |
} bfd_print_symbol_type; |
/* Information about a symbol that nm needs. */ |
typedef struct _symbol_info |
{ |
symvalue value; |
char type; |
const char *name; /* Symbol name. */ |
unsigned char stab_type; /* Stab type. */ |
char stab_other; /* Stab other. */ |
short stab_desc; /* Stab desc. */ |
const char *stab_name; /* String for stab type. */ |
} symbol_info; |
/* Get the name of a stabs type code. */ |
extern const char *bfd_get_stab_name (int); |
/* Hash table routines. There is no way to free up a hash table. */ |
/* An element in the hash table. Most uses will actually use a larger |
structure, and an instance of this will be the first field. */ |
struct bfd_hash_entry |
{ |
/* Next entry for this hash code. */ |
struct bfd_hash_entry *next; |
/* String being hashed. */ |
const char *string; |
/* Hash code. This is the full hash code, not the index into the |
table. */ |
unsigned long hash; |
}; |
/* A hash table. */ |
struct bfd_hash_table |
{ |
/* The hash array. */ |
struct bfd_hash_entry **table; |
/* A function used to create new elements in the hash table. The |
first entry is itself a pointer to an element. When this |
function is first invoked, this pointer will be NULL. However, |
having the pointer permits a hierarchy of method functions to be |
built each of which calls the function in the superclass. Thus |
each function should be written to allocate a new block of memory |
only if the argument is NULL. */ |
struct bfd_hash_entry *(*newfunc) |
(struct bfd_hash_entry *, struct bfd_hash_table *, const char *); |
/* An objalloc for this hash table. This is a struct objalloc *, |
but we use void * to avoid requiring the inclusion of objalloc.h. */ |
void *memory; |
/* The number of slots in the hash table. */ |
unsigned int size; |
/* The number of entries in the hash table. */ |
unsigned int count; |
/* The size of elements. */ |
unsigned int entsize; |
/* If non-zero, don't grow the hash table. */ |
unsigned int frozen:1; |
}; |
/* Initialize a hash table. */ |
extern bfd_boolean bfd_hash_table_init |
(struct bfd_hash_table *, |
struct bfd_hash_entry *(*) (struct bfd_hash_entry *, |
struct bfd_hash_table *, |
const char *), |
unsigned int); |
/* Initialize a hash table specifying a size. */ |
extern bfd_boolean bfd_hash_table_init_n |
(struct bfd_hash_table *, |
struct bfd_hash_entry *(*) (struct bfd_hash_entry *, |
struct bfd_hash_table *, |
const char *), |
unsigned int, unsigned int); |
/* Free up a hash table. */ |
extern void bfd_hash_table_free |
(struct bfd_hash_table *); |
/* Look up a string in a hash table. If CREATE is TRUE, a new entry |
will be created for this string if one does not already exist. The |
COPY argument must be TRUE if this routine should copy the string |
into newly allocated memory when adding an entry. */ |
extern struct bfd_hash_entry *bfd_hash_lookup |
(struct bfd_hash_table *, const char *, bfd_boolean create, |
bfd_boolean copy); |
/* Insert an entry in a hash table. */ |
extern struct bfd_hash_entry *bfd_hash_insert |
(struct bfd_hash_table *, const char *, unsigned long); |
/* Rename an entry in a hash table. */ |
extern void bfd_hash_rename |
(struct bfd_hash_table *, const char *, struct bfd_hash_entry *); |
/* Replace an entry in a hash table. */ |
extern void bfd_hash_replace |
(struct bfd_hash_table *, struct bfd_hash_entry *old, |
struct bfd_hash_entry *nw); |
/* Base method for creating a hash table entry. */ |
extern struct bfd_hash_entry *bfd_hash_newfunc |
(struct bfd_hash_entry *, struct bfd_hash_table *, const char *); |
/* Grab some space for a hash table entry. */ |
extern void *bfd_hash_allocate |
(struct bfd_hash_table *, unsigned int); |
/* Traverse a hash table in a random order, calling a function on each |
element. If the function returns FALSE, the traversal stops. The |
INFO argument is passed to the function. */ |
extern void bfd_hash_traverse |
(struct bfd_hash_table *, |
bfd_boolean (*) (struct bfd_hash_entry *, void *), |
void *info); |
/* Allows the default size of a hash table to be configured. New hash |
tables allocated using bfd_hash_table_init will be created with |
this size. */ |
extern unsigned long bfd_hash_set_default_size (unsigned long); |
/* This structure is used to keep track of stabs in sections |
information while linking. */ |
struct stab_info |
{ |
/* A hash table used to hold stabs strings. */ |
struct bfd_strtab_hash *strings; |
/* The header file hash table. */ |
struct bfd_hash_table includes; |
/* The first .stabstr section. */ |
struct bfd_section *stabstr; |
}; |
#define COFF_SWAP_TABLE (void *) &bfd_coff_std_swap_table |
/* User program access to BFD facilities. */ |
/* Direct I/O routines, for programs which know more about the object |
file than BFD does. Use higher level routines if possible. */ |
extern bfd_size_type bfd_bread (void *, bfd_size_type, bfd *); |
extern bfd_size_type bfd_bwrite (const void *, bfd_size_type, bfd *); |
extern int bfd_seek (bfd *, file_ptr, int); |
extern file_ptr bfd_tell (bfd *); |
extern int bfd_flush (bfd *); |
extern int bfd_stat (bfd *, struct stat *); |
/* Deprecated old routines. */ |
#if __GNUC__ |
#define bfd_read(BUF, ELTSIZE, NITEMS, ABFD) \ |
(warn_deprecated ("bfd_read", __FILE__, __LINE__, __FUNCTION__), \ |
bfd_bread ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) |
#define bfd_write(BUF, ELTSIZE, NITEMS, ABFD) \ |
(warn_deprecated ("bfd_write", __FILE__, __LINE__, __FUNCTION__), \ |
bfd_bwrite ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) |
#else |
#define bfd_read(BUF, ELTSIZE, NITEMS, ABFD) \ |
(warn_deprecated ("bfd_read", (const char *) 0, 0, (const char *) 0), \ |
bfd_bread ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) |
#define bfd_write(BUF, ELTSIZE, NITEMS, ABFD) \ |
(warn_deprecated ("bfd_write", (const char *) 0, 0, (const char *) 0),\ |
bfd_bwrite ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) |
#endif |
extern void warn_deprecated (const char *, const char *, int, const char *); |
/* Cast from const char * to char * so that caller can assign to |
a char * without a warning. */ |
#define bfd_get_filename(abfd) ((char *) (abfd)->filename) |
#define bfd_get_cacheable(abfd) ((abfd)->cacheable) |
#define bfd_get_format(abfd) ((abfd)->format) |
#define bfd_get_target(abfd) ((abfd)->xvec->name) |
#define bfd_get_flavour(abfd) ((abfd)->xvec->flavour) |
#define bfd_family_coff(abfd) \ |
(bfd_get_flavour (abfd) == bfd_target_coff_flavour || \ |
bfd_get_flavour (abfd) == bfd_target_xcoff_flavour) |
#define bfd_big_endian(abfd) ((abfd)->xvec->byteorder == BFD_ENDIAN_BIG) |
#define bfd_little_endian(abfd) ((abfd)->xvec->byteorder == BFD_ENDIAN_LITTLE) |
#define bfd_header_big_endian(abfd) \ |
((abfd)->xvec->header_byteorder == BFD_ENDIAN_BIG) |
#define bfd_header_little_endian(abfd) \ |
((abfd)->xvec->header_byteorder == BFD_ENDIAN_LITTLE) |
#define bfd_get_file_flags(abfd) ((abfd)->flags) |
#define bfd_applicable_file_flags(abfd) ((abfd)->xvec->object_flags) |
#define bfd_applicable_section_flags(abfd) ((abfd)->xvec->section_flags) |
#define bfd_my_archive(abfd) ((abfd)->my_archive) |
#define bfd_has_map(abfd) ((abfd)->has_armap) |
#define bfd_is_thin_archive(abfd) ((abfd)->is_thin_archive) |
#define bfd_valid_reloc_types(abfd) ((abfd)->xvec->valid_reloc_types) |
#define bfd_usrdata(abfd) ((abfd)->usrdata) |
#define bfd_get_start_address(abfd) ((abfd)->start_address) |
#define bfd_get_symcount(abfd) ((abfd)->symcount) |
#define bfd_get_outsymbols(abfd) ((abfd)->outsymbols) |
#define bfd_count_sections(abfd) ((abfd)->section_count) |
#define bfd_get_dynamic_symcount(abfd) ((abfd)->dynsymcount) |
#define bfd_get_symbol_leading_char(abfd) ((abfd)->xvec->symbol_leading_char) |
#define bfd_set_cacheable(abfd,bool) (((abfd)->cacheable = bool), TRUE) |
extern bfd_boolean bfd_cache_close |
(bfd *abfd); |
/* NB: This declaration should match the autogenerated one in libbfd.h. */ |
extern bfd_boolean bfd_cache_close_all (void); |
extern bfd_boolean bfd_record_phdr |
(bfd *, unsigned long, bfd_boolean, flagword, bfd_boolean, bfd_vma, |
bfd_boolean, bfd_boolean, unsigned int, struct bfd_section **); |
/* Byte swapping routines. */ |
bfd_uint64_t bfd_getb64 (const void *); |
bfd_uint64_t bfd_getl64 (const void *); |
bfd_int64_t bfd_getb_signed_64 (const void *); |
bfd_int64_t bfd_getl_signed_64 (const void *); |
bfd_vma bfd_getb32 (const void *); |
bfd_vma bfd_getl32 (const void *); |
bfd_signed_vma bfd_getb_signed_32 (const void *); |
bfd_signed_vma bfd_getl_signed_32 (const void *); |
bfd_vma bfd_getb16 (const void *); |
bfd_vma bfd_getl16 (const void *); |
bfd_signed_vma bfd_getb_signed_16 (const void *); |
bfd_signed_vma bfd_getl_signed_16 (const void *); |
void bfd_putb64 (bfd_uint64_t, void *); |
void bfd_putl64 (bfd_uint64_t, void *); |
void bfd_putb32 (bfd_vma, void *); |
void bfd_putl32 (bfd_vma, void *); |
void bfd_putb16 (bfd_vma, void *); |
void bfd_putl16 (bfd_vma, void *); |
/* Byte swapping routines which take size and endiannes as arguments. */ |
bfd_uint64_t bfd_get_bits (const void *, int, bfd_boolean); |
void bfd_put_bits (bfd_uint64_t, void *, int, bfd_boolean); |
#if defined(__STDC__) || defined(ALMOST_STDC) |
struct ecoff_debug_info; |
struct ecoff_debug_swap; |
struct ecoff_extr; |
struct bfd_symbol; |
struct bfd_link_info; |
struct bfd_link_hash_entry; |
struct bfd_section_already_linked; |
struct bfd_elf_version_tree; |
#endif |
extern bfd_boolean bfd_section_already_linked_table_init (void); |
extern void bfd_section_already_linked_table_free (void); |
extern bfd_boolean _bfd_handle_already_linked |
(struct bfd_section *, struct bfd_section_already_linked *, |
struct bfd_link_info *); |
/* Externally visible ECOFF routines. */ |
extern bfd_vma bfd_ecoff_get_gp_value |
(bfd * abfd); |
extern bfd_boolean bfd_ecoff_set_gp_value |
(bfd *abfd, bfd_vma gp_value); |
extern bfd_boolean bfd_ecoff_set_regmasks |
(bfd *abfd, unsigned long gprmask, unsigned long fprmask, |
unsigned long *cprmask); |
extern void *bfd_ecoff_debug_init |
(bfd *output_bfd, struct ecoff_debug_info *output_debug, |
const struct ecoff_debug_swap *output_swap, struct bfd_link_info *); |
extern void bfd_ecoff_debug_free |
(void *handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, |
const struct ecoff_debug_swap *output_swap, struct bfd_link_info *); |
extern bfd_boolean bfd_ecoff_debug_accumulate |
(void *handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, |
const struct ecoff_debug_swap *output_swap, bfd *input_bfd, |
struct ecoff_debug_info *input_debug, |
const struct ecoff_debug_swap *input_swap, struct bfd_link_info *); |
extern bfd_boolean bfd_ecoff_debug_accumulate_other |
(void *handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, |
const struct ecoff_debug_swap *output_swap, bfd *input_bfd, |
struct bfd_link_info *); |
extern bfd_boolean bfd_ecoff_debug_externals |
(bfd *abfd, struct ecoff_debug_info *debug, |
const struct ecoff_debug_swap *swap, bfd_boolean relocatable, |
bfd_boolean (*get_extr) (struct bfd_symbol *, struct ecoff_extr *), |
void (*set_index) (struct bfd_symbol *, bfd_size_type)); |
extern bfd_boolean bfd_ecoff_debug_one_external |
(bfd *abfd, struct ecoff_debug_info *debug, |
const struct ecoff_debug_swap *swap, const char *name, |
struct ecoff_extr *esym); |
extern bfd_size_type bfd_ecoff_debug_size |
(bfd *abfd, struct ecoff_debug_info *debug, |
const struct ecoff_debug_swap *swap); |
extern bfd_boolean bfd_ecoff_write_debug |
(bfd *abfd, struct ecoff_debug_info *debug, |
const struct ecoff_debug_swap *swap, file_ptr where); |
extern bfd_boolean bfd_ecoff_write_accumulated_debug |
(void *handle, bfd *abfd, struct ecoff_debug_info *debug, |
const struct ecoff_debug_swap *swap, |
struct bfd_link_info *info, file_ptr where); |
/* Externally visible ELF routines. */ |
struct bfd_link_needed_list |
{ |
struct bfd_link_needed_list *next; |
bfd *by; |
const char *name; |
}; |
enum dynamic_lib_link_class { |
DYN_NORMAL = 0, |
DYN_AS_NEEDED = 1, |
DYN_DT_NEEDED = 2, |
DYN_NO_ADD_NEEDED = 4, |
DYN_NO_NEEDED = 8 |
}; |
enum notice_asneeded_action { |
notice_as_needed, |
notice_not_needed, |
notice_needed |
}; |
extern bfd_boolean bfd_elf_record_link_assignment |
(bfd *, struct bfd_link_info *, const char *, bfd_boolean, |
bfd_boolean); |
extern struct bfd_link_needed_list *bfd_elf_get_needed_list |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean bfd_elf_get_bfd_needed_list |
(bfd *, struct bfd_link_needed_list **); |
extern bfd_boolean bfd_elf_stack_segment_size (bfd *, struct bfd_link_info *, |
const char *, bfd_vma); |
extern bfd_boolean bfd_elf_size_dynamic_sections |
(bfd *, const char *, const char *, const char *, const char *, const char *, |
const char * const *, struct bfd_link_info *, struct bfd_section **); |
extern bfd_boolean bfd_elf_size_dynsym_hash_dynstr |
(bfd *, struct bfd_link_info *); |
extern void bfd_elf_set_dt_needed_name |
(bfd *, const char *); |
extern const char *bfd_elf_get_dt_soname |
(bfd *); |
extern void bfd_elf_set_dyn_lib_class |
(bfd *, enum dynamic_lib_link_class); |
extern int bfd_elf_get_dyn_lib_class |
(bfd *); |
extern struct bfd_link_needed_list *bfd_elf_get_runpath_list |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean bfd_elf_discard_info |
(bfd *, struct bfd_link_info *); |
extern unsigned int _bfd_elf_default_action_discarded |
(struct bfd_section *); |
/* Return an upper bound on the number of bytes required to store a |
copy of ABFD's program header table entries. Return -1 if an error |
occurs; bfd_get_error will return an appropriate code. */ |
extern long bfd_get_elf_phdr_upper_bound |
(bfd *abfd); |
/* Copy ABFD's program header table entries to *PHDRS. The entries |
will be stored as an array of Elf_Internal_Phdr structures, as |
defined in include/elf/internal.h. To find out how large the |
buffer needs to be, call bfd_get_elf_phdr_upper_bound. |
Return the number of program header table entries read, or -1 if an |
error occurs; bfd_get_error will return an appropriate code. */ |
extern int bfd_get_elf_phdrs |
(bfd *abfd, void *phdrs); |
/* Create a new BFD as if by bfd_openr. Rather than opening a file, |
reconstruct an ELF file by reading the segments out of remote memory |
based on the ELF file header at EHDR_VMA and the ELF program headers it |
points to. If not null, *LOADBASEP is filled in with the difference |
between the VMAs from which the segments were read, and the VMAs the |
file headers (and hence BFD's idea of each section's VMA) put them at. |
The function TARGET_READ_MEMORY is called to copy LEN bytes from the |
remote memory at target address VMA into the local buffer at MYADDR; it |
should return zero on success or an `errno' code on failure. TEMPL must |
be a BFD for an ELF target with the word size and byte order found in |
the remote memory. */ |
extern bfd *bfd_elf_bfd_from_remote_memory |
(bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, |
int (*target_read_memory) (bfd_vma vma, bfd_byte *myaddr, |
bfd_size_type len)); |
extern struct bfd_section *_bfd_elf_tls_setup |
(bfd *, struct bfd_link_info *); |
extern struct bfd_section * |
_bfd_nearby_section (bfd *, struct bfd_section *, bfd_vma); |
extern void _bfd_fix_excluded_sec_syms |
(bfd *, struct bfd_link_info *); |
extern unsigned bfd_m68k_mach_to_features (int); |
extern int bfd_m68k_features_to_mach (unsigned); |
extern bfd_boolean bfd_m68k_elf32_create_embedded_relocs |
(bfd *, struct bfd_link_info *, struct bfd_section *, struct bfd_section *, |
char **); |
extern void bfd_elf_m68k_set_target_options (struct bfd_link_info *, int); |
extern bfd_boolean bfd_bfin_elf32_create_embedded_relocs |
(bfd *, struct bfd_link_info *, struct bfd_section *, struct bfd_section *, |
char **); |
extern bfd_boolean bfd_cr16_elf32_create_embedded_relocs |
(bfd *, struct bfd_link_info *, struct bfd_section *, struct bfd_section *, |
char **); |
/* SunOS shared library support routines for the linker. */ |
extern struct bfd_link_needed_list *bfd_sunos_get_needed_list |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean bfd_sunos_record_link_assignment |
(bfd *, struct bfd_link_info *, const char *); |
extern bfd_boolean bfd_sunos_size_dynamic_sections |
(bfd *, struct bfd_link_info *, struct bfd_section **, |
struct bfd_section **, struct bfd_section **); |
/* Linux shared library support routines for the linker. */ |
extern bfd_boolean bfd_i386linux_size_dynamic_sections |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean bfd_m68klinux_size_dynamic_sections |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean bfd_sparclinux_size_dynamic_sections |
(bfd *, struct bfd_link_info *); |
/* mmap hacks */ |
struct _bfd_window_internal; |
typedef struct _bfd_window_internal bfd_window_internal; |
typedef struct _bfd_window |
{ |
/* What the user asked for. */ |
void *data; |
bfd_size_type size; |
/* The actual window used by BFD. Small user-requested read-only |
regions sharing a page may share a single window into the object |
file. Read-write versions shouldn't until I've fixed things to |
keep track of which portions have been claimed by the |
application; don't want to give the same region back when the |
application wants two writable copies! */ |
struct _bfd_window_internal *i; |
} |
bfd_window; |
extern void bfd_init_window |
(bfd_window *); |
extern void bfd_free_window |
(bfd_window *); |
extern bfd_boolean bfd_get_file_window |
(bfd *, file_ptr, bfd_size_type, bfd_window *, bfd_boolean); |
/* XCOFF support routines for the linker. */ |
extern bfd_boolean bfd_xcoff_split_import_path |
(bfd *, const char *, const char **, const char **); |
extern bfd_boolean bfd_xcoff_set_archive_import_path |
(struct bfd_link_info *, bfd *, const char *); |
extern bfd_boolean bfd_xcoff_link_record_set |
(bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, bfd_size_type); |
extern bfd_boolean bfd_xcoff_import_symbol |
(bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, bfd_vma, |
const char *, const char *, const char *, unsigned int); |
extern bfd_boolean bfd_xcoff_export_symbol |
(bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *); |
extern bfd_boolean bfd_xcoff_link_count_reloc |
(bfd *, struct bfd_link_info *, const char *); |
extern bfd_boolean bfd_xcoff_record_link_assignment |
(bfd *, struct bfd_link_info *, const char *); |
extern bfd_boolean bfd_xcoff_size_dynamic_sections |
(bfd *, struct bfd_link_info *, const char *, const char *, |
unsigned long, unsigned long, unsigned long, bfd_boolean, |
int, bfd_boolean, unsigned int, struct bfd_section **, bfd_boolean); |
extern bfd_boolean bfd_xcoff_link_generate_rtinit |
(bfd *, const char *, const char *, bfd_boolean); |
/* XCOFF support routines for ar. */ |
extern bfd_boolean bfd_xcoff_ar_archive_set_magic |
(bfd *, char *); |
/* Externally visible COFF routines. */ |
#if defined(__STDC__) || defined(ALMOST_STDC) |
struct internal_syment; |
union internal_auxent; |
#endif |
extern bfd_boolean bfd_coff_get_syment |
(bfd *, struct bfd_symbol *, struct internal_syment *); |
extern bfd_boolean bfd_coff_get_auxent |
(bfd *, struct bfd_symbol *, int, union internal_auxent *); |
extern bfd_boolean bfd_coff_set_symbol_class |
(bfd *, struct bfd_symbol *, unsigned int); |
extern bfd_boolean bfd_m68k_coff_create_embedded_relocs |
(bfd *, struct bfd_link_info *, struct bfd_section *, struct bfd_section *, char **); |
/* ARM VFP11 erratum workaround support. */ |
typedef enum |
{ |
BFD_ARM_VFP11_FIX_DEFAULT, |
BFD_ARM_VFP11_FIX_NONE, |
BFD_ARM_VFP11_FIX_SCALAR, |
BFD_ARM_VFP11_FIX_VECTOR |
} bfd_arm_vfp11_fix; |
extern void bfd_elf32_arm_init_maps |
(bfd *); |
extern void bfd_elf32_arm_set_vfp11_fix |
(bfd *, struct bfd_link_info *); |
extern void bfd_elf32_arm_set_cortex_a8_fix |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean bfd_elf32_arm_vfp11_erratum_scan |
(bfd *, struct bfd_link_info *); |
extern void bfd_elf32_arm_vfp11_fix_veneer_locations |
(bfd *, struct bfd_link_info *); |
/* ARM Interworking support. Called from linker. */ |
extern bfd_boolean bfd_arm_allocate_interworking_sections |
(struct bfd_link_info *); |
extern bfd_boolean bfd_arm_process_before_allocation |
(bfd *, struct bfd_link_info *, int); |
extern bfd_boolean bfd_arm_get_bfd_for_interworking |
(bfd *, struct bfd_link_info *); |
/* PE ARM Interworking support. Called from linker. */ |
extern bfd_boolean bfd_arm_pe_allocate_interworking_sections |
(struct bfd_link_info *); |
extern bfd_boolean bfd_arm_pe_process_before_allocation |
(bfd *, struct bfd_link_info *, int); |
extern bfd_boolean bfd_arm_pe_get_bfd_for_interworking |
(bfd *, struct bfd_link_info *); |
/* ELF ARM Interworking support. Called from linker. */ |
extern bfd_boolean bfd_elf32_arm_allocate_interworking_sections |
(struct bfd_link_info *); |
extern bfd_boolean bfd_elf32_arm_process_before_allocation |
(bfd *, struct bfd_link_info *); |
void bfd_elf32_arm_set_target_relocs |
(bfd *, struct bfd_link_info *, int, char *, int, int, bfd_arm_vfp11_fix, |
int, int, int, int, int); |
extern bfd_boolean bfd_elf32_arm_get_bfd_for_interworking |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean bfd_elf32_arm_add_glue_sections_to_bfd |
(bfd *, struct bfd_link_info *); |
/* ELF ARM mapping symbol support */ |
#define BFD_ARM_SPECIAL_SYM_TYPE_MAP (1 << 0) |
#define BFD_ARM_SPECIAL_SYM_TYPE_TAG (1 << 1) |
#define BFD_ARM_SPECIAL_SYM_TYPE_OTHER (1 << 2) |
#define BFD_ARM_SPECIAL_SYM_TYPE_ANY (~0) |
extern bfd_boolean bfd_is_arm_special_symbol_name |
(const char * name, int type); |
extern void bfd_elf32_arm_set_byteswap_code (struct bfd_link_info *, int); |
/* ARM Note section processing. */ |
extern bfd_boolean bfd_arm_merge_machines |
(bfd *, bfd *); |
extern bfd_boolean bfd_arm_update_notes |
(bfd *, const char *); |
extern unsigned int bfd_arm_get_mach_from_notes |
(bfd *, const char *); |
/* ARM stub generation support. Called from the linker. */ |
extern int elf32_arm_setup_section_lists |
(bfd *, struct bfd_link_info *); |
extern void elf32_arm_next_input_section |
(struct bfd_link_info *, struct bfd_section *); |
extern bfd_boolean elf32_arm_size_stubs |
(bfd *, bfd *, struct bfd_link_info *, bfd_signed_vma, |
struct bfd_section * (*) (const char *, struct bfd_section *, unsigned int), |
void (*) (void)); |
extern bfd_boolean elf32_arm_build_stubs |
(struct bfd_link_info *); |
/* ARM unwind section editing support. */ |
extern bfd_boolean elf32_arm_fix_exidx_coverage |
(struct bfd_section **, unsigned int, struct bfd_link_info *, bfd_boolean); |
/* C6x unwind section editing support. */ |
extern bfd_boolean elf32_tic6x_fix_exidx_coverage |
(struct bfd_section **, unsigned int, struct bfd_link_info *, bfd_boolean); |
/* PowerPC @tls opcode transform/validate. */ |
extern unsigned int _bfd_elf_ppc_at_tls_transform |
(unsigned int, unsigned int); |
/* PowerPC @tprel opcode transform/validate. */ |
extern unsigned int _bfd_elf_ppc_at_tprel_transform |
(unsigned int, unsigned int); |
extern void bfd_elf64_aarch64_init_maps |
(bfd *); |
extern void bfd_elf32_aarch64_init_maps |
(bfd *); |
extern void bfd_elf64_aarch64_set_options |
(bfd *, struct bfd_link_info *, int, int, int); |
extern void bfd_elf32_aarch64_set_options |
(bfd *, struct bfd_link_info *, int, int, int); |
/* ELF AArch64 mapping symbol support. */ |
#define BFD_AARCH64_SPECIAL_SYM_TYPE_MAP (1 << 0) |
#define BFD_AARCH64_SPECIAL_SYM_TYPE_TAG (1 << 1) |
#define BFD_AARCH64_SPECIAL_SYM_TYPE_OTHER (1 << 2) |
#define BFD_AARCH64_SPECIAL_SYM_TYPE_ANY (~0) |
extern bfd_boolean bfd_is_aarch64_special_symbol_name |
(const char * name, int type); |
/* AArch64 stub generation support for ELF64. Called from the linker. */ |
extern int elf64_aarch64_setup_section_lists |
(bfd *, struct bfd_link_info *); |
extern void elf64_aarch64_next_input_section |
(struct bfd_link_info *, struct bfd_section *); |
extern bfd_boolean elf64_aarch64_size_stubs |
(bfd *, bfd *, struct bfd_link_info *, bfd_signed_vma, |
struct bfd_section * (*) (const char *, struct bfd_section *), |
void (*) (void)); |
extern bfd_boolean elf64_aarch64_build_stubs |
(struct bfd_link_info *); |
/* AArch64 stub generation support for ELF32. Called from the linker. */ |
extern int elf32_aarch64_setup_section_lists |
(bfd *, struct bfd_link_info *); |
extern void elf32_aarch64_next_input_section |
(struct bfd_link_info *, struct bfd_section *); |
extern bfd_boolean elf32_aarch64_size_stubs |
(bfd *, bfd *, struct bfd_link_info *, bfd_signed_vma, |
struct bfd_section * (*) (const char *, struct bfd_section *), |
void (*) (void)); |
extern bfd_boolean elf32_aarch64_build_stubs |
(struct bfd_link_info *); |
/* TI COFF load page support. */ |
extern void bfd_ticoff_set_section_load_page |
(struct bfd_section *, int); |
extern int bfd_ticoff_get_section_load_page |
(struct bfd_section *); |
/* H8/300 functions. */ |
extern bfd_vma bfd_h8300_pad_address |
(bfd *, bfd_vma); |
/* IA64 Itanium code generation. Called from linker. */ |
extern void bfd_elf32_ia64_after_parse |
(int); |
extern void bfd_elf64_ia64_after_parse |
(int); |
/* This structure is used for a comdat section, as in PE. A comdat |
section is associated with a particular symbol. When the linker |
sees a comdat section, it keeps only one of the sections with a |
given name and associated with a given symbol. */ |
struct coff_comdat_info |
{ |
/* The name of the symbol associated with a comdat section. */ |
const char *name; |
/* The local symbol table index of the symbol associated with a |
comdat section. This is only meaningful to the object file format |
specific code; it is not an index into the list returned by |
bfd_canonicalize_symtab. */ |
long symbol; |
}; |
extern struct coff_comdat_info * bfd_coff_get_comdat_section |
(bfd *, struct bfd_section *); |
/* Extracted from init.c. */ |
void bfd_init (void); |
/* Extracted from opncls.c. */ |
extern unsigned int bfd_use_reserved_id; |
bfd *bfd_fopen (const char *filename, const char *target, |
const char *mode, int fd); |
bfd *bfd_openr (const char *filename, const char *target); |
bfd *bfd_fdopenr (const char *filename, const char *target, int fd); |
bfd *bfd_openstreamr (const char *, const char *, void *); |
bfd *bfd_openr_iovec (const char *filename, const char *target, |
void *(*open_func) (struct bfd *nbfd, |
void *open_closure), |
void *open_closure, |
file_ptr (*pread_func) (struct bfd *nbfd, |
void *stream, |
void *buf, |
file_ptr nbytes, |
file_ptr offset), |
int (*close_func) (struct bfd *nbfd, |
void *stream), |
int (*stat_func) (struct bfd *abfd, |
void *stream, |
struct stat *sb)); |
bfd *bfd_openw (const char *filename, const char *target); |
bfd_boolean bfd_close (bfd *abfd); |
bfd_boolean bfd_close_all_done (bfd *); |
bfd *bfd_create (const char *filename, bfd *templ); |
bfd_boolean bfd_make_writable (bfd *abfd); |
bfd_boolean bfd_make_readable (bfd *abfd); |
void *bfd_alloc (bfd *abfd, bfd_size_type wanted); |
void *bfd_zalloc (bfd *abfd, bfd_size_type wanted); |
unsigned long bfd_calc_gnu_debuglink_crc32 |
(unsigned long crc, const unsigned char *buf, bfd_size_type len); |
char *bfd_get_debug_link_info (bfd *abfd, unsigned long *crc32_out); |
char *bfd_get_alt_debug_link_info (bfd *abfd, unsigned long *crc32_out); |
char *bfd_follow_gnu_debuglink (bfd *abfd, const char *dir); |
char *bfd_follow_gnu_debugaltlink (bfd *abfd, const char *dir); |
struct bfd_section *bfd_create_gnu_debuglink_section |
(bfd *abfd, const char *filename); |
bfd_boolean bfd_fill_in_gnu_debuglink_section |
(bfd *abfd, struct bfd_section *sect, const char *filename); |
/* Extracted from libbfd.c. */ |
/* Byte swapping macros for user section data. */ |
#define bfd_put_8(abfd, val, ptr) \ |
((void) (*((unsigned char *) (ptr)) = (val) & 0xff)) |
#define bfd_put_signed_8 \ |
bfd_put_8 |
#define bfd_get_8(abfd, ptr) \ |
(*(const unsigned char *) (ptr) & 0xff) |
#define bfd_get_signed_8(abfd, ptr) \ |
(((*(const unsigned char *) (ptr) & 0xff) ^ 0x80) - 0x80) |
#define bfd_put_16(abfd, val, ptr) \ |
BFD_SEND (abfd, bfd_putx16, ((val),(ptr))) |
#define bfd_put_signed_16 \ |
bfd_put_16 |
#define bfd_get_16(abfd, ptr) \ |
BFD_SEND (abfd, bfd_getx16, (ptr)) |
#define bfd_get_signed_16(abfd, ptr) \ |
BFD_SEND (abfd, bfd_getx_signed_16, (ptr)) |
#define bfd_put_32(abfd, val, ptr) \ |
BFD_SEND (abfd, bfd_putx32, ((val),(ptr))) |
#define bfd_put_signed_32 \ |
bfd_put_32 |
#define bfd_get_32(abfd, ptr) \ |
BFD_SEND (abfd, bfd_getx32, (ptr)) |
#define bfd_get_signed_32(abfd, ptr) \ |
BFD_SEND (abfd, bfd_getx_signed_32, (ptr)) |
#define bfd_put_64(abfd, val, ptr) \ |
BFD_SEND (abfd, bfd_putx64, ((val), (ptr))) |
#define bfd_put_signed_64 \ |
bfd_put_64 |
#define bfd_get_64(abfd, ptr) \ |
BFD_SEND (abfd, bfd_getx64, (ptr)) |
#define bfd_get_signed_64(abfd, ptr) \ |
BFD_SEND (abfd, bfd_getx_signed_64, (ptr)) |
#define bfd_get(bits, abfd, ptr) \ |
((bits) == 8 ? (bfd_vma) bfd_get_8 (abfd, ptr) \ |
: (bits) == 16 ? bfd_get_16 (abfd, ptr) \ |
: (bits) == 32 ? bfd_get_32 (abfd, ptr) \ |
: (bits) == 64 ? bfd_get_64 (abfd, ptr) \ |
: (abort (), (bfd_vma) - 1)) |
#define bfd_put(bits, abfd, val, ptr) \ |
((bits) == 8 ? bfd_put_8 (abfd, val, ptr) \ |
: (bits) == 16 ? bfd_put_16 (abfd, val, ptr) \ |
: (bits) == 32 ? bfd_put_32 (abfd, val, ptr) \ |
: (bits) == 64 ? bfd_put_64 (abfd, val, ptr) \ |
: (abort (), (void) 0)) |
/* Byte swapping macros for file header data. */ |
#define bfd_h_put_8(abfd, val, ptr) \ |
bfd_put_8 (abfd, val, ptr) |
#define bfd_h_put_signed_8(abfd, val, ptr) \ |
bfd_put_8 (abfd, val, ptr) |
#define bfd_h_get_8(abfd, ptr) \ |
bfd_get_8 (abfd, ptr) |
#define bfd_h_get_signed_8(abfd, ptr) \ |
bfd_get_signed_8 (abfd, ptr) |
#define bfd_h_put_16(abfd, val, ptr) \ |
BFD_SEND (abfd, bfd_h_putx16, (val, ptr)) |
#define bfd_h_put_signed_16 \ |
bfd_h_put_16 |
#define bfd_h_get_16(abfd, ptr) \ |
BFD_SEND (abfd, bfd_h_getx16, (ptr)) |
#define bfd_h_get_signed_16(abfd, ptr) \ |
BFD_SEND (abfd, bfd_h_getx_signed_16, (ptr)) |
#define bfd_h_put_32(abfd, val, ptr) \ |
BFD_SEND (abfd, bfd_h_putx32, (val, ptr)) |
#define bfd_h_put_signed_32 \ |
bfd_h_put_32 |
#define bfd_h_get_32(abfd, ptr) \ |
BFD_SEND (abfd, bfd_h_getx32, (ptr)) |
#define bfd_h_get_signed_32(abfd, ptr) \ |
BFD_SEND (abfd, bfd_h_getx_signed_32, (ptr)) |
#define bfd_h_put_64(abfd, val, ptr) \ |
BFD_SEND (abfd, bfd_h_putx64, (val, ptr)) |
#define bfd_h_put_signed_64 \ |
bfd_h_put_64 |
#define bfd_h_get_64(abfd, ptr) \ |
BFD_SEND (abfd, bfd_h_getx64, (ptr)) |
#define bfd_h_get_signed_64(abfd, ptr) \ |
BFD_SEND (abfd, bfd_h_getx_signed_64, (ptr)) |
/* Aliases for the above, which should eventually go away. */ |
#define H_PUT_64 bfd_h_put_64 |
#define H_PUT_32 bfd_h_put_32 |
#define H_PUT_16 bfd_h_put_16 |
#define H_PUT_8 bfd_h_put_8 |
#define H_PUT_S64 bfd_h_put_signed_64 |
#define H_PUT_S32 bfd_h_put_signed_32 |
#define H_PUT_S16 bfd_h_put_signed_16 |
#define H_PUT_S8 bfd_h_put_signed_8 |
#define H_GET_64 bfd_h_get_64 |
#define H_GET_32 bfd_h_get_32 |
#define H_GET_16 bfd_h_get_16 |
#define H_GET_8 bfd_h_get_8 |
#define H_GET_S64 bfd_h_get_signed_64 |
#define H_GET_S32 bfd_h_get_signed_32 |
#define H_GET_S16 bfd_h_get_signed_16 |
#define H_GET_S8 bfd_h_get_signed_8 |
/* Extracted from bfdio.c. */ |
long bfd_get_mtime (bfd *abfd); |
file_ptr bfd_get_size (bfd *abfd); |
void *bfd_mmap (bfd *abfd, void *addr, bfd_size_type len, |
int prot, int flags, file_ptr offset, |
void **map_addr, bfd_size_type *map_len); |
/* Extracted from bfdwin.c. */ |
/* Extracted from section.c. */ |
typedef struct bfd_section |
{ |
/* The name of the section; the name isn't a copy, the pointer is |
the same as that passed to bfd_make_section. */ |
const char *name; |
/* A unique sequence number. */ |
int id; |
/* Which section in the bfd; 0..n-1 as sections are created in a bfd. */ |
int index; |
/* The next section in the list belonging to the BFD, or NULL. */ |
struct bfd_section *next; |
/* The previous section in the list belonging to the BFD, or NULL. */ |
struct bfd_section *prev; |
/* The field flags contains attributes of the section. Some |
flags are read in from the object file, and some are |
synthesized from other information. */ |
flagword flags; |
#define SEC_NO_FLAGS 0x000 |
/* Tells the OS to allocate space for this section when loading. |
This is clear for a section containing debug information only. */ |
#define SEC_ALLOC 0x001 |
/* Tells the OS to load the section from the file when loading. |
This is clear for a .bss section. */ |
#define SEC_LOAD 0x002 |
/* The section contains data still to be relocated, so there is |
some relocation information too. */ |
#define SEC_RELOC 0x004 |
/* A signal to the OS that the section contains read only data. */ |
#define SEC_READONLY 0x008 |
/* The section contains code only. */ |
#define SEC_CODE 0x010 |
/* The section contains data only. */ |
#define SEC_DATA 0x020 |
/* The section will reside in ROM. */ |
#define SEC_ROM 0x040 |
/* The section contains constructor information. This section |
type is used by the linker to create lists of constructors and |
destructors used by <<g++>>. When a back end sees a symbol |
which should be used in a constructor list, it creates a new |
section for the type of name (e.g., <<__CTOR_LIST__>>), attaches |
the symbol to it, and builds a relocation. To build the lists |
of constructors, all the linker has to do is catenate all the |
sections called <<__CTOR_LIST__>> and relocate the data |
contained within - exactly the operations it would peform on |
standard data. */ |
#define SEC_CONSTRUCTOR 0x080 |
/* The section has contents - a data section could be |
<<SEC_ALLOC>> | <<SEC_HAS_CONTENTS>>; a debug section could be |
<<SEC_HAS_CONTENTS>> */ |
#define SEC_HAS_CONTENTS 0x100 |
/* An instruction to the linker to not output the section |
even if it has information which would normally be written. */ |
#define SEC_NEVER_LOAD 0x200 |
/* The section contains thread local data. */ |
#define SEC_THREAD_LOCAL 0x400 |
/* The section has GOT references. This flag is only for the |
linker, and is currently only used by the elf32-hppa back end. |
It will be set if global offset table references were detected |
in this section, which indicate to the linker that the section |
contains PIC code, and must be handled specially when doing a |
static link. */ |
#define SEC_HAS_GOT_REF 0x800 |
/* The section contains common symbols (symbols may be defined |
multiple times, the value of a symbol is the amount of |
space it requires, and the largest symbol value is the one |
used). Most targets have exactly one of these (which we |
translate to bfd_com_section_ptr), but ECOFF has two. */ |
#define SEC_IS_COMMON 0x1000 |
/* The section contains only debugging information. For |
example, this is set for ELF .debug and .stab sections. |
strip tests this flag to see if a section can be |
discarded. */ |
#define SEC_DEBUGGING 0x2000 |
/* The contents of this section are held in memory pointed to |
by the contents field. This is checked by bfd_get_section_contents, |
and the data is retrieved from memory if appropriate. */ |
#define SEC_IN_MEMORY 0x4000 |
/* The contents of this section are to be excluded by the |
linker for executable and shared objects unless those |
objects are to be further relocated. */ |
#define SEC_EXCLUDE 0x8000 |
/* The contents of this section are to be sorted based on the sum of |
the symbol and addend values specified by the associated relocation |
entries. Entries without associated relocation entries will be |
appended to the end of the section in an unspecified order. */ |
#define SEC_SORT_ENTRIES 0x10000 |
/* When linking, duplicate sections of the same name should be |
discarded, rather than being combined into a single section as |
is usually done. This is similar to how common symbols are |
handled. See SEC_LINK_DUPLICATES below. */ |
#define SEC_LINK_ONCE 0x20000 |
/* If SEC_LINK_ONCE is set, this bitfield describes how the linker |
should handle duplicate sections. */ |
#define SEC_LINK_DUPLICATES 0xc0000 |
/* This value for SEC_LINK_DUPLICATES means that duplicate |
sections with the same name should simply be discarded. */ |
#define SEC_LINK_DUPLICATES_DISCARD 0x0 |
/* This value for SEC_LINK_DUPLICATES means that the linker |
should warn if there are any duplicate sections, although |
it should still only link one copy. */ |
#define SEC_LINK_DUPLICATES_ONE_ONLY 0x40000 |
/* This value for SEC_LINK_DUPLICATES means that the linker |
should warn if any duplicate sections are a different size. */ |
#define SEC_LINK_DUPLICATES_SAME_SIZE 0x80000 |
/* This value for SEC_LINK_DUPLICATES means that the linker |
should warn if any duplicate sections contain different |
contents. */ |
#define SEC_LINK_DUPLICATES_SAME_CONTENTS \ |
(SEC_LINK_DUPLICATES_ONE_ONLY | SEC_LINK_DUPLICATES_SAME_SIZE) |
/* This section was created by the linker as part of dynamic |
relocation or other arcane processing. It is skipped when |
going through the first-pass output, trusting that someone |
else up the line will take care of it later. */ |
#define SEC_LINKER_CREATED 0x100000 |
/* This section should not be subject to garbage collection. |
Also set to inform the linker that this section should not be |
listed in the link map as discarded. */ |
#define SEC_KEEP 0x200000 |
/* This section contains "short" data, and should be placed |
"near" the GP. */ |
#define SEC_SMALL_DATA 0x400000 |
/* Attempt to merge identical entities in the section. |
Entity size is given in the entsize field. */ |
#define SEC_MERGE 0x800000 |
/* If given with SEC_MERGE, entities to merge are zero terminated |
strings where entsize specifies character size instead of fixed |
size entries. */ |
#define SEC_STRINGS 0x1000000 |
/* This section contains data about section groups. */ |
#define SEC_GROUP 0x2000000 |
/* The section is a COFF shared library section. This flag is |
only for the linker. If this type of section appears in |
the input file, the linker must copy it to the output file |
without changing the vma or size. FIXME: Although this |
was originally intended to be general, it really is COFF |
specific (and the flag was renamed to indicate this). It |
might be cleaner to have some more general mechanism to |
allow the back end to control what the linker does with |
sections. */ |
#define SEC_COFF_SHARED_LIBRARY 0x4000000 |
/* This input section should be copied to output in reverse order |
as an array of pointers. This is for ELF linker internal use |
only. */ |
#define SEC_ELF_REVERSE_COPY 0x4000000 |
/* This section contains data which may be shared with other |
executables or shared objects. This is for COFF only. */ |
#define SEC_COFF_SHARED 0x8000000 |
/* When a section with this flag is being linked, then if the size of |
the input section is less than a page, it should not cross a page |
boundary. If the size of the input section is one page or more, |
it should be aligned on a page boundary. This is for TI |
TMS320C54X only. */ |
#define SEC_TIC54X_BLOCK 0x10000000 |
/* Conditionally link this section; do not link if there are no |
references found to any symbol in the section. This is for TI |
TMS320C54X only. */ |
#define SEC_TIC54X_CLINK 0x20000000 |
/* Indicate that section has the no read flag set. This happens |
when memory read flag isn't set. */ |
#define SEC_COFF_NOREAD 0x40000000 |
/* End of section flags. */ |
/* Some internal packed boolean fields. */ |
/* See the vma field. */ |
unsigned int user_set_vma : 1; |
/* A mark flag used by some of the linker backends. */ |
unsigned int linker_mark : 1; |
/* Another mark flag used by some of the linker backends. Set for |
output sections that have an input section. */ |
unsigned int linker_has_input : 1; |
/* Mark flag used by some linker backends for garbage collection. */ |
unsigned int gc_mark : 1; |
/* Section compression status. */ |
unsigned int compress_status : 2; |
#define COMPRESS_SECTION_NONE 0 |
#define COMPRESS_SECTION_DONE 1 |
#define DECOMPRESS_SECTION_SIZED 2 |
/* The following flags are used by the ELF linker. */ |
/* Mark sections which have been allocated to segments. */ |
unsigned int segment_mark : 1; |
/* Type of sec_info information. */ |
unsigned int sec_info_type:3; |
#define SEC_INFO_TYPE_NONE 0 |
#define SEC_INFO_TYPE_STABS 1 |
#define SEC_INFO_TYPE_MERGE 2 |
#define SEC_INFO_TYPE_EH_FRAME 3 |
#define SEC_INFO_TYPE_JUST_SYMS 4 |
/* Nonzero if this section uses RELA relocations, rather than REL. */ |
unsigned int use_rela_p:1; |
/* Bits used by various backends. The generic code doesn't touch |
these fields. */ |
unsigned int sec_flg0:1; |
unsigned int sec_flg1:1; |
unsigned int sec_flg2:1; |
unsigned int sec_flg3:1; |
unsigned int sec_flg4:1; |
unsigned int sec_flg5:1; |
/* End of internal packed boolean fields. */ |
/* The virtual memory address of the section - where it will be |
at run time. The symbols are relocated against this. The |
user_set_vma flag is maintained by bfd; if it's not set, the |
backend can assign addresses (for example, in <<a.out>>, where |
the default address for <<.data>> is dependent on the specific |
target and various flags). */ |
bfd_vma vma; |
/* The load address of the section - where it would be in a |
rom image; really only used for writing section header |
information. */ |
bfd_vma lma; |
/* The size of the section in octets, as it will be output. |
Contains a value even if the section has no contents (e.g., the |
size of <<.bss>>). */ |
bfd_size_type size; |
/* For input sections, the original size on disk of the section, in |
octets. This field should be set for any section whose size is |
changed by linker relaxation. It is required for sections where |
the linker relaxation scheme doesn't cache altered section and |
reloc contents (stabs, eh_frame, SEC_MERGE, some coff relaxing |
targets), and thus the original size needs to be kept to read the |
section multiple times. For output sections, rawsize holds the |
section size calculated on a previous linker relaxation pass. */ |
bfd_size_type rawsize; |
/* The compressed size of the section in octets. */ |
bfd_size_type compressed_size; |
/* Relaxation table. */ |
struct relax_table *relax; |
/* Count of used relaxation table entries. */ |
int relax_count; |
/* If this section is going to be output, then this value is the |
offset in *bytes* into the output section of the first byte in the |
input section (byte ==> smallest addressable unit on the |
target). In most cases, if this was going to start at the |
100th octet (8-bit quantity) in the output section, this value |
would be 100. However, if the target byte size is 16 bits |
(bfd_octets_per_byte is "2"), this value would be 50. */ |
bfd_vma output_offset; |
/* The output section through which to map on output. */ |
struct bfd_section *output_section; |
/* The alignment requirement of the section, as an exponent of 2 - |
e.g., 3 aligns to 2^3 (or 8). */ |
unsigned int alignment_power; |
/* If an input section, a pointer to a vector of relocation |
records for the data in this section. */ |
struct reloc_cache_entry *relocation; |
/* If an output section, a pointer to a vector of pointers to |
relocation records for the data in this section. */ |
struct reloc_cache_entry **orelocation; |
/* The number of relocation records in one of the above. */ |
unsigned reloc_count; |
/* Information below is back end specific - and not always used |
or updated. */ |
/* File position of section data. */ |
file_ptr filepos; |
/* File position of relocation info. */ |
file_ptr rel_filepos; |
/* File position of line data. */ |
file_ptr line_filepos; |
/* Pointer to data for applications. */ |
void *userdata; |
/* If the SEC_IN_MEMORY flag is set, this points to the actual |
contents. */ |
unsigned char *contents; |
/* Attached line number information. */ |
alent *lineno; |
/* Number of line number records. */ |
unsigned int lineno_count; |
/* Entity size for merging purposes. */ |
unsigned int entsize; |
/* Points to the kept section if this section is a link-once section, |
and is discarded. */ |
struct bfd_section *kept_section; |
/* When a section is being output, this value changes as more |
linenumbers are written out. */ |
file_ptr moving_line_filepos; |
/* What the section number is in the target world. */ |
int target_index; |
void *used_by_bfd; |
/* If this is a constructor section then here is a list of the |
relocations created to relocate items within it. */ |
struct relent_chain *constructor_chain; |
/* The BFD which owns the section. */ |
bfd *owner; |
/* A symbol which points at this section only. */ |
struct bfd_symbol *symbol; |
struct bfd_symbol **symbol_ptr_ptr; |
/* Early in the link process, map_head and map_tail are used to build |
a list of input sections attached to an output section. Later, |
output sections use these fields for a list of bfd_link_order |
structs. */ |
union { |
struct bfd_link_order *link_order; |
struct bfd_section *s; |
} map_head, map_tail; |
} asection; |
/* Relax table contains information about instructions which can |
be removed by relaxation -- replacing a long address with a |
short address. */ |
struct relax_table { |
/* Address where bytes may be deleted. */ |
bfd_vma addr; |
/* Number of bytes to be deleted. */ |
int size; |
}; |
/* These sections are global, and are managed by BFD. The application |
and target back end are not permitted to change the values in |
these sections. */ |
extern asection _bfd_std_section[4]; |
#define BFD_ABS_SECTION_NAME "*ABS*" |
#define BFD_UND_SECTION_NAME "*UND*" |
#define BFD_COM_SECTION_NAME "*COM*" |
#define BFD_IND_SECTION_NAME "*IND*" |
/* Pointer to the common section. */ |
#define bfd_com_section_ptr (&_bfd_std_section[0]) |
/* Pointer to the undefined section. */ |
#define bfd_und_section_ptr (&_bfd_std_section[1]) |
/* Pointer to the absolute section. */ |
#define bfd_abs_section_ptr (&_bfd_std_section[2]) |
/* Pointer to the indirect section. */ |
#define bfd_ind_section_ptr (&_bfd_std_section[3]) |
#define bfd_is_und_section(sec) ((sec) == bfd_und_section_ptr) |
#define bfd_is_abs_section(sec) ((sec) == bfd_abs_section_ptr) |
#define bfd_is_ind_section(sec) ((sec) == bfd_ind_section_ptr) |
#define bfd_is_const_section(SEC) \ |
( ((SEC) == bfd_abs_section_ptr) \ |
|| ((SEC) == bfd_und_section_ptr) \ |
|| ((SEC) == bfd_com_section_ptr) \ |
|| ((SEC) == bfd_ind_section_ptr)) |
/* Macros to handle insertion and deletion of a bfd's sections. These |
only handle the list pointers, ie. do not adjust section_count, |
target_index etc. */ |
#define bfd_section_list_remove(ABFD, S) \ |
do \ |
{ \ |
asection *_s = S; \ |
asection *_next = _s->next; \ |
asection *_prev = _s->prev; \ |
if (_prev) \ |
_prev->next = _next; \ |
else \ |
(ABFD)->sections = _next; \ |
if (_next) \ |
_next->prev = _prev; \ |
else \ |
(ABFD)->section_last = _prev; \ |
} \ |
while (0) |
#define bfd_section_list_append(ABFD, S) \ |
do \ |
{ \ |
asection *_s = S; \ |
bfd *_abfd = ABFD; \ |
_s->next = NULL; \ |
if (_abfd->section_last) \ |
{ \ |
_s->prev = _abfd->section_last; \ |
_abfd->section_last->next = _s; \ |
} \ |
else \ |
{ \ |
_s->prev = NULL; \ |
_abfd->sections = _s; \ |
} \ |
_abfd->section_last = _s; \ |
} \ |
while (0) |
#define bfd_section_list_prepend(ABFD, S) \ |
do \ |
{ \ |
asection *_s = S; \ |
bfd *_abfd = ABFD; \ |
_s->prev = NULL; \ |
if (_abfd->sections) \ |
{ \ |
_s->next = _abfd->sections; \ |
_abfd->sections->prev = _s; \ |
} \ |
else \ |
{ \ |
_s->next = NULL; \ |
_abfd->section_last = _s; \ |
} \ |
_abfd->sections = _s; \ |
} \ |
while (0) |
#define bfd_section_list_insert_after(ABFD, A, S) \ |
do \ |
{ \ |
asection *_a = A; \ |
asection *_s = S; \ |
asection *_next = _a->next; \ |
_s->next = _next; \ |
_s->prev = _a; \ |
_a->next = _s; \ |
if (_next) \ |
_next->prev = _s; \ |
else \ |
(ABFD)->section_last = _s; \ |
} \ |
while (0) |
#define bfd_section_list_insert_before(ABFD, B, S) \ |
do \ |
{ \ |
asection *_b = B; \ |
asection *_s = S; \ |
asection *_prev = _b->prev; \ |
_s->prev = _prev; \ |
_s->next = _b; \ |
_b->prev = _s; \ |
if (_prev) \ |
_prev->next = _s; \ |
else \ |
(ABFD)->sections = _s; \ |
} \ |
while (0) |
#define bfd_section_removed_from_list(ABFD, S) \ |
((S)->next == NULL ? (ABFD)->section_last != (S) : (S)->next->prev != (S)) |
#define BFD_FAKE_SECTION(SEC, FLAGS, SYM, NAME, IDX) \ |
/* name, id, index, next, prev, flags, user_set_vma, */ \ |
{ NAME, IDX, 0, NULL, NULL, FLAGS, 0, \ |
\ |
/* linker_mark, linker_has_input, gc_mark, decompress_status, */ \ |
0, 0, 1, 0, \ |
\ |
/* segment_mark, sec_info_type, use_rela_p, */ \ |
0, 0, 0, \ |
\ |
/* sec_flg0, sec_flg1, sec_flg2, sec_flg3, sec_flg4, sec_flg5, */ \ |
0, 0, 0, 0, 0, 0, \ |
\ |
/* vma, lma, size, rawsize, compressed_size, relax, relax_count, */ \ |
0, 0, 0, 0, 0, 0, 0, \ |
\ |
/* output_offset, output_section, alignment_power, */ \ |
0, &SEC, 0, \ |
\ |
/* relocation, orelocation, reloc_count, filepos, rel_filepos, */ \ |
NULL, NULL, 0, 0, 0, \ |
\ |
/* line_filepos, userdata, contents, lineno, lineno_count, */ \ |
0, NULL, NULL, NULL, 0, \ |
\ |
/* entsize, kept_section, moving_line_filepos, */ \ |
0, NULL, 0, \ |
\ |
/* target_index, used_by_bfd, constructor_chain, owner, */ \ |
0, NULL, NULL, NULL, \ |
\ |
/* symbol, symbol_ptr_ptr, */ \ |
(struct bfd_symbol *) SYM, &SEC.symbol, \ |
\ |
/* map_head, map_tail */ \ |
{ NULL }, { NULL } \ |
} |
void bfd_section_list_clear (bfd *); |
asection *bfd_get_section_by_name (bfd *abfd, const char *name); |
asection *bfd_get_next_section_by_name (asection *sec); |
asection *bfd_get_linker_section (bfd *abfd, const char *name); |
asection *bfd_get_section_by_name_if |
(bfd *abfd, |
const char *name, |
bfd_boolean (*func) (bfd *abfd, asection *sect, void *obj), |
void *obj); |
char *bfd_get_unique_section_name |
(bfd *abfd, const char *templat, int *count); |
asection *bfd_make_section_old_way (bfd *abfd, const char *name); |
asection *bfd_make_section_anyway_with_flags |
(bfd *abfd, const char *name, flagword flags); |
asection *bfd_make_section_anyway (bfd *abfd, const char *name); |
asection *bfd_make_section_with_flags |
(bfd *, const char *name, flagword flags); |
asection *bfd_make_section (bfd *, const char *name); |
bfd_boolean bfd_set_section_flags |
(bfd *abfd, asection *sec, flagword flags); |
void bfd_rename_section |
(bfd *abfd, asection *sec, const char *newname); |
void bfd_map_over_sections |
(bfd *abfd, |
void (*func) (bfd *abfd, asection *sect, void *obj), |
void *obj); |
asection *bfd_sections_find_if |
(bfd *abfd, |
bfd_boolean (*operation) (bfd *abfd, asection *sect, void *obj), |
void *obj); |
bfd_boolean bfd_set_section_size |
(bfd *abfd, asection *sec, bfd_size_type val); |
bfd_boolean bfd_set_section_contents |
(bfd *abfd, asection *section, const void *data, |
file_ptr offset, bfd_size_type count); |
bfd_boolean bfd_get_section_contents |
(bfd *abfd, asection *section, void *location, file_ptr offset, |
bfd_size_type count); |
bfd_boolean bfd_malloc_and_get_section |
(bfd *abfd, asection *section, bfd_byte **buf); |
bfd_boolean bfd_copy_private_section_data |
(bfd *ibfd, asection *isec, bfd *obfd, asection *osec); |
#define bfd_copy_private_section_data(ibfd, isection, obfd, osection) \ |
BFD_SEND (obfd, _bfd_copy_private_section_data, \ |
(ibfd, isection, obfd, osection)) |
bfd_boolean bfd_generic_is_group_section (bfd *, const asection *sec); |
bfd_boolean bfd_generic_discard_group (bfd *abfd, asection *group); |
/* Extracted from archures.c. */ |
enum bfd_architecture |
{ |
bfd_arch_unknown, /* File arch not known. */ |
bfd_arch_obscure, /* Arch known, not one of these. */ |
bfd_arch_m68k, /* Motorola 68xxx */ |
#define bfd_mach_m68000 1 |
#define bfd_mach_m68008 2 |
#define bfd_mach_m68010 3 |
#define bfd_mach_m68020 4 |
#define bfd_mach_m68030 5 |
#define bfd_mach_m68040 6 |
#define bfd_mach_m68060 7 |
#define bfd_mach_cpu32 8 |
#define bfd_mach_fido 9 |
#define bfd_mach_mcf_isa_a_nodiv 10 |
#define bfd_mach_mcf_isa_a 11 |
#define bfd_mach_mcf_isa_a_mac 12 |
#define bfd_mach_mcf_isa_a_emac 13 |
#define bfd_mach_mcf_isa_aplus 14 |
#define bfd_mach_mcf_isa_aplus_mac 15 |
#define bfd_mach_mcf_isa_aplus_emac 16 |
#define bfd_mach_mcf_isa_b_nousp 17 |
#define bfd_mach_mcf_isa_b_nousp_mac 18 |
#define bfd_mach_mcf_isa_b_nousp_emac 19 |
#define bfd_mach_mcf_isa_b 20 |
#define bfd_mach_mcf_isa_b_mac 21 |
#define bfd_mach_mcf_isa_b_emac 22 |
#define bfd_mach_mcf_isa_b_float 23 |
#define bfd_mach_mcf_isa_b_float_mac 24 |
#define bfd_mach_mcf_isa_b_float_emac 25 |
#define bfd_mach_mcf_isa_c 26 |
#define bfd_mach_mcf_isa_c_mac 27 |
#define bfd_mach_mcf_isa_c_emac 28 |
#define bfd_mach_mcf_isa_c_nodiv 29 |
#define bfd_mach_mcf_isa_c_nodiv_mac 30 |
#define bfd_mach_mcf_isa_c_nodiv_emac 31 |
bfd_arch_vax, /* DEC Vax */ |
bfd_arch_i960, /* Intel 960 */ |
/* The order of the following is important. |
lower number indicates a machine type that |
only accepts a subset of the instructions |
available to machines with higher numbers. |
The exception is the "ca", which is |
incompatible with all other machines except |
"core". */ |
#define bfd_mach_i960_core 1 |
#define bfd_mach_i960_ka_sa 2 |
#define bfd_mach_i960_kb_sb 3 |
#define bfd_mach_i960_mc 4 |
#define bfd_mach_i960_xa 5 |
#define bfd_mach_i960_ca 6 |
#define bfd_mach_i960_jx 7 |
#define bfd_mach_i960_hx 8 |
bfd_arch_or32, /* OpenRISC 32 */ |
bfd_arch_sparc, /* SPARC */ |
#define bfd_mach_sparc 1 |
/* The difference between v8plus and v9 is that v9 is a true 64 bit env. */ |
#define bfd_mach_sparc_sparclet 2 |
#define bfd_mach_sparc_sparclite 3 |
#define bfd_mach_sparc_v8plus 4 |
#define bfd_mach_sparc_v8plusa 5 /* with ultrasparc add'ns. */ |
#define bfd_mach_sparc_sparclite_le 6 |
#define bfd_mach_sparc_v9 7 |
#define bfd_mach_sparc_v9a 8 /* with ultrasparc add'ns. */ |
#define bfd_mach_sparc_v8plusb 9 /* with cheetah add'ns. */ |
#define bfd_mach_sparc_v9b 10 /* with cheetah add'ns. */ |
/* Nonzero if MACH has the v9 instruction set. */ |
#define bfd_mach_sparc_v9_p(mach) \ |
((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9b \ |
&& (mach) != bfd_mach_sparc_sparclite_le) |
/* Nonzero if MACH is a 64 bit sparc architecture. */ |
#define bfd_mach_sparc_64bit_p(mach) \ |
((mach) >= bfd_mach_sparc_v9 && (mach) != bfd_mach_sparc_v8plusb) |
bfd_arch_spu, /* PowerPC SPU */ |
#define bfd_mach_spu 256 |
bfd_arch_mips, /* MIPS Rxxxx */ |
#define bfd_mach_mips3000 3000 |
#define bfd_mach_mips3900 3900 |
#define bfd_mach_mips4000 4000 |
#define bfd_mach_mips4010 4010 |
#define bfd_mach_mips4100 4100 |
#define bfd_mach_mips4111 4111 |
#define bfd_mach_mips4120 4120 |
#define bfd_mach_mips4300 4300 |
#define bfd_mach_mips4400 4400 |
#define bfd_mach_mips4600 4600 |
#define bfd_mach_mips4650 4650 |
#define bfd_mach_mips5000 5000 |
#define bfd_mach_mips5400 5400 |
#define bfd_mach_mips5500 5500 |
#define bfd_mach_mips5900 5900 |
#define bfd_mach_mips6000 6000 |
#define bfd_mach_mips7000 7000 |
#define bfd_mach_mips8000 8000 |
#define bfd_mach_mips9000 9000 |
#define bfd_mach_mips10000 10000 |
#define bfd_mach_mips12000 12000 |
#define bfd_mach_mips14000 14000 |
#define bfd_mach_mips16000 16000 |
#define bfd_mach_mips16 16 |
#define bfd_mach_mips5 5 |
#define bfd_mach_mips_loongson_2e 3001 |
#define bfd_mach_mips_loongson_2f 3002 |
#define bfd_mach_mips_loongson_3a 3003 |
#define bfd_mach_mips_sb1 12310201 /* octal 'SB', 01 */ |
#define bfd_mach_mips_octeon 6501 |
#define bfd_mach_mips_octeonp 6601 |
#define bfd_mach_mips_octeon2 6502 |
#define bfd_mach_mips_xlr 887682 /* decimal 'XLR' */ |
#define bfd_mach_mipsisa32 32 |
#define bfd_mach_mipsisa32r2 33 |
#define bfd_mach_mipsisa64 64 |
#define bfd_mach_mipsisa64r2 65 |
#define bfd_mach_mips_micromips 96 |
bfd_arch_i386, /* Intel 386 */ |
#define bfd_mach_i386_intel_syntax (1 << 0) |
#define bfd_mach_i386_i8086 (1 << 1) |
#define bfd_mach_i386_i386 (1 << 2) |
#define bfd_mach_x86_64 (1 << 3) |
#define bfd_mach_x64_32 (1 << 4) |
#define bfd_mach_i386_i386_intel_syntax (bfd_mach_i386_i386 | bfd_mach_i386_intel_syntax) |
#define bfd_mach_x86_64_intel_syntax (bfd_mach_x86_64 | bfd_mach_i386_intel_syntax) |
#define bfd_mach_x64_32_intel_syntax (bfd_mach_x64_32 | bfd_mach_i386_intel_syntax) |
bfd_arch_l1om, /* Intel L1OM */ |
#define bfd_mach_l1om (1 << 5) |
#define bfd_mach_l1om_intel_syntax (bfd_mach_l1om | bfd_mach_i386_intel_syntax) |
bfd_arch_k1om, /* Intel K1OM */ |
#define bfd_mach_k1om (1 << 6) |
#define bfd_mach_k1om_intel_syntax (bfd_mach_k1om | bfd_mach_i386_intel_syntax) |
#define bfd_mach_i386_nacl (1 << 7) |
#define bfd_mach_i386_i386_nacl (bfd_mach_i386_i386 | bfd_mach_i386_nacl) |
#define bfd_mach_x86_64_nacl (bfd_mach_x86_64 | bfd_mach_i386_nacl) |
#define bfd_mach_x64_32_nacl (bfd_mach_x64_32 | bfd_mach_i386_nacl) |
bfd_arch_we32k, /* AT&T WE32xxx */ |
bfd_arch_tahoe, /* CCI/Harris Tahoe */ |
bfd_arch_i860, /* Intel 860 */ |
bfd_arch_i370, /* IBM 360/370 Mainframes */ |
bfd_arch_romp, /* IBM ROMP PC/RT */ |
bfd_arch_convex, /* Convex */ |
bfd_arch_m88k, /* Motorola 88xxx */ |
bfd_arch_m98k, /* Motorola 98xxx */ |
bfd_arch_pyramid, /* Pyramid Technology */ |
bfd_arch_h8300, /* Renesas H8/300 (formerly Hitachi H8/300) */ |
#define bfd_mach_h8300 1 |
#define bfd_mach_h8300h 2 |
#define bfd_mach_h8300s 3 |
#define bfd_mach_h8300hn 4 |
#define bfd_mach_h8300sn 5 |
#define bfd_mach_h8300sx 6 |
#define bfd_mach_h8300sxn 7 |
bfd_arch_pdp11, /* DEC PDP-11 */ |
bfd_arch_plugin, |
bfd_arch_powerpc, /* PowerPC */ |
#define bfd_mach_ppc 32 |
#define bfd_mach_ppc64 64 |
#define bfd_mach_ppc_403 403 |
#define bfd_mach_ppc_403gc 4030 |
#define bfd_mach_ppc_405 405 |
#define bfd_mach_ppc_505 505 |
#define bfd_mach_ppc_601 601 |
#define bfd_mach_ppc_602 602 |
#define bfd_mach_ppc_603 603 |
#define bfd_mach_ppc_ec603e 6031 |
#define bfd_mach_ppc_604 604 |
#define bfd_mach_ppc_620 620 |
#define bfd_mach_ppc_630 630 |
#define bfd_mach_ppc_750 750 |
#define bfd_mach_ppc_860 860 |
#define bfd_mach_ppc_a35 35 |
#define bfd_mach_ppc_rs64ii 642 |
#define bfd_mach_ppc_rs64iii 643 |
#define bfd_mach_ppc_7400 7400 |
#define bfd_mach_ppc_e500 500 |
#define bfd_mach_ppc_e500mc 5001 |
#define bfd_mach_ppc_e500mc64 5005 |
#define bfd_mach_ppc_e5500 5006 |
#define bfd_mach_ppc_e6500 5007 |
#define bfd_mach_ppc_titan 83 |
#define bfd_mach_ppc_vle 84 |
bfd_arch_rs6000, /* IBM RS/6000 */ |
#define bfd_mach_rs6k 6000 |
#define bfd_mach_rs6k_rs1 6001 |
#define bfd_mach_rs6k_rsc 6003 |
#define bfd_mach_rs6k_rs2 6002 |
bfd_arch_hppa, /* HP PA RISC */ |
#define bfd_mach_hppa10 10 |
#define bfd_mach_hppa11 11 |
#define bfd_mach_hppa20 20 |
#define bfd_mach_hppa20w 25 |
bfd_arch_d10v, /* Mitsubishi D10V */ |
#define bfd_mach_d10v 1 |
#define bfd_mach_d10v_ts2 2 |
#define bfd_mach_d10v_ts3 3 |
bfd_arch_d30v, /* Mitsubishi D30V */ |
bfd_arch_dlx, /* DLX */ |
bfd_arch_m68hc11, /* Motorola 68HC11 */ |
bfd_arch_m68hc12, /* Motorola 68HC12 */ |
#define bfd_mach_m6812_default 0 |
#define bfd_mach_m6812 1 |
#define bfd_mach_m6812s 2 |
bfd_arch_m9s12x, /* Freescale S12X */ |
bfd_arch_m9s12xg, /* Freescale XGATE */ |
bfd_arch_z8k, /* Zilog Z8000 */ |
#define bfd_mach_z8001 1 |
#define bfd_mach_z8002 2 |
bfd_arch_h8500, /* Renesas H8/500 (formerly Hitachi H8/500) */ |
bfd_arch_sh, /* Renesas / SuperH SH (formerly Hitachi SH) */ |
#define bfd_mach_sh 1 |
#define bfd_mach_sh2 0x20 |
#define bfd_mach_sh_dsp 0x2d |
#define bfd_mach_sh2a 0x2a |
#define bfd_mach_sh2a_nofpu 0x2b |
#define bfd_mach_sh2a_nofpu_or_sh4_nommu_nofpu 0x2a1 |
#define bfd_mach_sh2a_nofpu_or_sh3_nommu 0x2a2 |
#define bfd_mach_sh2a_or_sh4 0x2a3 |
#define bfd_mach_sh2a_or_sh3e 0x2a4 |
#define bfd_mach_sh2e 0x2e |
#define bfd_mach_sh3 0x30 |
#define bfd_mach_sh3_nommu 0x31 |
#define bfd_mach_sh3_dsp 0x3d |
#define bfd_mach_sh3e 0x3e |
#define bfd_mach_sh4 0x40 |
#define bfd_mach_sh4_nofpu 0x41 |
#define bfd_mach_sh4_nommu_nofpu 0x42 |
#define bfd_mach_sh4a 0x4a |
#define bfd_mach_sh4a_nofpu 0x4b |
#define bfd_mach_sh4al_dsp 0x4d |
#define bfd_mach_sh5 0x50 |
bfd_arch_alpha, /* Dec Alpha */ |
#define bfd_mach_alpha_ev4 0x10 |
#define bfd_mach_alpha_ev5 0x20 |
#define bfd_mach_alpha_ev6 0x30 |
bfd_arch_arm, /* Advanced Risc Machines ARM. */ |
#define bfd_mach_arm_unknown 0 |
#define bfd_mach_arm_2 1 |
#define bfd_mach_arm_2a 2 |
#define bfd_mach_arm_3 3 |
#define bfd_mach_arm_3M 4 |
#define bfd_mach_arm_4 5 |
#define bfd_mach_arm_4T 6 |
#define bfd_mach_arm_5 7 |
#define bfd_mach_arm_5T 8 |
#define bfd_mach_arm_5TE 9 |
#define bfd_mach_arm_XScale 10 |
#define bfd_mach_arm_ep9312 11 |
#define bfd_mach_arm_iWMMXt 12 |
#define bfd_mach_arm_iWMMXt2 13 |
bfd_arch_ns32k, /* National Semiconductors ns32000 */ |
bfd_arch_w65, /* WDC 65816 */ |
bfd_arch_tic30, /* Texas Instruments TMS320C30 */ |
bfd_arch_tic4x, /* Texas Instruments TMS320C3X/4X */ |
#define bfd_mach_tic3x 30 |
#define bfd_mach_tic4x 40 |
bfd_arch_tic54x, /* Texas Instruments TMS320C54X */ |
bfd_arch_tic6x, /* Texas Instruments TMS320C6X */ |
bfd_arch_tic80, /* TI TMS320c80 (MVP) */ |
bfd_arch_v850, /* NEC V850 */ |
bfd_arch_v850_rh850,/* NEC V850 (using RH850 ABI) */ |
#define bfd_mach_v850 1 |
#define bfd_mach_v850e 'E' |
#define bfd_mach_v850e1 '1' |
#define bfd_mach_v850e2 0x4532 |
#define bfd_mach_v850e2v3 0x45325633 |
#define bfd_mach_v850e3v5 0x45335635 /* ('E'|'3'|'V'|'5') */ |
bfd_arch_arc, /* ARC Cores */ |
#define bfd_mach_arc_5 5 |
#define bfd_mach_arc_6 6 |
#define bfd_mach_arc_7 7 |
#define bfd_mach_arc_8 8 |
bfd_arch_m32c, /* Renesas M16C/M32C. */ |
#define bfd_mach_m16c 0x75 |
#define bfd_mach_m32c 0x78 |
bfd_arch_m32r, /* Renesas M32R (formerly Mitsubishi M32R/D) */ |
#define bfd_mach_m32r 1 /* For backwards compatibility. */ |
#define bfd_mach_m32rx 'x' |
#define bfd_mach_m32r2 '2' |
bfd_arch_mn10200, /* Matsushita MN10200 */ |
bfd_arch_mn10300, /* Matsushita MN10300 */ |
#define bfd_mach_mn10300 300 |
#define bfd_mach_am33 330 |
#define bfd_mach_am33_2 332 |
bfd_arch_fr30, |
#define bfd_mach_fr30 0x46523330 |
bfd_arch_frv, |
#define bfd_mach_frv 1 |
#define bfd_mach_frvsimple 2 |
#define bfd_mach_fr300 300 |
#define bfd_mach_fr400 400 |
#define bfd_mach_fr450 450 |
#define bfd_mach_frvtomcat 499 /* fr500 prototype */ |
#define bfd_mach_fr500 500 |
#define bfd_mach_fr550 550 |
bfd_arch_moxie, /* The moxie processor */ |
#define bfd_mach_moxie 1 |
bfd_arch_mcore, |
bfd_arch_mep, |
#define bfd_mach_mep 1 |
#define bfd_mach_mep_h1 0x6831 |
#define bfd_mach_mep_c5 0x6335 |
bfd_arch_metag, |
#define bfd_mach_metag 1 |
bfd_arch_ia64, /* HP/Intel ia64 */ |
#define bfd_mach_ia64_elf64 64 |
#define bfd_mach_ia64_elf32 32 |
bfd_arch_ip2k, /* Ubicom IP2K microcontrollers. */ |
#define bfd_mach_ip2022 1 |
#define bfd_mach_ip2022ext 2 |
bfd_arch_iq2000, /* Vitesse IQ2000. */ |
#define bfd_mach_iq2000 1 |
#define bfd_mach_iq10 2 |
bfd_arch_epiphany, /* Adapteva EPIPHANY */ |
#define bfd_mach_epiphany16 1 |
#define bfd_mach_epiphany32 2 |
bfd_arch_mt, |
#define bfd_mach_ms1 1 |
#define bfd_mach_mrisc2 2 |
#define bfd_mach_ms2 3 |
bfd_arch_pj, |
bfd_arch_avr, /* Atmel AVR microcontrollers. */ |
#define bfd_mach_avr1 1 |
#define bfd_mach_avr2 2 |
#define bfd_mach_avr25 25 |
#define bfd_mach_avr3 3 |
#define bfd_mach_avr31 31 |
#define bfd_mach_avr35 35 |
#define bfd_mach_avr4 4 |
#define bfd_mach_avr5 5 |
#define bfd_mach_avr51 51 |
#define bfd_mach_avr6 6 |
#define bfd_mach_avrxmega1 101 |
#define bfd_mach_avrxmega2 102 |
#define bfd_mach_avrxmega3 103 |
#define bfd_mach_avrxmega4 104 |
#define bfd_mach_avrxmega5 105 |
#define bfd_mach_avrxmega6 106 |
#define bfd_mach_avrxmega7 107 |
bfd_arch_bfin, /* ADI Blackfin */ |
#define bfd_mach_bfin 1 |
bfd_arch_cr16, /* National Semiconductor CompactRISC (ie CR16). */ |
#define bfd_mach_cr16 1 |
bfd_arch_cr16c, /* National Semiconductor CompactRISC. */ |
#define bfd_mach_cr16c 1 |
bfd_arch_crx, /* National Semiconductor CRX. */ |
#define bfd_mach_crx 1 |
bfd_arch_cris, /* Axis CRIS */ |
#define bfd_mach_cris_v0_v10 255 |
#define bfd_mach_cris_v32 32 |
#define bfd_mach_cris_v10_v32 1032 |
bfd_arch_rl78, |
#define bfd_mach_rl78 0x75 |
bfd_arch_rx, /* Renesas RX. */ |
#define bfd_mach_rx 0x75 |
bfd_arch_s390, /* IBM s390 */ |
#define bfd_mach_s390_31 31 |
#define bfd_mach_s390_64 64 |
bfd_arch_score, /* Sunplus score */ |
#define bfd_mach_score3 3 |
#define bfd_mach_score7 7 |
bfd_arch_openrisc, /* OpenRISC */ |
bfd_arch_mmix, /* Donald Knuth's educational processor. */ |
bfd_arch_xstormy16, |
#define bfd_mach_xstormy16 1 |
bfd_arch_msp430, /* Texas Instruments MSP430 architecture. */ |
#define bfd_mach_msp11 11 |
#define bfd_mach_msp110 110 |
#define bfd_mach_msp12 12 |
#define bfd_mach_msp13 13 |
#define bfd_mach_msp14 14 |
#define bfd_mach_msp15 15 |
#define bfd_mach_msp16 16 |
#define bfd_mach_msp20 20 |
#define bfd_mach_msp21 21 |
#define bfd_mach_msp22 22 |
#define bfd_mach_msp23 23 |
#define bfd_mach_msp24 24 |
#define bfd_mach_msp26 26 |
#define bfd_mach_msp31 31 |
#define bfd_mach_msp32 32 |
#define bfd_mach_msp33 33 |
#define bfd_mach_msp41 41 |
#define bfd_mach_msp42 42 |
#define bfd_mach_msp43 43 |
#define bfd_mach_msp44 44 |
#define bfd_mach_msp430x 45 |
#define bfd_mach_msp46 46 |
#define bfd_mach_msp47 47 |
#define bfd_mach_msp54 54 |
bfd_arch_xc16x, /* Infineon's XC16X Series. */ |
#define bfd_mach_xc16x 1 |
#define bfd_mach_xc16xl 2 |
#define bfd_mach_xc16xs 3 |
bfd_arch_xgate, /* Freescale XGATE */ |
#define bfd_mach_xgate 1 |
bfd_arch_xtensa, /* Tensilica's Xtensa cores. */ |
#define bfd_mach_xtensa 1 |
bfd_arch_z80, |
#define bfd_mach_z80strict 1 /* No undocumented opcodes. */ |
#define bfd_mach_z80 3 /* With ixl, ixh, iyl, and iyh. */ |
#define bfd_mach_z80full 7 /* All undocumented instructions. */ |
#define bfd_mach_r800 11 /* R800: successor with multiplication. */ |
bfd_arch_lm32, /* Lattice Mico32 */ |
#define bfd_mach_lm32 1 |
bfd_arch_microblaze,/* Xilinx MicroBlaze. */ |
bfd_arch_tilepro, /* Tilera TILEPro */ |
bfd_arch_tilegx, /* Tilera TILE-Gx */ |
#define bfd_mach_tilepro 1 |
#define bfd_mach_tilegx 1 |
#define bfd_mach_tilegx32 2 |
bfd_arch_aarch64, /* AArch64 */ |
#define bfd_mach_aarch64 0 |
#define bfd_mach_aarch64_ilp32 32 |
bfd_arch_nios2, |
#define bfd_mach_nios2 0 |
bfd_arch_last |
}; |
typedef struct bfd_arch_info |
{ |
int bits_per_word; |
int bits_per_address; |
int bits_per_byte; |
enum bfd_architecture arch; |
unsigned long mach; |
const char *arch_name; |
const char *printable_name; |
unsigned int section_align_power; |
/* TRUE if this is the default machine for the architecture. |
The default arch should be the first entry for an arch so that |
all the entries for that arch can be accessed via <<next>>. */ |
bfd_boolean the_default; |
const struct bfd_arch_info * (*compatible) |
(const struct bfd_arch_info *a, const struct bfd_arch_info *b); |
bfd_boolean (*scan) (const struct bfd_arch_info *, const char *); |
/* Allocate via bfd_malloc and return a fill buffer of size COUNT. If |
IS_BIGENDIAN is TRUE, the order of bytes is big endian. If CODE is |
TRUE, the buffer contains code. */ |
void *(*fill) (bfd_size_type count, bfd_boolean is_bigendian, |
bfd_boolean code); |
const struct bfd_arch_info *next; |
} |
bfd_arch_info_type; |
const char *bfd_printable_name (bfd *abfd); |
const bfd_arch_info_type *bfd_scan_arch (const char *string); |
const char **bfd_arch_list (void); |
const bfd_arch_info_type *bfd_arch_get_compatible |
(const bfd *abfd, const bfd *bbfd, bfd_boolean accept_unknowns); |
void bfd_set_arch_info (bfd *abfd, const bfd_arch_info_type *arg); |
enum bfd_architecture bfd_get_arch (bfd *abfd); |
unsigned long bfd_get_mach (bfd *abfd); |
unsigned int bfd_arch_bits_per_byte (bfd *abfd); |
unsigned int bfd_arch_bits_per_address (bfd *abfd); |
const bfd_arch_info_type *bfd_get_arch_info (bfd *abfd); |
const bfd_arch_info_type *bfd_lookup_arch |
(enum bfd_architecture arch, unsigned long machine); |
const char *bfd_printable_arch_mach |
(enum bfd_architecture arch, unsigned long machine); |
unsigned int bfd_octets_per_byte (bfd *abfd); |
unsigned int bfd_arch_mach_octets_per_byte |
(enum bfd_architecture arch, unsigned long machine); |
/* Extracted from reloc.c. */ |
typedef enum bfd_reloc_status |
{ |
/* No errors detected. */ |
bfd_reloc_ok, |
/* The relocation was performed, but there was an overflow. */ |
bfd_reloc_overflow, |
/* The address to relocate was not within the section supplied. */ |
bfd_reloc_outofrange, |
/* Used by special functions. */ |
bfd_reloc_continue, |
/* Unsupported relocation size requested. */ |
bfd_reloc_notsupported, |
/* Unused. */ |
bfd_reloc_other, |
/* The symbol to relocate against was undefined. */ |
bfd_reloc_undefined, |
/* The relocation was performed, but may not be ok - presently |
generated only when linking i960 coff files with i960 b.out |
symbols. If this type is returned, the error_message argument |
to bfd_perform_relocation will be set. */ |
bfd_reloc_dangerous |
} |
bfd_reloc_status_type; |
typedef struct reloc_cache_entry |
{ |
/* A pointer into the canonical table of pointers. */ |
struct bfd_symbol **sym_ptr_ptr; |
/* offset in section. */ |
bfd_size_type address; |
/* addend for relocation value. */ |
bfd_vma addend; |
/* Pointer to how to perform the required relocation. */ |
reloc_howto_type *howto; |
} |
arelent; |
enum complain_overflow |
{ |
/* Do not complain on overflow. */ |
complain_overflow_dont, |
/* Complain if the value overflows when considered as a signed |
number one bit larger than the field. ie. A bitfield of N bits |
is allowed to represent -2**n to 2**n-1. */ |
complain_overflow_bitfield, |
/* Complain if the value overflows when considered as a signed |
number. */ |
complain_overflow_signed, |
/* Complain if the value overflows when considered as an |
unsigned number. */ |
complain_overflow_unsigned |
}; |
struct reloc_howto_struct |
{ |
/* The type field has mainly a documentary use - the back end can |
do what it wants with it, though normally the back end's |
external idea of what a reloc number is stored |
in this field. For example, a PC relative word relocation |
in a coff environment has the type 023 - because that's |
what the outside world calls a R_PCRWORD reloc. */ |
unsigned int type; |
/* The value the final relocation is shifted right by. This drops |
unwanted data from the relocation. */ |
unsigned int rightshift; |
/* The size of the item to be relocated. This is *not* a |
power-of-two measure. To get the number of bytes operated |
on by a type of relocation, use bfd_get_reloc_size. */ |
int size; |
/* The number of bits in the item to be relocated. This is used |
when doing overflow checking. */ |
unsigned int bitsize; |
/* The relocation is relative to the field being relocated. */ |
bfd_boolean pc_relative; |
/* The bit position of the reloc value in the destination. |
The relocated value is left shifted by this amount. */ |
unsigned int bitpos; |
/* What type of overflow error should be checked for when |
relocating. */ |
enum complain_overflow complain_on_overflow; |
/* If this field is non null, then the supplied function is |
called rather than the normal function. This allows really |
strange relocation methods to be accommodated (e.g., i960 callj |
instructions). */ |
bfd_reloc_status_type (*special_function) |
(bfd *, arelent *, struct bfd_symbol *, void *, asection *, |
bfd *, char **); |
/* The textual name of the relocation type. */ |
char *name; |
/* Some formats record a relocation addend in the section contents |
rather than with the relocation. For ELF formats this is the |
distinction between USE_REL and USE_RELA (though the code checks |
for USE_REL == 1/0). The value of this field is TRUE if the |
addend is recorded with the section contents; when performing a |
partial link (ld -r) the section contents (the data) will be |
modified. The value of this field is FALSE if addends are |
recorded with the relocation (in arelent.addend); when performing |
a partial link the relocation will be modified. |
All relocations for all ELF USE_RELA targets should set this field |
to FALSE (values of TRUE should be looked on with suspicion). |
However, the converse is not true: not all relocations of all ELF |
USE_REL targets set this field to TRUE. Why this is so is peculiar |
to each particular target. For relocs that aren't used in partial |
links (e.g. GOT stuff) it doesn't matter what this is set to. */ |
bfd_boolean partial_inplace; |
/* src_mask selects the part of the instruction (or data) to be used |
in the relocation sum. If the target relocations don't have an |
addend in the reloc, eg. ELF USE_REL, src_mask will normally equal |
dst_mask to extract the addend from the section contents. If |
relocations do have an addend in the reloc, eg. ELF USE_RELA, this |
field should be zero. Non-zero values for ELF USE_RELA targets are |
bogus as in those cases the value in the dst_mask part of the |
section contents should be treated as garbage. */ |
bfd_vma src_mask; |
/* dst_mask selects which parts of the instruction (or data) are |
replaced with a relocated value. */ |
bfd_vma dst_mask; |
/* When some formats create PC relative instructions, they leave |
the value of the pc of the place being relocated in the offset |
slot of the instruction, so that a PC relative relocation can |
be made just by adding in an ordinary offset (e.g., sun3 a.out). |
Some formats leave the displacement part of an instruction |
empty (e.g., m88k bcs); this flag signals the fact. */ |
bfd_boolean pcrel_offset; |
}; |
#define HOWTO(C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC) \ |
{ (unsigned) C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC } |
#define NEWHOWTO(FUNCTION, NAME, SIZE, REL, IN) \ |
HOWTO (0, 0, SIZE, 0, REL, 0, complain_overflow_dont, FUNCTION, \ |
NAME, FALSE, 0, 0, IN) |
#define EMPTY_HOWTO(C) \ |
HOWTO ((C), 0, 0, 0, FALSE, 0, complain_overflow_dont, NULL, \ |
NULL, FALSE, 0, 0, FALSE) |
#define HOWTO_PREPARE(relocation, symbol) \ |
{ \ |
if (symbol != NULL) \ |
{ \ |
if (bfd_is_com_section (symbol->section)) \ |
{ \ |
relocation = 0; \ |
} \ |
else \ |
{ \ |
relocation = symbol->value; \ |
} \ |
} \ |
} |
unsigned int bfd_get_reloc_size (reloc_howto_type *); |
typedef struct relent_chain |
{ |
arelent relent; |
struct relent_chain *next; |
} |
arelent_chain; |
bfd_reloc_status_type bfd_check_overflow |
(enum complain_overflow how, |
unsigned int bitsize, |
unsigned int rightshift, |
unsigned int addrsize, |
bfd_vma relocation); |
bfd_reloc_status_type bfd_perform_relocation |
(bfd *abfd, |
arelent *reloc_entry, |
void *data, |
asection *input_section, |
bfd *output_bfd, |
char **error_message); |
bfd_reloc_status_type bfd_install_relocation |
(bfd *abfd, |
arelent *reloc_entry, |
void *data, bfd_vma data_start, |
asection *input_section, |
char **error_message); |
enum bfd_reloc_code_real { |
_dummy_first_bfd_reloc_code_real, |
/* Basic absolute relocations of N bits. */ |
BFD_RELOC_64, |
BFD_RELOC_32, |
BFD_RELOC_26, |
BFD_RELOC_24, |
BFD_RELOC_16, |
BFD_RELOC_14, |
BFD_RELOC_8, |
/* PC-relative relocations. Sometimes these are relative to the address |
of the relocation itself; sometimes they are relative to the start of |
the section containing the relocation. It depends on the specific target. |
The 24-bit relocation is used in some Intel 960 configurations. */ |
BFD_RELOC_64_PCREL, |
BFD_RELOC_32_PCREL, |
BFD_RELOC_24_PCREL, |
BFD_RELOC_16_PCREL, |
BFD_RELOC_12_PCREL, |
BFD_RELOC_8_PCREL, |
/* Section relative relocations. Some targets need this for DWARF2. */ |
BFD_RELOC_32_SECREL, |
/* For ELF. */ |
BFD_RELOC_32_GOT_PCREL, |
BFD_RELOC_16_GOT_PCREL, |
BFD_RELOC_8_GOT_PCREL, |
BFD_RELOC_32_GOTOFF, |
BFD_RELOC_16_GOTOFF, |
BFD_RELOC_LO16_GOTOFF, |
BFD_RELOC_HI16_GOTOFF, |
BFD_RELOC_HI16_S_GOTOFF, |
BFD_RELOC_8_GOTOFF, |
BFD_RELOC_64_PLT_PCREL, |
BFD_RELOC_32_PLT_PCREL, |
BFD_RELOC_24_PLT_PCREL, |
BFD_RELOC_16_PLT_PCREL, |
BFD_RELOC_8_PLT_PCREL, |
BFD_RELOC_64_PLTOFF, |
BFD_RELOC_32_PLTOFF, |
BFD_RELOC_16_PLTOFF, |
BFD_RELOC_LO16_PLTOFF, |
BFD_RELOC_HI16_PLTOFF, |
BFD_RELOC_HI16_S_PLTOFF, |
BFD_RELOC_8_PLTOFF, |
/* Size relocations. */ |
BFD_RELOC_SIZE32, |
BFD_RELOC_SIZE64, |
/* Relocations used by 68K ELF. */ |
BFD_RELOC_68K_GLOB_DAT, |
BFD_RELOC_68K_JMP_SLOT, |
BFD_RELOC_68K_RELATIVE, |
BFD_RELOC_68K_TLS_GD32, |
BFD_RELOC_68K_TLS_GD16, |
BFD_RELOC_68K_TLS_GD8, |
BFD_RELOC_68K_TLS_LDM32, |
BFD_RELOC_68K_TLS_LDM16, |
BFD_RELOC_68K_TLS_LDM8, |
BFD_RELOC_68K_TLS_LDO32, |
BFD_RELOC_68K_TLS_LDO16, |
BFD_RELOC_68K_TLS_LDO8, |
BFD_RELOC_68K_TLS_IE32, |
BFD_RELOC_68K_TLS_IE16, |
BFD_RELOC_68K_TLS_IE8, |
BFD_RELOC_68K_TLS_LE32, |
BFD_RELOC_68K_TLS_LE16, |
BFD_RELOC_68K_TLS_LE8, |
/* Linkage-table relative. */ |
BFD_RELOC_32_BASEREL, |
BFD_RELOC_16_BASEREL, |
BFD_RELOC_LO16_BASEREL, |
BFD_RELOC_HI16_BASEREL, |
BFD_RELOC_HI16_S_BASEREL, |
BFD_RELOC_8_BASEREL, |
BFD_RELOC_RVA, |
/* Absolute 8-bit relocation, but used to form an address like 0xFFnn. */ |
BFD_RELOC_8_FFnn, |
/* These PC-relative relocations are stored as word displacements -- |
i.e., byte displacements shifted right two bits. The 30-bit word |
displacement (<<32_PCREL_S2>> -- 32 bits, shifted 2) is used on the |
SPARC. (SPARC tools generally refer to this as <<WDISP30>>.) The |
signed 16-bit displacement is used on the MIPS, and the 23-bit |
displacement is used on the Alpha. */ |
BFD_RELOC_32_PCREL_S2, |
BFD_RELOC_16_PCREL_S2, |
BFD_RELOC_23_PCREL_S2, |
/* High 22 bits and low 10 bits of 32-bit value, placed into lower bits of |
the target word. These are used on the SPARC. */ |
BFD_RELOC_HI22, |
BFD_RELOC_LO10, |
/* For systems that allocate a Global Pointer register, these are |
displacements off that register. These relocation types are |
handled specially, because the value the register will have is |
decided relatively late. */ |
BFD_RELOC_GPREL16, |
BFD_RELOC_GPREL32, |
/* Reloc types used for i960/b.out. */ |
BFD_RELOC_I960_CALLJ, |
/* SPARC ELF relocations. There is probably some overlap with other |
relocation types already defined. */ |
BFD_RELOC_NONE, |
BFD_RELOC_SPARC_WDISP22, |
BFD_RELOC_SPARC22, |
BFD_RELOC_SPARC13, |
BFD_RELOC_SPARC_GOT10, |
BFD_RELOC_SPARC_GOT13, |
BFD_RELOC_SPARC_GOT22, |
BFD_RELOC_SPARC_PC10, |
BFD_RELOC_SPARC_PC22, |
BFD_RELOC_SPARC_WPLT30, |
BFD_RELOC_SPARC_COPY, |
BFD_RELOC_SPARC_GLOB_DAT, |
BFD_RELOC_SPARC_JMP_SLOT, |
BFD_RELOC_SPARC_RELATIVE, |
BFD_RELOC_SPARC_UA16, |
BFD_RELOC_SPARC_UA32, |
BFD_RELOC_SPARC_UA64, |
BFD_RELOC_SPARC_GOTDATA_HIX22, |
BFD_RELOC_SPARC_GOTDATA_LOX10, |
BFD_RELOC_SPARC_GOTDATA_OP_HIX22, |
BFD_RELOC_SPARC_GOTDATA_OP_LOX10, |
BFD_RELOC_SPARC_GOTDATA_OP, |
BFD_RELOC_SPARC_JMP_IREL, |
BFD_RELOC_SPARC_IRELATIVE, |
/* I think these are specific to SPARC a.out (e.g., Sun 4). */ |
BFD_RELOC_SPARC_BASE13, |
BFD_RELOC_SPARC_BASE22, |
/* SPARC64 relocations */ |
#define BFD_RELOC_SPARC_64 BFD_RELOC_64 |
BFD_RELOC_SPARC_10, |
BFD_RELOC_SPARC_11, |
BFD_RELOC_SPARC_OLO10, |
BFD_RELOC_SPARC_HH22, |
BFD_RELOC_SPARC_HM10, |
BFD_RELOC_SPARC_LM22, |
BFD_RELOC_SPARC_PC_HH22, |
BFD_RELOC_SPARC_PC_HM10, |
BFD_RELOC_SPARC_PC_LM22, |
BFD_RELOC_SPARC_WDISP16, |
BFD_RELOC_SPARC_WDISP19, |
BFD_RELOC_SPARC_7, |
BFD_RELOC_SPARC_6, |
BFD_RELOC_SPARC_5, |
#define BFD_RELOC_SPARC_DISP64 BFD_RELOC_64_PCREL |
BFD_RELOC_SPARC_PLT32, |
BFD_RELOC_SPARC_PLT64, |
BFD_RELOC_SPARC_HIX22, |
BFD_RELOC_SPARC_LOX10, |
BFD_RELOC_SPARC_H44, |
BFD_RELOC_SPARC_M44, |
BFD_RELOC_SPARC_L44, |
BFD_RELOC_SPARC_REGISTER, |
BFD_RELOC_SPARC_H34, |
BFD_RELOC_SPARC_SIZE32, |
BFD_RELOC_SPARC_SIZE64, |
BFD_RELOC_SPARC_WDISP10, |
/* SPARC little endian relocation */ |
BFD_RELOC_SPARC_REV32, |
/* SPARC TLS relocations */ |
BFD_RELOC_SPARC_TLS_GD_HI22, |
BFD_RELOC_SPARC_TLS_GD_LO10, |
BFD_RELOC_SPARC_TLS_GD_ADD, |
BFD_RELOC_SPARC_TLS_GD_CALL, |
BFD_RELOC_SPARC_TLS_LDM_HI22, |
BFD_RELOC_SPARC_TLS_LDM_LO10, |
BFD_RELOC_SPARC_TLS_LDM_ADD, |
BFD_RELOC_SPARC_TLS_LDM_CALL, |
BFD_RELOC_SPARC_TLS_LDO_HIX22, |
BFD_RELOC_SPARC_TLS_LDO_LOX10, |
BFD_RELOC_SPARC_TLS_LDO_ADD, |
BFD_RELOC_SPARC_TLS_IE_HI22, |
BFD_RELOC_SPARC_TLS_IE_LO10, |
BFD_RELOC_SPARC_TLS_IE_LD, |
BFD_RELOC_SPARC_TLS_IE_LDX, |
BFD_RELOC_SPARC_TLS_IE_ADD, |
BFD_RELOC_SPARC_TLS_LE_HIX22, |
BFD_RELOC_SPARC_TLS_LE_LOX10, |
BFD_RELOC_SPARC_TLS_DTPMOD32, |
BFD_RELOC_SPARC_TLS_DTPMOD64, |
BFD_RELOC_SPARC_TLS_DTPOFF32, |
BFD_RELOC_SPARC_TLS_DTPOFF64, |
BFD_RELOC_SPARC_TLS_TPOFF32, |
BFD_RELOC_SPARC_TLS_TPOFF64, |
/* SPU Relocations. */ |
BFD_RELOC_SPU_IMM7, |
BFD_RELOC_SPU_IMM8, |
BFD_RELOC_SPU_IMM10, |
BFD_RELOC_SPU_IMM10W, |
BFD_RELOC_SPU_IMM16, |
BFD_RELOC_SPU_IMM16W, |
BFD_RELOC_SPU_IMM18, |
BFD_RELOC_SPU_PCREL9a, |
BFD_RELOC_SPU_PCREL9b, |
BFD_RELOC_SPU_PCREL16, |
BFD_RELOC_SPU_LO16, |
BFD_RELOC_SPU_HI16, |
BFD_RELOC_SPU_PPU32, |
BFD_RELOC_SPU_PPU64, |
BFD_RELOC_SPU_ADD_PIC, |
/* Alpha ECOFF and ELF relocations. Some of these treat the symbol or |
"addend" in some special way. |
For GPDISP_HI16 ("gpdisp") relocations, the symbol is ignored when |
writing; when reading, it will be the absolute section symbol. The |
addend is the displacement in bytes of the "lda" instruction from |
the "ldah" instruction (which is at the address of this reloc). */ |
BFD_RELOC_ALPHA_GPDISP_HI16, |
/* For GPDISP_LO16 ("ignore") relocations, the symbol is handled as |
with GPDISP_HI16 relocs. The addend is ignored when writing the |
relocations out, and is filled in with the file's GP value on |
reading, for convenience. */ |
BFD_RELOC_ALPHA_GPDISP_LO16, |
/* The ELF GPDISP relocation is exactly the same as the GPDISP_HI16 |
relocation except that there is no accompanying GPDISP_LO16 |
relocation. */ |
BFD_RELOC_ALPHA_GPDISP, |
/* The Alpha LITERAL/LITUSE relocs are produced by a symbol reference; |
the assembler turns it into a LDQ instruction to load the address of |
the symbol, and then fills in a register in the real instruction. |
The LITERAL reloc, at the LDQ instruction, refers to the .lita |
section symbol. The addend is ignored when writing, but is filled |
in with the file's GP value on reading, for convenience, as with the |
GPDISP_LO16 reloc. |
The ELF_LITERAL reloc is somewhere between 16_GOTOFF and GPDISP_LO16. |
It should refer to the symbol to be referenced, as with 16_GOTOFF, |
but it generates output not based on the position within the .got |
section, but relative to the GP value chosen for the file during the |
final link stage. |
The LITUSE reloc, on the instruction using the loaded address, gives |
information to the linker that it might be able to use to optimize |
away some literal section references. The symbol is ignored (read |
as the absolute section symbol), and the "addend" indicates the type |
of instruction using the register: |
1 - "memory" fmt insn |
2 - byte-manipulation (byte offset reg) |
3 - jsr (target of branch) */ |
BFD_RELOC_ALPHA_LITERAL, |
BFD_RELOC_ALPHA_ELF_LITERAL, |
BFD_RELOC_ALPHA_LITUSE, |
/* The HINT relocation indicates a value that should be filled into the |
"hint" field of a jmp/jsr/ret instruction, for possible branch- |
prediction logic which may be provided on some processors. */ |
BFD_RELOC_ALPHA_HINT, |
/* The LINKAGE relocation outputs a linkage pair in the object file, |
which is filled by the linker. */ |
BFD_RELOC_ALPHA_LINKAGE, |
/* The CODEADDR relocation outputs a STO_CA in the object file, |
which is filled by the linker. */ |
BFD_RELOC_ALPHA_CODEADDR, |
/* The GPREL_HI/LO relocations together form a 32-bit offset from the |
GP register. */ |
BFD_RELOC_ALPHA_GPREL_HI16, |
BFD_RELOC_ALPHA_GPREL_LO16, |
/* Like BFD_RELOC_23_PCREL_S2, except that the source and target must |
share a common GP, and the target address is adjusted for |
STO_ALPHA_STD_GPLOAD. */ |
BFD_RELOC_ALPHA_BRSGP, |
/* The NOP relocation outputs a NOP if the longword displacement |
between two procedure entry points is < 2^21. */ |
BFD_RELOC_ALPHA_NOP, |
/* The BSR relocation outputs a BSR if the longword displacement |
between two procedure entry points is < 2^21. */ |
BFD_RELOC_ALPHA_BSR, |
/* The LDA relocation outputs a LDA if the longword displacement |
between two procedure entry points is < 2^16. */ |
BFD_RELOC_ALPHA_LDA, |
/* The BOH relocation outputs a BSR if the longword displacement |
between two procedure entry points is < 2^21, or else a hint. */ |
BFD_RELOC_ALPHA_BOH, |
/* Alpha thread-local storage relocations. */ |
BFD_RELOC_ALPHA_TLSGD, |
BFD_RELOC_ALPHA_TLSLDM, |
BFD_RELOC_ALPHA_DTPMOD64, |
BFD_RELOC_ALPHA_GOTDTPREL16, |
BFD_RELOC_ALPHA_DTPREL64, |
BFD_RELOC_ALPHA_DTPREL_HI16, |
BFD_RELOC_ALPHA_DTPREL_LO16, |
BFD_RELOC_ALPHA_DTPREL16, |
BFD_RELOC_ALPHA_GOTTPREL16, |
BFD_RELOC_ALPHA_TPREL64, |
BFD_RELOC_ALPHA_TPREL_HI16, |
BFD_RELOC_ALPHA_TPREL_LO16, |
BFD_RELOC_ALPHA_TPREL16, |
/* The MIPS jump instruction. */ |
BFD_RELOC_MIPS_JMP, |
BFD_RELOC_MICROMIPS_JMP, |
/* The MIPS16 jump instruction. */ |
BFD_RELOC_MIPS16_JMP, |
/* MIPS16 GP relative reloc. */ |
BFD_RELOC_MIPS16_GPREL, |
/* High 16 bits of 32-bit value; simple reloc. */ |
BFD_RELOC_HI16, |
/* High 16 bits of 32-bit value but the low 16 bits will be sign |
extended and added to form the final result. If the low 16 |
bits form a negative number, we need to add one to the high value |
to compensate for the borrow when the low bits are added. */ |
BFD_RELOC_HI16_S, |
/* Low 16 bits. */ |
BFD_RELOC_LO16, |
/* High 16 bits of 32-bit pc-relative value */ |
BFD_RELOC_HI16_PCREL, |
/* High 16 bits of 32-bit pc-relative value, adjusted */ |
BFD_RELOC_HI16_S_PCREL, |
/* Low 16 bits of pc-relative value */ |
BFD_RELOC_LO16_PCREL, |
/* Equivalent of BFD_RELOC_MIPS_*, but with the MIPS16 layout of |
16-bit immediate fields */ |
BFD_RELOC_MIPS16_GOT16, |
BFD_RELOC_MIPS16_CALL16, |
/* MIPS16 high 16 bits of 32-bit value. */ |
BFD_RELOC_MIPS16_HI16, |
/* MIPS16 high 16 bits of 32-bit value but the low 16 bits will be sign |
extended and added to form the final result. If the low 16 |
bits form a negative number, we need to add one to the high value |
to compensate for the borrow when the low bits are added. */ |
BFD_RELOC_MIPS16_HI16_S, |
/* MIPS16 low 16 bits. */ |
BFD_RELOC_MIPS16_LO16, |
/* MIPS16 TLS relocations */ |
BFD_RELOC_MIPS16_TLS_GD, |
BFD_RELOC_MIPS16_TLS_LDM, |
BFD_RELOC_MIPS16_TLS_DTPREL_HI16, |
BFD_RELOC_MIPS16_TLS_DTPREL_LO16, |
BFD_RELOC_MIPS16_TLS_GOTTPREL, |
BFD_RELOC_MIPS16_TLS_TPREL_HI16, |
BFD_RELOC_MIPS16_TLS_TPREL_LO16, |
/* Relocation against a MIPS literal section. */ |
BFD_RELOC_MIPS_LITERAL, |
BFD_RELOC_MICROMIPS_LITERAL, |
/* microMIPS PC-relative relocations. */ |
BFD_RELOC_MICROMIPS_7_PCREL_S1, |
BFD_RELOC_MICROMIPS_10_PCREL_S1, |
BFD_RELOC_MICROMIPS_16_PCREL_S1, |
/* microMIPS versions of generic BFD relocs. */ |
BFD_RELOC_MICROMIPS_GPREL16, |
BFD_RELOC_MICROMIPS_HI16, |
BFD_RELOC_MICROMIPS_HI16_S, |
BFD_RELOC_MICROMIPS_LO16, |
/* MIPS ELF relocations. */ |
BFD_RELOC_MIPS_GOT16, |
BFD_RELOC_MICROMIPS_GOT16, |
BFD_RELOC_MIPS_CALL16, |
BFD_RELOC_MICROMIPS_CALL16, |
BFD_RELOC_MIPS_GOT_HI16, |
BFD_RELOC_MICROMIPS_GOT_HI16, |
BFD_RELOC_MIPS_GOT_LO16, |
BFD_RELOC_MICROMIPS_GOT_LO16, |
BFD_RELOC_MIPS_CALL_HI16, |
BFD_RELOC_MICROMIPS_CALL_HI16, |
BFD_RELOC_MIPS_CALL_LO16, |
BFD_RELOC_MICROMIPS_CALL_LO16, |
BFD_RELOC_MIPS_SUB, |
BFD_RELOC_MICROMIPS_SUB, |
BFD_RELOC_MIPS_GOT_PAGE, |
BFD_RELOC_MICROMIPS_GOT_PAGE, |
BFD_RELOC_MIPS_GOT_OFST, |
BFD_RELOC_MICROMIPS_GOT_OFST, |
BFD_RELOC_MIPS_GOT_DISP, |
BFD_RELOC_MICROMIPS_GOT_DISP, |
BFD_RELOC_MIPS_SHIFT5, |
BFD_RELOC_MIPS_SHIFT6, |
BFD_RELOC_MIPS_INSERT_A, |
BFD_RELOC_MIPS_INSERT_B, |
BFD_RELOC_MIPS_DELETE, |
BFD_RELOC_MIPS_HIGHEST, |
BFD_RELOC_MICROMIPS_HIGHEST, |
BFD_RELOC_MIPS_HIGHER, |
BFD_RELOC_MICROMIPS_HIGHER, |
BFD_RELOC_MIPS_SCN_DISP, |
BFD_RELOC_MICROMIPS_SCN_DISP, |
BFD_RELOC_MIPS_REL16, |
BFD_RELOC_MIPS_RELGOT, |
BFD_RELOC_MIPS_JALR, |
BFD_RELOC_MICROMIPS_JALR, |
BFD_RELOC_MIPS_TLS_DTPMOD32, |
BFD_RELOC_MIPS_TLS_DTPREL32, |
BFD_RELOC_MIPS_TLS_DTPMOD64, |
BFD_RELOC_MIPS_TLS_DTPREL64, |
BFD_RELOC_MIPS_TLS_GD, |
BFD_RELOC_MICROMIPS_TLS_GD, |
BFD_RELOC_MIPS_TLS_LDM, |
BFD_RELOC_MICROMIPS_TLS_LDM, |
BFD_RELOC_MIPS_TLS_DTPREL_HI16, |
BFD_RELOC_MICROMIPS_TLS_DTPREL_HI16, |
BFD_RELOC_MIPS_TLS_DTPREL_LO16, |
BFD_RELOC_MICROMIPS_TLS_DTPREL_LO16, |
BFD_RELOC_MIPS_TLS_GOTTPREL, |
BFD_RELOC_MICROMIPS_TLS_GOTTPREL, |
BFD_RELOC_MIPS_TLS_TPREL32, |
BFD_RELOC_MIPS_TLS_TPREL64, |
BFD_RELOC_MIPS_TLS_TPREL_HI16, |
BFD_RELOC_MICROMIPS_TLS_TPREL_HI16, |
BFD_RELOC_MIPS_TLS_TPREL_LO16, |
BFD_RELOC_MICROMIPS_TLS_TPREL_LO16, |
BFD_RELOC_MIPS_EH, |
/* MIPS ELF relocations (VxWorks and PLT extensions). */ |
BFD_RELOC_MIPS_COPY, |
BFD_RELOC_MIPS_JUMP_SLOT, |
/* Moxie ELF relocations. */ |
BFD_RELOC_MOXIE_10_PCREL, |
/* Fujitsu Frv Relocations. */ |
BFD_RELOC_FRV_LABEL16, |
BFD_RELOC_FRV_LABEL24, |
BFD_RELOC_FRV_LO16, |
BFD_RELOC_FRV_HI16, |
BFD_RELOC_FRV_GPREL12, |
BFD_RELOC_FRV_GPRELU12, |
BFD_RELOC_FRV_GPREL32, |
BFD_RELOC_FRV_GPRELHI, |
BFD_RELOC_FRV_GPRELLO, |
BFD_RELOC_FRV_GOT12, |
BFD_RELOC_FRV_GOTHI, |
BFD_RELOC_FRV_GOTLO, |
BFD_RELOC_FRV_FUNCDESC, |
BFD_RELOC_FRV_FUNCDESC_GOT12, |
BFD_RELOC_FRV_FUNCDESC_GOTHI, |
BFD_RELOC_FRV_FUNCDESC_GOTLO, |
BFD_RELOC_FRV_FUNCDESC_VALUE, |
BFD_RELOC_FRV_FUNCDESC_GOTOFF12, |
BFD_RELOC_FRV_FUNCDESC_GOTOFFHI, |
BFD_RELOC_FRV_FUNCDESC_GOTOFFLO, |
BFD_RELOC_FRV_GOTOFF12, |
BFD_RELOC_FRV_GOTOFFHI, |
BFD_RELOC_FRV_GOTOFFLO, |
BFD_RELOC_FRV_GETTLSOFF, |
BFD_RELOC_FRV_TLSDESC_VALUE, |
BFD_RELOC_FRV_GOTTLSDESC12, |
BFD_RELOC_FRV_GOTTLSDESCHI, |
BFD_RELOC_FRV_GOTTLSDESCLO, |
BFD_RELOC_FRV_TLSMOFF12, |
BFD_RELOC_FRV_TLSMOFFHI, |
BFD_RELOC_FRV_TLSMOFFLO, |
BFD_RELOC_FRV_GOTTLSOFF12, |
BFD_RELOC_FRV_GOTTLSOFFHI, |
BFD_RELOC_FRV_GOTTLSOFFLO, |
BFD_RELOC_FRV_TLSOFF, |
BFD_RELOC_FRV_TLSDESC_RELAX, |
BFD_RELOC_FRV_GETTLSOFF_RELAX, |
BFD_RELOC_FRV_TLSOFF_RELAX, |
BFD_RELOC_FRV_TLSMOFF, |
/* This is a 24bit GOT-relative reloc for the mn10300. */ |
BFD_RELOC_MN10300_GOTOFF24, |
/* This is a 32bit GOT-relative reloc for the mn10300, offset by two bytes |
in the instruction. */ |
BFD_RELOC_MN10300_GOT32, |
/* This is a 24bit GOT-relative reloc for the mn10300, offset by two bytes |
in the instruction. */ |
BFD_RELOC_MN10300_GOT24, |
/* This is a 16bit GOT-relative reloc for the mn10300, offset by two bytes |
in the instruction. */ |
BFD_RELOC_MN10300_GOT16, |
/* Copy symbol at runtime. */ |
BFD_RELOC_MN10300_COPY, |
/* Create GOT entry. */ |
BFD_RELOC_MN10300_GLOB_DAT, |
/* Create PLT entry. */ |
BFD_RELOC_MN10300_JMP_SLOT, |
/* Adjust by program base. */ |
BFD_RELOC_MN10300_RELATIVE, |
/* Together with another reloc targeted at the same location, |
allows for a value that is the difference of two symbols |
in the same section. */ |
BFD_RELOC_MN10300_SYM_DIFF, |
/* The addend of this reloc is an alignment power that must |
be honoured at the offset's location, regardless of linker |
relaxation. */ |
BFD_RELOC_MN10300_ALIGN, |
/* Various TLS-related relocations. */ |
BFD_RELOC_MN10300_TLS_GD, |
BFD_RELOC_MN10300_TLS_LD, |
BFD_RELOC_MN10300_TLS_LDO, |
BFD_RELOC_MN10300_TLS_GOTIE, |
BFD_RELOC_MN10300_TLS_IE, |
BFD_RELOC_MN10300_TLS_LE, |
BFD_RELOC_MN10300_TLS_DTPMOD, |
BFD_RELOC_MN10300_TLS_DTPOFF, |
BFD_RELOC_MN10300_TLS_TPOFF, |
/* This is a 32bit pcrel reloc for the mn10300, offset by two bytes in the |
instruction. */ |
BFD_RELOC_MN10300_32_PCREL, |
/* This is a 16bit pcrel reloc for the mn10300, offset by two bytes in the |
instruction. */ |
BFD_RELOC_MN10300_16_PCREL, |
/* i386/elf relocations */ |
BFD_RELOC_386_GOT32, |
BFD_RELOC_386_PLT32, |
BFD_RELOC_386_COPY, |
BFD_RELOC_386_GLOB_DAT, |
BFD_RELOC_386_JUMP_SLOT, |
BFD_RELOC_386_RELATIVE, |
BFD_RELOC_386_GOTOFF, |
BFD_RELOC_386_GOTPC, |
BFD_RELOC_386_TLS_TPOFF, |
BFD_RELOC_386_TLS_IE, |
BFD_RELOC_386_TLS_GOTIE, |
BFD_RELOC_386_TLS_LE, |
BFD_RELOC_386_TLS_GD, |
BFD_RELOC_386_TLS_LDM, |
BFD_RELOC_386_TLS_LDO_32, |
BFD_RELOC_386_TLS_IE_32, |
BFD_RELOC_386_TLS_LE_32, |
BFD_RELOC_386_TLS_DTPMOD32, |
BFD_RELOC_386_TLS_DTPOFF32, |
BFD_RELOC_386_TLS_TPOFF32, |
BFD_RELOC_386_TLS_GOTDESC, |
BFD_RELOC_386_TLS_DESC_CALL, |
BFD_RELOC_386_TLS_DESC, |
BFD_RELOC_386_IRELATIVE, |
/* x86-64/elf relocations */ |
BFD_RELOC_X86_64_GOT32, |
BFD_RELOC_X86_64_PLT32, |
BFD_RELOC_X86_64_COPY, |
BFD_RELOC_X86_64_GLOB_DAT, |
BFD_RELOC_X86_64_JUMP_SLOT, |
BFD_RELOC_X86_64_RELATIVE, |
BFD_RELOC_X86_64_GOTPCREL, |
BFD_RELOC_X86_64_32S, |
BFD_RELOC_X86_64_DTPMOD64, |
BFD_RELOC_X86_64_DTPOFF64, |
BFD_RELOC_X86_64_TPOFF64, |
BFD_RELOC_X86_64_TLSGD, |
BFD_RELOC_X86_64_TLSLD, |
BFD_RELOC_X86_64_DTPOFF32, |
BFD_RELOC_X86_64_GOTTPOFF, |
BFD_RELOC_X86_64_TPOFF32, |
BFD_RELOC_X86_64_GOTOFF64, |
BFD_RELOC_X86_64_GOTPC32, |
BFD_RELOC_X86_64_GOT64, |
BFD_RELOC_X86_64_GOTPCREL64, |
BFD_RELOC_X86_64_GOTPC64, |
BFD_RELOC_X86_64_GOTPLT64, |
BFD_RELOC_X86_64_PLTOFF64, |
BFD_RELOC_X86_64_GOTPC32_TLSDESC, |
BFD_RELOC_X86_64_TLSDESC_CALL, |
BFD_RELOC_X86_64_TLSDESC, |
BFD_RELOC_X86_64_IRELATIVE, |
BFD_RELOC_X86_64_PC32_BND, |
BFD_RELOC_X86_64_PLT32_BND, |
/* ns32k relocations */ |
BFD_RELOC_NS32K_IMM_8, |
BFD_RELOC_NS32K_IMM_16, |
BFD_RELOC_NS32K_IMM_32, |
BFD_RELOC_NS32K_IMM_8_PCREL, |
BFD_RELOC_NS32K_IMM_16_PCREL, |
BFD_RELOC_NS32K_IMM_32_PCREL, |
BFD_RELOC_NS32K_DISP_8, |
BFD_RELOC_NS32K_DISP_16, |
BFD_RELOC_NS32K_DISP_32, |
BFD_RELOC_NS32K_DISP_8_PCREL, |
BFD_RELOC_NS32K_DISP_16_PCREL, |
BFD_RELOC_NS32K_DISP_32_PCREL, |
/* PDP11 relocations */ |
BFD_RELOC_PDP11_DISP_8_PCREL, |
BFD_RELOC_PDP11_DISP_6_PCREL, |
/* Picojava relocs. Not all of these appear in object files. */ |
BFD_RELOC_PJ_CODE_HI16, |
BFD_RELOC_PJ_CODE_LO16, |
BFD_RELOC_PJ_CODE_DIR16, |
BFD_RELOC_PJ_CODE_DIR32, |
BFD_RELOC_PJ_CODE_REL16, |
BFD_RELOC_PJ_CODE_REL32, |
/* Power(rs6000) and PowerPC relocations. */ |
BFD_RELOC_PPC_B26, |
BFD_RELOC_PPC_BA26, |
BFD_RELOC_PPC_TOC16, |
BFD_RELOC_PPC_B16, |
BFD_RELOC_PPC_B16_BRTAKEN, |
BFD_RELOC_PPC_B16_BRNTAKEN, |
BFD_RELOC_PPC_BA16, |
BFD_RELOC_PPC_BA16_BRTAKEN, |
BFD_RELOC_PPC_BA16_BRNTAKEN, |
BFD_RELOC_PPC_COPY, |
BFD_RELOC_PPC_GLOB_DAT, |
BFD_RELOC_PPC_JMP_SLOT, |
BFD_RELOC_PPC_RELATIVE, |
BFD_RELOC_PPC_LOCAL24PC, |
BFD_RELOC_PPC_EMB_NADDR32, |
BFD_RELOC_PPC_EMB_NADDR16, |
BFD_RELOC_PPC_EMB_NADDR16_LO, |
BFD_RELOC_PPC_EMB_NADDR16_HI, |
BFD_RELOC_PPC_EMB_NADDR16_HA, |
BFD_RELOC_PPC_EMB_SDAI16, |
BFD_RELOC_PPC_EMB_SDA2I16, |
BFD_RELOC_PPC_EMB_SDA2REL, |
BFD_RELOC_PPC_EMB_SDA21, |
BFD_RELOC_PPC_EMB_MRKREF, |
BFD_RELOC_PPC_EMB_RELSEC16, |
BFD_RELOC_PPC_EMB_RELST_LO, |
BFD_RELOC_PPC_EMB_RELST_HI, |
BFD_RELOC_PPC_EMB_RELST_HA, |
BFD_RELOC_PPC_EMB_BIT_FLD, |
BFD_RELOC_PPC_EMB_RELSDA, |
BFD_RELOC_PPC_VLE_REL8, |
BFD_RELOC_PPC_VLE_REL15, |
BFD_RELOC_PPC_VLE_REL24, |
BFD_RELOC_PPC_VLE_LO16A, |
BFD_RELOC_PPC_VLE_LO16D, |
BFD_RELOC_PPC_VLE_HI16A, |
BFD_RELOC_PPC_VLE_HI16D, |
BFD_RELOC_PPC_VLE_HA16A, |
BFD_RELOC_PPC_VLE_HA16D, |
BFD_RELOC_PPC_VLE_SDA21, |
BFD_RELOC_PPC_VLE_SDA21_LO, |
BFD_RELOC_PPC_VLE_SDAREL_LO16A, |
BFD_RELOC_PPC_VLE_SDAREL_LO16D, |
BFD_RELOC_PPC_VLE_SDAREL_HI16A, |
BFD_RELOC_PPC_VLE_SDAREL_HI16D, |
BFD_RELOC_PPC_VLE_SDAREL_HA16A, |
BFD_RELOC_PPC_VLE_SDAREL_HA16D, |
BFD_RELOC_PPC64_HIGHER, |
BFD_RELOC_PPC64_HIGHER_S, |
BFD_RELOC_PPC64_HIGHEST, |
BFD_RELOC_PPC64_HIGHEST_S, |
BFD_RELOC_PPC64_TOC16_LO, |
BFD_RELOC_PPC64_TOC16_HI, |
BFD_RELOC_PPC64_TOC16_HA, |
BFD_RELOC_PPC64_TOC, |
BFD_RELOC_PPC64_PLTGOT16, |
BFD_RELOC_PPC64_PLTGOT16_LO, |
BFD_RELOC_PPC64_PLTGOT16_HI, |
BFD_RELOC_PPC64_PLTGOT16_HA, |
BFD_RELOC_PPC64_ADDR16_DS, |
BFD_RELOC_PPC64_ADDR16_LO_DS, |
BFD_RELOC_PPC64_GOT16_DS, |
BFD_RELOC_PPC64_GOT16_LO_DS, |
BFD_RELOC_PPC64_PLT16_LO_DS, |
BFD_RELOC_PPC64_SECTOFF_DS, |
BFD_RELOC_PPC64_SECTOFF_LO_DS, |
BFD_RELOC_PPC64_TOC16_DS, |
BFD_RELOC_PPC64_TOC16_LO_DS, |
BFD_RELOC_PPC64_PLTGOT16_DS, |
BFD_RELOC_PPC64_PLTGOT16_LO_DS, |
BFD_RELOC_PPC64_ADDR16_HIGH, |
BFD_RELOC_PPC64_ADDR16_HIGHA, |
/* PowerPC and PowerPC64 thread-local storage relocations. */ |
BFD_RELOC_PPC_TLS, |
BFD_RELOC_PPC_TLSGD, |
BFD_RELOC_PPC_TLSLD, |
BFD_RELOC_PPC_DTPMOD, |
BFD_RELOC_PPC_TPREL16, |
BFD_RELOC_PPC_TPREL16_LO, |
BFD_RELOC_PPC_TPREL16_HI, |
BFD_RELOC_PPC_TPREL16_HA, |
BFD_RELOC_PPC_TPREL, |
BFD_RELOC_PPC_DTPREL16, |
BFD_RELOC_PPC_DTPREL16_LO, |
BFD_RELOC_PPC_DTPREL16_HI, |
BFD_RELOC_PPC_DTPREL16_HA, |
BFD_RELOC_PPC_DTPREL, |
BFD_RELOC_PPC_GOT_TLSGD16, |
BFD_RELOC_PPC_GOT_TLSGD16_LO, |
BFD_RELOC_PPC_GOT_TLSGD16_HI, |
BFD_RELOC_PPC_GOT_TLSGD16_HA, |
BFD_RELOC_PPC_GOT_TLSLD16, |
BFD_RELOC_PPC_GOT_TLSLD16_LO, |
BFD_RELOC_PPC_GOT_TLSLD16_HI, |
BFD_RELOC_PPC_GOT_TLSLD16_HA, |
BFD_RELOC_PPC_GOT_TPREL16, |
BFD_RELOC_PPC_GOT_TPREL16_LO, |
BFD_RELOC_PPC_GOT_TPREL16_HI, |
BFD_RELOC_PPC_GOT_TPREL16_HA, |
BFD_RELOC_PPC_GOT_DTPREL16, |
BFD_RELOC_PPC_GOT_DTPREL16_LO, |
BFD_RELOC_PPC_GOT_DTPREL16_HI, |
BFD_RELOC_PPC_GOT_DTPREL16_HA, |
BFD_RELOC_PPC64_TPREL16_DS, |
BFD_RELOC_PPC64_TPREL16_LO_DS, |
BFD_RELOC_PPC64_TPREL16_HIGHER, |
BFD_RELOC_PPC64_TPREL16_HIGHERA, |
BFD_RELOC_PPC64_TPREL16_HIGHEST, |
BFD_RELOC_PPC64_TPREL16_HIGHESTA, |
BFD_RELOC_PPC64_DTPREL16_DS, |
BFD_RELOC_PPC64_DTPREL16_LO_DS, |
BFD_RELOC_PPC64_DTPREL16_HIGHER, |
BFD_RELOC_PPC64_DTPREL16_HIGHERA, |
BFD_RELOC_PPC64_DTPREL16_HIGHEST, |
BFD_RELOC_PPC64_DTPREL16_HIGHESTA, |
BFD_RELOC_PPC64_TPREL16_HIGH, |
BFD_RELOC_PPC64_TPREL16_HIGHA, |
BFD_RELOC_PPC64_DTPREL16_HIGH, |
BFD_RELOC_PPC64_DTPREL16_HIGHA, |
/* IBM 370/390 relocations */ |
BFD_RELOC_I370_D12, |
/* The type of reloc used to build a constructor table - at the moment |
probably a 32 bit wide absolute relocation, but the target can choose. |
It generally does map to one of the other relocation types. */ |
BFD_RELOC_CTOR, |
/* ARM 26 bit pc-relative branch. The lowest two bits must be zero and are |
not stored in the instruction. */ |
BFD_RELOC_ARM_PCREL_BRANCH, |
/* ARM 26 bit pc-relative branch. The lowest bit must be zero and is |
not stored in the instruction. The 2nd lowest bit comes from a 1 bit |
field in the instruction. */ |
BFD_RELOC_ARM_PCREL_BLX, |
/* Thumb 22 bit pc-relative branch. The lowest bit must be zero and is |
not stored in the instruction. The 2nd lowest bit comes from a 1 bit |
field in the instruction. */ |
BFD_RELOC_THUMB_PCREL_BLX, |
/* ARM 26-bit pc-relative branch for an unconditional BL or BLX instruction. */ |
BFD_RELOC_ARM_PCREL_CALL, |
/* ARM 26-bit pc-relative branch for B or conditional BL instruction. */ |
BFD_RELOC_ARM_PCREL_JUMP, |
/* Thumb 7-, 9-, 12-, 20-, 23-, and 25-bit pc-relative branches. |
The lowest bit must be zero and is not stored in the instruction. |
Note that the corresponding ELF R_ARM_THM_JUMPnn constant has an |
"nn" one smaller in all cases. Note further that BRANCH23 |
corresponds to R_ARM_THM_CALL. */ |
BFD_RELOC_THUMB_PCREL_BRANCH7, |
BFD_RELOC_THUMB_PCREL_BRANCH9, |
BFD_RELOC_THUMB_PCREL_BRANCH12, |
BFD_RELOC_THUMB_PCREL_BRANCH20, |
BFD_RELOC_THUMB_PCREL_BRANCH23, |
BFD_RELOC_THUMB_PCREL_BRANCH25, |
/* 12-bit immediate offset, used in ARM-format ldr and str instructions. */ |
BFD_RELOC_ARM_OFFSET_IMM, |
/* 5-bit immediate offset, used in Thumb-format ldr and str instructions. */ |
BFD_RELOC_ARM_THUMB_OFFSET, |
/* Pc-relative or absolute relocation depending on target. Used for |
entries in .init_array sections. */ |
BFD_RELOC_ARM_TARGET1, |
/* Read-only segment base relative address. */ |
BFD_RELOC_ARM_ROSEGREL32, |
/* Data segment base relative address. */ |
BFD_RELOC_ARM_SBREL32, |
/* This reloc is used for references to RTTI data from exception handling |
tables. The actual definition depends on the target. It may be a |
pc-relative or some form of GOT-indirect relocation. */ |
BFD_RELOC_ARM_TARGET2, |
/* 31-bit PC relative address. */ |
BFD_RELOC_ARM_PREL31, |
/* Low and High halfword relocations for MOVW and MOVT instructions. */ |
BFD_RELOC_ARM_MOVW, |
BFD_RELOC_ARM_MOVT, |
BFD_RELOC_ARM_MOVW_PCREL, |
BFD_RELOC_ARM_MOVT_PCREL, |
BFD_RELOC_ARM_THUMB_MOVW, |
BFD_RELOC_ARM_THUMB_MOVT, |
BFD_RELOC_ARM_THUMB_MOVW_PCREL, |
BFD_RELOC_ARM_THUMB_MOVT_PCREL, |
/* Relocations for setting up GOTs and PLTs for shared libraries. */ |
BFD_RELOC_ARM_JUMP_SLOT, |
BFD_RELOC_ARM_GLOB_DAT, |
BFD_RELOC_ARM_GOT32, |
BFD_RELOC_ARM_PLT32, |
BFD_RELOC_ARM_RELATIVE, |
BFD_RELOC_ARM_GOTOFF, |
BFD_RELOC_ARM_GOTPC, |
BFD_RELOC_ARM_GOT_PREL, |
/* ARM thread-local storage relocations. */ |
BFD_RELOC_ARM_TLS_GD32, |
BFD_RELOC_ARM_TLS_LDO32, |
BFD_RELOC_ARM_TLS_LDM32, |
BFD_RELOC_ARM_TLS_DTPOFF32, |
BFD_RELOC_ARM_TLS_DTPMOD32, |
BFD_RELOC_ARM_TLS_TPOFF32, |
BFD_RELOC_ARM_TLS_IE32, |
BFD_RELOC_ARM_TLS_LE32, |
BFD_RELOC_ARM_TLS_GOTDESC, |
BFD_RELOC_ARM_TLS_CALL, |
BFD_RELOC_ARM_THM_TLS_CALL, |
BFD_RELOC_ARM_TLS_DESCSEQ, |
BFD_RELOC_ARM_THM_TLS_DESCSEQ, |
BFD_RELOC_ARM_TLS_DESC, |
/* ARM group relocations. */ |
BFD_RELOC_ARM_ALU_PC_G0_NC, |
BFD_RELOC_ARM_ALU_PC_G0, |
BFD_RELOC_ARM_ALU_PC_G1_NC, |
BFD_RELOC_ARM_ALU_PC_G1, |
BFD_RELOC_ARM_ALU_PC_G2, |
BFD_RELOC_ARM_LDR_PC_G0, |
BFD_RELOC_ARM_LDR_PC_G1, |
BFD_RELOC_ARM_LDR_PC_G2, |
BFD_RELOC_ARM_LDRS_PC_G0, |
BFD_RELOC_ARM_LDRS_PC_G1, |
BFD_RELOC_ARM_LDRS_PC_G2, |
BFD_RELOC_ARM_LDC_PC_G0, |
BFD_RELOC_ARM_LDC_PC_G1, |
BFD_RELOC_ARM_LDC_PC_G2, |
BFD_RELOC_ARM_ALU_SB_G0_NC, |
BFD_RELOC_ARM_ALU_SB_G0, |
BFD_RELOC_ARM_ALU_SB_G1_NC, |
BFD_RELOC_ARM_ALU_SB_G1, |
BFD_RELOC_ARM_ALU_SB_G2, |
BFD_RELOC_ARM_LDR_SB_G0, |
BFD_RELOC_ARM_LDR_SB_G1, |
BFD_RELOC_ARM_LDR_SB_G2, |
BFD_RELOC_ARM_LDRS_SB_G0, |
BFD_RELOC_ARM_LDRS_SB_G1, |
BFD_RELOC_ARM_LDRS_SB_G2, |
BFD_RELOC_ARM_LDC_SB_G0, |
BFD_RELOC_ARM_LDC_SB_G1, |
BFD_RELOC_ARM_LDC_SB_G2, |
/* Annotation of BX instructions. */ |
BFD_RELOC_ARM_V4BX, |
/* ARM support for STT_GNU_IFUNC. */ |
BFD_RELOC_ARM_IRELATIVE, |
/* These relocs are only used within the ARM assembler. They are not |
(at present) written to any object files. */ |
BFD_RELOC_ARM_IMMEDIATE, |
BFD_RELOC_ARM_ADRL_IMMEDIATE, |
BFD_RELOC_ARM_T32_IMMEDIATE, |
BFD_RELOC_ARM_T32_ADD_IMM, |
BFD_RELOC_ARM_T32_IMM12, |
BFD_RELOC_ARM_T32_ADD_PC12, |
BFD_RELOC_ARM_SHIFT_IMM, |
BFD_RELOC_ARM_SMC, |
BFD_RELOC_ARM_HVC, |
BFD_RELOC_ARM_SWI, |
BFD_RELOC_ARM_MULTI, |
BFD_RELOC_ARM_CP_OFF_IMM, |
BFD_RELOC_ARM_CP_OFF_IMM_S2, |
BFD_RELOC_ARM_T32_CP_OFF_IMM, |
BFD_RELOC_ARM_T32_CP_OFF_IMM_S2, |
BFD_RELOC_ARM_ADR_IMM, |
BFD_RELOC_ARM_LDR_IMM, |
BFD_RELOC_ARM_LITERAL, |
BFD_RELOC_ARM_IN_POOL, |
BFD_RELOC_ARM_OFFSET_IMM8, |
BFD_RELOC_ARM_T32_OFFSET_U8, |
BFD_RELOC_ARM_T32_OFFSET_IMM, |
BFD_RELOC_ARM_HWLITERAL, |
BFD_RELOC_ARM_THUMB_ADD, |
BFD_RELOC_ARM_THUMB_IMM, |
BFD_RELOC_ARM_THUMB_SHIFT, |
/* Renesas / SuperH SH relocs. Not all of these appear in object files. */ |
BFD_RELOC_SH_PCDISP8BY2, |
BFD_RELOC_SH_PCDISP12BY2, |
BFD_RELOC_SH_IMM3, |
BFD_RELOC_SH_IMM3U, |
BFD_RELOC_SH_DISP12, |
BFD_RELOC_SH_DISP12BY2, |
BFD_RELOC_SH_DISP12BY4, |
BFD_RELOC_SH_DISP12BY8, |
BFD_RELOC_SH_DISP20, |
BFD_RELOC_SH_DISP20BY8, |
BFD_RELOC_SH_IMM4, |
BFD_RELOC_SH_IMM4BY2, |
BFD_RELOC_SH_IMM4BY4, |
BFD_RELOC_SH_IMM8, |
BFD_RELOC_SH_IMM8BY2, |
BFD_RELOC_SH_IMM8BY4, |
BFD_RELOC_SH_PCRELIMM8BY2, |
BFD_RELOC_SH_PCRELIMM8BY4, |
BFD_RELOC_SH_SWITCH16, |
BFD_RELOC_SH_SWITCH32, |
BFD_RELOC_SH_USES, |
BFD_RELOC_SH_COUNT, |
BFD_RELOC_SH_ALIGN, |
BFD_RELOC_SH_CODE, |
BFD_RELOC_SH_DATA, |
BFD_RELOC_SH_LABEL, |
BFD_RELOC_SH_LOOP_START, |
BFD_RELOC_SH_LOOP_END, |
BFD_RELOC_SH_COPY, |
BFD_RELOC_SH_GLOB_DAT, |
BFD_RELOC_SH_JMP_SLOT, |
BFD_RELOC_SH_RELATIVE, |
BFD_RELOC_SH_GOTPC, |
BFD_RELOC_SH_GOT_LOW16, |
BFD_RELOC_SH_GOT_MEDLOW16, |
BFD_RELOC_SH_GOT_MEDHI16, |
BFD_RELOC_SH_GOT_HI16, |
BFD_RELOC_SH_GOTPLT_LOW16, |
BFD_RELOC_SH_GOTPLT_MEDLOW16, |
BFD_RELOC_SH_GOTPLT_MEDHI16, |
BFD_RELOC_SH_GOTPLT_HI16, |
BFD_RELOC_SH_PLT_LOW16, |
BFD_RELOC_SH_PLT_MEDLOW16, |
BFD_RELOC_SH_PLT_MEDHI16, |
BFD_RELOC_SH_PLT_HI16, |
BFD_RELOC_SH_GOTOFF_LOW16, |
BFD_RELOC_SH_GOTOFF_MEDLOW16, |
BFD_RELOC_SH_GOTOFF_MEDHI16, |
BFD_RELOC_SH_GOTOFF_HI16, |
BFD_RELOC_SH_GOTPC_LOW16, |
BFD_RELOC_SH_GOTPC_MEDLOW16, |
BFD_RELOC_SH_GOTPC_MEDHI16, |
BFD_RELOC_SH_GOTPC_HI16, |
BFD_RELOC_SH_COPY64, |
BFD_RELOC_SH_GLOB_DAT64, |
BFD_RELOC_SH_JMP_SLOT64, |
BFD_RELOC_SH_RELATIVE64, |
BFD_RELOC_SH_GOT10BY4, |
BFD_RELOC_SH_GOT10BY8, |
BFD_RELOC_SH_GOTPLT10BY4, |
BFD_RELOC_SH_GOTPLT10BY8, |
BFD_RELOC_SH_GOTPLT32, |
BFD_RELOC_SH_SHMEDIA_CODE, |
BFD_RELOC_SH_IMMU5, |
BFD_RELOC_SH_IMMS6, |
BFD_RELOC_SH_IMMS6BY32, |
BFD_RELOC_SH_IMMU6, |
BFD_RELOC_SH_IMMS10, |
BFD_RELOC_SH_IMMS10BY2, |
BFD_RELOC_SH_IMMS10BY4, |
BFD_RELOC_SH_IMMS10BY8, |
BFD_RELOC_SH_IMMS16, |
BFD_RELOC_SH_IMMU16, |
BFD_RELOC_SH_IMM_LOW16, |
BFD_RELOC_SH_IMM_LOW16_PCREL, |
BFD_RELOC_SH_IMM_MEDLOW16, |
BFD_RELOC_SH_IMM_MEDLOW16_PCREL, |
BFD_RELOC_SH_IMM_MEDHI16, |
BFD_RELOC_SH_IMM_MEDHI16_PCREL, |
BFD_RELOC_SH_IMM_HI16, |
BFD_RELOC_SH_IMM_HI16_PCREL, |
BFD_RELOC_SH_PT_16, |
BFD_RELOC_SH_TLS_GD_32, |
BFD_RELOC_SH_TLS_LD_32, |
BFD_RELOC_SH_TLS_LDO_32, |
BFD_RELOC_SH_TLS_IE_32, |
BFD_RELOC_SH_TLS_LE_32, |
BFD_RELOC_SH_TLS_DTPMOD32, |
BFD_RELOC_SH_TLS_DTPOFF32, |
BFD_RELOC_SH_TLS_TPOFF32, |
BFD_RELOC_SH_GOT20, |
BFD_RELOC_SH_GOTOFF20, |
BFD_RELOC_SH_GOTFUNCDESC, |
BFD_RELOC_SH_GOTFUNCDESC20, |
BFD_RELOC_SH_GOTOFFFUNCDESC, |
BFD_RELOC_SH_GOTOFFFUNCDESC20, |
BFD_RELOC_SH_FUNCDESC, |
/* ARC Cores relocs. |
ARC 22 bit pc-relative branch. The lowest two bits must be zero and are |
not stored in the instruction. The high 20 bits are installed in bits 26 |
through 7 of the instruction. */ |
BFD_RELOC_ARC_B22_PCREL, |
/* ARC 26 bit absolute branch. The lowest two bits must be zero and are not |
stored in the instruction. The high 24 bits are installed in bits 23 |
through 0. */ |
BFD_RELOC_ARC_B26, |
/* ADI Blackfin 16 bit immediate absolute reloc. */ |
BFD_RELOC_BFIN_16_IMM, |
/* ADI Blackfin 16 bit immediate absolute reloc higher 16 bits. */ |
BFD_RELOC_BFIN_16_HIGH, |
/* ADI Blackfin 'a' part of LSETUP. */ |
BFD_RELOC_BFIN_4_PCREL, |
/* ADI Blackfin. */ |
BFD_RELOC_BFIN_5_PCREL, |
/* ADI Blackfin 16 bit immediate absolute reloc lower 16 bits. */ |
BFD_RELOC_BFIN_16_LOW, |
/* ADI Blackfin. */ |
BFD_RELOC_BFIN_10_PCREL, |
/* ADI Blackfin 'b' part of LSETUP. */ |
BFD_RELOC_BFIN_11_PCREL, |
/* ADI Blackfin. */ |
BFD_RELOC_BFIN_12_PCREL_JUMP, |
/* ADI Blackfin Short jump, pcrel. */ |
BFD_RELOC_BFIN_12_PCREL_JUMP_S, |
/* ADI Blackfin Call.x not implemented. */ |
BFD_RELOC_BFIN_24_PCREL_CALL_X, |
/* ADI Blackfin Long Jump pcrel. */ |
BFD_RELOC_BFIN_24_PCREL_JUMP_L, |
/* ADI Blackfin FD-PIC relocations. */ |
BFD_RELOC_BFIN_GOT17M4, |
BFD_RELOC_BFIN_GOTHI, |
BFD_RELOC_BFIN_GOTLO, |
BFD_RELOC_BFIN_FUNCDESC, |
BFD_RELOC_BFIN_FUNCDESC_GOT17M4, |
BFD_RELOC_BFIN_FUNCDESC_GOTHI, |
BFD_RELOC_BFIN_FUNCDESC_GOTLO, |
BFD_RELOC_BFIN_FUNCDESC_VALUE, |
BFD_RELOC_BFIN_FUNCDESC_GOTOFF17M4, |
BFD_RELOC_BFIN_FUNCDESC_GOTOFFHI, |
BFD_RELOC_BFIN_FUNCDESC_GOTOFFLO, |
BFD_RELOC_BFIN_GOTOFF17M4, |
BFD_RELOC_BFIN_GOTOFFHI, |
BFD_RELOC_BFIN_GOTOFFLO, |
/* ADI Blackfin GOT relocation. */ |
BFD_RELOC_BFIN_GOT, |
/* ADI Blackfin PLTPC relocation. */ |
BFD_RELOC_BFIN_PLTPC, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_PUSH, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_CONST, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_ADD, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_SUB, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_MULT, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_DIV, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_MOD, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_LSHIFT, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_RSHIFT, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_AND, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_OR, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_XOR, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_LAND, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_LOR, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_LEN, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_NEG, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_COMP, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_PAGE, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_HWPAGE, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_ADDR, |
/* Mitsubishi D10V relocs. |
This is a 10-bit reloc with the right 2 bits |
assumed to be 0. */ |
BFD_RELOC_D10V_10_PCREL_R, |
/* Mitsubishi D10V relocs. |
This is a 10-bit reloc with the right 2 bits |
assumed to be 0. This is the same as the previous reloc |
except it is in the left container, i.e., |
shifted left 15 bits. */ |
BFD_RELOC_D10V_10_PCREL_L, |
/* This is an 18-bit reloc with the right 2 bits |
assumed to be 0. */ |
BFD_RELOC_D10V_18, |
/* This is an 18-bit reloc with the right 2 bits |
assumed to be 0. */ |
BFD_RELOC_D10V_18_PCREL, |
/* Mitsubishi D30V relocs. |
This is a 6-bit absolute reloc. */ |
BFD_RELOC_D30V_6, |
/* This is a 6-bit pc-relative reloc with |
the right 3 bits assumed to be 0. */ |
BFD_RELOC_D30V_9_PCREL, |
/* This is a 6-bit pc-relative reloc with |
the right 3 bits assumed to be 0. Same |
as the previous reloc but on the right side |
of the container. */ |
BFD_RELOC_D30V_9_PCREL_R, |
/* This is a 12-bit absolute reloc with the |
right 3 bitsassumed to be 0. */ |
BFD_RELOC_D30V_15, |
/* This is a 12-bit pc-relative reloc with |
the right 3 bits assumed to be 0. */ |
BFD_RELOC_D30V_15_PCREL, |
/* This is a 12-bit pc-relative reloc with |
the right 3 bits assumed to be 0. Same |
as the previous reloc but on the right side |
of the container. */ |
BFD_RELOC_D30V_15_PCREL_R, |
/* This is an 18-bit absolute reloc with |
the right 3 bits assumed to be 0. */ |
BFD_RELOC_D30V_21, |
/* This is an 18-bit pc-relative reloc with |
the right 3 bits assumed to be 0. */ |
BFD_RELOC_D30V_21_PCREL, |
/* This is an 18-bit pc-relative reloc with |
the right 3 bits assumed to be 0. Same |
as the previous reloc but on the right side |
of the container. */ |
BFD_RELOC_D30V_21_PCREL_R, |
/* This is a 32-bit absolute reloc. */ |
BFD_RELOC_D30V_32, |
/* This is a 32-bit pc-relative reloc. */ |
BFD_RELOC_D30V_32_PCREL, |
/* DLX relocs */ |
BFD_RELOC_DLX_HI16_S, |
/* DLX relocs */ |
BFD_RELOC_DLX_LO16, |
/* DLX relocs */ |
BFD_RELOC_DLX_JMP26, |
/* Renesas M16C/M32C Relocations. */ |
BFD_RELOC_M32C_HI8, |
BFD_RELOC_M32C_RL_JUMP, |
BFD_RELOC_M32C_RL_1ADDR, |
BFD_RELOC_M32C_RL_2ADDR, |
/* Renesas M32R (formerly Mitsubishi M32R) relocs. |
This is a 24 bit absolute address. */ |
BFD_RELOC_M32R_24, |
/* This is a 10-bit pc-relative reloc with the right 2 bits assumed to be 0. */ |
BFD_RELOC_M32R_10_PCREL, |
/* This is an 18-bit reloc with the right 2 bits assumed to be 0. */ |
BFD_RELOC_M32R_18_PCREL, |
/* This is a 26-bit reloc with the right 2 bits assumed to be 0. */ |
BFD_RELOC_M32R_26_PCREL, |
/* This is a 16-bit reloc containing the high 16 bits of an address |
used when the lower 16 bits are treated as unsigned. */ |
BFD_RELOC_M32R_HI16_ULO, |
/* This is a 16-bit reloc containing the high 16 bits of an address |
used when the lower 16 bits are treated as signed. */ |
BFD_RELOC_M32R_HI16_SLO, |
/* This is a 16-bit reloc containing the lower 16 bits of an address. */ |
BFD_RELOC_M32R_LO16, |
/* This is a 16-bit reloc containing the small data area offset for use in |
add3, load, and store instructions. */ |
BFD_RELOC_M32R_SDA16, |
/* For PIC. */ |
BFD_RELOC_M32R_GOT24, |
BFD_RELOC_M32R_26_PLTREL, |
BFD_RELOC_M32R_COPY, |
BFD_RELOC_M32R_GLOB_DAT, |
BFD_RELOC_M32R_JMP_SLOT, |
BFD_RELOC_M32R_RELATIVE, |
BFD_RELOC_M32R_GOTOFF, |
BFD_RELOC_M32R_GOTOFF_HI_ULO, |
BFD_RELOC_M32R_GOTOFF_HI_SLO, |
BFD_RELOC_M32R_GOTOFF_LO, |
BFD_RELOC_M32R_GOTPC24, |
BFD_RELOC_M32R_GOT16_HI_ULO, |
BFD_RELOC_M32R_GOT16_HI_SLO, |
BFD_RELOC_M32R_GOT16_LO, |
BFD_RELOC_M32R_GOTPC_HI_ULO, |
BFD_RELOC_M32R_GOTPC_HI_SLO, |
BFD_RELOC_M32R_GOTPC_LO, |
/* This is a 9-bit reloc */ |
BFD_RELOC_V850_9_PCREL, |
/* This is a 22-bit reloc */ |
BFD_RELOC_V850_22_PCREL, |
/* This is a 16 bit offset from the short data area pointer. */ |
BFD_RELOC_V850_SDA_16_16_OFFSET, |
/* This is a 16 bit offset (of which only 15 bits are used) from the |
short data area pointer. */ |
BFD_RELOC_V850_SDA_15_16_OFFSET, |
/* This is a 16 bit offset from the zero data area pointer. */ |
BFD_RELOC_V850_ZDA_16_16_OFFSET, |
/* This is a 16 bit offset (of which only 15 bits are used) from the |
zero data area pointer. */ |
BFD_RELOC_V850_ZDA_15_16_OFFSET, |
/* This is an 8 bit offset (of which only 6 bits are used) from the |
tiny data area pointer. */ |
BFD_RELOC_V850_TDA_6_8_OFFSET, |
/* This is an 8bit offset (of which only 7 bits are used) from the tiny |
data area pointer. */ |
BFD_RELOC_V850_TDA_7_8_OFFSET, |
/* This is a 7 bit offset from the tiny data area pointer. */ |
BFD_RELOC_V850_TDA_7_7_OFFSET, |
/* This is a 16 bit offset from the tiny data area pointer. */ |
BFD_RELOC_V850_TDA_16_16_OFFSET, |
/* This is a 5 bit offset (of which only 4 bits are used) from the tiny |
data area pointer. */ |
BFD_RELOC_V850_TDA_4_5_OFFSET, |
/* This is a 4 bit offset from the tiny data area pointer. */ |
BFD_RELOC_V850_TDA_4_4_OFFSET, |
/* This is a 16 bit offset from the short data area pointer, with the |
bits placed non-contiguously in the instruction. */ |
BFD_RELOC_V850_SDA_16_16_SPLIT_OFFSET, |
/* This is a 16 bit offset from the zero data area pointer, with the |
bits placed non-contiguously in the instruction. */ |
BFD_RELOC_V850_ZDA_16_16_SPLIT_OFFSET, |
/* This is a 6 bit offset from the call table base pointer. */ |
BFD_RELOC_V850_CALLT_6_7_OFFSET, |
/* This is a 16 bit offset from the call table base pointer. */ |
BFD_RELOC_V850_CALLT_16_16_OFFSET, |
/* Used for relaxing indirect function calls. */ |
BFD_RELOC_V850_LONGCALL, |
/* Used for relaxing indirect jumps. */ |
BFD_RELOC_V850_LONGJUMP, |
/* Used to maintain alignment whilst relaxing. */ |
BFD_RELOC_V850_ALIGN, |
/* This is a variation of BFD_RELOC_LO16 that can be used in v850e ld.bu |
instructions. */ |
BFD_RELOC_V850_LO16_SPLIT_OFFSET, |
/* This is a 16-bit reloc. */ |
BFD_RELOC_V850_16_PCREL, |
/* This is a 17-bit reloc. */ |
BFD_RELOC_V850_17_PCREL, |
/* This is a 23-bit reloc. */ |
BFD_RELOC_V850_23, |
/* This is a 32-bit reloc. */ |
BFD_RELOC_V850_32_PCREL, |
/* This is a 32-bit reloc. */ |
BFD_RELOC_V850_32_ABS, |
/* This is a 16-bit reloc. */ |
BFD_RELOC_V850_16_SPLIT_OFFSET, |
/* This is a 16-bit reloc. */ |
BFD_RELOC_V850_16_S1, |
/* Low 16 bits. 16 bit shifted by 1. */ |
BFD_RELOC_V850_LO16_S1, |
/* This is a 16 bit offset from the call table base pointer. */ |
BFD_RELOC_V850_CALLT_15_16_OFFSET, |
/* DSO relocations. */ |
BFD_RELOC_V850_32_GOTPCREL, |
/* DSO relocations. */ |
BFD_RELOC_V850_16_GOT, |
/* DSO relocations. */ |
BFD_RELOC_V850_32_GOT, |
/* DSO relocations. */ |
BFD_RELOC_V850_22_PLT_PCREL, |
/* DSO relocations. */ |
BFD_RELOC_V850_32_PLT_PCREL, |
/* DSO relocations. */ |
BFD_RELOC_V850_COPY, |
/* DSO relocations. */ |
BFD_RELOC_V850_GLOB_DAT, |
/* DSO relocations. */ |
BFD_RELOC_V850_JMP_SLOT, |
/* DSO relocations. */ |
BFD_RELOC_V850_RELATIVE, |
/* DSO relocations. */ |
BFD_RELOC_V850_16_GOTOFF, |
/* DSO relocations. */ |
BFD_RELOC_V850_32_GOTOFF, |
/* start code. */ |
BFD_RELOC_V850_CODE, |
/* start data in text. */ |
BFD_RELOC_V850_DATA, |
/* This is a 8bit DP reloc for the tms320c30, where the most |
significant 8 bits of a 24 bit word are placed into the least |
significant 8 bits of the opcode. */ |
BFD_RELOC_TIC30_LDP, |
/* This is a 7bit reloc for the tms320c54x, where the least |
significant 7 bits of a 16 bit word are placed into the least |
significant 7 bits of the opcode. */ |
BFD_RELOC_TIC54X_PARTLS7, |
/* This is a 9bit DP reloc for the tms320c54x, where the most |
significant 9 bits of a 16 bit word are placed into the least |
significant 9 bits of the opcode. */ |
BFD_RELOC_TIC54X_PARTMS9, |
/* This is an extended address 23-bit reloc for the tms320c54x. */ |
BFD_RELOC_TIC54X_23, |
/* This is a 16-bit reloc for the tms320c54x, where the least |
significant 16 bits of a 23-bit extended address are placed into |
the opcode. */ |
BFD_RELOC_TIC54X_16_OF_23, |
/* This is a reloc for the tms320c54x, where the most |
significant 7 bits of a 23-bit extended address are placed into |
the opcode. */ |
BFD_RELOC_TIC54X_MS7_OF_23, |
/* TMS320C6000 relocations. */ |
BFD_RELOC_C6000_PCR_S21, |
BFD_RELOC_C6000_PCR_S12, |
BFD_RELOC_C6000_PCR_S10, |
BFD_RELOC_C6000_PCR_S7, |
BFD_RELOC_C6000_ABS_S16, |
BFD_RELOC_C6000_ABS_L16, |
BFD_RELOC_C6000_ABS_H16, |
BFD_RELOC_C6000_SBR_U15_B, |
BFD_RELOC_C6000_SBR_U15_H, |
BFD_RELOC_C6000_SBR_U15_W, |
BFD_RELOC_C6000_SBR_S16, |
BFD_RELOC_C6000_SBR_L16_B, |
BFD_RELOC_C6000_SBR_L16_H, |
BFD_RELOC_C6000_SBR_L16_W, |
BFD_RELOC_C6000_SBR_H16_B, |
BFD_RELOC_C6000_SBR_H16_H, |
BFD_RELOC_C6000_SBR_H16_W, |
BFD_RELOC_C6000_SBR_GOT_U15_W, |
BFD_RELOC_C6000_SBR_GOT_L16_W, |
BFD_RELOC_C6000_SBR_GOT_H16_W, |
BFD_RELOC_C6000_DSBT_INDEX, |
BFD_RELOC_C6000_PREL31, |
BFD_RELOC_C6000_COPY, |
BFD_RELOC_C6000_JUMP_SLOT, |
BFD_RELOC_C6000_EHTYPE, |
BFD_RELOC_C6000_PCR_H16, |
BFD_RELOC_C6000_PCR_L16, |
BFD_RELOC_C6000_ALIGN, |
BFD_RELOC_C6000_FPHEAD, |
BFD_RELOC_C6000_NOCMP, |
/* This is a 48 bit reloc for the FR30 that stores 32 bits. */ |
BFD_RELOC_FR30_48, |
/* This is a 32 bit reloc for the FR30 that stores 20 bits split up into |
two sections. */ |
BFD_RELOC_FR30_20, |
/* This is a 16 bit reloc for the FR30 that stores a 6 bit word offset in |
4 bits. */ |
BFD_RELOC_FR30_6_IN_4, |
/* This is a 16 bit reloc for the FR30 that stores an 8 bit byte offset |
into 8 bits. */ |
BFD_RELOC_FR30_8_IN_8, |
/* This is a 16 bit reloc for the FR30 that stores a 9 bit short offset |
into 8 bits. */ |
BFD_RELOC_FR30_9_IN_8, |
/* This is a 16 bit reloc for the FR30 that stores a 10 bit word offset |
into 8 bits. */ |
BFD_RELOC_FR30_10_IN_8, |
/* This is a 16 bit reloc for the FR30 that stores a 9 bit pc relative |
short offset into 8 bits. */ |
BFD_RELOC_FR30_9_PCREL, |
/* This is a 16 bit reloc for the FR30 that stores a 12 bit pc relative |
short offset into 11 bits. */ |
BFD_RELOC_FR30_12_PCREL, |
/* Motorola Mcore relocations. */ |
BFD_RELOC_MCORE_PCREL_IMM8BY4, |
BFD_RELOC_MCORE_PCREL_IMM11BY2, |
BFD_RELOC_MCORE_PCREL_IMM4BY2, |
BFD_RELOC_MCORE_PCREL_32, |
BFD_RELOC_MCORE_PCREL_JSR_IMM11BY2, |
BFD_RELOC_MCORE_RVA, |
/* Toshiba Media Processor Relocations. */ |
BFD_RELOC_MEP_8, |
BFD_RELOC_MEP_16, |
BFD_RELOC_MEP_32, |
BFD_RELOC_MEP_PCREL8A2, |
BFD_RELOC_MEP_PCREL12A2, |
BFD_RELOC_MEP_PCREL17A2, |
BFD_RELOC_MEP_PCREL24A2, |
BFD_RELOC_MEP_PCABS24A2, |
BFD_RELOC_MEP_LOW16, |
BFD_RELOC_MEP_HI16U, |
BFD_RELOC_MEP_HI16S, |
BFD_RELOC_MEP_GPREL, |
BFD_RELOC_MEP_TPREL, |
BFD_RELOC_MEP_TPREL7, |
BFD_RELOC_MEP_TPREL7A2, |
BFD_RELOC_MEP_TPREL7A4, |
BFD_RELOC_MEP_UIMM24, |
BFD_RELOC_MEP_ADDR24A4, |
BFD_RELOC_MEP_GNU_VTINHERIT, |
BFD_RELOC_MEP_GNU_VTENTRY, |
/* Imagination Technologies Meta relocations. */ |
BFD_RELOC_METAG_HIADDR16, |
BFD_RELOC_METAG_LOADDR16, |
BFD_RELOC_METAG_RELBRANCH, |
BFD_RELOC_METAG_GETSETOFF, |
BFD_RELOC_METAG_HIOG, |
BFD_RELOC_METAG_LOOG, |
BFD_RELOC_METAG_REL8, |
BFD_RELOC_METAG_REL16, |
BFD_RELOC_METAG_HI16_GOTOFF, |
BFD_RELOC_METAG_LO16_GOTOFF, |
BFD_RELOC_METAG_GETSET_GOTOFF, |
BFD_RELOC_METAG_GETSET_GOT, |
BFD_RELOC_METAG_HI16_GOTPC, |
BFD_RELOC_METAG_LO16_GOTPC, |
BFD_RELOC_METAG_HI16_PLT, |
BFD_RELOC_METAG_LO16_PLT, |
BFD_RELOC_METAG_RELBRANCH_PLT, |
BFD_RELOC_METAG_GOTOFF, |
BFD_RELOC_METAG_PLT, |
BFD_RELOC_METAG_COPY, |
BFD_RELOC_METAG_JMP_SLOT, |
BFD_RELOC_METAG_RELATIVE, |
BFD_RELOC_METAG_GLOB_DAT, |
BFD_RELOC_METAG_TLS_GD, |
BFD_RELOC_METAG_TLS_LDM, |
BFD_RELOC_METAG_TLS_LDO_HI16, |
BFD_RELOC_METAG_TLS_LDO_LO16, |
BFD_RELOC_METAG_TLS_LDO, |
BFD_RELOC_METAG_TLS_IE, |
BFD_RELOC_METAG_TLS_IENONPIC, |
BFD_RELOC_METAG_TLS_IENONPIC_HI16, |
BFD_RELOC_METAG_TLS_IENONPIC_LO16, |
BFD_RELOC_METAG_TLS_TPOFF, |
BFD_RELOC_METAG_TLS_DTPMOD, |
BFD_RELOC_METAG_TLS_DTPOFF, |
BFD_RELOC_METAG_TLS_LE, |
BFD_RELOC_METAG_TLS_LE_HI16, |
BFD_RELOC_METAG_TLS_LE_LO16, |
/* These are relocations for the GETA instruction. */ |
BFD_RELOC_MMIX_GETA, |
BFD_RELOC_MMIX_GETA_1, |
BFD_RELOC_MMIX_GETA_2, |
BFD_RELOC_MMIX_GETA_3, |
/* These are relocations for a conditional branch instruction. */ |
BFD_RELOC_MMIX_CBRANCH, |
BFD_RELOC_MMIX_CBRANCH_J, |
BFD_RELOC_MMIX_CBRANCH_1, |
BFD_RELOC_MMIX_CBRANCH_2, |
BFD_RELOC_MMIX_CBRANCH_3, |
/* These are relocations for the PUSHJ instruction. */ |
BFD_RELOC_MMIX_PUSHJ, |
BFD_RELOC_MMIX_PUSHJ_1, |
BFD_RELOC_MMIX_PUSHJ_2, |
BFD_RELOC_MMIX_PUSHJ_3, |
BFD_RELOC_MMIX_PUSHJ_STUBBABLE, |
/* These are relocations for the JMP instruction. */ |
BFD_RELOC_MMIX_JMP, |
BFD_RELOC_MMIX_JMP_1, |
BFD_RELOC_MMIX_JMP_2, |
BFD_RELOC_MMIX_JMP_3, |
/* This is a relocation for a relative address as in a GETA instruction or |
a branch. */ |
BFD_RELOC_MMIX_ADDR19, |
/* This is a relocation for a relative address as in a JMP instruction. */ |
BFD_RELOC_MMIX_ADDR27, |
/* This is a relocation for an instruction field that may be a general |
register or a value 0..255. */ |
BFD_RELOC_MMIX_REG_OR_BYTE, |
/* This is a relocation for an instruction field that may be a general |
register. */ |
BFD_RELOC_MMIX_REG, |
/* This is a relocation for two instruction fields holding a register and |
an offset, the equivalent of the relocation. */ |
BFD_RELOC_MMIX_BASE_PLUS_OFFSET, |
/* This relocation is an assertion that the expression is not allocated as |
a global register. It does not modify contents. */ |
BFD_RELOC_MMIX_LOCAL, |
/* This is a 16 bit reloc for the AVR that stores 8 bit pc relative |
short offset into 7 bits. */ |
BFD_RELOC_AVR_7_PCREL, |
/* This is a 16 bit reloc for the AVR that stores 13 bit pc relative |
short offset into 12 bits. */ |
BFD_RELOC_AVR_13_PCREL, |
/* This is a 16 bit reloc for the AVR that stores 17 bit value (usually |
program memory address) into 16 bits. */ |
BFD_RELOC_AVR_16_PM, |
/* This is a 16 bit reloc for the AVR that stores 8 bit value (usually |
data memory address) into 8 bit immediate value of LDI insn. */ |
BFD_RELOC_AVR_LO8_LDI, |
/* This is a 16 bit reloc for the AVR that stores 8 bit value (high 8 bit |
of data memory address) into 8 bit immediate value of LDI insn. */ |
BFD_RELOC_AVR_HI8_LDI, |
/* This is a 16 bit reloc for the AVR that stores 8 bit value (most high 8 bit |
of program memory address) into 8 bit immediate value of LDI insn. */ |
BFD_RELOC_AVR_HH8_LDI, |
/* This is a 16 bit reloc for the AVR that stores 8 bit value (most high 8 bit |
of 32 bit value) into 8 bit immediate value of LDI insn. */ |
BFD_RELOC_AVR_MS8_LDI, |
/* This is a 16 bit reloc for the AVR that stores negated 8 bit value |
(usually data memory address) into 8 bit immediate value of SUBI insn. */ |
BFD_RELOC_AVR_LO8_LDI_NEG, |
/* This is a 16 bit reloc for the AVR that stores negated 8 bit value |
(high 8 bit of data memory address) into 8 bit immediate value of |
SUBI insn. */ |
BFD_RELOC_AVR_HI8_LDI_NEG, |
/* This is a 16 bit reloc for the AVR that stores negated 8 bit value |
(most high 8 bit of program memory address) into 8 bit immediate value |
of LDI or SUBI insn. */ |
BFD_RELOC_AVR_HH8_LDI_NEG, |
/* This is a 16 bit reloc for the AVR that stores negated 8 bit value (msb |
of 32 bit value) into 8 bit immediate value of LDI insn. */ |
BFD_RELOC_AVR_MS8_LDI_NEG, |
/* This is a 16 bit reloc for the AVR that stores 8 bit value (usually |
command address) into 8 bit immediate value of LDI insn. */ |
BFD_RELOC_AVR_LO8_LDI_PM, |
/* This is a 16 bit reloc for the AVR that stores 8 bit value |
(command address) into 8 bit immediate value of LDI insn. If the address |
is beyond the 128k boundary, the linker inserts a jump stub for this reloc |
in the lower 128k. */ |
BFD_RELOC_AVR_LO8_LDI_GS, |
/* This is a 16 bit reloc for the AVR that stores 8 bit value (high 8 bit |
of command address) into 8 bit immediate value of LDI insn. */ |
BFD_RELOC_AVR_HI8_LDI_PM, |
/* This is a 16 bit reloc for the AVR that stores 8 bit value (high 8 bit |
of command address) into 8 bit immediate value of LDI insn. If the address |
is beyond the 128k boundary, the linker inserts a jump stub for this reloc |
below 128k. */ |
BFD_RELOC_AVR_HI8_LDI_GS, |
/* This is a 16 bit reloc for the AVR that stores 8 bit value (most high 8 bit |
of command address) into 8 bit immediate value of LDI insn. */ |
BFD_RELOC_AVR_HH8_LDI_PM, |
/* This is a 16 bit reloc for the AVR that stores negated 8 bit value |
(usually command address) into 8 bit immediate value of SUBI insn. */ |
BFD_RELOC_AVR_LO8_LDI_PM_NEG, |
/* This is a 16 bit reloc for the AVR that stores negated 8 bit value |
(high 8 bit of 16 bit command address) into 8 bit immediate value |
of SUBI insn. */ |
BFD_RELOC_AVR_HI8_LDI_PM_NEG, |
/* This is a 16 bit reloc for the AVR that stores negated 8 bit value |
(high 6 bit of 22 bit command address) into 8 bit immediate |
value of SUBI insn. */ |
BFD_RELOC_AVR_HH8_LDI_PM_NEG, |
/* This is a 32 bit reloc for the AVR that stores 23 bit value |
into 22 bits. */ |
BFD_RELOC_AVR_CALL, |
/* This is a 16 bit reloc for the AVR that stores all needed bits |
for absolute addressing with ldi with overflow check to linktime */ |
BFD_RELOC_AVR_LDI, |
/* This is a 6 bit reloc for the AVR that stores offset for ldd/std |
instructions */ |
BFD_RELOC_AVR_6, |
/* This is a 6 bit reloc for the AVR that stores offset for adiw/sbiw |
instructions */ |
BFD_RELOC_AVR_6_ADIW, |
/* This is a 8 bit reloc for the AVR that stores bits 0..7 of a symbol |
in .byte lo8(symbol) */ |
BFD_RELOC_AVR_8_LO, |
/* This is a 8 bit reloc for the AVR that stores bits 8..15 of a symbol |
in .byte hi8(symbol) */ |
BFD_RELOC_AVR_8_HI, |
/* This is a 8 bit reloc for the AVR that stores bits 16..23 of a symbol |
in .byte hlo8(symbol) */ |
BFD_RELOC_AVR_8_HLO, |
/* Renesas RL78 Relocations. */ |
BFD_RELOC_RL78_NEG8, |
BFD_RELOC_RL78_NEG16, |
BFD_RELOC_RL78_NEG24, |
BFD_RELOC_RL78_NEG32, |
BFD_RELOC_RL78_16_OP, |
BFD_RELOC_RL78_24_OP, |
BFD_RELOC_RL78_32_OP, |
BFD_RELOC_RL78_8U, |
BFD_RELOC_RL78_16U, |
BFD_RELOC_RL78_24U, |
BFD_RELOC_RL78_DIR3U_PCREL, |
BFD_RELOC_RL78_DIFF, |
BFD_RELOC_RL78_GPRELB, |
BFD_RELOC_RL78_GPRELW, |
BFD_RELOC_RL78_GPRELL, |
BFD_RELOC_RL78_SYM, |
BFD_RELOC_RL78_OP_SUBTRACT, |
BFD_RELOC_RL78_OP_NEG, |
BFD_RELOC_RL78_OP_AND, |
BFD_RELOC_RL78_OP_SHRA, |
BFD_RELOC_RL78_ABS8, |
BFD_RELOC_RL78_ABS16, |
BFD_RELOC_RL78_ABS16_REV, |
BFD_RELOC_RL78_ABS32, |
BFD_RELOC_RL78_ABS32_REV, |
BFD_RELOC_RL78_ABS16U, |
BFD_RELOC_RL78_ABS16UW, |
BFD_RELOC_RL78_ABS16UL, |
BFD_RELOC_RL78_RELAX, |
BFD_RELOC_RL78_HI16, |
BFD_RELOC_RL78_HI8, |
BFD_RELOC_RL78_LO16, |
BFD_RELOC_RL78_CODE, |
/* Renesas RX Relocations. */ |
BFD_RELOC_RX_NEG8, |
BFD_RELOC_RX_NEG16, |
BFD_RELOC_RX_NEG24, |
BFD_RELOC_RX_NEG32, |
BFD_RELOC_RX_16_OP, |
BFD_RELOC_RX_24_OP, |
BFD_RELOC_RX_32_OP, |
BFD_RELOC_RX_8U, |
BFD_RELOC_RX_16U, |
BFD_RELOC_RX_24U, |
BFD_RELOC_RX_DIR3U_PCREL, |
BFD_RELOC_RX_DIFF, |
BFD_RELOC_RX_GPRELB, |
BFD_RELOC_RX_GPRELW, |
BFD_RELOC_RX_GPRELL, |
BFD_RELOC_RX_SYM, |
BFD_RELOC_RX_OP_SUBTRACT, |
BFD_RELOC_RX_OP_NEG, |
BFD_RELOC_RX_ABS8, |
BFD_RELOC_RX_ABS16, |
BFD_RELOC_RX_ABS16_REV, |
BFD_RELOC_RX_ABS32, |
BFD_RELOC_RX_ABS32_REV, |
BFD_RELOC_RX_ABS16U, |
BFD_RELOC_RX_ABS16UW, |
BFD_RELOC_RX_ABS16UL, |
BFD_RELOC_RX_RELAX, |
/* Direct 12 bit. */ |
BFD_RELOC_390_12, |
/* 12 bit GOT offset. */ |
BFD_RELOC_390_GOT12, |
/* 32 bit PC relative PLT address. */ |
BFD_RELOC_390_PLT32, |
/* Copy symbol at runtime. */ |
BFD_RELOC_390_COPY, |
/* Create GOT entry. */ |
BFD_RELOC_390_GLOB_DAT, |
/* Create PLT entry. */ |
BFD_RELOC_390_JMP_SLOT, |
/* Adjust by program base. */ |
BFD_RELOC_390_RELATIVE, |
/* 32 bit PC relative offset to GOT. */ |
BFD_RELOC_390_GOTPC, |
/* 16 bit GOT offset. */ |
BFD_RELOC_390_GOT16, |
/* PC relative 12 bit shifted by 1. */ |
BFD_RELOC_390_PC12DBL, |
/* 12 bit PC rel. PLT shifted by 1. */ |
BFD_RELOC_390_PLT12DBL, |
/* PC relative 16 bit shifted by 1. */ |
BFD_RELOC_390_PC16DBL, |
/* 16 bit PC rel. PLT shifted by 1. */ |
BFD_RELOC_390_PLT16DBL, |
/* PC relative 24 bit shifted by 1. */ |
BFD_RELOC_390_PC24DBL, |
/* 24 bit PC rel. PLT shifted by 1. */ |
BFD_RELOC_390_PLT24DBL, |
/* PC relative 32 bit shifted by 1. */ |
BFD_RELOC_390_PC32DBL, |
/* 32 bit PC rel. PLT shifted by 1. */ |
BFD_RELOC_390_PLT32DBL, |
/* 32 bit PC rel. GOT shifted by 1. */ |
BFD_RELOC_390_GOTPCDBL, |
/* 64 bit GOT offset. */ |
BFD_RELOC_390_GOT64, |
/* 64 bit PC relative PLT address. */ |
BFD_RELOC_390_PLT64, |
/* 32 bit rel. offset to GOT entry. */ |
BFD_RELOC_390_GOTENT, |
/* 64 bit offset to GOT. */ |
BFD_RELOC_390_GOTOFF64, |
/* 12-bit offset to symbol-entry within GOT, with PLT handling. */ |
BFD_RELOC_390_GOTPLT12, |
/* 16-bit offset to symbol-entry within GOT, with PLT handling. */ |
BFD_RELOC_390_GOTPLT16, |
/* 32-bit offset to symbol-entry within GOT, with PLT handling. */ |
BFD_RELOC_390_GOTPLT32, |
/* 64-bit offset to symbol-entry within GOT, with PLT handling. */ |
BFD_RELOC_390_GOTPLT64, |
/* 32-bit rel. offset to symbol-entry within GOT, with PLT handling. */ |
BFD_RELOC_390_GOTPLTENT, |
/* 16-bit rel. offset from the GOT to a PLT entry. */ |
BFD_RELOC_390_PLTOFF16, |
/* 32-bit rel. offset from the GOT to a PLT entry. */ |
BFD_RELOC_390_PLTOFF32, |
/* 64-bit rel. offset from the GOT to a PLT entry. */ |
BFD_RELOC_390_PLTOFF64, |
/* s390 tls relocations. */ |
BFD_RELOC_390_TLS_LOAD, |
BFD_RELOC_390_TLS_GDCALL, |
BFD_RELOC_390_TLS_LDCALL, |
BFD_RELOC_390_TLS_GD32, |
BFD_RELOC_390_TLS_GD64, |
BFD_RELOC_390_TLS_GOTIE12, |
BFD_RELOC_390_TLS_GOTIE32, |
BFD_RELOC_390_TLS_GOTIE64, |
BFD_RELOC_390_TLS_LDM32, |
BFD_RELOC_390_TLS_LDM64, |
BFD_RELOC_390_TLS_IE32, |
BFD_RELOC_390_TLS_IE64, |
BFD_RELOC_390_TLS_IEENT, |
BFD_RELOC_390_TLS_LE32, |
BFD_RELOC_390_TLS_LE64, |
BFD_RELOC_390_TLS_LDO32, |
BFD_RELOC_390_TLS_LDO64, |
BFD_RELOC_390_TLS_DTPMOD, |
BFD_RELOC_390_TLS_DTPOFF, |
BFD_RELOC_390_TLS_TPOFF, |
/* Long displacement extension. */ |
BFD_RELOC_390_20, |
BFD_RELOC_390_GOT20, |
BFD_RELOC_390_GOTPLT20, |
BFD_RELOC_390_TLS_GOTIE20, |
/* STT_GNU_IFUNC relocation. */ |
BFD_RELOC_390_IRELATIVE, |
/* Score relocations |
Low 16 bit for load/store */ |
BFD_RELOC_SCORE_GPREL15, |
/* This is a 24-bit reloc with the right 1 bit assumed to be 0 */ |
BFD_RELOC_SCORE_DUMMY2, |
BFD_RELOC_SCORE_JMP, |
/* This is a 19-bit reloc with the right 1 bit assumed to be 0 */ |
BFD_RELOC_SCORE_BRANCH, |
/* This is a 32-bit reloc for 48-bit instructions. */ |
BFD_RELOC_SCORE_IMM30, |
/* This is a 32-bit reloc for 48-bit instructions. */ |
BFD_RELOC_SCORE_IMM32, |
/* This is a 11-bit reloc with the right 1 bit assumed to be 0 */ |
BFD_RELOC_SCORE16_JMP, |
/* This is a 8-bit reloc with the right 1 bit assumed to be 0 */ |
BFD_RELOC_SCORE16_BRANCH, |
/* This is a 9-bit reloc with the right 1 bit assumed to be 0 */ |
BFD_RELOC_SCORE_BCMP, |
/* Undocumented Score relocs */ |
BFD_RELOC_SCORE_GOT15, |
BFD_RELOC_SCORE_GOT_LO16, |
BFD_RELOC_SCORE_CALL15, |
BFD_RELOC_SCORE_DUMMY_HI16, |
/* Scenix IP2K - 9-bit register number / data address */ |
BFD_RELOC_IP2K_FR9, |
/* Scenix IP2K - 4-bit register/data bank number */ |
BFD_RELOC_IP2K_BANK, |
/* Scenix IP2K - low 13 bits of instruction word address */ |
BFD_RELOC_IP2K_ADDR16CJP, |
/* Scenix IP2K - high 3 bits of instruction word address */ |
BFD_RELOC_IP2K_PAGE3, |
/* Scenix IP2K - ext/low/high 8 bits of data address */ |
BFD_RELOC_IP2K_LO8DATA, |
BFD_RELOC_IP2K_HI8DATA, |
BFD_RELOC_IP2K_EX8DATA, |
/* Scenix IP2K - low/high 8 bits of instruction word address */ |
BFD_RELOC_IP2K_LO8INSN, |
BFD_RELOC_IP2K_HI8INSN, |
/* Scenix IP2K - even/odd PC modifier to modify snb pcl.0 */ |
BFD_RELOC_IP2K_PC_SKIP, |
/* Scenix IP2K - 16 bit word address in text section. */ |
BFD_RELOC_IP2K_TEXT, |
/* Scenix IP2K - 7-bit sp or dp offset */ |
BFD_RELOC_IP2K_FR_OFFSET, |
/* Scenix VPE4K coprocessor - data/insn-space addressing */ |
BFD_RELOC_VPE4KMATH_DATA, |
BFD_RELOC_VPE4KMATH_INSN, |
/* These two relocations are used by the linker to determine which of |
the entries in a C++ virtual function table are actually used. When |
the --gc-sections option is given, the linker will zero out the entries |
that are not used, so that the code for those functions need not be |
included in the output. |
VTABLE_INHERIT is a zero-space relocation used to describe to the |
linker the inheritance tree of a C++ virtual function table. The |
relocation's symbol should be the parent class' vtable, and the |
relocation should be located at the child vtable. |
VTABLE_ENTRY is a zero-space relocation that describes the use of a |
virtual function table entry. The reloc's symbol should refer to the |
table of the class mentioned in the code. Off of that base, an offset |
describes the entry that is being used. For Rela hosts, this offset |
is stored in the reloc's addend. For Rel hosts, we are forced to put |
this offset in the reloc's section offset. */ |
BFD_RELOC_VTABLE_INHERIT, |
BFD_RELOC_VTABLE_ENTRY, |
/* Intel IA64 Relocations. */ |
BFD_RELOC_IA64_IMM14, |
BFD_RELOC_IA64_IMM22, |
BFD_RELOC_IA64_IMM64, |
BFD_RELOC_IA64_DIR32MSB, |
BFD_RELOC_IA64_DIR32LSB, |
BFD_RELOC_IA64_DIR64MSB, |
BFD_RELOC_IA64_DIR64LSB, |
BFD_RELOC_IA64_GPREL22, |
BFD_RELOC_IA64_GPREL64I, |
BFD_RELOC_IA64_GPREL32MSB, |
BFD_RELOC_IA64_GPREL32LSB, |
BFD_RELOC_IA64_GPREL64MSB, |
BFD_RELOC_IA64_GPREL64LSB, |
BFD_RELOC_IA64_LTOFF22, |
BFD_RELOC_IA64_LTOFF64I, |
BFD_RELOC_IA64_PLTOFF22, |
BFD_RELOC_IA64_PLTOFF64I, |
BFD_RELOC_IA64_PLTOFF64MSB, |
BFD_RELOC_IA64_PLTOFF64LSB, |
BFD_RELOC_IA64_FPTR64I, |
BFD_RELOC_IA64_FPTR32MSB, |
BFD_RELOC_IA64_FPTR32LSB, |
BFD_RELOC_IA64_FPTR64MSB, |
BFD_RELOC_IA64_FPTR64LSB, |
BFD_RELOC_IA64_PCREL21B, |
BFD_RELOC_IA64_PCREL21BI, |
BFD_RELOC_IA64_PCREL21M, |
BFD_RELOC_IA64_PCREL21F, |
BFD_RELOC_IA64_PCREL22, |
BFD_RELOC_IA64_PCREL60B, |
BFD_RELOC_IA64_PCREL64I, |
BFD_RELOC_IA64_PCREL32MSB, |
BFD_RELOC_IA64_PCREL32LSB, |
BFD_RELOC_IA64_PCREL64MSB, |
BFD_RELOC_IA64_PCREL64LSB, |
BFD_RELOC_IA64_LTOFF_FPTR22, |
BFD_RELOC_IA64_LTOFF_FPTR64I, |
BFD_RELOC_IA64_LTOFF_FPTR32MSB, |
BFD_RELOC_IA64_LTOFF_FPTR32LSB, |
BFD_RELOC_IA64_LTOFF_FPTR64MSB, |
BFD_RELOC_IA64_LTOFF_FPTR64LSB, |
BFD_RELOC_IA64_SEGREL32MSB, |
BFD_RELOC_IA64_SEGREL32LSB, |
BFD_RELOC_IA64_SEGREL64MSB, |
BFD_RELOC_IA64_SEGREL64LSB, |
BFD_RELOC_IA64_SECREL32MSB, |
BFD_RELOC_IA64_SECREL32LSB, |
BFD_RELOC_IA64_SECREL64MSB, |
BFD_RELOC_IA64_SECREL64LSB, |
BFD_RELOC_IA64_REL32MSB, |
BFD_RELOC_IA64_REL32LSB, |
BFD_RELOC_IA64_REL64MSB, |
BFD_RELOC_IA64_REL64LSB, |
BFD_RELOC_IA64_LTV32MSB, |
BFD_RELOC_IA64_LTV32LSB, |
BFD_RELOC_IA64_LTV64MSB, |
BFD_RELOC_IA64_LTV64LSB, |
BFD_RELOC_IA64_IPLTMSB, |
BFD_RELOC_IA64_IPLTLSB, |
BFD_RELOC_IA64_COPY, |
BFD_RELOC_IA64_LTOFF22X, |
BFD_RELOC_IA64_LDXMOV, |
BFD_RELOC_IA64_TPREL14, |
BFD_RELOC_IA64_TPREL22, |
BFD_RELOC_IA64_TPREL64I, |
BFD_RELOC_IA64_TPREL64MSB, |
BFD_RELOC_IA64_TPREL64LSB, |
BFD_RELOC_IA64_LTOFF_TPREL22, |
BFD_RELOC_IA64_DTPMOD64MSB, |
BFD_RELOC_IA64_DTPMOD64LSB, |
BFD_RELOC_IA64_LTOFF_DTPMOD22, |
BFD_RELOC_IA64_DTPREL14, |
BFD_RELOC_IA64_DTPREL22, |
BFD_RELOC_IA64_DTPREL64I, |
BFD_RELOC_IA64_DTPREL32MSB, |
BFD_RELOC_IA64_DTPREL32LSB, |
BFD_RELOC_IA64_DTPREL64MSB, |
BFD_RELOC_IA64_DTPREL64LSB, |
BFD_RELOC_IA64_LTOFF_DTPREL22, |
/* Motorola 68HC11 reloc. |
This is the 8 bit high part of an absolute address. */ |
BFD_RELOC_M68HC11_HI8, |
/* Motorola 68HC11 reloc. |
This is the 8 bit low part of an absolute address. */ |
BFD_RELOC_M68HC11_LO8, |
/* Motorola 68HC11 reloc. |
This is the 3 bit of a value. */ |
BFD_RELOC_M68HC11_3B, |
/* Motorola 68HC11 reloc. |
This reloc marks the beginning of a jump/call instruction. |
It is used for linker relaxation to correctly identify beginning |
of instruction and change some branches to use PC-relative |
addressing mode. */ |
BFD_RELOC_M68HC11_RL_JUMP, |
/* Motorola 68HC11 reloc. |
This reloc marks a group of several instructions that gcc generates |
and for which the linker relaxation pass can modify and/or remove |
some of them. */ |
BFD_RELOC_M68HC11_RL_GROUP, |
/* Motorola 68HC11 reloc. |
This is the 16-bit lower part of an address. It is used for 'call' |
instruction to specify the symbol address without any special |
transformation (due to memory bank window). */ |
BFD_RELOC_M68HC11_LO16, |
/* Motorola 68HC11 reloc. |
This is a 8-bit reloc that specifies the page number of an address. |
It is used by 'call' instruction to specify the page number of |
the symbol. */ |
BFD_RELOC_M68HC11_PAGE, |
/* Motorola 68HC11 reloc. |
This is a 24-bit reloc that represents the address with a 16-bit |
value and a 8-bit page number. The symbol address is transformed |
to follow the 16K memory bank of 68HC12 (seen as mapped in the window). */ |
BFD_RELOC_M68HC11_24, |
/* Motorola 68HC12 reloc. |
This is the 5 bits of a value. */ |
BFD_RELOC_M68HC12_5B, |
/* Freescale XGATE reloc. |
This reloc marks the beginning of a bra/jal instruction. */ |
BFD_RELOC_XGATE_RL_JUMP, |
/* Freescale XGATE reloc. |
This reloc marks a group of several instructions that gcc generates |
and for which the linker relaxation pass can modify and/or remove |
some of them. */ |
BFD_RELOC_XGATE_RL_GROUP, |
/* Freescale XGATE reloc. |
This is the 16-bit lower part of an address. It is used for the '16-bit' |
instructions. */ |
BFD_RELOC_XGATE_LO16, |
/* Freescale XGATE reloc. */ |
BFD_RELOC_XGATE_GPAGE, |
/* Freescale XGATE reloc. */ |
BFD_RELOC_XGATE_24, |
/* Freescale XGATE reloc. |
This is a 9-bit pc-relative reloc. */ |
BFD_RELOC_XGATE_PCREL_9, |
/* Freescale XGATE reloc. |
This is a 10-bit pc-relative reloc. */ |
BFD_RELOC_XGATE_PCREL_10, |
/* Freescale XGATE reloc. |
This is the 16-bit lower part of an address. It is used for the '16-bit' |
instructions. */ |
BFD_RELOC_XGATE_IMM8_LO, |
/* Freescale XGATE reloc. |
This is the 16-bit higher part of an address. It is used for the '16-bit' |
instructions. */ |
BFD_RELOC_XGATE_IMM8_HI, |
/* Freescale XGATE reloc. |
This is a 3-bit pc-relative reloc. */ |
BFD_RELOC_XGATE_IMM3, |
/* Freescale XGATE reloc. |
This is a 4-bit pc-relative reloc. */ |
BFD_RELOC_XGATE_IMM4, |
/* Freescale XGATE reloc. |
This is a 5-bit pc-relative reloc. */ |
BFD_RELOC_XGATE_IMM5, |
/* Motorola 68HC12 reloc. |
This is the 9 bits of a value. */ |
BFD_RELOC_M68HC12_9B, |
/* Motorola 68HC12 reloc. |
This is the 16 bits of a value. */ |
BFD_RELOC_M68HC12_16B, |
/* Motorola 68HC12/XGATE reloc. |
This is a PCREL9 branch. */ |
BFD_RELOC_M68HC12_9_PCREL, |
/* Motorola 68HC12/XGATE reloc. |
This is a PCREL10 branch. */ |
BFD_RELOC_M68HC12_10_PCREL, |
/* Motorola 68HC12/XGATE reloc. |
This is the 8 bit low part of an absolute address and immediately precedes |
a matching HI8XG part. */ |
BFD_RELOC_M68HC12_LO8XG, |
/* Motorola 68HC12/XGATE reloc. |
This is the 8 bit high part of an absolute address and immediately follows |
a matching LO8XG part. */ |
BFD_RELOC_M68HC12_HI8XG, |
/* NS CR16C Relocations. */ |
BFD_RELOC_16C_NUM08, |
BFD_RELOC_16C_NUM08_C, |
BFD_RELOC_16C_NUM16, |
BFD_RELOC_16C_NUM16_C, |
BFD_RELOC_16C_NUM32, |
BFD_RELOC_16C_NUM32_C, |
BFD_RELOC_16C_DISP04, |
BFD_RELOC_16C_DISP04_C, |
BFD_RELOC_16C_DISP08, |
BFD_RELOC_16C_DISP08_C, |
BFD_RELOC_16C_DISP16, |
BFD_RELOC_16C_DISP16_C, |
BFD_RELOC_16C_DISP24, |
BFD_RELOC_16C_DISP24_C, |
BFD_RELOC_16C_DISP24a, |
BFD_RELOC_16C_DISP24a_C, |
BFD_RELOC_16C_REG04, |
BFD_RELOC_16C_REG04_C, |
BFD_RELOC_16C_REG04a, |
BFD_RELOC_16C_REG04a_C, |
BFD_RELOC_16C_REG14, |
BFD_RELOC_16C_REG14_C, |
BFD_RELOC_16C_REG16, |
BFD_RELOC_16C_REG16_C, |
BFD_RELOC_16C_REG20, |
BFD_RELOC_16C_REG20_C, |
BFD_RELOC_16C_ABS20, |
BFD_RELOC_16C_ABS20_C, |
BFD_RELOC_16C_ABS24, |
BFD_RELOC_16C_ABS24_C, |
BFD_RELOC_16C_IMM04, |
BFD_RELOC_16C_IMM04_C, |
BFD_RELOC_16C_IMM16, |
BFD_RELOC_16C_IMM16_C, |
BFD_RELOC_16C_IMM20, |
BFD_RELOC_16C_IMM20_C, |
BFD_RELOC_16C_IMM24, |
BFD_RELOC_16C_IMM24_C, |
BFD_RELOC_16C_IMM32, |
BFD_RELOC_16C_IMM32_C, |
/* NS CR16 Relocations. */ |
BFD_RELOC_CR16_NUM8, |
BFD_RELOC_CR16_NUM16, |
BFD_RELOC_CR16_NUM32, |
BFD_RELOC_CR16_NUM32a, |
BFD_RELOC_CR16_REGREL0, |
BFD_RELOC_CR16_REGREL4, |
BFD_RELOC_CR16_REGREL4a, |
BFD_RELOC_CR16_REGREL14, |
BFD_RELOC_CR16_REGREL14a, |
BFD_RELOC_CR16_REGREL16, |
BFD_RELOC_CR16_REGREL20, |
BFD_RELOC_CR16_REGREL20a, |
BFD_RELOC_CR16_ABS20, |
BFD_RELOC_CR16_ABS24, |
BFD_RELOC_CR16_IMM4, |
BFD_RELOC_CR16_IMM8, |
BFD_RELOC_CR16_IMM16, |
BFD_RELOC_CR16_IMM20, |
BFD_RELOC_CR16_IMM24, |
BFD_RELOC_CR16_IMM32, |
BFD_RELOC_CR16_IMM32a, |
BFD_RELOC_CR16_DISP4, |
BFD_RELOC_CR16_DISP8, |
BFD_RELOC_CR16_DISP16, |
BFD_RELOC_CR16_DISP20, |
BFD_RELOC_CR16_DISP24, |
BFD_RELOC_CR16_DISP24a, |
BFD_RELOC_CR16_SWITCH8, |
BFD_RELOC_CR16_SWITCH16, |
BFD_RELOC_CR16_SWITCH32, |
BFD_RELOC_CR16_GOT_REGREL20, |
BFD_RELOC_CR16_GOTC_REGREL20, |
BFD_RELOC_CR16_GLOB_DAT, |
/* NS CRX Relocations. */ |
BFD_RELOC_CRX_REL4, |
BFD_RELOC_CRX_REL8, |
BFD_RELOC_CRX_REL8_CMP, |
BFD_RELOC_CRX_REL16, |
BFD_RELOC_CRX_REL24, |
BFD_RELOC_CRX_REL32, |
BFD_RELOC_CRX_REGREL12, |
BFD_RELOC_CRX_REGREL22, |
BFD_RELOC_CRX_REGREL28, |
BFD_RELOC_CRX_REGREL32, |
BFD_RELOC_CRX_ABS16, |
BFD_RELOC_CRX_ABS32, |
BFD_RELOC_CRX_NUM8, |
BFD_RELOC_CRX_NUM16, |
BFD_RELOC_CRX_NUM32, |
BFD_RELOC_CRX_IMM16, |
BFD_RELOC_CRX_IMM32, |
BFD_RELOC_CRX_SWITCH8, |
BFD_RELOC_CRX_SWITCH16, |
BFD_RELOC_CRX_SWITCH32, |
/* These relocs are only used within the CRIS assembler. They are not |
(at present) written to any object files. */ |
BFD_RELOC_CRIS_BDISP8, |
BFD_RELOC_CRIS_UNSIGNED_5, |
BFD_RELOC_CRIS_SIGNED_6, |
BFD_RELOC_CRIS_UNSIGNED_6, |
BFD_RELOC_CRIS_SIGNED_8, |
BFD_RELOC_CRIS_UNSIGNED_8, |
BFD_RELOC_CRIS_SIGNED_16, |
BFD_RELOC_CRIS_UNSIGNED_16, |
BFD_RELOC_CRIS_LAPCQ_OFFSET, |
BFD_RELOC_CRIS_UNSIGNED_4, |
/* Relocs used in ELF shared libraries for CRIS. */ |
BFD_RELOC_CRIS_COPY, |
BFD_RELOC_CRIS_GLOB_DAT, |
BFD_RELOC_CRIS_JUMP_SLOT, |
BFD_RELOC_CRIS_RELATIVE, |
/* 32-bit offset to symbol-entry within GOT. */ |
BFD_RELOC_CRIS_32_GOT, |
/* 16-bit offset to symbol-entry within GOT. */ |
BFD_RELOC_CRIS_16_GOT, |
/* 32-bit offset to symbol-entry within GOT, with PLT handling. */ |
BFD_RELOC_CRIS_32_GOTPLT, |
/* 16-bit offset to symbol-entry within GOT, with PLT handling. */ |
BFD_RELOC_CRIS_16_GOTPLT, |
/* 32-bit offset to symbol, relative to GOT. */ |
BFD_RELOC_CRIS_32_GOTREL, |
/* 32-bit offset to symbol with PLT entry, relative to GOT. */ |
BFD_RELOC_CRIS_32_PLT_GOTREL, |
/* 32-bit offset to symbol with PLT entry, relative to this relocation. */ |
BFD_RELOC_CRIS_32_PLT_PCREL, |
/* Relocs used in TLS code for CRIS. */ |
BFD_RELOC_CRIS_32_GOT_GD, |
BFD_RELOC_CRIS_16_GOT_GD, |
BFD_RELOC_CRIS_32_GD, |
BFD_RELOC_CRIS_DTP, |
BFD_RELOC_CRIS_32_DTPREL, |
BFD_RELOC_CRIS_16_DTPREL, |
BFD_RELOC_CRIS_32_GOT_TPREL, |
BFD_RELOC_CRIS_16_GOT_TPREL, |
BFD_RELOC_CRIS_32_TPREL, |
BFD_RELOC_CRIS_16_TPREL, |
BFD_RELOC_CRIS_DTPMOD, |
BFD_RELOC_CRIS_32_IE, |
/* Intel i860 Relocations. */ |
BFD_RELOC_860_COPY, |
BFD_RELOC_860_GLOB_DAT, |
BFD_RELOC_860_JUMP_SLOT, |
BFD_RELOC_860_RELATIVE, |
BFD_RELOC_860_PC26, |
BFD_RELOC_860_PLT26, |
BFD_RELOC_860_PC16, |
BFD_RELOC_860_LOW0, |
BFD_RELOC_860_SPLIT0, |
BFD_RELOC_860_LOW1, |
BFD_RELOC_860_SPLIT1, |
BFD_RELOC_860_LOW2, |
BFD_RELOC_860_SPLIT2, |
BFD_RELOC_860_LOW3, |
BFD_RELOC_860_LOGOT0, |
BFD_RELOC_860_SPGOT0, |
BFD_RELOC_860_LOGOT1, |
BFD_RELOC_860_SPGOT1, |
BFD_RELOC_860_LOGOTOFF0, |
BFD_RELOC_860_SPGOTOFF0, |
BFD_RELOC_860_LOGOTOFF1, |
BFD_RELOC_860_SPGOTOFF1, |
BFD_RELOC_860_LOGOTOFF2, |
BFD_RELOC_860_LOGOTOFF3, |
BFD_RELOC_860_LOPC, |
BFD_RELOC_860_HIGHADJ, |
BFD_RELOC_860_HAGOT, |
BFD_RELOC_860_HAGOTOFF, |
BFD_RELOC_860_HAPC, |
BFD_RELOC_860_HIGH, |
BFD_RELOC_860_HIGOT, |
BFD_RELOC_860_HIGOTOFF, |
/* OpenRISC Relocations. */ |
BFD_RELOC_OPENRISC_ABS_26, |
BFD_RELOC_OPENRISC_REL_26, |
/* H8 elf Relocations. */ |
BFD_RELOC_H8_DIR16A8, |
BFD_RELOC_H8_DIR16R8, |
BFD_RELOC_H8_DIR24A8, |
BFD_RELOC_H8_DIR24R8, |
BFD_RELOC_H8_DIR32A16, |
BFD_RELOC_H8_DISP32A16, |
/* Sony Xstormy16 Relocations. */ |
BFD_RELOC_XSTORMY16_REL_12, |
BFD_RELOC_XSTORMY16_12, |
BFD_RELOC_XSTORMY16_24, |
BFD_RELOC_XSTORMY16_FPTR16, |
/* Self-describing complex relocations. */ |
BFD_RELOC_RELC, |
/* Infineon Relocations. */ |
BFD_RELOC_XC16X_PAG, |
BFD_RELOC_XC16X_POF, |
BFD_RELOC_XC16X_SEG, |
BFD_RELOC_XC16X_SOF, |
/* Relocations used by VAX ELF. */ |
BFD_RELOC_VAX_GLOB_DAT, |
BFD_RELOC_VAX_JMP_SLOT, |
BFD_RELOC_VAX_RELATIVE, |
/* Morpho MT - 16 bit immediate relocation. */ |
BFD_RELOC_MT_PC16, |
/* Morpho MT - Hi 16 bits of an address. */ |
BFD_RELOC_MT_HI16, |
/* Morpho MT - Low 16 bits of an address. */ |
BFD_RELOC_MT_LO16, |
/* Morpho MT - Used to tell the linker which vtable entries are used. */ |
BFD_RELOC_MT_GNU_VTINHERIT, |
/* Morpho MT - Used to tell the linker which vtable entries are used. */ |
BFD_RELOC_MT_GNU_VTENTRY, |
/* Morpho MT - 8 bit immediate relocation. */ |
BFD_RELOC_MT_PCINSN8, |
/* msp430 specific relocation codes */ |
BFD_RELOC_MSP430_10_PCREL, |
BFD_RELOC_MSP430_16_PCREL, |
BFD_RELOC_MSP430_16, |
BFD_RELOC_MSP430_16_PCREL_BYTE, |
BFD_RELOC_MSP430_16_BYTE, |
BFD_RELOC_MSP430_2X_PCREL, |
BFD_RELOC_MSP430_RL_PCREL, |
BFD_RELOC_MSP430_ABS8, |
BFD_RELOC_MSP430X_PCR20_EXT_SRC, |
BFD_RELOC_MSP430X_PCR20_EXT_DST, |
BFD_RELOC_MSP430X_PCR20_EXT_ODST, |
BFD_RELOC_MSP430X_ABS20_EXT_SRC, |
BFD_RELOC_MSP430X_ABS20_EXT_DST, |
BFD_RELOC_MSP430X_ABS20_EXT_ODST, |
BFD_RELOC_MSP430X_ABS20_ADR_SRC, |
BFD_RELOC_MSP430X_ABS20_ADR_DST, |
BFD_RELOC_MSP430X_PCR16, |
BFD_RELOC_MSP430X_PCR20_CALL, |
BFD_RELOC_MSP430X_ABS16, |
BFD_RELOC_MSP430_ABS_HI16, |
BFD_RELOC_MSP430_PREL31, |
BFD_RELOC_MSP430_SYM_DIFF, |
/* Relocations used by the Altera Nios II core. */ |
BFD_RELOC_NIOS2_S16, |
BFD_RELOC_NIOS2_U16, |
BFD_RELOC_NIOS2_CALL26, |
BFD_RELOC_NIOS2_IMM5, |
BFD_RELOC_NIOS2_CACHE_OPX, |
BFD_RELOC_NIOS2_IMM6, |
BFD_RELOC_NIOS2_IMM8, |
BFD_RELOC_NIOS2_HI16, |
BFD_RELOC_NIOS2_LO16, |
BFD_RELOC_NIOS2_HIADJ16, |
BFD_RELOC_NIOS2_GPREL, |
BFD_RELOC_NIOS2_UJMP, |
BFD_RELOC_NIOS2_CJMP, |
BFD_RELOC_NIOS2_CALLR, |
BFD_RELOC_NIOS2_ALIGN, |
BFD_RELOC_NIOS2_GOT16, |
BFD_RELOC_NIOS2_CALL16, |
BFD_RELOC_NIOS2_GOTOFF_LO, |
BFD_RELOC_NIOS2_GOTOFF_HA, |
BFD_RELOC_NIOS2_PCREL_LO, |
BFD_RELOC_NIOS2_PCREL_HA, |
BFD_RELOC_NIOS2_TLS_GD16, |
BFD_RELOC_NIOS2_TLS_LDM16, |
BFD_RELOC_NIOS2_TLS_LDO16, |
BFD_RELOC_NIOS2_TLS_IE16, |
BFD_RELOC_NIOS2_TLS_LE16, |
BFD_RELOC_NIOS2_TLS_DTPMOD, |
BFD_RELOC_NIOS2_TLS_DTPREL, |
BFD_RELOC_NIOS2_TLS_TPREL, |
BFD_RELOC_NIOS2_COPY, |
BFD_RELOC_NIOS2_GLOB_DAT, |
BFD_RELOC_NIOS2_JUMP_SLOT, |
BFD_RELOC_NIOS2_RELATIVE, |
BFD_RELOC_NIOS2_GOTOFF, |
/* IQ2000 Relocations. */ |
BFD_RELOC_IQ2000_OFFSET_16, |
BFD_RELOC_IQ2000_OFFSET_21, |
BFD_RELOC_IQ2000_UHI16, |
/* Special Xtensa relocation used only by PLT entries in ELF shared |
objects to indicate that the runtime linker should set the value |
to one of its own internal functions or data structures. */ |
BFD_RELOC_XTENSA_RTLD, |
/* Xtensa relocations for ELF shared objects. */ |
BFD_RELOC_XTENSA_GLOB_DAT, |
BFD_RELOC_XTENSA_JMP_SLOT, |
BFD_RELOC_XTENSA_RELATIVE, |
/* Xtensa relocation used in ELF object files for symbols that may require |
PLT entries. Otherwise, this is just a generic 32-bit relocation. */ |
BFD_RELOC_XTENSA_PLT, |
/* Xtensa relocations to mark the difference of two local symbols. |
These are only needed to support linker relaxation and can be ignored |
when not relaxing. The field is set to the value of the difference |
assuming no relaxation. The relocation encodes the position of the |
first symbol so the linker can determine whether to adjust the field |
value. */ |
BFD_RELOC_XTENSA_DIFF8, |
BFD_RELOC_XTENSA_DIFF16, |
BFD_RELOC_XTENSA_DIFF32, |
/* Generic Xtensa relocations for instruction operands. Only the slot |
number is encoded in the relocation. The relocation applies to the |
last PC-relative immediate operand, or if there are no PC-relative |
immediates, to the last immediate operand. */ |
BFD_RELOC_XTENSA_SLOT0_OP, |
BFD_RELOC_XTENSA_SLOT1_OP, |
BFD_RELOC_XTENSA_SLOT2_OP, |
BFD_RELOC_XTENSA_SLOT3_OP, |
BFD_RELOC_XTENSA_SLOT4_OP, |
BFD_RELOC_XTENSA_SLOT5_OP, |
BFD_RELOC_XTENSA_SLOT6_OP, |
BFD_RELOC_XTENSA_SLOT7_OP, |
BFD_RELOC_XTENSA_SLOT8_OP, |
BFD_RELOC_XTENSA_SLOT9_OP, |
BFD_RELOC_XTENSA_SLOT10_OP, |
BFD_RELOC_XTENSA_SLOT11_OP, |
BFD_RELOC_XTENSA_SLOT12_OP, |
BFD_RELOC_XTENSA_SLOT13_OP, |
BFD_RELOC_XTENSA_SLOT14_OP, |
/* Alternate Xtensa relocations. Only the slot is encoded in the |
relocation. The meaning of these relocations is opcode-specific. */ |
BFD_RELOC_XTENSA_SLOT0_ALT, |
BFD_RELOC_XTENSA_SLOT1_ALT, |
BFD_RELOC_XTENSA_SLOT2_ALT, |
BFD_RELOC_XTENSA_SLOT3_ALT, |
BFD_RELOC_XTENSA_SLOT4_ALT, |
BFD_RELOC_XTENSA_SLOT5_ALT, |
BFD_RELOC_XTENSA_SLOT6_ALT, |
BFD_RELOC_XTENSA_SLOT7_ALT, |
BFD_RELOC_XTENSA_SLOT8_ALT, |
BFD_RELOC_XTENSA_SLOT9_ALT, |
BFD_RELOC_XTENSA_SLOT10_ALT, |
BFD_RELOC_XTENSA_SLOT11_ALT, |
BFD_RELOC_XTENSA_SLOT12_ALT, |
BFD_RELOC_XTENSA_SLOT13_ALT, |
BFD_RELOC_XTENSA_SLOT14_ALT, |
/* Xtensa relocations for backward compatibility. These have all been |
replaced by BFD_RELOC_XTENSA_SLOT0_OP. */ |
BFD_RELOC_XTENSA_OP0, |
BFD_RELOC_XTENSA_OP1, |
BFD_RELOC_XTENSA_OP2, |
/* Xtensa relocation to mark that the assembler expanded the |
instructions from an original target. The expansion size is |
encoded in the reloc size. */ |
BFD_RELOC_XTENSA_ASM_EXPAND, |
/* Xtensa relocation to mark that the linker should simplify |
assembler-expanded instructions. This is commonly used |
internally by the linker after analysis of a |
BFD_RELOC_XTENSA_ASM_EXPAND. */ |
BFD_RELOC_XTENSA_ASM_SIMPLIFY, |
/* Xtensa TLS relocations. */ |
BFD_RELOC_XTENSA_TLSDESC_FN, |
BFD_RELOC_XTENSA_TLSDESC_ARG, |
BFD_RELOC_XTENSA_TLS_DTPOFF, |
BFD_RELOC_XTENSA_TLS_TPOFF, |
BFD_RELOC_XTENSA_TLS_FUNC, |
BFD_RELOC_XTENSA_TLS_ARG, |
BFD_RELOC_XTENSA_TLS_CALL, |
/* 8 bit signed offset in (ix+d) or (iy+d). */ |
BFD_RELOC_Z80_DISP8, |
/* DJNZ offset. */ |
BFD_RELOC_Z8K_DISP7, |
/* CALR offset. */ |
BFD_RELOC_Z8K_CALLR, |
/* 4 bit value. */ |
BFD_RELOC_Z8K_IMM4L, |
/* Lattice Mico32 relocations. */ |
BFD_RELOC_LM32_CALL, |
BFD_RELOC_LM32_BRANCH, |
BFD_RELOC_LM32_16_GOT, |
BFD_RELOC_LM32_GOTOFF_HI16, |
BFD_RELOC_LM32_GOTOFF_LO16, |
BFD_RELOC_LM32_COPY, |
BFD_RELOC_LM32_GLOB_DAT, |
BFD_RELOC_LM32_JMP_SLOT, |
BFD_RELOC_LM32_RELATIVE, |
/* Difference between two section addreses. Must be followed by a |
BFD_RELOC_MACH_O_PAIR. */ |
BFD_RELOC_MACH_O_SECTDIFF, |
/* Like BFD_RELOC_MACH_O_SECTDIFF but with a local symbol. */ |
BFD_RELOC_MACH_O_LOCAL_SECTDIFF, |
/* Pair of relocation. Contains the first symbol. */ |
BFD_RELOC_MACH_O_PAIR, |
/* PCREL relocations. They are marked as branch to create PLT entry if |
required. */ |
BFD_RELOC_MACH_O_X86_64_BRANCH32, |
BFD_RELOC_MACH_O_X86_64_BRANCH8, |
/* Used when referencing a GOT entry. */ |
BFD_RELOC_MACH_O_X86_64_GOT, |
/* Used when loading a GOT entry with movq. It is specially marked so that |
the linker could optimize the movq to a leaq if possible. */ |
BFD_RELOC_MACH_O_X86_64_GOT_LOAD, |
/* Symbol will be substracted. Must be followed by a BFD_RELOC_64. */ |
BFD_RELOC_MACH_O_X86_64_SUBTRACTOR32, |
/* Symbol will be substracted. Must be followed by a BFD_RELOC_64. */ |
BFD_RELOC_MACH_O_X86_64_SUBTRACTOR64, |
/* Same as BFD_RELOC_32_PCREL but with an implicit -1 addend. */ |
BFD_RELOC_MACH_O_X86_64_PCREL32_1, |
/* Same as BFD_RELOC_32_PCREL but with an implicit -2 addend. */ |
BFD_RELOC_MACH_O_X86_64_PCREL32_2, |
/* Same as BFD_RELOC_32_PCREL but with an implicit -4 addend. */ |
BFD_RELOC_MACH_O_X86_64_PCREL32_4, |
/* This is a 32 bit reloc for the microblaze that stores the |
low 16 bits of a value */ |
BFD_RELOC_MICROBLAZE_32_LO, |
/* This is a 32 bit pc-relative reloc for the microblaze that |
stores the low 16 bits of a value */ |
BFD_RELOC_MICROBLAZE_32_LO_PCREL, |
/* This is a 32 bit reloc for the microblaze that stores a |
value relative to the read-only small data area anchor */ |
BFD_RELOC_MICROBLAZE_32_ROSDA, |
/* This is a 32 bit reloc for the microblaze that stores a |
value relative to the read-write small data area anchor */ |
BFD_RELOC_MICROBLAZE_32_RWSDA, |
/* This is a 32 bit reloc for the microblaze to handle |
expressions of the form "Symbol Op Symbol" */ |
BFD_RELOC_MICROBLAZE_32_SYM_OP_SYM, |
/* This is a 64 bit reloc that stores the 32 bit pc relative |
value in two words (with an imm instruction). No relocation is |
done here - only used for relaxing */ |
BFD_RELOC_MICROBLAZE_64_NONE, |
/* This is a 64 bit reloc that stores the 32 bit pc relative |
value in two words (with an imm instruction). The relocation is |
PC-relative GOT offset */ |
BFD_RELOC_MICROBLAZE_64_GOTPC, |
/* This is a 64 bit reloc that stores the 32 bit pc relative |
value in two words (with an imm instruction). The relocation is |
GOT offset */ |
BFD_RELOC_MICROBLAZE_64_GOT, |
/* This is a 64 bit reloc that stores the 32 bit pc relative |
value in two words (with an imm instruction). The relocation is |
PC-relative offset into PLT */ |
BFD_RELOC_MICROBLAZE_64_PLT, |
/* This is a 64 bit reloc that stores the 32 bit GOT relative |
value in two words (with an imm instruction). The relocation is |
relative offset from _GLOBAL_OFFSET_TABLE_ */ |
BFD_RELOC_MICROBLAZE_64_GOTOFF, |
/* This is a 32 bit reloc that stores the 32 bit GOT relative |
value in a word. The relocation is relative offset from */ |
BFD_RELOC_MICROBLAZE_32_GOTOFF, |
/* This is used to tell the dynamic linker to copy the value out of |
the dynamic object into the runtime process image. */ |
BFD_RELOC_MICROBLAZE_COPY, |
/* Unused Reloc */ |
BFD_RELOC_MICROBLAZE_64_TLS, |
/* This is a 64 bit reloc that stores the 32 bit GOT relative value |
of the GOT TLS GD info entry in two words (with an imm instruction). The |
relocation is GOT offset. */ |
BFD_RELOC_MICROBLAZE_64_TLSGD, |
/* This is a 64 bit reloc that stores the 32 bit GOT relative value |
of the GOT TLS LD info entry in two words (with an imm instruction). The |
relocation is GOT offset. */ |
BFD_RELOC_MICROBLAZE_64_TLSLD, |
/* This is a 32 bit reloc that stores the Module ID to GOT(n). */ |
BFD_RELOC_MICROBLAZE_32_TLSDTPMOD, |
/* This is a 32 bit reloc that stores TLS offset to GOT(n+1). */ |
BFD_RELOC_MICROBLAZE_32_TLSDTPREL, |
/* This is a 32 bit reloc for storing TLS offset to two words (uses imm |
instruction) */ |
BFD_RELOC_MICROBLAZE_64_TLSDTPREL, |
/* This is a 64 bit reloc that stores 32-bit thread pointer relative offset |
to two words (uses imm instruction). */ |
BFD_RELOC_MICROBLAZE_64_TLSGOTTPREL, |
/* This is a 64 bit reloc that stores 32-bit thread pointer relative offset |
to two words (uses imm instruction). */ |
BFD_RELOC_MICROBLAZE_64_TLSTPREL, |
/* AArch64 pseudo relocation code to mark the start of the AArch64 |
relocation enumerators. N.B. the order of the enumerators is |
important as several tables in the AArch64 bfd backend are indexed |
by these enumerators; make sure they are all synced. */ |
BFD_RELOC_AARCH64_RELOC_START, |
/* AArch64 null relocation code. */ |
BFD_RELOC_AARCH64_NONE, |
/* Basic absolute relocations of N bits. These are equivalent to |
BFD_RELOC_N and they were added to assist the indexing of the howto |
table. */ |
BFD_RELOC_AARCH64_64, |
BFD_RELOC_AARCH64_32, |
BFD_RELOC_AARCH64_16, |
/* PC-relative relocations. These are equivalent to BFD_RELOC_N_PCREL |
and they were added to assist the indexing of the howto table. */ |
BFD_RELOC_AARCH64_64_PCREL, |
BFD_RELOC_AARCH64_32_PCREL, |
BFD_RELOC_AARCH64_16_PCREL, |
/* AArch64 MOV[NZK] instruction with most significant bits 0 to 15 |
of an unsigned address/value. */ |
BFD_RELOC_AARCH64_MOVW_G0, |
/* AArch64 MOV[NZK] instruction with less significant bits 0 to 15 of |
an address/value. No overflow checking. */ |
BFD_RELOC_AARCH64_MOVW_G0_NC, |
/* AArch64 MOV[NZK] instruction with most significant bits 16 to 31 |
of an unsigned address/value. */ |
BFD_RELOC_AARCH64_MOVW_G1, |
/* AArch64 MOV[NZK] instruction with less significant bits 16 to 31 |
of an address/value. No overflow checking. */ |
BFD_RELOC_AARCH64_MOVW_G1_NC, |
/* AArch64 MOV[NZK] instruction with most significant bits 32 to 47 |
of an unsigned address/value. */ |
BFD_RELOC_AARCH64_MOVW_G2, |
/* AArch64 MOV[NZK] instruction with less significant bits 32 to 47 |
of an address/value. No overflow checking. */ |
BFD_RELOC_AARCH64_MOVW_G2_NC, |
/* AArch64 MOV[NZK] instruction with most signficant bits 48 to 64 |
of a signed or unsigned address/value. */ |
BFD_RELOC_AARCH64_MOVW_G3, |
/* AArch64 MOV[NZ] instruction with most significant bits 0 to 15 |
of a signed value. Changes instruction to MOVZ or MOVN depending on the |
value's sign. */ |
BFD_RELOC_AARCH64_MOVW_G0_S, |
/* AArch64 MOV[NZ] instruction with most significant bits 16 to 31 |
of a signed value. Changes instruction to MOVZ or MOVN depending on the |
value's sign. */ |
BFD_RELOC_AARCH64_MOVW_G1_S, |
/* AArch64 MOV[NZ] instruction with most significant bits 32 to 47 |
of a signed value. Changes instruction to MOVZ or MOVN depending on the |
value's sign. */ |
BFD_RELOC_AARCH64_MOVW_G2_S, |
/* AArch64 Load Literal instruction, holding a 19 bit pc-relative word |
offset. The lowest two bits must be zero and are not stored in the |
instruction, giving a 21 bit signed byte offset. */ |
BFD_RELOC_AARCH64_LD_LO19_PCREL, |
/* AArch64 ADR instruction, holding a simple 21 bit pc-relative byte offset. */ |
BFD_RELOC_AARCH64_ADR_LO21_PCREL, |
/* AArch64 ADRP instruction, with bits 12 to 32 of a pc-relative page |
offset, giving a 4KB aligned page base address. */ |
BFD_RELOC_AARCH64_ADR_HI21_PCREL, |
/* AArch64 ADRP instruction, with bits 12 to 32 of a pc-relative page |
offset, giving a 4KB aligned page base address, but with no overflow |
checking. */ |
BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL, |
/* AArch64 ADD immediate instruction, holding bits 0 to 11 of the address. |
Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ |
BFD_RELOC_AARCH64_ADD_LO12, |
/* AArch64 8-bit load/store instruction, holding bits 0 to 11 of the |
address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ |
BFD_RELOC_AARCH64_LDST8_LO12, |
/* AArch64 14 bit pc-relative test bit and branch. |
The lowest two bits must be zero and are not stored in the instruction, |
giving a 16 bit signed byte offset. */ |
BFD_RELOC_AARCH64_TSTBR14, |
/* AArch64 19 bit pc-relative conditional branch and compare & branch. |
The lowest two bits must be zero and are not stored in the instruction, |
giving a 21 bit signed byte offset. */ |
BFD_RELOC_AARCH64_BRANCH19, |
/* AArch64 26 bit pc-relative unconditional branch. |
The lowest two bits must be zero and are not stored in the instruction, |
giving a 28 bit signed byte offset. */ |
BFD_RELOC_AARCH64_JUMP26, |
/* AArch64 26 bit pc-relative unconditional branch and link. |
The lowest two bits must be zero and are not stored in the instruction, |
giving a 28 bit signed byte offset. */ |
BFD_RELOC_AARCH64_CALL26, |
/* AArch64 16-bit load/store instruction, holding bits 0 to 11 of the |
address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ |
BFD_RELOC_AARCH64_LDST16_LO12, |
/* AArch64 32-bit load/store instruction, holding bits 0 to 11 of the |
address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ |
BFD_RELOC_AARCH64_LDST32_LO12, |
/* AArch64 64-bit load/store instruction, holding bits 0 to 11 of the |
address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ |
BFD_RELOC_AARCH64_LDST64_LO12, |
/* AArch64 128-bit load/store instruction, holding bits 0 to 11 of the |
address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ |
BFD_RELOC_AARCH64_LDST128_LO12, |
/* AArch64 Load Literal instruction, holding a 19 bit PC relative word |
offset of the global offset table entry for a symbol. The lowest two |
bits must be zero and are not stored in the instruction, giving a 21 |
bit signed byte offset. This relocation type requires signed overflow |
checking. */ |
BFD_RELOC_AARCH64_GOT_LD_PREL19, |
/* Get to the page base of the global offset table entry for a symbol as |
part of an ADRP instruction using a 21 bit PC relative value.Used in |
conjunction with BFD_RELOC_AARCH64_LD64_GOT_LO12_NC. */ |
BFD_RELOC_AARCH64_ADR_GOT_PAGE, |
/* Unsigned 12 bit byte offset for 64 bit load/store from the page of |
the GOT entry for this symbol. Used in conjunction with |
BFD_RELOC_AARCH64_ADR_GOTPAGE. Valid in LP64 ABI only. */ |
BFD_RELOC_AARCH64_LD64_GOT_LO12_NC, |
/* Unsigned 12 bit byte offset for 32 bit load/store from the page of |
the GOT entry for this symbol. Used in conjunction with |
BFD_RELOC_AARCH64_ADR_GOTPAGE. Valid in ILP32 ABI only. */ |
BFD_RELOC_AARCH64_LD32_GOT_LO12_NC, |
/* Get to the page base of the global offset table entry for a symbols |
tls_index structure as part of an adrp instruction using a 21 bit PC |
relative value. Used in conjunction with |
BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC. */ |
BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21, |
/* Unsigned 12 bit byte offset to global offset table entry for a symbols |
tls_index structure. Used in conjunction with |
BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21. */ |
BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC, |
/* AArch64 TLS INITIAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1, |
/* AArch64 TLS INITIAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC, |
/* AArch64 TLS INITIAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, |
/* AArch64 TLS INITIAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, |
/* AArch64 TLS INITIAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSIE_LD32_GOTTPREL_LO12_NC, |
/* AArch64 TLS INITIAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19, |
/* AArch64 TLS LOCAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2, |
/* AArch64 TLS LOCAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1, |
/* AArch64 TLS LOCAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC, |
/* AArch64 TLS LOCAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0, |
/* AArch64 TLS LOCAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC, |
/* AArch64 TLS LOCAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12, |
/* AArch64 TLS LOCAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12, |
/* AArch64 TLS LOCAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC, |
/* AArch64 TLS DESC relocation. */ |
BFD_RELOC_AARCH64_TLSDESC_LD_PREL19, |
/* AArch64 TLS DESC relocation. */ |
BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21, |
/* AArch64 TLS DESC relocation. */ |
BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21, |
/* AArch64 TLS DESC relocation. */ |
BFD_RELOC_AARCH64_TLSDESC_LD64_LO12_NC, |
/* AArch64 TLS DESC relocation. */ |
BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC, |
/* AArch64 TLS DESC relocation. */ |
BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC, |
/* AArch64 TLS DESC relocation. */ |
BFD_RELOC_AARCH64_TLSDESC_OFF_G1, |
/* AArch64 TLS DESC relocation. */ |
BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC, |
/* AArch64 TLS DESC relocation. */ |
BFD_RELOC_AARCH64_TLSDESC_LDR, |
/* AArch64 TLS DESC relocation. */ |
BFD_RELOC_AARCH64_TLSDESC_ADD, |
/* AArch64 TLS DESC relocation. */ |
BFD_RELOC_AARCH64_TLSDESC_CALL, |
/* AArch64 TLS relocation. */ |
BFD_RELOC_AARCH64_COPY, |
/* AArch64 TLS relocation. */ |
BFD_RELOC_AARCH64_GLOB_DAT, |
/* AArch64 TLS relocation. */ |
BFD_RELOC_AARCH64_JUMP_SLOT, |
/* AArch64 TLS relocation. */ |
BFD_RELOC_AARCH64_RELATIVE, |
/* AArch64 TLS relocation. */ |
BFD_RELOC_AARCH64_TLS_DTPMOD, |
/* AArch64 TLS relocation. */ |
BFD_RELOC_AARCH64_TLS_DTPREL, |
/* AArch64 TLS relocation. */ |
BFD_RELOC_AARCH64_TLS_TPREL, |
/* AArch64 TLS relocation. */ |
BFD_RELOC_AARCH64_TLSDESC, |
/* AArch64 support for STT_GNU_IFUNC. */ |
BFD_RELOC_AARCH64_IRELATIVE, |
/* AArch64 pseudo relocation code to mark the end of the AArch64 |
relocation enumerators that have direct mapping to ELF reloc codes. |
There are a few more enumerators after this one; those are mainly |
used by the AArch64 assembler for the internal fixup or to select |
one of the above enumerators. */ |
BFD_RELOC_AARCH64_RELOC_END, |
/* AArch64 pseudo relocation code to be used internally by the AArch64 |
assembler and not (currently) written to any object files. */ |
BFD_RELOC_AARCH64_GAS_INTERNAL_FIXUP, |
/* AArch64 unspecified load/store instruction, holding bits 0 to 11 of the |
address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ |
BFD_RELOC_AARCH64_LDST_LO12, |
/* AArch64 pseudo relocation code to be used internally by the AArch64 |
assembler and not (currently) written to any object files. */ |
BFD_RELOC_AARCH64_LD_GOT_LO12_NC, |
/* AArch64 pseudo relocation code to be used internally by the AArch64 |
assembler and not (currently) written to any object files. */ |
BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_LO12_NC, |
/* AArch64 pseudo relocation code to be used internally by the AArch64 |
assembler and not (currently) written to any object files. */ |
BFD_RELOC_AARCH64_TLSDESC_LD_LO12_NC, |
/* Tilera TILEPro Relocations. */ |
BFD_RELOC_TILEPRO_COPY, |
BFD_RELOC_TILEPRO_GLOB_DAT, |
BFD_RELOC_TILEPRO_JMP_SLOT, |
BFD_RELOC_TILEPRO_RELATIVE, |
BFD_RELOC_TILEPRO_BROFF_X1, |
BFD_RELOC_TILEPRO_JOFFLONG_X1, |
BFD_RELOC_TILEPRO_JOFFLONG_X1_PLT, |
BFD_RELOC_TILEPRO_IMM8_X0, |
BFD_RELOC_TILEPRO_IMM8_Y0, |
BFD_RELOC_TILEPRO_IMM8_X1, |
BFD_RELOC_TILEPRO_IMM8_Y1, |
BFD_RELOC_TILEPRO_DEST_IMM8_X1, |
BFD_RELOC_TILEPRO_MT_IMM15_X1, |
BFD_RELOC_TILEPRO_MF_IMM15_X1, |
BFD_RELOC_TILEPRO_IMM16_X0, |
BFD_RELOC_TILEPRO_IMM16_X1, |
BFD_RELOC_TILEPRO_IMM16_X0_LO, |
BFD_RELOC_TILEPRO_IMM16_X1_LO, |
BFD_RELOC_TILEPRO_IMM16_X0_HI, |
BFD_RELOC_TILEPRO_IMM16_X1_HI, |
BFD_RELOC_TILEPRO_IMM16_X0_HA, |
BFD_RELOC_TILEPRO_IMM16_X1_HA, |
BFD_RELOC_TILEPRO_IMM16_X0_PCREL, |
BFD_RELOC_TILEPRO_IMM16_X1_PCREL, |
BFD_RELOC_TILEPRO_IMM16_X0_LO_PCREL, |
BFD_RELOC_TILEPRO_IMM16_X1_LO_PCREL, |
BFD_RELOC_TILEPRO_IMM16_X0_HI_PCREL, |
BFD_RELOC_TILEPRO_IMM16_X1_HI_PCREL, |
BFD_RELOC_TILEPRO_IMM16_X0_HA_PCREL, |
BFD_RELOC_TILEPRO_IMM16_X1_HA_PCREL, |
BFD_RELOC_TILEPRO_IMM16_X0_GOT, |
BFD_RELOC_TILEPRO_IMM16_X1_GOT, |
BFD_RELOC_TILEPRO_IMM16_X0_GOT_LO, |
BFD_RELOC_TILEPRO_IMM16_X1_GOT_LO, |
BFD_RELOC_TILEPRO_IMM16_X0_GOT_HI, |
BFD_RELOC_TILEPRO_IMM16_X1_GOT_HI, |
BFD_RELOC_TILEPRO_IMM16_X0_GOT_HA, |
BFD_RELOC_TILEPRO_IMM16_X1_GOT_HA, |
BFD_RELOC_TILEPRO_MMSTART_X0, |
BFD_RELOC_TILEPRO_MMEND_X0, |
BFD_RELOC_TILEPRO_MMSTART_X1, |
BFD_RELOC_TILEPRO_MMEND_X1, |
BFD_RELOC_TILEPRO_SHAMT_X0, |
BFD_RELOC_TILEPRO_SHAMT_X1, |
BFD_RELOC_TILEPRO_SHAMT_Y0, |
BFD_RELOC_TILEPRO_SHAMT_Y1, |
BFD_RELOC_TILEPRO_TLS_GD_CALL, |
BFD_RELOC_TILEPRO_IMM8_X0_TLS_GD_ADD, |
BFD_RELOC_TILEPRO_IMM8_X1_TLS_GD_ADD, |
BFD_RELOC_TILEPRO_IMM8_Y0_TLS_GD_ADD, |
BFD_RELOC_TILEPRO_IMM8_Y1_TLS_GD_ADD, |
BFD_RELOC_TILEPRO_TLS_IE_LOAD, |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD, |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD, |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD_LO, |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD_LO, |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD_HI, |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD_HI, |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD_HA, |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD_HA, |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE, |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE, |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE_LO, |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE_LO, |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE_HI, |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE_HI, |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE_HA, |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE_HA, |
BFD_RELOC_TILEPRO_TLS_DTPMOD32, |
BFD_RELOC_TILEPRO_TLS_DTPOFF32, |
BFD_RELOC_TILEPRO_TLS_TPOFF32, |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE, |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE, |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_LO, |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_LO, |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_HI, |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_HI, |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_HA, |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_HA, |
/* Tilera TILE-Gx Relocations. */ |
BFD_RELOC_TILEGX_HW0, |
BFD_RELOC_TILEGX_HW1, |
BFD_RELOC_TILEGX_HW2, |
BFD_RELOC_TILEGX_HW3, |
BFD_RELOC_TILEGX_HW0_LAST, |
BFD_RELOC_TILEGX_HW1_LAST, |
BFD_RELOC_TILEGX_HW2_LAST, |
BFD_RELOC_TILEGX_COPY, |
BFD_RELOC_TILEGX_GLOB_DAT, |
BFD_RELOC_TILEGX_JMP_SLOT, |
BFD_RELOC_TILEGX_RELATIVE, |
BFD_RELOC_TILEGX_BROFF_X1, |
BFD_RELOC_TILEGX_JUMPOFF_X1, |
BFD_RELOC_TILEGX_JUMPOFF_X1_PLT, |
BFD_RELOC_TILEGX_IMM8_X0, |
BFD_RELOC_TILEGX_IMM8_Y0, |
BFD_RELOC_TILEGX_IMM8_X1, |
BFD_RELOC_TILEGX_IMM8_Y1, |
BFD_RELOC_TILEGX_DEST_IMM8_X1, |
BFD_RELOC_TILEGX_MT_IMM14_X1, |
BFD_RELOC_TILEGX_MF_IMM14_X1, |
BFD_RELOC_TILEGX_MMSTART_X0, |
BFD_RELOC_TILEGX_MMEND_X0, |
BFD_RELOC_TILEGX_SHAMT_X0, |
BFD_RELOC_TILEGX_SHAMT_X1, |
BFD_RELOC_TILEGX_SHAMT_Y0, |
BFD_RELOC_TILEGX_SHAMT_Y1, |
BFD_RELOC_TILEGX_IMM16_X0_HW0, |
BFD_RELOC_TILEGX_IMM16_X1_HW0, |
BFD_RELOC_TILEGX_IMM16_X0_HW1, |
BFD_RELOC_TILEGX_IMM16_X1_HW1, |
BFD_RELOC_TILEGX_IMM16_X0_HW2, |
BFD_RELOC_TILEGX_IMM16_X1_HW2, |
BFD_RELOC_TILEGX_IMM16_X0_HW3, |
BFD_RELOC_TILEGX_IMM16_X1_HW3, |
BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST, |
BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST, |
BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST, |
BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST, |
BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST, |
BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST, |
BFD_RELOC_TILEGX_IMM16_X0_HW0_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW0_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW1_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW1_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW2_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW2_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW3_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW3_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW0_GOT, |
BFD_RELOC_TILEGX_IMM16_X1_HW0_GOT, |
BFD_RELOC_TILEGX_IMM16_X0_HW0_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW0_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW1_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW1_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW2_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW2_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_GOT, |
BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_GOT, |
BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_GOT, |
BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_GOT, |
BFD_RELOC_TILEGX_IMM16_X0_HW3_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW3_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_GD, |
BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_GD, |
BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_LE, |
BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_LE, |
BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_LE, |
BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_TLS_LE, |
BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_LE, |
BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_LE, |
BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_GD, |
BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_TLS_GD, |
BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_GD, |
BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_GD, |
BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_IE, |
BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_IE, |
BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_IE, |
BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_TLS_IE, |
BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_IE, |
BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_IE, |
BFD_RELOC_TILEGX_TLS_DTPMOD64, |
BFD_RELOC_TILEGX_TLS_DTPOFF64, |
BFD_RELOC_TILEGX_TLS_TPOFF64, |
BFD_RELOC_TILEGX_TLS_DTPMOD32, |
BFD_RELOC_TILEGX_TLS_DTPOFF32, |
BFD_RELOC_TILEGX_TLS_TPOFF32, |
BFD_RELOC_TILEGX_TLS_GD_CALL, |
BFD_RELOC_TILEGX_IMM8_X0_TLS_GD_ADD, |
BFD_RELOC_TILEGX_IMM8_X1_TLS_GD_ADD, |
BFD_RELOC_TILEGX_IMM8_Y0_TLS_GD_ADD, |
BFD_RELOC_TILEGX_IMM8_Y1_TLS_GD_ADD, |
BFD_RELOC_TILEGX_TLS_IE_LOAD, |
BFD_RELOC_TILEGX_IMM8_X0_TLS_ADD, |
BFD_RELOC_TILEGX_IMM8_X1_TLS_ADD, |
BFD_RELOC_TILEGX_IMM8_Y0_TLS_ADD, |
BFD_RELOC_TILEGX_IMM8_Y1_TLS_ADD, |
/* Adapteva EPIPHANY - 8 bit signed pc-relative displacement */ |
BFD_RELOC_EPIPHANY_SIMM8, |
/* Adapteva EPIPHANY - 24 bit signed pc-relative displacement */ |
BFD_RELOC_EPIPHANY_SIMM24, |
/* Adapteva EPIPHANY - 16 most-significant bits of absolute address */ |
BFD_RELOC_EPIPHANY_HIGH, |
/* Adapteva EPIPHANY - 16 least-significant bits of absolute address */ |
BFD_RELOC_EPIPHANY_LOW, |
/* Adapteva EPIPHANY - 11 bit signed number - add/sub immediate */ |
BFD_RELOC_EPIPHANY_SIMM11, |
/* Adapteva EPIPHANY - 11 bit sign-magnitude number (ld/st displacement) */ |
BFD_RELOC_EPIPHANY_IMM11, |
/* Adapteva EPIPHANY - 8 bit immediate for 16 bit mov instruction. */ |
BFD_RELOC_EPIPHANY_IMM8, |
BFD_RELOC_UNUSED }; |
typedef enum bfd_reloc_code_real bfd_reloc_code_real_type; |
reloc_howto_type *bfd_reloc_type_lookup |
(bfd *abfd, bfd_reloc_code_real_type code); |
reloc_howto_type *bfd_reloc_name_lookup |
(bfd *abfd, const char *reloc_name); |
const char *bfd_get_reloc_code_name (bfd_reloc_code_real_type code); |
/* Extracted from syms.c. */ |
typedef struct bfd_symbol |
{ |
/* A pointer to the BFD which owns the symbol. This information |
is necessary so that a back end can work out what additional |
information (invisible to the application writer) is carried |
with the symbol. |
This field is *almost* redundant, since you can use section->owner |
instead, except that some symbols point to the global sections |
bfd_{abs,com,und}_section. This could be fixed by making |
these globals be per-bfd (or per-target-flavor). FIXME. */ |
struct bfd *the_bfd; /* Use bfd_asymbol_bfd(sym) to access this field. */ |
/* The text of the symbol. The name is left alone, and not copied; the |
application may not alter it. */ |
const char *name; |
/* The value of the symbol. This really should be a union of a |
numeric value with a pointer, since some flags indicate that |
a pointer to another symbol is stored here. */ |
symvalue value; |
/* Attributes of a symbol. */ |
#define BSF_NO_FLAGS 0x00 |
/* The symbol has local scope; <<static>> in <<C>>. The value |
is the offset into the section of the data. */ |
#define BSF_LOCAL (1 << 0) |
/* The symbol has global scope; initialized data in <<C>>. The |
value is the offset into the section of the data. */ |
#define BSF_GLOBAL (1 << 1) |
/* The symbol has global scope and is exported. The value is |
the offset into the section of the data. */ |
#define BSF_EXPORT BSF_GLOBAL /* No real difference. */ |
/* A normal C symbol would be one of: |
<<BSF_LOCAL>>, <<BSF_COMMON>>, <<BSF_UNDEFINED>> or |
<<BSF_GLOBAL>>. */ |
/* The symbol is a debugging record. The value has an arbitrary |
meaning, unless BSF_DEBUGGING_RELOC is also set. */ |
#define BSF_DEBUGGING (1 << 2) |
/* The symbol denotes a function entry point. Used in ELF, |
perhaps others someday. */ |
#define BSF_FUNCTION (1 << 3) |
/* Used by the linker. */ |
#define BSF_KEEP (1 << 5) |
#define BSF_KEEP_G (1 << 6) |
/* A weak global symbol, overridable without warnings by |
a regular global symbol of the same name. */ |
#define BSF_WEAK (1 << 7) |
/* This symbol was created to point to a section, e.g. ELF's |
STT_SECTION symbols. */ |
#define BSF_SECTION_SYM (1 << 8) |
/* The symbol used to be a common symbol, but now it is |
allocated. */ |
#define BSF_OLD_COMMON (1 << 9) |
/* In some files the type of a symbol sometimes alters its |
location in an output file - ie in coff a <<ISFCN>> symbol |
which is also <<C_EXT>> symbol appears where it was |
declared and not at the end of a section. This bit is set |
by the target BFD part to convey this information. */ |
#define BSF_NOT_AT_END (1 << 10) |
/* Signal that the symbol is the label of constructor section. */ |
#define BSF_CONSTRUCTOR (1 << 11) |
/* Signal that the symbol is a warning symbol. The name is a |
warning. The name of the next symbol is the one to warn about; |
if a reference is made to a symbol with the same name as the next |
symbol, a warning is issued by the linker. */ |
#define BSF_WARNING (1 << 12) |
/* Signal that the symbol is indirect. This symbol is an indirect |
pointer to the symbol with the same name as the next symbol. */ |
#define BSF_INDIRECT (1 << 13) |
/* BSF_FILE marks symbols that contain a file name. This is used |
for ELF STT_FILE symbols. */ |
#define BSF_FILE (1 << 14) |
/* Symbol is from dynamic linking information. */ |
#define BSF_DYNAMIC (1 << 15) |
/* The symbol denotes a data object. Used in ELF, and perhaps |
others someday. */ |
#define BSF_OBJECT (1 << 16) |
/* This symbol is a debugging symbol. The value is the offset |
into the section of the data. BSF_DEBUGGING should be set |
as well. */ |
#define BSF_DEBUGGING_RELOC (1 << 17) |
/* This symbol is thread local. Used in ELF. */ |
#define BSF_THREAD_LOCAL (1 << 18) |
/* This symbol represents a complex relocation expression, |
with the expression tree serialized in the symbol name. */ |
#define BSF_RELC (1 << 19) |
/* This symbol represents a signed complex relocation expression, |
with the expression tree serialized in the symbol name. */ |
#define BSF_SRELC (1 << 20) |
/* This symbol was created by bfd_get_synthetic_symtab. */ |
#define BSF_SYNTHETIC (1 << 21) |
/* This symbol is an indirect code object. Unrelated to BSF_INDIRECT. |
The dynamic linker will compute the value of this symbol by |
calling the function that it points to. BSF_FUNCTION must |
also be also set. */ |
#define BSF_GNU_INDIRECT_FUNCTION (1 << 22) |
/* This symbol is a globally unique data object. The dynamic linker |
will make sure that in the entire process there is just one symbol |
with this name and type in use. BSF_OBJECT must also be set. */ |
#define BSF_GNU_UNIQUE (1 << 23) |
flagword flags; |
/* A pointer to the section to which this symbol is |
relative. This will always be non NULL, there are special |
sections for undefined and absolute symbols. */ |
struct bfd_section *section; |
/* Back end special data. */ |
union |
{ |
void *p; |
bfd_vma i; |
} |
udata; |
} |
asymbol; |
#define bfd_get_symtab_upper_bound(abfd) \ |
BFD_SEND (abfd, _bfd_get_symtab_upper_bound, (abfd)) |
bfd_boolean bfd_is_local_label (bfd *abfd, asymbol *sym); |
bfd_boolean bfd_is_local_label_name (bfd *abfd, const char *name); |
#define bfd_is_local_label_name(abfd, name) \ |
BFD_SEND (abfd, _bfd_is_local_label_name, (abfd, name)) |
bfd_boolean bfd_is_target_special_symbol (bfd *abfd, asymbol *sym); |
#define bfd_is_target_special_symbol(abfd, sym) \ |
BFD_SEND (abfd, _bfd_is_target_special_symbol, (abfd, sym)) |
#define bfd_canonicalize_symtab(abfd, location) \ |
BFD_SEND (abfd, _bfd_canonicalize_symtab, (abfd, location)) |
bfd_boolean bfd_set_symtab |
(bfd *abfd, asymbol **location, unsigned int count); |
void bfd_print_symbol_vandf (bfd *abfd, void *file, asymbol *symbol); |
#define bfd_make_empty_symbol(abfd) \ |
BFD_SEND (abfd, _bfd_make_empty_symbol, (abfd)) |
asymbol *_bfd_generic_make_empty_symbol (bfd *); |
#define bfd_make_debug_symbol(abfd,ptr,size) \ |
BFD_SEND (abfd, _bfd_make_debug_symbol, (abfd, ptr, size)) |
int bfd_decode_symclass (asymbol *symbol); |
bfd_boolean bfd_is_undefined_symclass (int symclass); |
void bfd_symbol_info (asymbol *symbol, symbol_info *ret); |
bfd_boolean bfd_copy_private_symbol_data |
(bfd *ibfd, asymbol *isym, bfd *obfd, asymbol *osym); |
#define bfd_copy_private_symbol_data(ibfd, isymbol, obfd, osymbol) \ |
BFD_SEND (obfd, _bfd_copy_private_symbol_data, \ |
(ibfd, isymbol, obfd, osymbol)) |
/* Extracted from bfd.c. */ |
enum bfd_direction |
{ |
no_direction = 0, |
read_direction = 1, |
write_direction = 2, |
both_direction = 3 |
}; |
struct bfd |
{ |
/* A unique identifier of the BFD */ |
unsigned int id; |
/* The filename the application opened the BFD with. */ |
const char *filename; |
/* A pointer to the target jump table. */ |
const struct bfd_target *xvec; |
/* The IOSTREAM, and corresponding IO vector that provide access |
to the file backing the BFD. */ |
void *iostream; |
const struct bfd_iovec *iovec; |
/* The caching routines use these to maintain a |
least-recently-used list of BFDs. */ |
struct bfd *lru_prev, *lru_next; |
/* When a file is closed by the caching routines, BFD retains |
state information on the file here... */ |
ufile_ptr where; |
/* File modified time, if mtime_set is TRUE. */ |
long mtime; |
/* Reserved for an unimplemented file locking extension. */ |
int ifd; |
/* The format which belongs to the BFD. (object, core, etc.) */ |
bfd_format format; |
/* The direction with which the BFD was opened. */ |
enum bfd_direction direction; |
/* Format_specific flags. */ |
flagword flags; |
/* Values that may appear in the flags field of a BFD. These also |
appear in the object_flags field of the bfd_target structure, where |
they indicate the set of flags used by that backend (not all flags |
are meaningful for all object file formats) (FIXME: at the moment, |
the object_flags values have mostly just been copied from backend |
to another, and are not necessarily correct). */ |
#define BFD_NO_FLAGS 0x00 |
/* BFD contains relocation entries. */ |
#define HAS_RELOC 0x01 |
/* BFD is directly executable. */ |
#define EXEC_P 0x02 |
/* BFD has line number information (basically used for F_LNNO in a |
COFF header). */ |
#define HAS_LINENO 0x04 |
/* BFD has debugging information. */ |
#define HAS_DEBUG 0x08 |
/* BFD has symbols. */ |
#define HAS_SYMS 0x10 |
/* BFD has local symbols (basically used for F_LSYMS in a COFF |
header). */ |
#define HAS_LOCALS 0x20 |
/* BFD is a dynamic object. */ |
#define DYNAMIC 0x40 |
/* Text section is write protected (if D_PAGED is not set, this is |
like an a.out NMAGIC file) (the linker sets this by default, but |
clears it for -r or -N). */ |
#define WP_TEXT 0x80 |
/* BFD is dynamically paged (this is like an a.out ZMAGIC file) (the |
linker sets this by default, but clears it for -r or -n or -N). */ |
#define D_PAGED 0x100 |
/* BFD is relaxable (this means that bfd_relax_section may be able to |
do something) (sometimes bfd_relax_section can do something even if |
this is not set). */ |
#define BFD_IS_RELAXABLE 0x200 |
/* This may be set before writing out a BFD to request using a |
traditional format. For example, this is used to request that when |
writing out an a.out object the symbols not be hashed to eliminate |
duplicates. */ |
#define BFD_TRADITIONAL_FORMAT 0x400 |
/* This flag indicates that the BFD contents are actually cached |
in memory. If this is set, iostream points to a bfd_in_memory |
struct. */ |
#define BFD_IN_MEMORY 0x800 |
/* The sections in this BFD specify a memory page. */ |
#define HAS_LOAD_PAGE 0x1000 |
/* This BFD has been created by the linker and doesn't correspond |
to any input file. */ |
#define BFD_LINKER_CREATED 0x2000 |
/* This may be set before writing out a BFD to request that it |
be written using values for UIDs, GIDs, timestamps, etc. that |
will be consistent from run to run. */ |
#define BFD_DETERMINISTIC_OUTPUT 0x4000 |
/* Compress sections in this BFD. */ |
#define BFD_COMPRESS 0x8000 |
/* Decompress sections in this BFD. */ |
#define BFD_DECOMPRESS 0x10000 |
/* BFD is a dummy, for plugins. */ |
#define BFD_PLUGIN 0x20000 |
/* Flags bits to be saved in bfd_preserve_save. */ |
#define BFD_FLAGS_SAVED \ |
(BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_PLUGIN) |
/* Flags bits which are for BFD use only. */ |
#define BFD_FLAGS_FOR_BFD_USE_MASK \ |
(BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \ |
| BFD_PLUGIN | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT) |
/* Currently my_archive is tested before adding origin to |
anything. I believe that this can become always an add of |
origin, with origin set to 0 for non archive files. */ |
ufile_ptr origin; |
/* The origin in the archive of the proxy entry. This will |
normally be the same as origin, except for thin archives, |
when it will contain the current offset of the proxy in the |
thin archive rather than the offset of the bfd in its actual |
container. */ |
ufile_ptr proxy_origin; |
/* A hash table for section names. */ |
struct bfd_hash_table section_htab; |
/* Pointer to linked list of sections. */ |
struct bfd_section *sections; |
/* The last section on the section list. */ |
struct bfd_section *section_last; |
/* The number of sections. */ |
unsigned int section_count; |
/* Stuff only useful for object files: |
The start address. */ |
bfd_vma start_address; |
/* Used for input and output. */ |
unsigned int symcount; |
/* Symbol table for output BFD (with symcount entries). |
Also used by the linker to cache input BFD symbols. */ |
struct bfd_symbol **outsymbols; |
/* Used for slurped dynamic symbol tables. */ |
unsigned int dynsymcount; |
/* Pointer to structure which contains architecture information. */ |
const struct bfd_arch_info *arch_info; |
/* Stuff only useful for archives. */ |
void *arelt_data; |
struct bfd *my_archive; /* The containing archive BFD. */ |
struct bfd *archive_next; /* The next BFD in the archive. */ |
struct bfd *archive_head; /* The first BFD in the archive. */ |
struct bfd *nested_archives; /* List of nested archive in a flattened |
thin archive. */ |
/* A chain of BFD structures involved in a link. */ |
struct bfd *link_next; |
/* A field used by _bfd_generic_link_add_archive_symbols. This will |
be used only for archive elements. */ |
int archive_pass; |
/* Used by the back end to hold private data. */ |
union |
{ |
struct aout_data_struct *aout_data; |
struct artdata *aout_ar_data; |
struct _oasys_data *oasys_obj_data; |
struct _oasys_ar_data *oasys_ar_data; |
struct coff_tdata *coff_obj_data; |
struct pe_tdata *pe_obj_data; |
struct xcoff_tdata *xcoff_obj_data; |
struct ecoff_tdata *ecoff_obj_data; |
struct ieee_data_struct *ieee_data; |
struct ieee_ar_data_struct *ieee_ar_data; |
struct srec_data_struct *srec_data; |
struct verilog_data_struct *verilog_data; |
struct ihex_data_struct *ihex_data; |
struct tekhex_data_struct *tekhex_data; |
struct elf_obj_tdata *elf_obj_data; |
struct nlm_obj_tdata *nlm_obj_data; |
struct bout_data_struct *bout_data; |
struct mmo_data_struct *mmo_data; |
struct sun_core_struct *sun_core_data; |
struct sco5_core_struct *sco5_core_data; |
struct trad_core_struct *trad_core_data; |
struct som_data_struct *som_data; |
struct hpux_core_struct *hpux_core_data; |
struct hppabsd_core_struct *hppabsd_core_data; |
struct sgi_core_struct *sgi_core_data; |
struct lynx_core_struct *lynx_core_data; |
struct osf_core_struct *osf_core_data; |
struct cisco_core_struct *cisco_core_data; |
struct versados_data_struct *versados_data; |
struct netbsd_core_struct *netbsd_core_data; |
struct mach_o_data_struct *mach_o_data; |
struct mach_o_fat_data_struct *mach_o_fat_data; |
struct plugin_data_struct *plugin_data; |
struct bfd_pef_data_struct *pef_data; |
struct bfd_pef_xlib_data_struct *pef_xlib_data; |
struct bfd_sym_data_struct *sym_data; |
void *any; |
} |
tdata; |
/* Used by the application to hold private data. */ |
void *usrdata; |
/* Where all the allocated stuff under this BFD goes. This is a |
struct objalloc *, but we use void * to avoid requiring the inclusion |
of objalloc.h. */ |
void *memory; |
/* Is the file descriptor being cached? That is, can it be closed as |
needed, and re-opened when accessed later? */ |
unsigned int cacheable : 1; |
/* Marks whether there was a default target specified when the |
BFD was opened. This is used to select which matching algorithm |
to use to choose the back end. */ |
unsigned int target_defaulted : 1; |
/* ... and here: (``once'' means at least once). */ |
unsigned int opened_once : 1; |
/* Set if we have a locally maintained mtime value, rather than |
getting it from the file each time. */ |
unsigned int mtime_set : 1; |
/* Flag set if symbols from this BFD should not be exported. */ |
unsigned int no_export : 1; |
/* Remember when output has begun, to stop strange things |
from happening. */ |
unsigned int output_has_begun : 1; |
/* Have archive map. */ |
unsigned int has_armap : 1; |
/* Set if this is a thin archive. */ |
unsigned int is_thin_archive : 1; |
/* Set if only required symbols should be added in the link hash table for |
this object. Used by VMS linkers. */ |
unsigned int selective_search : 1; |
}; |
typedef enum bfd_error |
{ |
bfd_error_no_error = 0, |
bfd_error_system_call, |
bfd_error_invalid_target, |
bfd_error_wrong_format, |
bfd_error_wrong_object_format, |
bfd_error_invalid_operation, |
bfd_error_no_memory, |
bfd_error_no_symbols, |
bfd_error_no_armap, |
bfd_error_no_more_archived_files, |
bfd_error_malformed_archive, |
bfd_error_missing_dso, |
bfd_error_file_not_recognized, |
bfd_error_file_ambiguously_recognized, |
bfd_error_no_contents, |
bfd_error_nonrepresentable_section, |
bfd_error_no_debug_section, |
bfd_error_bad_value, |
bfd_error_file_truncated, |
bfd_error_file_too_big, |
bfd_error_on_input, |
bfd_error_invalid_error_code |
} |
bfd_error_type; |
bfd_error_type bfd_get_error (void); |
void bfd_set_error (bfd_error_type error_tag, ...); |
const char *bfd_errmsg (bfd_error_type error_tag); |
void bfd_perror (const char *message); |
typedef void (*bfd_error_handler_type) (const char *, ...); |
bfd_error_handler_type bfd_set_error_handler (bfd_error_handler_type); |
void bfd_set_error_program_name (const char *); |
bfd_error_handler_type bfd_get_error_handler (void); |
typedef void (*bfd_assert_handler_type) (const char *bfd_formatmsg, |
const char *bfd_version, |
const char *bfd_file, |
int bfd_line); |
bfd_assert_handler_type bfd_set_assert_handler (bfd_assert_handler_type); |
bfd_assert_handler_type bfd_get_assert_handler (void); |
long bfd_get_reloc_upper_bound (bfd *abfd, asection *sect); |
long bfd_canonicalize_reloc |
(bfd *abfd, asection *sec, arelent **loc, asymbol **syms); |
void bfd_set_reloc |
(bfd *abfd, asection *sec, arelent **rel, unsigned int count); |
bfd_boolean bfd_set_file_flags (bfd *abfd, flagword flags); |
int bfd_get_arch_size (bfd *abfd); |
int bfd_get_sign_extend_vma (bfd *abfd); |
bfd_boolean bfd_set_start_address (bfd *abfd, bfd_vma vma); |
unsigned int bfd_get_gp_size (bfd *abfd); |
void bfd_set_gp_size (bfd *abfd, unsigned int i); |
bfd_vma bfd_scan_vma (const char *string, const char **end, int base); |
bfd_boolean bfd_copy_private_header_data (bfd *ibfd, bfd *obfd); |
#define bfd_copy_private_header_data(ibfd, obfd) \ |
BFD_SEND (obfd, _bfd_copy_private_header_data, \ |
(ibfd, obfd)) |
bfd_boolean bfd_copy_private_bfd_data (bfd *ibfd, bfd *obfd); |
#define bfd_copy_private_bfd_data(ibfd, obfd) \ |
BFD_SEND (obfd, _bfd_copy_private_bfd_data, \ |
(ibfd, obfd)) |
bfd_boolean bfd_merge_private_bfd_data (bfd *ibfd, bfd *obfd); |
#define bfd_merge_private_bfd_data(ibfd, obfd) \ |
BFD_SEND (obfd, _bfd_merge_private_bfd_data, \ |
(ibfd, obfd)) |
bfd_boolean bfd_set_private_flags (bfd *abfd, flagword flags); |
#define bfd_set_private_flags(abfd, flags) \ |
BFD_SEND (abfd, _bfd_set_private_flags, (abfd, flags)) |
#define bfd_sizeof_headers(abfd, info) \ |
BFD_SEND (abfd, _bfd_sizeof_headers, (abfd, info)) |
#define bfd_find_nearest_line(abfd, sec, syms, off, file, func, line) \ |
BFD_SEND (abfd, _bfd_find_nearest_line, \ |
(abfd, sec, syms, off, file, func, line)) |
#define bfd_find_nearest_line_discriminator(abfd, sec, syms, off, file, func, \ |
line, disc) \ |
BFD_SEND (abfd, _bfd_find_nearest_line_discriminator, \ |
(abfd, sec, syms, off, file, func, line, disc)) |
#define bfd_find_line(abfd, syms, sym, file, line) \ |
BFD_SEND (abfd, _bfd_find_line, \ |
(abfd, syms, sym, file, line)) |
#define bfd_find_inliner_info(abfd, file, func, line) \ |
BFD_SEND (abfd, _bfd_find_inliner_info, \ |
(abfd, file, func, line)) |
#define bfd_debug_info_start(abfd) \ |
BFD_SEND (abfd, _bfd_debug_info_start, (abfd)) |
#define bfd_debug_info_end(abfd) \ |
BFD_SEND (abfd, _bfd_debug_info_end, (abfd)) |
#define bfd_debug_info_accumulate(abfd, section) \ |
BFD_SEND (abfd, _bfd_debug_info_accumulate, (abfd, section)) |
#define bfd_stat_arch_elt(abfd, stat) \ |
BFD_SEND (abfd, _bfd_stat_arch_elt,(abfd, stat)) |
#define bfd_update_armap_timestamp(abfd) \ |
BFD_SEND (abfd, _bfd_update_armap_timestamp, (abfd)) |
#define bfd_set_arch_mach(abfd, arch, mach)\ |
BFD_SEND ( abfd, _bfd_set_arch_mach, (abfd, arch, mach)) |
#define bfd_relax_section(abfd, section, link_info, again) \ |
BFD_SEND (abfd, _bfd_relax_section, (abfd, section, link_info, again)) |
#define bfd_gc_sections(abfd, link_info) \ |
BFD_SEND (abfd, _bfd_gc_sections, (abfd, link_info)) |
#define bfd_lookup_section_flags(link_info, flag_info, section) \ |
BFD_SEND (abfd, _bfd_lookup_section_flags, (link_info, flag_info, section)) |
#define bfd_merge_sections(abfd, link_info) \ |
BFD_SEND (abfd, _bfd_merge_sections, (abfd, link_info)) |
#define bfd_is_group_section(abfd, sec) \ |
BFD_SEND (abfd, _bfd_is_group_section, (abfd, sec)) |
#define bfd_discard_group(abfd, sec) \ |
BFD_SEND (abfd, _bfd_discard_group, (abfd, sec)) |
#define bfd_link_hash_table_create(abfd) \ |
BFD_SEND (abfd, _bfd_link_hash_table_create, (abfd)) |
#define bfd_link_hash_table_free(abfd, hash) \ |
BFD_SEND (abfd, _bfd_link_hash_table_free, (hash)) |
#define bfd_link_add_symbols(abfd, info) \ |
BFD_SEND (abfd, _bfd_link_add_symbols, (abfd, info)) |
#define bfd_link_just_syms(abfd, sec, info) \ |
BFD_SEND (abfd, _bfd_link_just_syms, (sec, info)) |
#define bfd_final_link(abfd, info) \ |
BFD_SEND (abfd, _bfd_final_link, (abfd, info)) |
#define bfd_free_cached_info(abfd) \ |
BFD_SEND (abfd, _bfd_free_cached_info, (abfd)) |
#define bfd_get_dynamic_symtab_upper_bound(abfd) \ |
BFD_SEND (abfd, _bfd_get_dynamic_symtab_upper_bound, (abfd)) |
#define bfd_print_private_bfd_data(abfd, file)\ |
BFD_SEND (abfd, _bfd_print_private_bfd_data, (abfd, file)) |
#define bfd_canonicalize_dynamic_symtab(abfd, asymbols) \ |
BFD_SEND (abfd, _bfd_canonicalize_dynamic_symtab, (abfd, asymbols)) |
#define bfd_get_synthetic_symtab(abfd, count, syms, dyncount, dynsyms, ret) \ |
BFD_SEND (abfd, _bfd_get_synthetic_symtab, (abfd, count, syms, \ |
dyncount, dynsyms, ret)) |
#define bfd_get_dynamic_reloc_upper_bound(abfd) \ |
BFD_SEND (abfd, _bfd_get_dynamic_reloc_upper_bound, (abfd)) |
#define bfd_canonicalize_dynamic_reloc(abfd, arels, asyms) \ |
BFD_SEND (abfd, _bfd_canonicalize_dynamic_reloc, (abfd, arels, asyms)) |
extern bfd_byte *bfd_get_relocated_section_contents |
(bfd *, struct bfd_link_info *, struct bfd_link_order *, bfd_byte *, |
bfd_boolean, asymbol **); |
bfd_boolean bfd_alt_mach_code (bfd *abfd, int alternative); |
bfd_vma bfd_emul_get_maxpagesize (const char *); |
void bfd_emul_set_maxpagesize (const char *, bfd_vma); |
bfd_vma bfd_emul_get_commonpagesize (const char *); |
void bfd_emul_set_commonpagesize (const char *, bfd_vma); |
char *bfd_demangle (bfd *, const char *, int); |
/* Extracted from archive.c. */ |
symindex bfd_get_next_mapent |
(bfd *abfd, symindex previous, carsym **sym); |
bfd_boolean bfd_set_archive_head (bfd *output, bfd *new_head); |
bfd *bfd_openr_next_archived_file (bfd *archive, bfd *previous); |
/* Extracted from corefile.c. */ |
const char *bfd_core_file_failing_command (bfd *abfd); |
int bfd_core_file_failing_signal (bfd *abfd); |
int bfd_core_file_pid (bfd *abfd); |
bfd_boolean core_file_matches_executable_p |
(bfd *core_bfd, bfd *exec_bfd); |
bfd_boolean generic_core_file_matches_executable_p |
(bfd *core_bfd, bfd *exec_bfd); |
/* Extracted from targets.c. */ |
#define BFD_SEND(bfd, message, arglist) \ |
((*((bfd)->xvec->message)) arglist) |
#ifdef DEBUG_BFD_SEND |
#undef BFD_SEND |
#define BFD_SEND(bfd, message, arglist) \ |
(((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \ |
((*((bfd)->xvec->message)) arglist) : \ |
(bfd_assert (__FILE__,__LINE__), NULL)) |
#endif |
#define BFD_SEND_FMT(bfd, message, arglist) \ |
(((bfd)->xvec->message[(int) ((bfd)->format)]) arglist) |
#ifdef DEBUG_BFD_SEND |
#undef BFD_SEND_FMT |
#define BFD_SEND_FMT(bfd, message, arglist) \ |
(((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \ |
(((bfd)->xvec->message[(int) ((bfd)->format)]) arglist) : \ |
(bfd_assert (__FILE__,__LINE__), NULL)) |
#endif |
enum bfd_flavour |
{ |
bfd_target_unknown_flavour, |
bfd_target_aout_flavour, |
bfd_target_coff_flavour, |
bfd_target_ecoff_flavour, |
bfd_target_xcoff_flavour, |
bfd_target_elf_flavour, |
bfd_target_ieee_flavour, |
bfd_target_nlm_flavour, |
bfd_target_oasys_flavour, |
bfd_target_tekhex_flavour, |
bfd_target_srec_flavour, |
bfd_target_verilog_flavour, |
bfd_target_ihex_flavour, |
bfd_target_som_flavour, |
bfd_target_os9k_flavour, |
bfd_target_versados_flavour, |
bfd_target_msdos_flavour, |
bfd_target_ovax_flavour, |
bfd_target_evax_flavour, |
bfd_target_mmo_flavour, |
bfd_target_mach_o_flavour, |
bfd_target_pef_flavour, |
bfd_target_pef_xlib_flavour, |
bfd_target_sym_flavour |
}; |
enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN }; |
/* Forward declaration. */ |
typedef struct bfd_link_info _bfd_link_info; |
/* Forward declaration. */ |
typedef struct flag_info flag_info; |
typedef struct bfd_target |
{ |
/* Identifies the kind of target, e.g., SunOS4, Ultrix, etc. */ |
char *name; |
/* The "flavour" of a back end is a general indication about |
the contents of a file. */ |
enum bfd_flavour flavour; |
/* The order of bytes within the data area of a file. */ |
enum bfd_endian byteorder; |
/* The order of bytes within the header parts of a file. */ |
enum bfd_endian header_byteorder; |
/* A mask of all the flags which an executable may have set - |
from the set <<BFD_NO_FLAGS>>, <<HAS_RELOC>>, ...<<D_PAGED>>. */ |
flagword object_flags; |
/* A mask of all the flags which a section may have set - from |
the set <<SEC_NO_FLAGS>>, <<SEC_ALLOC>>, ...<<SET_NEVER_LOAD>>. */ |
flagword section_flags; |
/* The character normally found at the front of a symbol. |
(if any), perhaps `_'. */ |
char symbol_leading_char; |
/* The pad character for file names within an archive header. */ |
char ar_pad_char; |
/* The maximum number of characters in an archive header. */ |
unsigned char ar_max_namelen; |
/* How well this target matches, used to select between various |
possible targets when more than one target matches. */ |
unsigned char match_priority; |
/* Entries for byte swapping for data. These are different from the |
other entry points, since they don't take a BFD as the first argument. |
Certain other handlers could do the same. */ |
bfd_uint64_t (*bfd_getx64) (const void *); |
bfd_int64_t (*bfd_getx_signed_64) (const void *); |
void (*bfd_putx64) (bfd_uint64_t, void *); |
bfd_vma (*bfd_getx32) (const void *); |
bfd_signed_vma (*bfd_getx_signed_32) (const void *); |
void (*bfd_putx32) (bfd_vma, void *); |
bfd_vma (*bfd_getx16) (const void *); |
bfd_signed_vma (*bfd_getx_signed_16) (const void *); |
void (*bfd_putx16) (bfd_vma, void *); |
/* Byte swapping for the headers. */ |
bfd_uint64_t (*bfd_h_getx64) (const void *); |
bfd_int64_t (*bfd_h_getx_signed_64) (const void *); |
void (*bfd_h_putx64) (bfd_uint64_t, void *); |
bfd_vma (*bfd_h_getx32) (const void *); |
bfd_signed_vma (*bfd_h_getx_signed_32) (const void *); |
void (*bfd_h_putx32) (bfd_vma, void *); |
bfd_vma (*bfd_h_getx16) (const void *); |
bfd_signed_vma (*bfd_h_getx_signed_16) (const void *); |
void (*bfd_h_putx16) (bfd_vma, void *); |
/* Format dependent routines: these are vectors of entry points |
within the target vector structure, one for each format to check. */ |
/* Check the format of a file being read. Return a <<bfd_target *>> or zero. */ |
const struct bfd_target *(*_bfd_check_format[bfd_type_end]) (bfd *); |
/* Set the format of a file being written. */ |
bfd_boolean (*_bfd_set_format[bfd_type_end]) (bfd *); |
/* Write cached information into a file being written, at <<bfd_close>>. */ |
bfd_boolean (*_bfd_write_contents[bfd_type_end]) (bfd *); |
/* Generic entry points. */ |
#define BFD_JUMP_TABLE_GENERIC(NAME) \ |
NAME##_close_and_cleanup, \ |
NAME##_bfd_free_cached_info, \ |
NAME##_new_section_hook, \ |
NAME##_get_section_contents, \ |
NAME##_get_section_contents_in_window |
/* Called when the BFD is being closed to do any necessary cleanup. */ |
bfd_boolean (*_close_and_cleanup) (bfd *); |
/* Ask the BFD to free all cached information. */ |
bfd_boolean (*_bfd_free_cached_info) (bfd *); |
/* Called when a new section is created. */ |
bfd_boolean (*_new_section_hook) (bfd *, sec_ptr); |
/* Read the contents of a section. */ |
bfd_boolean (*_bfd_get_section_contents) |
(bfd *, sec_ptr, void *, file_ptr, bfd_size_type); |
bfd_boolean (*_bfd_get_section_contents_in_window) |
(bfd *, sec_ptr, bfd_window *, file_ptr, bfd_size_type); |
/* Entry points to copy private data. */ |
#define BFD_JUMP_TABLE_COPY(NAME) \ |
NAME##_bfd_copy_private_bfd_data, \ |
NAME##_bfd_merge_private_bfd_data, \ |
_bfd_generic_init_private_section_data, \ |
NAME##_bfd_copy_private_section_data, \ |
NAME##_bfd_copy_private_symbol_data, \ |
NAME##_bfd_copy_private_header_data, \ |
NAME##_bfd_set_private_flags, \ |
NAME##_bfd_print_private_bfd_data |
/* Called to copy BFD general private data from one object file |
to another. */ |
bfd_boolean (*_bfd_copy_private_bfd_data) (bfd *, bfd *); |
/* Called to merge BFD general private data from one object file |
to a common output file when linking. */ |
bfd_boolean (*_bfd_merge_private_bfd_data) (bfd *, bfd *); |
/* Called to initialize BFD private section data from one object file |
to another. */ |
#define bfd_init_private_section_data(ibfd, isec, obfd, osec, link_info) \ |
BFD_SEND (obfd, _bfd_init_private_section_data, (ibfd, isec, obfd, osec, link_info)) |
bfd_boolean (*_bfd_init_private_section_data) |
(bfd *, sec_ptr, bfd *, sec_ptr, struct bfd_link_info *); |
/* Called to copy BFD private section data from one object file |
to another. */ |
bfd_boolean (*_bfd_copy_private_section_data) |
(bfd *, sec_ptr, bfd *, sec_ptr); |
/* Called to copy BFD private symbol data from one symbol |
to another. */ |
bfd_boolean (*_bfd_copy_private_symbol_data) |
(bfd *, asymbol *, bfd *, asymbol *); |
/* Called to copy BFD private header data from one object file |
to another. */ |
bfd_boolean (*_bfd_copy_private_header_data) |
(bfd *, bfd *); |
/* Called to set private backend flags. */ |
bfd_boolean (*_bfd_set_private_flags) (bfd *, flagword); |
/* Called to print private BFD data. */ |
bfd_boolean (*_bfd_print_private_bfd_data) (bfd *, void *); |
/* Core file entry points. */ |
#define BFD_JUMP_TABLE_CORE(NAME) \ |
NAME##_core_file_failing_command, \ |
NAME##_core_file_failing_signal, \ |
NAME##_core_file_matches_executable_p, \ |
NAME##_core_file_pid |
char * (*_core_file_failing_command) (bfd *); |
int (*_core_file_failing_signal) (bfd *); |
bfd_boolean (*_core_file_matches_executable_p) (bfd *, bfd *); |
int (*_core_file_pid) (bfd *); |
/* Archive entry points. */ |
#define BFD_JUMP_TABLE_ARCHIVE(NAME) \ |
NAME##_slurp_armap, \ |
NAME##_slurp_extended_name_table, \ |
NAME##_construct_extended_name_table, \ |
NAME##_truncate_arname, \ |
NAME##_write_armap, \ |
NAME##_read_ar_hdr, \ |
NAME##_write_ar_hdr, \ |
NAME##_openr_next_archived_file, \ |
NAME##_get_elt_at_index, \ |
NAME##_generic_stat_arch_elt, \ |
NAME##_update_armap_timestamp |
bfd_boolean (*_bfd_slurp_armap) (bfd *); |
bfd_boolean (*_bfd_slurp_extended_name_table) (bfd *); |
bfd_boolean (*_bfd_construct_extended_name_table) |
(bfd *, char **, bfd_size_type *, const char **); |
void (*_bfd_truncate_arname) (bfd *, const char *, char *); |
bfd_boolean (*write_armap) |
(bfd *, unsigned int, struct orl *, unsigned int, int); |
void * (*_bfd_read_ar_hdr_fn) (bfd *); |
bfd_boolean (*_bfd_write_ar_hdr_fn) (bfd *, bfd *); |
bfd * (*openr_next_archived_file) (bfd *, bfd *); |
#define bfd_get_elt_at_index(b,i) BFD_SEND (b, _bfd_get_elt_at_index, (b,i)) |
bfd * (*_bfd_get_elt_at_index) (bfd *, symindex); |
int (*_bfd_stat_arch_elt) (bfd *, struct stat *); |
bfd_boolean (*_bfd_update_armap_timestamp) (bfd *); |
/* Entry points used for symbols. */ |
#define BFD_JUMP_TABLE_SYMBOLS(NAME) \ |
NAME##_get_symtab_upper_bound, \ |
NAME##_canonicalize_symtab, \ |
NAME##_make_empty_symbol, \ |
NAME##_print_symbol, \ |
NAME##_get_symbol_info, \ |
NAME##_bfd_is_local_label_name, \ |
NAME##_bfd_is_target_special_symbol, \ |
NAME##_get_lineno, \ |
NAME##_find_nearest_line, \ |
_bfd_generic_find_nearest_line_discriminator, \ |
_bfd_generic_find_line, \ |
NAME##_find_inliner_info, \ |
NAME##_bfd_make_debug_symbol, \ |
NAME##_read_minisymbols, \ |
NAME##_minisymbol_to_symbol |
long (*_bfd_get_symtab_upper_bound) (bfd *); |
long (*_bfd_canonicalize_symtab) |
(bfd *, struct bfd_symbol **); |
struct bfd_symbol * |
(*_bfd_make_empty_symbol) (bfd *); |
void (*_bfd_print_symbol) |
(bfd *, void *, struct bfd_symbol *, bfd_print_symbol_type); |
#define bfd_print_symbol(b,p,s,e) BFD_SEND (b, _bfd_print_symbol, (b,p,s,e)) |
void (*_bfd_get_symbol_info) |
(bfd *, struct bfd_symbol *, symbol_info *); |
#define bfd_get_symbol_info(b,p,e) BFD_SEND (b, _bfd_get_symbol_info, (b,p,e)) |
bfd_boolean (*_bfd_is_local_label_name) (bfd *, const char *); |
bfd_boolean (*_bfd_is_target_special_symbol) (bfd *, asymbol *); |
alent * (*_get_lineno) (bfd *, struct bfd_symbol *); |
bfd_boolean (*_bfd_find_nearest_line) |
(bfd *, struct bfd_section *, struct bfd_symbol **, bfd_vma, |
const char **, const char **, unsigned int *); |
bfd_boolean (*_bfd_find_nearest_line_discriminator) |
(bfd *, struct bfd_section *, struct bfd_symbol **, bfd_vma, |
const char **, const char **, unsigned int *, unsigned int *); |
bfd_boolean (*_bfd_find_line) |
(bfd *, struct bfd_symbol **, struct bfd_symbol *, |
const char **, unsigned int *); |
bfd_boolean (*_bfd_find_inliner_info) |
(bfd *, const char **, const char **, unsigned int *); |
/* Back-door to allow format-aware applications to create debug symbols |
while using BFD for everything else. Currently used by the assembler |
when creating COFF files. */ |
asymbol * (*_bfd_make_debug_symbol) |
(bfd *, void *, unsigned long size); |
#define bfd_read_minisymbols(b, d, m, s) \ |
BFD_SEND (b, _read_minisymbols, (b, d, m, s)) |
long (*_read_minisymbols) |
(bfd *, bfd_boolean, void **, unsigned int *); |
#define bfd_minisymbol_to_symbol(b, d, m, f) \ |
BFD_SEND (b, _minisymbol_to_symbol, (b, d, m, f)) |
asymbol * (*_minisymbol_to_symbol) |
(bfd *, bfd_boolean, const void *, asymbol *); |
/* Routines for relocs. */ |
#define BFD_JUMP_TABLE_RELOCS(NAME) \ |
NAME##_get_reloc_upper_bound, \ |
NAME##_canonicalize_reloc, \ |
NAME##_bfd_reloc_type_lookup, \ |
NAME##_bfd_reloc_name_lookup |
long (*_get_reloc_upper_bound) (bfd *, sec_ptr); |
long (*_bfd_canonicalize_reloc) |
(bfd *, sec_ptr, arelent **, struct bfd_symbol **); |
/* See documentation on reloc types. */ |
reloc_howto_type * |
(*reloc_type_lookup) (bfd *, bfd_reloc_code_real_type); |
reloc_howto_type * |
(*reloc_name_lookup) (bfd *, const char *); |
/* Routines used when writing an object file. */ |
#define BFD_JUMP_TABLE_WRITE(NAME) \ |
NAME##_set_arch_mach, \ |
NAME##_set_section_contents |
bfd_boolean (*_bfd_set_arch_mach) |
(bfd *, enum bfd_architecture, unsigned long); |
bfd_boolean (*_bfd_set_section_contents) |
(bfd *, sec_ptr, const void *, file_ptr, bfd_size_type); |
/* Routines used by the linker. */ |
#define BFD_JUMP_TABLE_LINK(NAME) \ |
NAME##_sizeof_headers, \ |
NAME##_bfd_get_relocated_section_contents, \ |
NAME##_bfd_relax_section, \ |
NAME##_bfd_link_hash_table_create, \ |
NAME##_bfd_link_hash_table_free, \ |
NAME##_bfd_link_add_symbols, \ |
NAME##_bfd_link_just_syms, \ |
NAME##_bfd_copy_link_hash_symbol_type, \ |
NAME##_bfd_final_link, \ |
NAME##_bfd_link_split_section, \ |
NAME##_bfd_gc_sections, \ |
NAME##_bfd_lookup_section_flags, \ |
NAME##_bfd_merge_sections, \ |
NAME##_bfd_is_group_section, \ |
NAME##_bfd_discard_group, \ |
NAME##_section_already_linked, \ |
NAME##_bfd_define_common_symbol |
int (*_bfd_sizeof_headers) (bfd *, struct bfd_link_info *); |
bfd_byte * (*_bfd_get_relocated_section_contents) |
(bfd *, struct bfd_link_info *, struct bfd_link_order *, |
bfd_byte *, bfd_boolean, struct bfd_symbol **); |
bfd_boolean (*_bfd_relax_section) |
(bfd *, struct bfd_section *, struct bfd_link_info *, bfd_boolean *); |
/* Create a hash table for the linker. Different backends store |
different information in this table. */ |
struct bfd_link_hash_table * |
(*_bfd_link_hash_table_create) (bfd *); |
/* Release the memory associated with the linker hash table. */ |
void (*_bfd_link_hash_table_free) (struct bfd_link_hash_table *); |
/* Add symbols from this object file into the hash table. */ |
bfd_boolean (*_bfd_link_add_symbols) (bfd *, struct bfd_link_info *); |
/* Indicate that we are only retrieving symbol values from this section. */ |
void (*_bfd_link_just_syms) (asection *, struct bfd_link_info *); |
/* Copy the symbol type of a linker hash table entry. */ |
#define bfd_copy_link_hash_symbol_type(b, t, f) \ |
BFD_SEND (b, _bfd_copy_link_hash_symbol_type, (b, t, f)) |
void (*_bfd_copy_link_hash_symbol_type) |
(bfd *, struct bfd_link_hash_entry *, struct bfd_link_hash_entry *); |
/* Do a link based on the link_order structures attached to each |
section of the BFD. */ |
bfd_boolean (*_bfd_final_link) (bfd *, struct bfd_link_info *); |
/* Should this section be split up into smaller pieces during linking. */ |
bfd_boolean (*_bfd_link_split_section) (bfd *, struct bfd_section *); |
/* Remove sections that are not referenced from the output. */ |
bfd_boolean (*_bfd_gc_sections) (bfd *, struct bfd_link_info *); |
/* Sets the bitmask of allowed and disallowed section flags. */ |
bfd_boolean (*_bfd_lookup_section_flags) (struct bfd_link_info *, |
struct flag_info *, |
asection *); |
/* Attempt to merge SEC_MERGE sections. */ |
bfd_boolean (*_bfd_merge_sections) (bfd *, struct bfd_link_info *); |
/* Is this section a member of a group? */ |
bfd_boolean (*_bfd_is_group_section) (bfd *, const struct bfd_section *); |
/* Discard members of a group. */ |
bfd_boolean (*_bfd_discard_group) (bfd *, struct bfd_section *); |
/* Check if SEC has been already linked during a reloceatable or |
final link. */ |
bfd_boolean (*_section_already_linked) (bfd *, asection *, |
struct bfd_link_info *); |
/* Define a common symbol. */ |
bfd_boolean (*_bfd_define_common_symbol) (bfd *, struct bfd_link_info *, |
struct bfd_link_hash_entry *); |
/* Routines to handle dynamic symbols and relocs. */ |
#define BFD_JUMP_TABLE_DYNAMIC(NAME) \ |
NAME##_get_dynamic_symtab_upper_bound, \ |
NAME##_canonicalize_dynamic_symtab, \ |
NAME##_get_synthetic_symtab, \ |
NAME##_get_dynamic_reloc_upper_bound, \ |
NAME##_canonicalize_dynamic_reloc |
/* Get the amount of memory required to hold the dynamic symbols. */ |
long (*_bfd_get_dynamic_symtab_upper_bound) (bfd *); |
/* Read in the dynamic symbols. */ |
long (*_bfd_canonicalize_dynamic_symtab) |
(bfd *, struct bfd_symbol **); |
/* Create synthetized symbols. */ |
long (*_bfd_get_synthetic_symtab) |
(bfd *, long, struct bfd_symbol **, long, struct bfd_symbol **, |
struct bfd_symbol **); |
/* Get the amount of memory required to hold the dynamic relocs. */ |
long (*_bfd_get_dynamic_reloc_upper_bound) (bfd *); |
/* Read in the dynamic relocs. */ |
long (*_bfd_canonicalize_dynamic_reloc) |
(bfd *, arelent **, struct bfd_symbol **); |
/* Opposite endian version of this target. */ |
const struct bfd_target * alternative_target; |
/* Data for use by back-end routines, which isn't |
generic enough to belong in this structure. */ |
const void *backend_data; |
} bfd_target; |
bfd_boolean bfd_set_default_target (const char *name); |
const bfd_target *bfd_find_target (const char *target_name, bfd *abfd); |
const bfd_target *bfd_get_target_info (const char *target_name, |
bfd *abfd, |
bfd_boolean *is_bigendian, |
int *underscoring, |
const char **def_target_arch); |
const char ** bfd_target_list (void); |
const bfd_target *bfd_search_for_target |
(int (*search_func) (const bfd_target *, void *), |
void *); |
/* Extracted from format.c. */ |
bfd_boolean bfd_check_format (bfd *abfd, bfd_format format); |
bfd_boolean bfd_check_format_matches |
(bfd *abfd, bfd_format format, char ***matching); |
bfd_boolean bfd_set_format (bfd *abfd, bfd_format format); |
const char *bfd_format_string (bfd_format format); |
/* Extracted from linker.c. */ |
bfd_boolean bfd_link_split_section (bfd *abfd, asection *sec); |
#define bfd_link_split_section(abfd, sec) \ |
BFD_SEND (abfd, _bfd_link_split_section, (abfd, sec)) |
bfd_boolean bfd_section_already_linked (bfd *abfd, |
asection *sec, |
struct bfd_link_info *info); |
#define bfd_section_already_linked(abfd, sec, info) \ |
BFD_SEND (abfd, _section_already_linked, (abfd, sec, info)) |
bfd_boolean bfd_generic_define_common_symbol |
(bfd *output_bfd, struct bfd_link_info *info, |
struct bfd_link_hash_entry *h); |
#define bfd_define_common_symbol(output_bfd, info, h) \ |
BFD_SEND (output_bfd, _bfd_define_common_symbol, (output_bfd, info, h)) |
struct bfd_elf_version_tree * bfd_find_version_for_sym |
(struct bfd_elf_version_tree *verdefs, |
const char *sym_name, bfd_boolean *hide); |
bfd_boolean bfd_hide_sym_by_version |
(struct bfd_elf_version_tree *verdefs, const char *sym_name); |
/* Extracted from simple.c. */ |
bfd_byte *bfd_simple_get_relocated_section_contents |
(bfd *abfd, asection *sec, bfd_byte *outbuf, asymbol **symbol_table); |
/* Extracted from compress.c. */ |
bfd_boolean bfd_compress_section_contents |
(bfd *abfd, asection *section, bfd_byte *uncompressed_buffer, |
bfd_size_type uncompressed_size); |
bfd_boolean bfd_get_full_section_contents |
(bfd *abfd, asection *section, bfd_byte **ptr); |
void bfd_cache_section_contents |
(asection *sec, void *contents); |
bfd_boolean bfd_is_section_compressed |
(bfd *abfd, asection *section); |
bfd_boolean bfd_init_section_decompress_status |
(bfd *abfd, asection *section); |
bfd_boolean bfd_init_section_compress_status |
(bfd *abfd, asection *section); |
#ifdef __cplusplus |
} |
#endif |
#endif |
/contrib/toolchain/binutils/bfd/bfd.c |
---|
0,0 → 1,1917 |
/* Generic BFD library interface and support routines. |
Copyright 1990-2013 Free Software Foundation, Inc. |
Written by Cygnus Support. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* |
INODE |
typedef bfd, Error reporting, BFD front end, BFD front end |
SECTION |
<<typedef bfd>> |
A BFD has type <<bfd>>; objects of this type are the |
cornerstone of any application using BFD. Using BFD |
consists of making references though the BFD and to data in the BFD. |
Here is the structure that defines the type <<bfd>>. It |
contains the major data about the file and pointers |
to the rest of the data. |
CODE_FRAGMENT |
. |
.enum bfd_direction |
. { |
. no_direction = 0, |
. read_direction = 1, |
. write_direction = 2, |
. both_direction = 3 |
. }; |
. |
.struct bfd |
.{ |
. {* A unique identifier of the BFD *} |
. unsigned int id; |
. |
. {* The filename the application opened the BFD with. *} |
. const char *filename; |
. |
. {* A pointer to the target jump table. *} |
. const struct bfd_target *xvec; |
. |
. {* The IOSTREAM, and corresponding IO vector that provide access |
. to the file backing the BFD. *} |
. void *iostream; |
. const struct bfd_iovec *iovec; |
. |
. {* The caching routines use these to maintain a |
. least-recently-used list of BFDs. *} |
. struct bfd *lru_prev, *lru_next; |
. |
. {* When a file is closed by the caching routines, BFD retains |
. state information on the file here... *} |
. ufile_ptr where; |
. |
. {* File modified time, if mtime_set is TRUE. *} |
. long mtime; |
. |
. {* Reserved for an unimplemented file locking extension. *} |
. int ifd; |
. |
. {* The format which belongs to the BFD. (object, core, etc.) *} |
. bfd_format format; |
. |
. {* The direction with which the BFD was opened. *} |
. enum bfd_direction direction; |
. |
. {* Format_specific flags. *} |
. flagword flags; |
. |
. {* Values that may appear in the flags field of a BFD. These also |
. appear in the object_flags field of the bfd_target structure, where |
. they indicate the set of flags used by that backend (not all flags |
. are meaningful for all object file formats) (FIXME: at the moment, |
. the object_flags values have mostly just been copied from backend |
. to another, and are not necessarily correct). *} |
. |
.#define BFD_NO_FLAGS 0x00 |
. |
. {* BFD contains relocation entries. *} |
.#define HAS_RELOC 0x01 |
. |
. {* BFD is directly executable. *} |
.#define EXEC_P 0x02 |
. |
. {* BFD has line number information (basically used for F_LNNO in a |
. COFF header). *} |
.#define HAS_LINENO 0x04 |
. |
. {* BFD has debugging information. *} |
.#define HAS_DEBUG 0x08 |
. |
. {* BFD has symbols. *} |
.#define HAS_SYMS 0x10 |
. |
. {* BFD has local symbols (basically used for F_LSYMS in a COFF |
. header). *} |
.#define HAS_LOCALS 0x20 |
. |
. {* BFD is a dynamic object. *} |
.#define DYNAMIC 0x40 |
. |
. {* Text section is write protected (if D_PAGED is not set, this is |
. like an a.out NMAGIC file) (the linker sets this by default, but |
. clears it for -r or -N). *} |
.#define WP_TEXT 0x80 |
. |
. {* BFD is dynamically paged (this is like an a.out ZMAGIC file) (the |
. linker sets this by default, but clears it for -r or -n or -N). *} |
.#define D_PAGED 0x100 |
. |
. {* BFD is relaxable (this means that bfd_relax_section may be able to |
. do something) (sometimes bfd_relax_section can do something even if |
. this is not set). *} |
.#define BFD_IS_RELAXABLE 0x200 |
. |
. {* This may be set before writing out a BFD to request using a |
. traditional format. For example, this is used to request that when |
. writing out an a.out object the symbols not be hashed to eliminate |
. duplicates. *} |
.#define BFD_TRADITIONAL_FORMAT 0x400 |
. |
. {* This flag indicates that the BFD contents are actually cached |
. in memory. If this is set, iostream points to a bfd_in_memory |
. struct. *} |
.#define BFD_IN_MEMORY 0x800 |
. |
. {* The sections in this BFD specify a memory page. *} |
.#define HAS_LOAD_PAGE 0x1000 |
. |
. {* This BFD has been created by the linker and doesn't correspond |
. to any input file. *} |
.#define BFD_LINKER_CREATED 0x2000 |
. |
. {* This may be set before writing out a BFD to request that it |
. be written using values for UIDs, GIDs, timestamps, etc. that |
. will be consistent from run to run. *} |
.#define BFD_DETERMINISTIC_OUTPUT 0x4000 |
. |
. {* Compress sections in this BFD. *} |
.#define BFD_COMPRESS 0x8000 |
. |
. {* Decompress sections in this BFD. *} |
.#define BFD_DECOMPRESS 0x10000 |
. |
. {* BFD is a dummy, for plugins. *} |
.#define BFD_PLUGIN 0x20000 |
. |
. {* Flags bits to be saved in bfd_preserve_save. *} |
.#define BFD_FLAGS_SAVED \ |
. (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_PLUGIN) |
. |
. {* Flags bits which are for BFD use only. *} |
.#define BFD_FLAGS_FOR_BFD_USE_MASK \ |
. (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \ |
. | BFD_PLUGIN | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT) |
. |
. {* Currently my_archive is tested before adding origin to |
. anything. I believe that this can become always an add of |
. origin, with origin set to 0 for non archive files. *} |
. ufile_ptr origin; |
. |
. {* The origin in the archive of the proxy entry. This will |
. normally be the same as origin, except for thin archives, |
. when it will contain the current offset of the proxy in the |
. thin archive rather than the offset of the bfd in its actual |
. container. *} |
. ufile_ptr proxy_origin; |
. |
. {* A hash table for section names. *} |
. struct bfd_hash_table section_htab; |
. |
. {* Pointer to linked list of sections. *} |
. struct bfd_section *sections; |
. |
. {* The last section on the section list. *} |
. struct bfd_section *section_last; |
. |
. {* The number of sections. *} |
. unsigned int section_count; |
. |
. {* Stuff only useful for object files: |
. The start address. *} |
. bfd_vma start_address; |
. |
. {* Used for input and output. *} |
. unsigned int symcount; |
. |
. {* Symbol table for output BFD (with symcount entries). |
. Also used by the linker to cache input BFD symbols. *} |
. struct bfd_symbol **outsymbols; |
. |
. {* Used for slurped dynamic symbol tables. *} |
. unsigned int dynsymcount; |
. |
. {* Pointer to structure which contains architecture information. *} |
. const struct bfd_arch_info *arch_info; |
. |
. {* Stuff only useful for archives. *} |
. void *arelt_data; |
. struct bfd *my_archive; {* The containing archive BFD. *} |
. struct bfd *archive_next; {* The next BFD in the archive. *} |
. struct bfd *archive_head; {* The first BFD in the archive. *} |
. struct bfd *nested_archives; {* List of nested archive in a flattened |
. thin archive. *} |
. |
. {* A chain of BFD structures involved in a link. *} |
. struct bfd *link_next; |
. |
. {* A field used by _bfd_generic_link_add_archive_symbols. This will |
. be used only for archive elements. *} |
. int archive_pass; |
. |
. {* Used by the back end to hold private data. *} |
. union |
. { |
. struct aout_data_struct *aout_data; |
. struct artdata *aout_ar_data; |
. struct _oasys_data *oasys_obj_data; |
. struct _oasys_ar_data *oasys_ar_data; |
. struct coff_tdata *coff_obj_data; |
. struct pe_tdata *pe_obj_data; |
. struct xcoff_tdata *xcoff_obj_data; |
. struct ecoff_tdata *ecoff_obj_data; |
. struct ieee_data_struct *ieee_data; |
. struct ieee_ar_data_struct *ieee_ar_data; |
. struct srec_data_struct *srec_data; |
. struct verilog_data_struct *verilog_data; |
. struct ihex_data_struct *ihex_data; |
. struct tekhex_data_struct *tekhex_data; |
. struct elf_obj_tdata *elf_obj_data; |
. struct nlm_obj_tdata *nlm_obj_data; |
. struct bout_data_struct *bout_data; |
. struct mmo_data_struct *mmo_data; |
. struct sun_core_struct *sun_core_data; |
. struct sco5_core_struct *sco5_core_data; |
. struct trad_core_struct *trad_core_data; |
. struct som_data_struct *som_data; |
. struct hpux_core_struct *hpux_core_data; |
. struct hppabsd_core_struct *hppabsd_core_data; |
. struct sgi_core_struct *sgi_core_data; |
. struct lynx_core_struct *lynx_core_data; |
. struct osf_core_struct *osf_core_data; |
. struct cisco_core_struct *cisco_core_data; |
. struct versados_data_struct *versados_data; |
. struct netbsd_core_struct *netbsd_core_data; |
. struct mach_o_data_struct *mach_o_data; |
. struct mach_o_fat_data_struct *mach_o_fat_data; |
. struct plugin_data_struct *plugin_data; |
. struct bfd_pef_data_struct *pef_data; |
. struct bfd_pef_xlib_data_struct *pef_xlib_data; |
. struct bfd_sym_data_struct *sym_data; |
. void *any; |
. } |
. tdata; |
. |
. {* Used by the application to hold private data. *} |
. void *usrdata; |
. |
. {* Where all the allocated stuff under this BFD goes. This is a |
. struct objalloc *, but we use void * to avoid requiring the inclusion |
. of objalloc.h. *} |
. void *memory; |
. |
. {* Is the file descriptor being cached? That is, can it be closed as |
. needed, and re-opened when accessed later? *} |
. unsigned int cacheable : 1; |
. |
. {* Marks whether there was a default target specified when the |
. BFD was opened. This is used to select which matching algorithm |
. to use to choose the back end. *} |
. unsigned int target_defaulted : 1; |
. |
. {* ... and here: (``once'' means at least once). *} |
. unsigned int opened_once : 1; |
. |
. {* Set if we have a locally maintained mtime value, rather than |
. getting it from the file each time. *} |
. unsigned int mtime_set : 1; |
. |
. {* Flag set if symbols from this BFD should not be exported. *} |
. unsigned int no_export : 1; |
. |
. {* Remember when output has begun, to stop strange things |
. from happening. *} |
. unsigned int output_has_begun : 1; |
. |
. {* Have archive map. *} |
. unsigned int has_armap : 1; |
. |
. {* Set if this is a thin archive. *} |
. unsigned int is_thin_archive : 1; |
. |
. {* Set if only required symbols should be added in the link hash table for |
. this object. Used by VMS linkers. *} |
. unsigned int selective_search : 1; |
.}; |
. |
*/ |
#include "sysdep.h" |
#include <stdarg.h> |
#include "bfd.h" |
#include "bfdver.h" |
#include "libiberty.h" |
#include "demangle.h" |
#include "safe-ctype.h" |
#include "bfdlink.h" |
#include "libbfd.h" |
#include "coff/internal.h" |
#include "coff/sym.h" |
#include "libcoff.h" |
#include "libecoff.h" |
#undef obj_symbols |
#include "elf-bfd.h" |
#ifndef EXIT_FAILURE |
#define EXIT_FAILURE 1 |
#endif |
/* provide storage for subsystem, stack and heap data which may have been |
passed in on the command line. Ld puts this data into a bfd_link_info |
struct which ultimately gets passed in to the bfd. When it arrives, copy |
it to the following struct so that the data will be available in coffcode.h |
where it is needed. The typedef's used are defined in bfd.h */ |
/* |
INODE |
Error reporting, Miscellaneous, typedef bfd, BFD front end |
SECTION |
Error reporting |
Most BFD functions return nonzero on success (check their |
individual documentation for precise semantics). On an error, |
they call <<bfd_set_error>> to set an error condition that callers |
can check by calling <<bfd_get_error>>. |
If that returns <<bfd_error_system_call>>, then check |
<<errno>>. |
The easiest way to report a BFD error to the user is to |
use <<bfd_perror>>. |
SUBSECTION |
Type <<bfd_error_type>> |
The values returned by <<bfd_get_error>> are defined by the |
enumerated type <<bfd_error_type>>. |
CODE_FRAGMENT |
. |
.typedef enum bfd_error |
.{ |
. bfd_error_no_error = 0, |
. bfd_error_system_call, |
. bfd_error_invalid_target, |
. bfd_error_wrong_format, |
. bfd_error_wrong_object_format, |
. bfd_error_invalid_operation, |
. bfd_error_no_memory, |
. bfd_error_no_symbols, |
. bfd_error_no_armap, |
. bfd_error_no_more_archived_files, |
. bfd_error_malformed_archive, |
. bfd_error_missing_dso, |
. bfd_error_file_not_recognized, |
. bfd_error_file_ambiguously_recognized, |
. bfd_error_no_contents, |
. bfd_error_nonrepresentable_section, |
. bfd_error_no_debug_section, |
. bfd_error_bad_value, |
. bfd_error_file_truncated, |
. bfd_error_file_too_big, |
. bfd_error_on_input, |
. bfd_error_invalid_error_code |
.} |
.bfd_error_type; |
. |
*/ |
static bfd_error_type bfd_error = bfd_error_no_error; |
static bfd *input_bfd = NULL; |
static bfd_error_type input_error = bfd_error_no_error; |
const char *const bfd_errmsgs[] = |
{ |
N_("No error"), |
N_("System call error"), |
N_("Invalid bfd target"), |
N_("File in wrong format"), |
N_("Archive object file in wrong format"), |
N_("Invalid operation"), |
N_("Memory exhausted"), |
N_("No symbols"), |
N_("Archive has no index; run ranlib to add one"), |
N_("No more archived files"), |
N_("Malformed archive"), |
N_("DSO missing from command line"), |
N_("File format not recognized"), |
N_("File format is ambiguous"), |
N_("Section has no contents"), |
N_("Nonrepresentable section on output"), |
N_("Symbol needs debug section which does not exist"), |
N_("Bad value"), |
N_("File truncated"), |
N_("File too big"), |
N_("Error reading %s: %s"), |
N_("#<Invalid error code>") |
}; |
/* |
FUNCTION |
bfd_get_error |
SYNOPSIS |
bfd_error_type bfd_get_error (void); |
DESCRIPTION |
Return the current BFD error condition. |
*/ |
bfd_error_type |
bfd_get_error (void) |
{ |
return bfd_error; |
} |
/* |
FUNCTION |
bfd_set_error |
SYNOPSIS |
void bfd_set_error (bfd_error_type error_tag, ...); |
DESCRIPTION |
Set the BFD error condition to be @var{error_tag}. |
If @var{error_tag} is bfd_error_on_input, then this function |
takes two more parameters, the input bfd where the error |
occurred, and the bfd_error_type error. |
*/ |
void |
bfd_set_error (bfd_error_type error_tag, ...) |
{ |
bfd_error = error_tag; |
if (error_tag == bfd_error_on_input) |
{ |
/* This is an error that occurred during bfd_close when |
writing an archive, but on one of the input files. */ |
va_list ap; |
va_start (ap, error_tag); |
input_bfd = va_arg (ap, bfd *); |
input_error = (bfd_error_type) va_arg (ap, int); |
if (input_error >= bfd_error_on_input) |
abort (); |
va_end (ap); |
} |
} |
/* |
FUNCTION |
bfd_errmsg |
SYNOPSIS |
const char *bfd_errmsg (bfd_error_type error_tag); |
DESCRIPTION |
Return a string describing the error @var{error_tag}, or |
the system error if @var{error_tag} is <<bfd_error_system_call>>. |
*/ |
const char * |
bfd_errmsg (bfd_error_type error_tag) |
{ |
#ifndef errno |
extern int errno; |
#endif |
if (error_tag == bfd_error_on_input) |
{ |
char *buf; |
const char *msg = bfd_errmsg (input_error); |
if (asprintf (&buf, _(bfd_errmsgs [error_tag]), input_bfd->filename, msg) |
!= -1) |
return buf; |
/* Ick, what to do on out of memory? */ |
return msg; |
} |
if (error_tag == bfd_error_system_call) |
return xstrerror (errno); |
if (error_tag > bfd_error_invalid_error_code) |
error_tag = bfd_error_invalid_error_code; /* sanity check */ |
return _(bfd_errmsgs [error_tag]); |
} |
/* |
FUNCTION |
bfd_perror |
SYNOPSIS |
void bfd_perror (const char *message); |
DESCRIPTION |
Print to the standard error stream a string describing the |
last BFD error that occurred, or the last system error if |
the last BFD error was a system call failure. If @var{message} |
is non-NULL and non-empty, the error string printed is preceded |
by @var{message}, a colon, and a space. It is followed by a newline. |
*/ |
void |
bfd_perror (const char *message) |
{ |
fflush (stdout); |
if (message == NULL || *message == '\0') |
fprintf (stderr, "%s\n", bfd_errmsg (bfd_get_error ())); |
else |
fprintf (stderr, "%s: %s\n", message, bfd_errmsg (bfd_get_error ())); |
fflush (stderr); |
} |
/* |
SUBSECTION |
BFD error handler |
Some BFD functions want to print messages describing the |
problem. They call a BFD error handler function. This |
function may be overridden by the program. |
The BFD error handler acts like printf. |
CODE_FRAGMENT |
. |
.typedef void (*bfd_error_handler_type) (const char *, ...); |
. |
*/ |
/* The program name used when printing BFD error messages. */ |
static const char *_bfd_error_program_name; |
/* This is the default routine to handle BFD error messages. |
Like fprintf (stderr, ...), but also handles some extra format specifiers. |
%A section name from section. For group components, print group name too. |
%B file name from bfd. For archive components, prints archive too. |
Note - because these two extra format specifiers require special handling |
they are scanned for and processed in this function, before calling |
vfprintf. This means that the *arguments* for these format specifiers |
must be the first ones in the variable argument list, regardless of where |
the specifiers appear in the format string. Thus for example calling |
this function with a format string of: |
"blah %s blah %A blah %d blah %B" |
would involve passing the arguments as: |
"blah %s blah %A blah %d blah %B", |
asection_for_the_%A, |
bfd_for_the_%B, |
string_for_the_%s, |
integer_for_the_%d); |
*/ |
void |
_bfd_default_error_handler (const char *fmt, ...) |
{ |
va_list ap; |
char *bufp; |
const char *new_fmt, *p; |
size_t avail = 1000; |
char buf[1000]; |
/* PR 4992: Don't interrupt output being sent to stdout. */ |
fflush (stdout); |
if (_bfd_error_program_name != NULL) |
fprintf (stderr, "%s: ", _bfd_error_program_name); |
else |
fprintf (stderr, "BFD: "); |
va_start (ap, fmt); |
new_fmt = fmt; |
bufp = buf; |
/* Reserve enough space for the existing format string. */ |
avail -= strlen (fmt) + 1; |
if (avail > 1000) |
_exit (EXIT_FAILURE); |
p = fmt; |
while (1) |
{ |
char *q; |
size_t len, extra, trim; |
p = strchr (p, '%'); |
if (p == NULL || p[1] == '\0') |
{ |
if (new_fmt == buf) |
{ |
len = strlen (fmt); |
memcpy (bufp, fmt, len + 1); |
} |
break; |
} |
if (p[1] == 'A' || p[1] == 'B') |
{ |
len = p - fmt; |
memcpy (bufp, fmt, len); |
bufp += len; |
fmt = p + 2; |
new_fmt = buf; |
/* If we run out of space, tough, you lose your ridiculously |
long file or section name. It's not safe to try to alloc |
memory here; We might be printing an out of memory message. */ |
if (avail == 0) |
{ |
*bufp++ = '*'; |
*bufp++ = '*'; |
*bufp = '\0'; |
} |
else |
{ |
if (p[1] == 'B') |
{ |
bfd *abfd = va_arg (ap, bfd *); |
if (abfd == NULL) |
/* Invoking %B with a null bfd pointer is an internal error. */ |
abort (); |
else if (abfd->my_archive) |
snprintf (bufp, avail, "%s(%s)", |
abfd->my_archive->filename, abfd->filename); |
else |
snprintf (bufp, avail, "%s", abfd->filename); |
} |
else |
{ |
asection *sec = va_arg (ap, asection *); |
bfd *abfd; |
const char *group = NULL; |
struct coff_comdat_info *ci; |
if (sec == NULL) |
/* Invoking %A with a null section pointer is an internal error. */ |
abort (); |
abfd = sec->owner; |
if (abfd != NULL |
&& bfd_get_flavour (abfd) == bfd_target_elf_flavour |
&& elf_next_in_group (sec) != NULL |
&& (sec->flags & SEC_GROUP) == 0) |
group = elf_group_name (sec); |
else if (abfd != NULL |
&& bfd_get_flavour (abfd) == bfd_target_coff_flavour |
&& (ci = bfd_coff_get_comdat_section (sec->owner, |
sec)) != NULL) |
group = ci->name; |
if (group != NULL) |
snprintf (bufp, avail, "%s[%s]", sec->name, group); |
else |
snprintf (bufp, avail, "%s", sec->name); |
} |
len = strlen (bufp); |
avail = avail - len + 2; |
/* We need to replace any '%' we printed by "%%". |
First count how many. */ |
q = bufp; |
bufp += len; |
extra = 0; |
while ((q = strchr (q, '%')) != NULL) |
{ |
++q; |
++extra; |
} |
/* If there isn't room, trim off the end of the string. */ |
q = bufp; |
bufp += extra; |
if (extra > avail) |
{ |
trim = extra - avail; |
bufp -= trim; |
do |
{ |
if (*--q == '%') |
--extra; |
} |
while (--trim != 0); |
*q = '\0'; |
avail = extra; |
} |
avail -= extra; |
/* Now double all '%' chars, shuffling the string as we go. */ |
while (extra != 0) |
{ |
while ((q[extra] = *q) != '%') |
--q; |
q[--extra] = '%'; |
--q; |
} |
} |
} |
p = p + 2; |
} |
vfprintf (stderr, new_fmt, ap); |
va_end (ap); |
/* On AIX, putc is implemented as a macro that triggers a -Wunused-value |
warning, so use the fputc function to avoid it. */ |
fputc ('\n', stderr); |
fflush (stderr); |
} |
/* This is a function pointer to the routine which should handle BFD |
error messages. It is called when a BFD routine encounters an |
error for which it wants to print a message. Going through a |
function pointer permits a program linked against BFD to intercept |
the messages and deal with them itself. */ |
bfd_error_handler_type _bfd_error_handler = _bfd_default_error_handler; |
/* |
FUNCTION |
bfd_set_error_handler |
SYNOPSIS |
bfd_error_handler_type bfd_set_error_handler (bfd_error_handler_type); |
DESCRIPTION |
Set the BFD error handler function. Returns the previous |
function. |
*/ |
bfd_error_handler_type |
bfd_set_error_handler (bfd_error_handler_type pnew) |
{ |
bfd_error_handler_type pold; |
pold = _bfd_error_handler; |
_bfd_error_handler = pnew; |
return pold; |
} |
/* |
FUNCTION |
bfd_set_error_program_name |
SYNOPSIS |
void bfd_set_error_program_name (const char *); |
DESCRIPTION |
Set the program name to use when printing a BFD error. This |
is printed before the error message followed by a colon and |
space. The string must not be changed after it is passed to |
this function. |
*/ |
void |
bfd_set_error_program_name (const char *name) |
{ |
_bfd_error_program_name = name; |
} |
/* |
FUNCTION |
bfd_get_error_handler |
SYNOPSIS |
bfd_error_handler_type bfd_get_error_handler (void); |
DESCRIPTION |
Return the BFD error handler function. |
*/ |
bfd_error_handler_type |
bfd_get_error_handler (void) |
{ |
return _bfd_error_handler; |
} |
/* |
SUBSECTION |
BFD assert handler |
If BFD finds an internal inconsistency, the bfd assert |
handler is called with information on the BFD version, BFD |
source file and line. If this happens, most programs linked |
against BFD are expected to want to exit with an error, or mark |
the current BFD operation as failed, so it is recommended to |
override the default handler, which just calls |
_bfd_error_handler and continues. |
CODE_FRAGMENT |
. |
.typedef void (*bfd_assert_handler_type) (const char *bfd_formatmsg, |
. const char *bfd_version, |
. const char *bfd_file, |
. int bfd_line); |
. |
*/ |
/* Note the use of bfd_ prefix on the parameter names above: we want to |
show which one is the message and which is the version by naming the |
parameters, but avoid polluting the program-using-bfd namespace as |
the typedef is visible in the exported headers that the program |
includes. Below, it's just for consistency. */ |
static void |
_bfd_default_assert_handler (const char *bfd_formatmsg, |
const char *bfd_version, |
const char *bfd_file, |
int bfd_line) |
{ |
(*_bfd_error_handler) (bfd_formatmsg, bfd_version, bfd_file, bfd_line); |
} |
/* Similar to _bfd_error_handler, a program can decide to exit on an |
internal BFD error. We use a non-variadic type to simplify passing |
on parameters to other functions, e.g. _bfd_error_handler. */ |
bfd_assert_handler_type _bfd_assert_handler = _bfd_default_assert_handler; |
/* |
FUNCTION |
bfd_set_assert_handler |
SYNOPSIS |
bfd_assert_handler_type bfd_set_assert_handler (bfd_assert_handler_type); |
DESCRIPTION |
Set the BFD assert handler function. Returns the previous |
function. |
*/ |
bfd_assert_handler_type |
bfd_set_assert_handler (bfd_assert_handler_type pnew) |
{ |
bfd_assert_handler_type pold; |
pold = _bfd_assert_handler; |
_bfd_assert_handler = pnew; |
return pold; |
} |
/* |
FUNCTION |
bfd_get_assert_handler |
SYNOPSIS |
bfd_assert_handler_type bfd_get_assert_handler (void); |
DESCRIPTION |
Return the BFD assert handler function. |
*/ |
bfd_assert_handler_type |
bfd_get_assert_handler (void) |
{ |
return _bfd_assert_handler; |
} |
/* |
INODE |
Miscellaneous, Memory Usage, Error reporting, BFD front end |
SECTION |
Miscellaneous |
SUBSECTION |
Miscellaneous functions |
*/ |
/* |
FUNCTION |
bfd_get_reloc_upper_bound |
SYNOPSIS |
long bfd_get_reloc_upper_bound (bfd *abfd, asection *sect); |
DESCRIPTION |
Return the number of bytes required to store the |
relocation information associated with section @var{sect} |
attached to bfd @var{abfd}. If an error occurs, return -1. |
*/ |
long |
bfd_get_reloc_upper_bound (bfd *abfd, sec_ptr asect) |
{ |
if (abfd->format != bfd_object) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return -1; |
} |
return BFD_SEND (abfd, _get_reloc_upper_bound, (abfd, asect)); |
} |
/* |
FUNCTION |
bfd_canonicalize_reloc |
SYNOPSIS |
long bfd_canonicalize_reloc |
(bfd *abfd, asection *sec, arelent **loc, asymbol **syms); |
DESCRIPTION |
Call the back end associated with the open BFD |
@var{abfd} and translate the external form of the relocation |
information attached to @var{sec} into the internal canonical |
form. Place the table into memory at @var{loc}, which has |
been preallocated, usually by a call to |
<<bfd_get_reloc_upper_bound>>. Returns the number of relocs, or |
-1 on error. |
The @var{syms} table is also needed for horrible internal magic |
reasons. |
*/ |
long |
bfd_canonicalize_reloc (bfd *abfd, |
sec_ptr asect, |
arelent **location, |
asymbol **symbols) |
{ |
if (abfd->format != bfd_object) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return -1; |
} |
return BFD_SEND (abfd, _bfd_canonicalize_reloc, |
(abfd, asect, location, symbols)); |
} |
/* |
FUNCTION |
bfd_set_reloc |
SYNOPSIS |
void bfd_set_reloc |
(bfd *abfd, asection *sec, arelent **rel, unsigned int count); |
DESCRIPTION |
Set the relocation pointer and count within |
section @var{sec} to the values @var{rel} and @var{count}. |
The argument @var{abfd} is ignored. |
*/ |
void |
bfd_set_reloc (bfd *ignore_abfd ATTRIBUTE_UNUSED, |
sec_ptr asect, |
arelent **location, |
unsigned int count) |
{ |
asect->orelocation = location; |
asect->reloc_count = count; |
} |
/* |
FUNCTION |
bfd_set_file_flags |
SYNOPSIS |
bfd_boolean bfd_set_file_flags (bfd *abfd, flagword flags); |
DESCRIPTION |
Set the flag word in the BFD @var{abfd} to the value @var{flags}. |
Possible errors are: |
o <<bfd_error_wrong_format>> - The target bfd was not of object format. |
o <<bfd_error_invalid_operation>> - The target bfd was open for reading. |
o <<bfd_error_invalid_operation>> - |
The flag word contained a bit which was not applicable to the |
type of file. E.g., an attempt was made to set the <<D_PAGED>> bit |
on a BFD format which does not support demand paging. |
*/ |
bfd_boolean |
bfd_set_file_flags (bfd *abfd, flagword flags) |
{ |
if (abfd->format != bfd_object) |
{ |
bfd_set_error (bfd_error_wrong_format); |
return FALSE; |
} |
if (bfd_read_p (abfd)) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
bfd_get_file_flags (abfd) = flags; |
if ((flags & bfd_applicable_file_flags (abfd)) != flags) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
return TRUE; |
} |
void |
bfd_assert (const char *file, int line) |
{ |
(*_bfd_assert_handler) (_("BFD %s assertion fail %s:%d"), |
BFD_VERSION_STRING, file, line); |
} |
/* A more or less friendly abort message. In libbfd.h abort is |
defined to call this function. */ |
void |
_bfd_abort (const char *file, int line, const char *fn) |
{ |
if (fn != NULL) |
(*_bfd_error_handler) |
(_("BFD %s internal error, aborting at %s line %d in %s\n"), |
BFD_VERSION_STRING, file, line, fn); |
else |
(*_bfd_error_handler) |
(_("BFD %s internal error, aborting at %s line %d\n"), |
BFD_VERSION_STRING, file, line); |
(*_bfd_error_handler) (_("Please report this bug.\n")); |
_exit (EXIT_FAILURE); |
} |
/* |
FUNCTION |
bfd_get_arch_size |
SYNOPSIS |
int bfd_get_arch_size (bfd *abfd); |
DESCRIPTION |
Returns the architecture address size, in bits, as determined |
by the object file's format. For ELF, this information is |
included in the header. |
RETURNS |
Returns the arch size in bits if known, <<-1>> otherwise. |
*/ |
int |
bfd_get_arch_size (bfd *abfd) |
{ |
if (abfd->xvec->flavour == bfd_target_elf_flavour) |
return get_elf_backend_data (abfd)->s->arch_size; |
return -1; |
} |
/* |
FUNCTION |
bfd_get_sign_extend_vma |
SYNOPSIS |
int bfd_get_sign_extend_vma (bfd *abfd); |
DESCRIPTION |
Indicates if the target architecture "naturally" sign extends |
an address. Some architectures implicitly sign extend address |
values when they are converted to types larger than the size |
of an address. For instance, bfd_get_start_address() will |
return an address sign extended to fill a bfd_vma when this is |
the case. |
RETURNS |
Returns <<1>> if the target architecture is known to sign |
extend addresses, <<0>> if the target architecture is known to |
not sign extend addresses, and <<-1>> otherwise. |
*/ |
int |
bfd_get_sign_extend_vma (bfd *abfd) |
{ |
char *name; |
if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) |
return get_elf_backend_data (abfd)->sign_extend_vma; |
name = bfd_get_target (abfd); |
/* Return a proper value for DJGPP & PE COFF. |
This function is required for DWARF2 support, but there is |
no place to store this information in the COFF back end. |
Should enough other COFF targets add support for DWARF2, |
a place will have to be found. Until then, this hack will do. */ |
if (CONST_STRNEQ (name, "coff-go32") |
|| strcmp (name, "pe-i386") == 0 |
|| strcmp (name, "pei-i386") == 0 |
|| strcmp (name, "pe-x86-64") == 0 |
|| strcmp (name, "pei-x86-64") == 0 |
|| strcmp (name, "pe-arm-wince-little") == 0 |
|| strcmp (name, "pei-arm-wince-little") == 0 |
|| strcmp (name, "aixcoff-rs6000") == 0) |
return 1; |
if (CONST_STRNEQ (name, "mach-o")) |
return 0; |
bfd_set_error (bfd_error_wrong_format); |
return -1; |
} |
/* |
FUNCTION |
bfd_set_start_address |
SYNOPSIS |
bfd_boolean bfd_set_start_address (bfd *abfd, bfd_vma vma); |
DESCRIPTION |
Make @var{vma} the entry point of output BFD @var{abfd}. |
RETURNS |
Returns <<TRUE>> on success, <<FALSE>> otherwise. |
*/ |
bfd_boolean |
bfd_set_start_address (bfd *abfd, bfd_vma vma) |
{ |
abfd->start_address = vma; |
return TRUE; |
} |
/* |
FUNCTION |
bfd_get_gp_size |
SYNOPSIS |
unsigned int bfd_get_gp_size (bfd *abfd); |
DESCRIPTION |
Return the maximum size of objects to be optimized using the GP |
register under MIPS ECOFF. This is typically set by the <<-G>> |
argument to the compiler, assembler or linker. |
*/ |
unsigned int |
bfd_get_gp_size (bfd *abfd) |
{ |
if (abfd->format == bfd_object) |
{ |
if (abfd->xvec->flavour == bfd_target_ecoff_flavour) |
return ecoff_data (abfd)->gp_size; |
else if (abfd->xvec->flavour == bfd_target_elf_flavour) |
return elf_gp_size (abfd); |
} |
return 0; |
} |
/* |
FUNCTION |
bfd_set_gp_size |
SYNOPSIS |
void bfd_set_gp_size (bfd *abfd, unsigned int i); |
DESCRIPTION |
Set the maximum size of objects to be optimized using the GP |
register under ECOFF or MIPS ELF. This is typically set by |
the <<-G>> argument to the compiler, assembler or linker. |
*/ |
void |
bfd_set_gp_size (bfd *abfd, unsigned int i) |
{ |
/* Don't try to set GP size on an archive or core file! */ |
if (abfd->format != bfd_object) |
return; |
if (abfd->xvec->flavour == bfd_target_ecoff_flavour) |
ecoff_data (abfd)->gp_size = i; |
else if (abfd->xvec->flavour == bfd_target_elf_flavour) |
elf_gp_size (abfd) = i; |
} |
/* Get the GP value. This is an internal function used by some of the |
relocation special_function routines on targets which support a GP |
register. */ |
bfd_vma |
_bfd_get_gp_value (bfd *abfd) |
{ |
if (! abfd) |
return 0; |
if (abfd->format != bfd_object) |
return 0; |
if (abfd->xvec->flavour == bfd_target_ecoff_flavour) |
return ecoff_data (abfd)->gp; |
else if (abfd->xvec->flavour == bfd_target_elf_flavour) |
return elf_gp (abfd); |
return 0; |
} |
/* Set the GP value. */ |
void |
_bfd_set_gp_value (bfd *abfd, bfd_vma v) |
{ |
if (! abfd) |
abort (); |
if (abfd->format != bfd_object) |
return; |
if (abfd->xvec->flavour == bfd_target_ecoff_flavour) |
ecoff_data (abfd)->gp = v; |
else if (abfd->xvec->flavour == bfd_target_elf_flavour) |
elf_gp (abfd) = v; |
} |
/* |
FUNCTION |
bfd_scan_vma |
SYNOPSIS |
bfd_vma bfd_scan_vma (const char *string, const char **end, int base); |
DESCRIPTION |
Convert, like <<strtoul>>, a numerical expression |
@var{string} into a <<bfd_vma>> integer, and return that integer. |
(Though without as many bells and whistles as <<strtoul>>.) |
The expression is assumed to be unsigned (i.e., positive). |
If given a @var{base}, it is used as the base for conversion. |
A base of 0 causes the function to interpret the string |
in hex if a leading "0x" or "0X" is found, otherwise |
in octal if a leading zero is found, otherwise in decimal. |
If the value would overflow, the maximum <<bfd_vma>> value is |
returned. |
*/ |
bfd_vma |
bfd_scan_vma (const char *string, const char **end, int base) |
{ |
bfd_vma value; |
bfd_vma cutoff; |
unsigned int cutlim; |
int overflow; |
/* Let the host do it if possible. */ |
if (sizeof (bfd_vma) <= sizeof (unsigned long)) |
return strtoul (string, (char **) end, base); |
#ifdef HAVE_STRTOULL |
if (sizeof (bfd_vma) <= sizeof (unsigned long long)) |
return strtoull (string, (char **) end, base); |
#endif |
if (base == 0) |
{ |
if (string[0] == '0') |
{ |
if ((string[1] == 'x') || (string[1] == 'X')) |
base = 16; |
else |
base = 8; |
} |
} |
if ((base < 2) || (base > 36)) |
base = 10; |
if (base == 16 |
&& string[0] == '0' |
&& (string[1] == 'x' || string[1] == 'X') |
&& ISXDIGIT (string[2])) |
{ |
string += 2; |
} |
cutoff = (~ (bfd_vma) 0) / (bfd_vma) base; |
cutlim = (~ (bfd_vma) 0) % (bfd_vma) base; |
value = 0; |
overflow = 0; |
while (1) |
{ |
unsigned int digit; |
digit = *string; |
if (ISDIGIT (digit)) |
digit = digit - '0'; |
else if (ISALPHA (digit)) |
digit = TOUPPER (digit) - 'A' + 10; |
else |
break; |
if (digit >= (unsigned int) base) |
break; |
if (value > cutoff || (value == cutoff && digit > cutlim)) |
overflow = 1; |
value = value * base + digit; |
++string; |
} |
if (overflow) |
value = ~ (bfd_vma) 0; |
if (end != NULL) |
*end = string; |
return value; |
} |
/* |
FUNCTION |
bfd_copy_private_header_data |
SYNOPSIS |
bfd_boolean bfd_copy_private_header_data (bfd *ibfd, bfd *obfd); |
DESCRIPTION |
Copy private BFD header information from the BFD @var{ibfd} to the |
the BFD @var{obfd}. This copies information that may require |
sections to exist, but does not require symbol tables. Return |
<<true>> on success, <<false>> on error. |
Possible error returns are: |
o <<bfd_error_no_memory>> - |
Not enough memory exists to create private data for @var{obfd}. |
.#define bfd_copy_private_header_data(ibfd, obfd) \ |
. BFD_SEND (obfd, _bfd_copy_private_header_data, \ |
. (ibfd, obfd)) |
*/ |
/* |
FUNCTION |
bfd_copy_private_bfd_data |
SYNOPSIS |
bfd_boolean bfd_copy_private_bfd_data (bfd *ibfd, bfd *obfd); |
DESCRIPTION |
Copy private BFD information from the BFD @var{ibfd} to the |
the BFD @var{obfd}. Return <<TRUE>> on success, <<FALSE>> on error. |
Possible error returns are: |
o <<bfd_error_no_memory>> - |
Not enough memory exists to create private data for @var{obfd}. |
.#define bfd_copy_private_bfd_data(ibfd, obfd) \ |
. BFD_SEND (obfd, _bfd_copy_private_bfd_data, \ |
. (ibfd, obfd)) |
*/ |
/* |
FUNCTION |
bfd_merge_private_bfd_data |
SYNOPSIS |
bfd_boolean bfd_merge_private_bfd_data (bfd *ibfd, bfd *obfd); |
DESCRIPTION |
Merge private BFD information from the BFD @var{ibfd} to the |
the output file BFD @var{obfd} when linking. Return <<TRUE>> |
on success, <<FALSE>> on error. Possible error returns are: |
o <<bfd_error_no_memory>> - |
Not enough memory exists to create private data for @var{obfd}. |
.#define bfd_merge_private_bfd_data(ibfd, obfd) \ |
. BFD_SEND (obfd, _bfd_merge_private_bfd_data, \ |
. (ibfd, obfd)) |
*/ |
/* |
FUNCTION |
bfd_set_private_flags |
SYNOPSIS |
bfd_boolean bfd_set_private_flags (bfd *abfd, flagword flags); |
DESCRIPTION |
Set private BFD flag information in the BFD @var{abfd}. |
Return <<TRUE>> on success, <<FALSE>> on error. Possible error |
returns are: |
o <<bfd_error_no_memory>> - |
Not enough memory exists to create private data for @var{obfd}. |
.#define bfd_set_private_flags(abfd, flags) \ |
. BFD_SEND (abfd, _bfd_set_private_flags, (abfd, flags)) |
*/ |
/* |
FUNCTION |
Other functions |
DESCRIPTION |
The following functions exist but have not yet been documented. |
.#define bfd_sizeof_headers(abfd, info) \ |
. BFD_SEND (abfd, _bfd_sizeof_headers, (abfd, info)) |
. |
.#define bfd_find_nearest_line(abfd, sec, syms, off, file, func, line) \ |
. BFD_SEND (abfd, _bfd_find_nearest_line, \ |
. (abfd, sec, syms, off, file, func, line)) |
. |
.#define bfd_find_nearest_line_discriminator(abfd, sec, syms, off, file, func, \ |
. line, disc) \ |
. BFD_SEND (abfd, _bfd_find_nearest_line_discriminator, \ |
. (abfd, sec, syms, off, file, func, line, disc)) |
. |
.#define bfd_find_line(abfd, syms, sym, file, line) \ |
. BFD_SEND (abfd, _bfd_find_line, \ |
. (abfd, syms, sym, file, line)) |
. |
.#define bfd_find_inliner_info(abfd, file, func, line) \ |
. BFD_SEND (abfd, _bfd_find_inliner_info, \ |
. (abfd, file, func, line)) |
. |
.#define bfd_debug_info_start(abfd) \ |
. BFD_SEND (abfd, _bfd_debug_info_start, (abfd)) |
. |
.#define bfd_debug_info_end(abfd) \ |
. BFD_SEND (abfd, _bfd_debug_info_end, (abfd)) |
. |
.#define bfd_debug_info_accumulate(abfd, section) \ |
. BFD_SEND (abfd, _bfd_debug_info_accumulate, (abfd, section)) |
. |
.#define bfd_stat_arch_elt(abfd, stat) \ |
. BFD_SEND (abfd, _bfd_stat_arch_elt,(abfd, stat)) |
. |
.#define bfd_update_armap_timestamp(abfd) \ |
. BFD_SEND (abfd, _bfd_update_armap_timestamp, (abfd)) |
. |
.#define bfd_set_arch_mach(abfd, arch, mach)\ |
. BFD_SEND ( abfd, _bfd_set_arch_mach, (abfd, arch, mach)) |
. |
.#define bfd_relax_section(abfd, section, link_info, again) \ |
. BFD_SEND (abfd, _bfd_relax_section, (abfd, section, link_info, again)) |
. |
.#define bfd_gc_sections(abfd, link_info) \ |
. BFD_SEND (abfd, _bfd_gc_sections, (abfd, link_info)) |
. |
.#define bfd_lookup_section_flags(link_info, flag_info, section) \ |
. BFD_SEND (abfd, _bfd_lookup_section_flags, (link_info, flag_info, section)) |
. |
.#define bfd_merge_sections(abfd, link_info) \ |
. BFD_SEND (abfd, _bfd_merge_sections, (abfd, link_info)) |
. |
.#define bfd_is_group_section(abfd, sec) \ |
. BFD_SEND (abfd, _bfd_is_group_section, (abfd, sec)) |
. |
.#define bfd_discard_group(abfd, sec) \ |
. BFD_SEND (abfd, _bfd_discard_group, (abfd, sec)) |
. |
.#define bfd_link_hash_table_create(abfd) \ |
. BFD_SEND (abfd, _bfd_link_hash_table_create, (abfd)) |
. |
.#define bfd_link_hash_table_free(abfd, hash) \ |
. BFD_SEND (abfd, _bfd_link_hash_table_free, (hash)) |
. |
.#define bfd_link_add_symbols(abfd, info) \ |
. BFD_SEND (abfd, _bfd_link_add_symbols, (abfd, info)) |
. |
.#define bfd_link_just_syms(abfd, sec, info) \ |
. BFD_SEND (abfd, _bfd_link_just_syms, (sec, info)) |
. |
.#define bfd_final_link(abfd, info) \ |
. BFD_SEND (abfd, _bfd_final_link, (abfd, info)) |
. |
.#define bfd_free_cached_info(abfd) \ |
. BFD_SEND (abfd, _bfd_free_cached_info, (abfd)) |
. |
.#define bfd_get_dynamic_symtab_upper_bound(abfd) \ |
. BFD_SEND (abfd, _bfd_get_dynamic_symtab_upper_bound, (abfd)) |
. |
.#define bfd_print_private_bfd_data(abfd, file)\ |
. BFD_SEND (abfd, _bfd_print_private_bfd_data, (abfd, file)) |
. |
.#define bfd_canonicalize_dynamic_symtab(abfd, asymbols) \ |
. BFD_SEND (abfd, _bfd_canonicalize_dynamic_symtab, (abfd, asymbols)) |
. |
.#define bfd_get_synthetic_symtab(abfd, count, syms, dyncount, dynsyms, ret) \ |
. BFD_SEND (abfd, _bfd_get_synthetic_symtab, (abfd, count, syms, \ |
. dyncount, dynsyms, ret)) |
. |
.#define bfd_get_dynamic_reloc_upper_bound(abfd) \ |
. BFD_SEND (abfd, _bfd_get_dynamic_reloc_upper_bound, (abfd)) |
. |
.#define bfd_canonicalize_dynamic_reloc(abfd, arels, asyms) \ |
. BFD_SEND (abfd, _bfd_canonicalize_dynamic_reloc, (abfd, arels, asyms)) |
. |
.extern bfd_byte *bfd_get_relocated_section_contents |
. (bfd *, struct bfd_link_info *, struct bfd_link_order *, bfd_byte *, |
. bfd_boolean, asymbol **); |
. |
*/ |
bfd_byte * |
bfd_get_relocated_section_contents (bfd *abfd, |
struct bfd_link_info *link_info, |
struct bfd_link_order *link_order, |
bfd_byte *data, |
bfd_boolean relocatable, |
asymbol **symbols) |
{ |
bfd *abfd2; |
bfd_byte *(*fn) (bfd *, struct bfd_link_info *, struct bfd_link_order *, |
bfd_byte *, bfd_boolean, asymbol **); |
if (link_order->type == bfd_indirect_link_order) |
{ |
abfd2 = link_order->u.indirect.section->owner; |
if (abfd2 == NULL) |
abfd2 = abfd; |
} |
else |
abfd2 = abfd; |
fn = abfd2->xvec->_bfd_get_relocated_section_contents; |
return (*fn) (abfd, link_info, link_order, data, relocatable, symbols); |
} |
/* Record information about an ELF program header. */ |
bfd_boolean |
bfd_record_phdr (bfd *abfd, |
unsigned long type, |
bfd_boolean flags_valid, |
flagword flags, |
bfd_boolean at_valid, |
bfd_vma at, |
bfd_boolean includes_filehdr, |
bfd_boolean includes_phdrs, |
unsigned int count, |
asection **secs) |
{ |
struct elf_segment_map *m, **pm; |
bfd_size_type amt; |
if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) |
return TRUE; |
amt = sizeof (struct elf_segment_map); |
amt += ((bfd_size_type) count - 1) * sizeof (asection *); |
m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); |
if (m == NULL) |
return FALSE; |
m->p_type = type; |
m->p_flags = flags; |
m->p_paddr = at; |
m->p_flags_valid = flags_valid; |
m->p_paddr_valid = at_valid; |
m->includes_filehdr = includes_filehdr; |
m->includes_phdrs = includes_phdrs; |
m->count = count; |
if (count > 0) |
memcpy (m->sections, secs, count * sizeof (asection *)); |
for (pm = &elf_seg_map (abfd); *pm != NULL; pm = &(*pm)->next) |
; |
*pm = m; |
return TRUE; |
} |
#ifdef BFD64 |
/* Return true iff this target is 32-bit. */ |
static bfd_boolean |
is32bit (bfd *abfd) |
{ |
if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) |
{ |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
return bed->s->elfclass == ELFCLASS32; |
} |
/* For non-ELF targets, use architecture information. */ |
return bfd_arch_bits_per_address (abfd) <= 32; |
} |
#endif |
/* bfd_sprintf_vma and bfd_fprintf_vma display an address in the |
target's address size. */ |
void |
bfd_sprintf_vma (bfd *abfd ATTRIBUTE_UNUSED, char *buf, bfd_vma value) |
{ |
#ifdef BFD64 |
if (is32bit (abfd)) |
{ |
sprintf (buf, "%08lx", (unsigned long) value & 0xffffffff); |
return; |
} |
#endif |
sprintf_vma (buf, value); |
} |
void |
bfd_fprintf_vma (bfd *abfd ATTRIBUTE_UNUSED, void *stream, bfd_vma value) |
{ |
#ifdef BFD64 |
if (is32bit (abfd)) |
{ |
fprintf ((FILE *) stream, "%08lx", (unsigned long) value & 0xffffffff); |
return; |
} |
#endif |
fprintf_vma ((FILE *) stream, value); |
} |
/* |
FUNCTION |
bfd_alt_mach_code |
SYNOPSIS |
bfd_boolean bfd_alt_mach_code (bfd *abfd, int alternative); |
DESCRIPTION |
When more than one machine code number is available for the |
same machine type, this function can be used to switch between |
the preferred one (alternative == 0) and any others. Currently, |
only ELF supports this feature, with up to two alternate |
machine codes. |
*/ |
bfd_boolean |
bfd_alt_mach_code (bfd *abfd, int alternative) |
{ |
if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) |
{ |
int code; |
switch (alternative) |
{ |
case 0: |
code = get_elf_backend_data (abfd)->elf_machine_code; |
break; |
case 1: |
code = get_elf_backend_data (abfd)->elf_machine_alt1; |
if (code == 0) |
return FALSE; |
break; |
case 2: |
code = get_elf_backend_data (abfd)->elf_machine_alt2; |
if (code == 0) |
return FALSE; |
break; |
default: |
return FALSE; |
} |
elf_elfheader (abfd)->e_machine = code; |
return TRUE; |
} |
return FALSE; |
} |
/* |
FUNCTION |
bfd_emul_get_maxpagesize |
SYNOPSIS |
bfd_vma bfd_emul_get_maxpagesize (const char *); |
DESCRIPTION |
Returns the maximum page size, in bytes, as determined by |
emulation. |
RETURNS |
Returns the maximum page size in bytes for ELF, 0 otherwise. |
*/ |
bfd_vma |
bfd_emul_get_maxpagesize (const char *emul) |
{ |
const bfd_target *target; |
target = bfd_find_target (emul, NULL); |
if (target != NULL |
&& target->flavour == bfd_target_elf_flavour) |
return xvec_get_elf_backend_data (target)->maxpagesize; |
return 0; |
} |
static void |
bfd_elf_set_pagesize (const bfd_target *target, bfd_vma size, |
int offset, const bfd_target *orig_target) |
{ |
if (target->flavour == bfd_target_elf_flavour) |
{ |
const struct elf_backend_data *bed; |
bed = xvec_get_elf_backend_data (target); |
*((bfd_vma *) ((char *) bed + offset)) = size; |
} |
if (target->alternative_target |
&& target->alternative_target != orig_target) |
bfd_elf_set_pagesize (target->alternative_target, size, offset, |
orig_target); |
} |
/* |
FUNCTION |
bfd_emul_set_maxpagesize |
SYNOPSIS |
void bfd_emul_set_maxpagesize (const char *, bfd_vma); |
DESCRIPTION |
For ELF, set the maximum page size for the emulation. It is |
a no-op for other formats. |
*/ |
void |
bfd_emul_set_maxpagesize (const char *emul, bfd_vma size) |
{ |
const bfd_target *target; |
target = bfd_find_target (emul, NULL); |
if (target) |
bfd_elf_set_pagesize (target, size, |
offsetof (struct elf_backend_data, |
maxpagesize), target); |
} |
/* |
FUNCTION |
bfd_emul_get_commonpagesize |
SYNOPSIS |
bfd_vma bfd_emul_get_commonpagesize (const char *); |
DESCRIPTION |
Returns the common page size, in bytes, as determined by |
emulation. |
RETURNS |
Returns the common page size in bytes for ELF, 0 otherwise. |
*/ |
bfd_vma |
bfd_emul_get_commonpagesize (const char *emul) |
{ |
const bfd_target *target; |
target = bfd_find_target (emul, NULL); |
if (target != NULL |
&& target->flavour == bfd_target_elf_flavour) |
return xvec_get_elf_backend_data (target)->commonpagesize; |
return 0; |
} |
/* |
FUNCTION |
bfd_emul_set_commonpagesize |
SYNOPSIS |
void bfd_emul_set_commonpagesize (const char *, bfd_vma); |
DESCRIPTION |
For ELF, set the common page size for the emulation. It is |
a no-op for other formats. |
*/ |
void |
bfd_emul_set_commonpagesize (const char *emul, bfd_vma size) |
{ |
const bfd_target *target; |
target = bfd_find_target (emul, NULL); |
if (target) |
bfd_elf_set_pagesize (target, size, |
offsetof (struct elf_backend_data, |
commonpagesize), target); |
} |
/* |
FUNCTION |
bfd_demangle |
SYNOPSIS |
char *bfd_demangle (bfd *, const char *, int); |
DESCRIPTION |
Wrapper around cplus_demangle. Strips leading underscores and |
other such chars that would otherwise confuse the demangler. |
If passed a g++ v3 ABI mangled name, returns a buffer allocated |
with malloc holding the demangled name. Returns NULL otherwise |
and on memory alloc failure. |
*/ |
char * |
bfd_demangle (bfd *abfd, const char *name, int options) |
{ |
char *res, *alloc; |
const char *pre, *suf; |
size_t pre_len; |
bfd_boolean skip_lead; |
skip_lead = (abfd != NULL |
&& *name != '\0' |
&& bfd_get_symbol_leading_char (abfd) == *name); |
if (skip_lead) |
++name; |
/* This is a hack for better error reporting on XCOFF, PowerPC64-ELF |
or the MS PE format. These formats have a number of leading '.'s |
on at least some symbols, so we remove all dots to avoid |
confusing the demangler. */ |
pre = name; |
while (*name == '.' || *name == '$') |
++name; |
pre_len = name - pre; |
/* Strip off @plt and suchlike too. */ |
alloc = NULL; |
suf = strchr (name, '@'); |
if (suf != NULL) |
{ |
alloc = (char *) bfd_malloc (suf - name + 1); |
if (alloc == NULL) |
return NULL; |
memcpy (alloc, name, suf - name); |
alloc[suf - name] = '\0'; |
name = alloc; |
} |
res = cplus_demangle (name, options); |
if (alloc != NULL) |
free (alloc); |
if (res == NULL) |
{ |
if (skip_lead) |
{ |
size_t len = strlen (pre) + 1; |
alloc = (char *) bfd_malloc (len); |
if (alloc == NULL) |
return NULL; |
memcpy (alloc, pre, len); |
return alloc; |
} |
return NULL; |
} |
/* Put back any prefix or suffix. */ |
if (pre_len != 0 || suf != NULL) |
{ |
size_t len; |
size_t suf_len; |
char *final; |
len = strlen (res); |
if (suf == NULL) |
suf = res + len; |
suf_len = strlen (suf) + 1; |
final = (char *) bfd_malloc (pre_len + len + suf_len); |
if (final != NULL) |
{ |
memcpy (final, pre, pre_len); |
memcpy (final + pre_len, res, len); |
memcpy (final + pre_len + len, suf, suf_len); |
} |
free (res); |
res = final; |
} |
return res; |
} |
/contrib/toolchain/binutils/bfd/bfd.h |
---|
0,0 → 1,6971 |
/* DO NOT EDIT! -*- buffer-read-only: t -*- This file is automatically |
generated from "bfd-in.h", "init.c", "opncls.c", "libbfd.c", |
"bfdio.c", "bfdwin.c", "section.c", "archures.c", "reloc.c", |
"syms.c", "bfd.c", "archive.c", "corefile.c", "targets.c", "format.c", |
"linker.c", "simple.c" and "compress.c". |
Run "make headers" in your build bfd/ to regenerate. */ |
/* Main header file for the bfd library -- portable access to object files. |
Copyright 1990-2013 Free Software Foundation, Inc. |
Contributed by Cygnus Support. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ |
#ifndef __BFD_H_SEEN__ |
#define __BFD_H_SEEN__ |
/* PR 14072: Ensure that config.h is included first. */ |
#if !defined PACKAGE && !defined PACKAGE_VERSION |
#error config.h must be included before this header |
#endif |
#ifdef __cplusplus |
extern "C" { |
#endif |
#include "ansidecl.h" |
#include "symcat.h" |
#include <sys/stat.h> |
#if defined (__STDC__) || defined (ALMOST_STDC) || defined (HAVE_STRINGIZE) |
#ifndef SABER |
/* This hack is to avoid a problem with some strict ANSI C preprocessors. |
The problem is, "32_" is not a valid preprocessing token, and we don't |
want extra underscores (e.g., "nlm_32_"). The XCONCAT2 macro will |
cause the inner CONCAT2 macros to be evaluated first, producing |
still-valid pp-tokens. Then the final concatenation can be done. */ |
#undef CONCAT4 |
#define CONCAT4(a,b,c,d) XCONCAT2(CONCAT2(a,b),CONCAT2(c,d)) |
#endif |
#endif |
/* This is a utility macro to handle the situation where the code |
wants to place a constant string into the code, followed by a |
comma and then the length of the string. Doing this by hand |
is error prone, so using this macro is safer. */ |
#define STRING_COMMA_LEN(STR) (STR), (sizeof (STR) - 1) |
/* Unfortunately it is not possible to use the STRING_COMMA_LEN macro |
to create the arguments to another macro, since the preprocessor |
will mis-count the number of arguments to the outer macro (by not |
evaluating STRING_COMMA_LEN and so missing the comma). This is a |
problem for example when trying to use STRING_COMMA_LEN to build |
the arguments to the strncmp() macro. Hence this alternative |
definition of strncmp is provided here. |
Note - these macros do NOT work if STR2 is not a constant string. */ |
#define CONST_STRNEQ(STR1,STR2) (strncmp ((STR1), (STR2), sizeof (STR2) - 1) == 0) |
/* strcpy() can have a similar problem, but since we know we are |
copying a constant string, we can use memcpy which will be faster |
since there is no need to check for a NUL byte inside STR. We |
can also save time if we do not need to copy the terminating NUL. */ |
#define LITMEMCPY(DEST,STR2) memcpy ((DEST), (STR2), sizeof (STR2) - 1) |
#define LITSTRCPY(DEST,STR2) memcpy ((DEST), (STR2), sizeof (STR2)) |
#define BFD_SUPPORTS_PLUGINS 0 |
/* The word size used by BFD on the host. This may be 64 with a 32 |
bit target if the host is 64 bit, or if other 64 bit targets have |
been selected with --enable-targets, or if --enable-64-bit-bfd. */ |
#define BFD_ARCH_SIZE 32 |
/* The word size of the default bfd target. */ |
#define BFD_DEFAULT_TARGET_SIZE 32 |
#define BFD_HOST_64BIT_LONG 0 |
#define BFD_HOST_64BIT_LONG_LONG 1 |
#if 1 |
#define BFD_HOST_64_BIT long long |
#define BFD_HOST_U_64_BIT unsigned long long |
typedef BFD_HOST_64_BIT bfd_int64_t; |
typedef BFD_HOST_U_64_BIT bfd_uint64_t; |
#endif |
#if BFD_ARCH_SIZE >= 64 |
#define BFD64 |
#endif |
#ifndef INLINE |
#if __GNUC__ >= 2 |
#define INLINE __inline__ |
#else |
#define INLINE |
#endif |
#endif |
/* Declaring a type wide enough to hold a host long and a host pointer. */ |
#define BFD_HOSTPTR_T unsigned long |
typedef BFD_HOSTPTR_T bfd_hostptr_t; |
/* Forward declaration. */ |
typedef struct bfd bfd; |
/* Boolean type used in bfd. Too many systems define their own |
versions of "boolean" for us to safely typedef a "boolean" of |
our own. Using an enum for "bfd_boolean" has its own set of |
problems, with strange looking casts required to avoid warnings |
on some older compilers. Thus we just use an int. |
General rule: Functions which are bfd_boolean return TRUE on |
success and FALSE on failure (unless they're a predicate). */ |
typedef int bfd_boolean; |
#undef FALSE |
#undef TRUE |
#define FALSE 0 |
#define TRUE 1 |
#ifdef BFD64 |
#ifndef BFD_HOST_64_BIT |
#error No 64 bit integer type available |
#endif /* ! defined (BFD_HOST_64_BIT) */ |
typedef BFD_HOST_U_64_BIT bfd_vma; |
typedef BFD_HOST_64_BIT bfd_signed_vma; |
typedef BFD_HOST_U_64_BIT bfd_size_type; |
typedef BFD_HOST_U_64_BIT symvalue; |
#if BFD_HOST_64BIT_LONG |
#define BFD_VMA_FMT "l" |
#elif defined (__MSVCRT__) |
#define BFD_VMA_FMT "I64" |
#else |
#define BFD_VMA_FMT "ll" |
#endif |
#ifndef fprintf_vma |
#define sprintf_vma(s,x) sprintf (s, "%016" BFD_VMA_FMT "x", x) |
#define fprintf_vma(f,x) fprintf (f, "%016" BFD_VMA_FMT "x", x) |
#endif |
#else /* not BFD64 */ |
/* Represent a target address. Also used as a generic unsigned type |
which is guaranteed to be big enough to hold any arithmetic types |
we need to deal with. */ |
typedef unsigned long bfd_vma; |
/* A generic signed type which is guaranteed to be big enough to hold any |
arithmetic types we need to deal with. Can be assumed to be compatible |
with bfd_vma in the same way that signed and unsigned ints are compatible |
(as parameters, in assignment, etc). */ |
typedef long bfd_signed_vma; |
typedef unsigned long symvalue; |
typedef unsigned long bfd_size_type; |
/* Print a bfd_vma x on stream s. */ |
#define BFD_VMA_FMT "l" |
#define fprintf_vma(s,x) fprintf (s, "%08" BFD_VMA_FMT "x", x) |
#define sprintf_vma(s,x) sprintf (s, "%08" BFD_VMA_FMT "x", x) |
#endif /* not BFD64 */ |
#define HALF_BFD_SIZE_TYPE \ |
(((bfd_size_type) 1) << (8 * sizeof (bfd_size_type) / 2)) |
#ifndef BFD_HOST_64_BIT |
/* Fall back on a 32 bit type. The idea is to make these types always |
available for function return types, but in the case that |
BFD_HOST_64_BIT is undefined such a function should abort or |
otherwise signal an error. */ |
typedef bfd_signed_vma bfd_int64_t; |
typedef bfd_vma bfd_uint64_t; |
#endif |
/* An offset into a file. BFD always uses the largest possible offset |
based on the build time availability of fseek, fseeko, or fseeko64. */ |
typedef BFD_HOST_64_BIT file_ptr; |
typedef unsigned BFD_HOST_64_BIT ufile_ptr; |
extern void bfd_sprintf_vma (bfd *, char *, bfd_vma); |
extern void bfd_fprintf_vma (bfd *, void *, bfd_vma); |
#define printf_vma(x) fprintf_vma(stdout,x) |
#define bfd_printf_vma(abfd,x) bfd_fprintf_vma (abfd,stdout,x) |
typedef unsigned int flagword; /* 32 bits of flags */ |
typedef unsigned char bfd_byte; |
/* File formats. */ |
typedef enum bfd_format |
{ |
bfd_unknown = 0, /* File format is unknown. */ |
bfd_object, /* Linker/assembler/compiler output. */ |
bfd_archive, /* Object archive file. */ |
bfd_core, /* Core dump. */ |
bfd_type_end /* Marks the end; don't use it! */ |
} |
bfd_format; |
/* Symbols and relocation. */ |
/* A count of carsyms (canonical archive symbols). */ |
typedef unsigned long symindex; |
/* How to perform a relocation. */ |
typedef const struct reloc_howto_struct reloc_howto_type; |
#define BFD_NO_MORE_SYMBOLS ((symindex) ~0) |
/* General purpose part of a symbol X; |
target specific parts are in libcoff.h, libaout.h, etc. */ |
#define bfd_get_section(x) ((x)->section) |
#define bfd_get_output_section(x) ((x)->section->output_section) |
#define bfd_set_section(x,y) ((x)->section) = (y) |
#define bfd_asymbol_base(x) ((x)->section->vma) |
#define bfd_asymbol_value(x) (bfd_asymbol_base(x) + (x)->value) |
#define bfd_asymbol_name(x) ((x)->name) |
/*Perhaps future: #define bfd_asymbol_bfd(x) ((x)->section->owner)*/ |
#define bfd_asymbol_bfd(x) ((x)->the_bfd) |
#define bfd_asymbol_flavour(x) \ |
(((x)->flags & BSF_SYNTHETIC) != 0 \ |
? bfd_target_unknown_flavour \ |
: bfd_asymbol_bfd (x)->xvec->flavour) |
/* A canonical archive symbol. */ |
/* This is a type pun with struct ranlib on purpose! */ |
typedef struct carsym |
{ |
char *name; |
file_ptr file_offset; /* Look here to find the file. */ |
} |
carsym; /* To make these you call a carsymogen. */ |
/* Used in generating armaps (archive tables of contents). |
Perhaps just a forward definition would do? */ |
struct orl /* Output ranlib. */ |
{ |
char **name; /* Symbol name. */ |
union |
{ |
file_ptr pos; |
bfd *abfd; |
} u; /* bfd* or file position. */ |
int namidx; /* Index into string table. */ |
}; |
/* Linenumber stuff. */ |
typedef struct lineno_cache_entry |
{ |
unsigned int line_number; /* Linenumber from start of function. */ |
union |
{ |
struct bfd_symbol *sym; /* Function name. */ |
bfd_vma offset; /* Offset into section. */ |
} u; |
} |
alent; |
/* Object and core file sections. */ |
#define align_power(addr, align) \ |
(((addr) + ((bfd_vma) 1 << (align)) - 1) & ((bfd_vma) -1 << (align))) |
typedef struct bfd_section *sec_ptr; |
#define bfd_get_section_name(bfd, ptr) ((void) bfd, (ptr)->name) |
#define bfd_get_section_vma(bfd, ptr) ((void) bfd, (ptr)->vma) |
#define bfd_get_section_lma(bfd, ptr) ((void) bfd, (ptr)->lma) |
#define bfd_get_section_alignment(bfd, ptr) ((void) bfd, \ |
(ptr)->alignment_power) |
#define bfd_section_name(bfd, ptr) ((ptr)->name) |
#define bfd_section_size(bfd, ptr) ((ptr)->size) |
#define bfd_get_section_size(ptr) ((ptr)->size) |
#define bfd_section_vma(bfd, ptr) ((ptr)->vma) |
#define bfd_section_lma(bfd, ptr) ((ptr)->lma) |
#define bfd_section_alignment(bfd, ptr) ((ptr)->alignment_power) |
#define bfd_get_section_flags(bfd, ptr) ((void) bfd, (ptr)->flags) |
#define bfd_get_section_userdata(bfd, ptr) ((void) bfd, (ptr)->userdata) |
#define bfd_is_com_section(ptr) (((ptr)->flags & SEC_IS_COMMON) != 0) |
#define bfd_set_section_vma(bfd, ptr, val) (((ptr)->vma = (ptr)->lma = (val)), ((ptr)->user_set_vma = TRUE), TRUE) |
#define bfd_set_section_alignment(bfd, ptr, val) (((ptr)->alignment_power = (val)),TRUE) |
#define bfd_set_section_userdata(bfd, ptr, val) (((ptr)->userdata = (val)),TRUE) |
/* Find the address one past the end of SEC. */ |
#define bfd_get_section_limit(bfd, sec) \ |
(((bfd)->direction != write_direction && (sec)->rawsize != 0 \ |
? (sec)->rawsize : (sec)->size) / bfd_octets_per_byte (bfd)) |
/* Return TRUE if input section SEC has been discarded. */ |
#define discarded_section(sec) \ |
(!bfd_is_abs_section (sec) \ |
&& bfd_is_abs_section ((sec)->output_section) \ |
&& (sec)->sec_info_type != SEC_INFO_TYPE_MERGE \ |
&& (sec)->sec_info_type != SEC_INFO_TYPE_JUST_SYMS) |
typedef enum bfd_print_symbol |
{ |
bfd_print_symbol_name, |
bfd_print_symbol_more, |
bfd_print_symbol_all |
} bfd_print_symbol_type; |
/* Information about a symbol that nm needs. */ |
typedef struct _symbol_info |
{ |
symvalue value; |
char type; |
const char *name; /* Symbol name. */ |
unsigned char stab_type; /* Stab type. */ |
char stab_other; /* Stab other. */ |
short stab_desc; /* Stab desc. */ |
const char *stab_name; /* String for stab type. */ |
} symbol_info; |
/* Get the name of a stabs type code. */ |
extern const char *bfd_get_stab_name (int); |
/* Hash table routines. There is no way to free up a hash table. */ |
/* An element in the hash table. Most uses will actually use a larger |
structure, and an instance of this will be the first field. */ |
struct bfd_hash_entry |
{ |
/* Next entry for this hash code. */ |
struct bfd_hash_entry *next; |
/* String being hashed. */ |
const char *string; |
/* Hash code. This is the full hash code, not the index into the |
table. */ |
unsigned long hash; |
}; |
/* A hash table. */ |
struct bfd_hash_table |
{ |
/* The hash array. */ |
struct bfd_hash_entry **table; |
/* A function used to create new elements in the hash table. The |
first entry is itself a pointer to an element. When this |
function is first invoked, this pointer will be NULL. However, |
having the pointer permits a hierarchy of method functions to be |
built each of which calls the function in the superclass. Thus |
each function should be written to allocate a new block of memory |
only if the argument is NULL. */ |
struct bfd_hash_entry *(*newfunc) |
(struct bfd_hash_entry *, struct bfd_hash_table *, const char *); |
/* An objalloc for this hash table. This is a struct objalloc *, |
but we use void * to avoid requiring the inclusion of objalloc.h. */ |
void *memory; |
/* The number of slots in the hash table. */ |
unsigned int size; |
/* The number of entries in the hash table. */ |
unsigned int count; |
/* The size of elements. */ |
unsigned int entsize; |
/* If non-zero, don't grow the hash table. */ |
unsigned int frozen:1; |
}; |
/* Initialize a hash table. */ |
extern bfd_boolean bfd_hash_table_init |
(struct bfd_hash_table *, |
struct bfd_hash_entry *(*) (struct bfd_hash_entry *, |
struct bfd_hash_table *, |
const char *), |
unsigned int); |
/* Initialize a hash table specifying a size. */ |
extern bfd_boolean bfd_hash_table_init_n |
(struct bfd_hash_table *, |
struct bfd_hash_entry *(*) (struct bfd_hash_entry *, |
struct bfd_hash_table *, |
const char *), |
unsigned int, unsigned int); |
/* Free up a hash table. */ |
extern void bfd_hash_table_free |
(struct bfd_hash_table *); |
/* Look up a string in a hash table. If CREATE is TRUE, a new entry |
will be created for this string if one does not already exist. The |
COPY argument must be TRUE if this routine should copy the string |
into newly allocated memory when adding an entry. */ |
extern struct bfd_hash_entry *bfd_hash_lookup |
(struct bfd_hash_table *, const char *, bfd_boolean create, |
bfd_boolean copy); |
/* Insert an entry in a hash table. */ |
extern struct bfd_hash_entry *bfd_hash_insert |
(struct bfd_hash_table *, const char *, unsigned long); |
/* Rename an entry in a hash table. */ |
extern void bfd_hash_rename |
(struct bfd_hash_table *, const char *, struct bfd_hash_entry *); |
/* Replace an entry in a hash table. */ |
extern void bfd_hash_replace |
(struct bfd_hash_table *, struct bfd_hash_entry *old, |
struct bfd_hash_entry *nw); |
/* Base method for creating a hash table entry. */ |
extern struct bfd_hash_entry *bfd_hash_newfunc |
(struct bfd_hash_entry *, struct bfd_hash_table *, const char *); |
/* Grab some space for a hash table entry. */ |
extern void *bfd_hash_allocate |
(struct bfd_hash_table *, unsigned int); |
/* Traverse a hash table in a random order, calling a function on each |
element. If the function returns FALSE, the traversal stops. The |
INFO argument is passed to the function. */ |
extern void bfd_hash_traverse |
(struct bfd_hash_table *, |
bfd_boolean (*) (struct bfd_hash_entry *, void *), |
void *info); |
/* Allows the default size of a hash table to be configured. New hash |
tables allocated using bfd_hash_table_init will be created with |
this size. */ |
extern unsigned long bfd_hash_set_default_size (unsigned long); |
/* This structure is used to keep track of stabs in sections |
information while linking. */ |
struct stab_info |
{ |
/* A hash table used to hold stabs strings. */ |
struct bfd_strtab_hash *strings; |
/* The header file hash table. */ |
struct bfd_hash_table includes; |
/* The first .stabstr section. */ |
struct bfd_section *stabstr; |
}; |
#define COFF_SWAP_TABLE (void *) &bfd_coff_std_swap_table |
/* User program access to BFD facilities. */ |
/* Direct I/O routines, for programs which know more about the object |
file than BFD does. Use higher level routines if possible. */ |
extern bfd_size_type bfd_bread (void *, bfd_size_type, bfd *); |
extern bfd_size_type bfd_bwrite (const void *, bfd_size_type, bfd *); |
extern int bfd_seek (bfd *, file_ptr, int); |
extern file_ptr bfd_tell (bfd *); |
extern int bfd_flush (bfd *); |
extern int bfd_stat (bfd *, struct stat *); |
/* Deprecated old routines. */ |
#if __GNUC__ |
#define bfd_read(BUF, ELTSIZE, NITEMS, ABFD) \ |
(warn_deprecated ("bfd_read", __FILE__, __LINE__, __FUNCTION__), \ |
bfd_bread ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) |
#define bfd_write(BUF, ELTSIZE, NITEMS, ABFD) \ |
(warn_deprecated ("bfd_write", __FILE__, __LINE__, __FUNCTION__), \ |
bfd_bwrite ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) |
#else |
#define bfd_read(BUF, ELTSIZE, NITEMS, ABFD) \ |
(warn_deprecated ("bfd_read", (const char *) 0, 0, (const char *) 0), \ |
bfd_bread ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) |
#define bfd_write(BUF, ELTSIZE, NITEMS, ABFD) \ |
(warn_deprecated ("bfd_write", (const char *) 0, 0, (const char *) 0),\ |
bfd_bwrite ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) |
#endif |
extern void warn_deprecated (const char *, const char *, int, const char *); |
/* Cast from const char * to char * so that caller can assign to |
a char * without a warning. */ |
#define bfd_get_filename(abfd) ((char *) (abfd)->filename) |
#define bfd_get_cacheable(abfd) ((abfd)->cacheable) |
#define bfd_get_format(abfd) ((abfd)->format) |
#define bfd_get_target(abfd) ((abfd)->xvec->name) |
#define bfd_get_flavour(abfd) ((abfd)->xvec->flavour) |
#define bfd_family_coff(abfd) \ |
(bfd_get_flavour (abfd) == bfd_target_coff_flavour || \ |
bfd_get_flavour (abfd) == bfd_target_xcoff_flavour) |
#define bfd_big_endian(abfd) ((abfd)->xvec->byteorder == BFD_ENDIAN_BIG) |
#define bfd_little_endian(abfd) ((abfd)->xvec->byteorder == BFD_ENDIAN_LITTLE) |
#define bfd_header_big_endian(abfd) \ |
((abfd)->xvec->header_byteorder == BFD_ENDIAN_BIG) |
#define bfd_header_little_endian(abfd) \ |
((abfd)->xvec->header_byteorder == BFD_ENDIAN_LITTLE) |
#define bfd_get_file_flags(abfd) ((abfd)->flags) |
#define bfd_applicable_file_flags(abfd) ((abfd)->xvec->object_flags) |
#define bfd_applicable_section_flags(abfd) ((abfd)->xvec->section_flags) |
#define bfd_my_archive(abfd) ((abfd)->my_archive) |
#define bfd_has_map(abfd) ((abfd)->has_armap) |
#define bfd_is_thin_archive(abfd) ((abfd)->is_thin_archive) |
#define bfd_valid_reloc_types(abfd) ((abfd)->xvec->valid_reloc_types) |
#define bfd_usrdata(abfd) ((abfd)->usrdata) |
#define bfd_get_start_address(abfd) ((abfd)->start_address) |
#define bfd_get_symcount(abfd) ((abfd)->symcount) |
#define bfd_get_outsymbols(abfd) ((abfd)->outsymbols) |
#define bfd_count_sections(abfd) ((abfd)->section_count) |
#define bfd_get_dynamic_symcount(abfd) ((abfd)->dynsymcount) |
#define bfd_get_symbol_leading_char(abfd) ((abfd)->xvec->symbol_leading_char) |
#define bfd_set_cacheable(abfd,bool) (((abfd)->cacheable = bool), TRUE) |
extern bfd_boolean bfd_cache_close |
(bfd *abfd); |
/* NB: This declaration should match the autogenerated one in libbfd.h. */ |
extern bfd_boolean bfd_cache_close_all (void); |
extern bfd_boolean bfd_record_phdr |
(bfd *, unsigned long, bfd_boolean, flagword, bfd_boolean, bfd_vma, |
bfd_boolean, bfd_boolean, unsigned int, struct bfd_section **); |
/* Byte swapping routines. */ |
bfd_uint64_t bfd_getb64 (const void *); |
bfd_uint64_t bfd_getl64 (const void *); |
bfd_int64_t bfd_getb_signed_64 (const void *); |
bfd_int64_t bfd_getl_signed_64 (const void *); |
bfd_vma bfd_getb32 (const void *); |
bfd_vma bfd_getl32 (const void *); |
bfd_signed_vma bfd_getb_signed_32 (const void *); |
bfd_signed_vma bfd_getl_signed_32 (const void *); |
bfd_vma bfd_getb16 (const void *); |
bfd_vma bfd_getl16 (const void *); |
bfd_signed_vma bfd_getb_signed_16 (const void *); |
bfd_signed_vma bfd_getl_signed_16 (const void *); |
void bfd_putb64 (bfd_uint64_t, void *); |
void bfd_putl64 (bfd_uint64_t, void *); |
void bfd_putb32 (bfd_vma, void *); |
void bfd_putl32 (bfd_vma, void *); |
void bfd_putb16 (bfd_vma, void *); |
void bfd_putl16 (bfd_vma, void *); |
/* Byte swapping routines which take size and endiannes as arguments. */ |
bfd_uint64_t bfd_get_bits (const void *, int, bfd_boolean); |
void bfd_put_bits (bfd_uint64_t, void *, int, bfd_boolean); |
#if defined(__STDC__) || defined(ALMOST_STDC) |
struct ecoff_debug_info; |
struct ecoff_debug_swap; |
struct ecoff_extr; |
struct bfd_symbol; |
struct bfd_link_info; |
struct bfd_link_hash_entry; |
struct bfd_section_already_linked; |
struct bfd_elf_version_tree; |
#endif |
extern bfd_boolean bfd_section_already_linked_table_init (void); |
extern void bfd_section_already_linked_table_free (void); |
extern bfd_boolean _bfd_handle_already_linked |
(struct bfd_section *, struct bfd_section_already_linked *, |
struct bfd_link_info *); |
/* Externally visible ECOFF routines. */ |
extern bfd_vma bfd_ecoff_get_gp_value |
(bfd * abfd); |
extern bfd_boolean bfd_ecoff_set_gp_value |
(bfd *abfd, bfd_vma gp_value); |
extern bfd_boolean bfd_ecoff_set_regmasks |
(bfd *abfd, unsigned long gprmask, unsigned long fprmask, |
unsigned long *cprmask); |
extern void *bfd_ecoff_debug_init |
(bfd *output_bfd, struct ecoff_debug_info *output_debug, |
const struct ecoff_debug_swap *output_swap, struct bfd_link_info *); |
extern void bfd_ecoff_debug_free |
(void *handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, |
const struct ecoff_debug_swap *output_swap, struct bfd_link_info *); |
extern bfd_boolean bfd_ecoff_debug_accumulate |
(void *handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, |
const struct ecoff_debug_swap *output_swap, bfd *input_bfd, |
struct ecoff_debug_info *input_debug, |
const struct ecoff_debug_swap *input_swap, struct bfd_link_info *); |
extern bfd_boolean bfd_ecoff_debug_accumulate_other |
(void *handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, |
const struct ecoff_debug_swap *output_swap, bfd *input_bfd, |
struct bfd_link_info *); |
extern bfd_boolean bfd_ecoff_debug_externals |
(bfd *abfd, struct ecoff_debug_info *debug, |
const struct ecoff_debug_swap *swap, bfd_boolean relocatable, |
bfd_boolean (*get_extr) (struct bfd_symbol *, struct ecoff_extr *), |
void (*set_index) (struct bfd_symbol *, bfd_size_type)); |
extern bfd_boolean bfd_ecoff_debug_one_external |
(bfd *abfd, struct ecoff_debug_info *debug, |
const struct ecoff_debug_swap *swap, const char *name, |
struct ecoff_extr *esym); |
extern bfd_size_type bfd_ecoff_debug_size |
(bfd *abfd, struct ecoff_debug_info *debug, |
const struct ecoff_debug_swap *swap); |
extern bfd_boolean bfd_ecoff_write_debug |
(bfd *abfd, struct ecoff_debug_info *debug, |
const struct ecoff_debug_swap *swap, file_ptr where); |
extern bfd_boolean bfd_ecoff_write_accumulated_debug |
(void *handle, bfd *abfd, struct ecoff_debug_info *debug, |
const struct ecoff_debug_swap *swap, |
struct bfd_link_info *info, file_ptr where); |
/* Externally visible ELF routines. */ |
struct bfd_link_needed_list |
{ |
struct bfd_link_needed_list *next; |
bfd *by; |
const char *name; |
}; |
enum dynamic_lib_link_class { |
DYN_NORMAL = 0, |
DYN_AS_NEEDED = 1, |
DYN_DT_NEEDED = 2, |
DYN_NO_ADD_NEEDED = 4, |
DYN_NO_NEEDED = 8 |
}; |
enum notice_asneeded_action { |
notice_as_needed, |
notice_not_needed, |
notice_needed |
}; |
extern bfd_boolean bfd_elf_record_link_assignment |
(bfd *, struct bfd_link_info *, const char *, bfd_boolean, |
bfd_boolean); |
extern struct bfd_link_needed_list *bfd_elf_get_needed_list |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean bfd_elf_get_bfd_needed_list |
(bfd *, struct bfd_link_needed_list **); |
extern bfd_boolean bfd_elf_stack_segment_size (bfd *, struct bfd_link_info *, |
const char *, bfd_vma); |
extern bfd_boolean bfd_elf_size_dynamic_sections |
(bfd *, const char *, const char *, const char *, const char *, const char *, |
const char * const *, struct bfd_link_info *, struct bfd_section **); |
extern bfd_boolean bfd_elf_size_dynsym_hash_dynstr |
(bfd *, struct bfd_link_info *); |
extern void bfd_elf_set_dt_needed_name |
(bfd *, const char *); |
extern const char *bfd_elf_get_dt_soname |
(bfd *); |
extern void bfd_elf_set_dyn_lib_class |
(bfd *, enum dynamic_lib_link_class); |
extern int bfd_elf_get_dyn_lib_class |
(bfd *); |
extern struct bfd_link_needed_list *bfd_elf_get_runpath_list |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean bfd_elf_discard_info |
(bfd *, struct bfd_link_info *); |
extern unsigned int _bfd_elf_default_action_discarded |
(struct bfd_section *); |
/* Return an upper bound on the number of bytes required to store a |
copy of ABFD's program header table entries. Return -1 if an error |
occurs; bfd_get_error will return an appropriate code. */ |
extern long bfd_get_elf_phdr_upper_bound |
(bfd *abfd); |
/* Copy ABFD's program header table entries to *PHDRS. The entries |
will be stored as an array of Elf_Internal_Phdr structures, as |
defined in include/elf/internal.h. To find out how large the |
buffer needs to be, call bfd_get_elf_phdr_upper_bound. |
Return the number of program header table entries read, or -1 if an |
error occurs; bfd_get_error will return an appropriate code. */ |
extern int bfd_get_elf_phdrs |
(bfd *abfd, void *phdrs); |
/* Create a new BFD as if by bfd_openr. Rather than opening a file, |
reconstruct an ELF file by reading the segments out of remote memory |
based on the ELF file header at EHDR_VMA and the ELF program headers it |
points to. If not null, *LOADBASEP is filled in with the difference |
between the VMAs from which the segments were read, and the VMAs the |
file headers (and hence BFD's idea of each section's VMA) put them at. |
The function TARGET_READ_MEMORY is called to copy LEN bytes from the |
remote memory at target address VMA into the local buffer at MYADDR; it |
should return zero on success or an `errno' code on failure. TEMPL must |
be a BFD for an ELF target with the word size and byte order found in |
the remote memory. */ |
extern bfd *bfd_elf_bfd_from_remote_memory |
(bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, |
int (*target_read_memory) (bfd_vma vma, bfd_byte *myaddr, |
bfd_size_type len)); |
extern struct bfd_section *_bfd_elf_tls_setup |
(bfd *, struct bfd_link_info *); |
extern struct bfd_section * |
_bfd_nearby_section (bfd *, struct bfd_section *, bfd_vma); |
extern void _bfd_fix_excluded_sec_syms |
(bfd *, struct bfd_link_info *); |
extern unsigned bfd_m68k_mach_to_features (int); |
extern int bfd_m68k_features_to_mach (unsigned); |
extern bfd_boolean bfd_m68k_elf32_create_embedded_relocs |
(bfd *, struct bfd_link_info *, struct bfd_section *, struct bfd_section *, |
char **); |
extern void bfd_elf_m68k_set_target_options (struct bfd_link_info *, int); |
extern bfd_boolean bfd_bfin_elf32_create_embedded_relocs |
(bfd *, struct bfd_link_info *, struct bfd_section *, struct bfd_section *, |
char **); |
extern bfd_boolean bfd_cr16_elf32_create_embedded_relocs |
(bfd *, struct bfd_link_info *, struct bfd_section *, struct bfd_section *, |
char **); |
/* SunOS shared library support routines for the linker. */ |
extern struct bfd_link_needed_list *bfd_sunos_get_needed_list |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean bfd_sunos_record_link_assignment |
(bfd *, struct bfd_link_info *, const char *); |
extern bfd_boolean bfd_sunos_size_dynamic_sections |
(bfd *, struct bfd_link_info *, struct bfd_section **, |
struct bfd_section **, struct bfd_section **); |
/* Linux shared library support routines for the linker. */ |
extern bfd_boolean bfd_i386linux_size_dynamic_sections |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean bfd_m68klinux_size_dynamic_sections |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean bfd_sparclinux_size_dynamic_sections |
(bfd *, struct bfd_link_info *); |
/* mmap hacks */ |
struct _bfd_window_internal; |
typedef struct _bfd_window_internal bfd_window_internal; |
typedef struct _bfd_window |
{ |
/* What the user asked for. */ |
void *data; |
bfd_size_type size; |
/* The actual window used by BFD. Small user-requested read-only |
regions sharing a page may share a single window into the object |
file. Read-write versions shouldn't until I've fixed things to |
keep track of which portions have been claimed by the |
application; don't want to give the same region back when the |
application wants two writable copies! */ |
struct _bfd_window_internal *i; |
} |
bfd_window; |
extern void bfd_init_window |
(bfd_window *); |
extern void bfd_free_window |
(bfd_window *); |
extern bfd_boolean bfd_get_file_window |
(bfd *, file_ptr, bfd_size_type, bfd_window *, bfd_boolean); |
/* XCOFF support routines for the linker. */ |
extern bfd_boolean bfd_xcoff_split_import_path |
(bfd *, const char *, const char **, const char **); |
extern bfd_boolean bfd_xcoff_set_archive_import_path |
(struct bfd_link_info *, bfd *, const char *); |
extern bfd_boolean bfd_xcoff_link_record_set |
(bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, bfd_size_type); |
extern bfd_boolean bfd_xcoff_import_symbol |
(bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, bfd_vma, |
const char *, const char *, const char *, unsigned int); |
extern bfd_boolean bfd_xcoff_export_symbol |
(bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *); |
extern bfd_boolean bfd_xcoff_link_count_reloc |
(bfd *, struct bfd_link_info *, const char *); |
extern bfd_boolean bfd_xcoff_record_link_assignment |
(bfd *, struct bfd_link_info *, const char *); |
extern bfd_boolean bfd_xcoff_size_dynamic_sections |
(bfd *, struct bfd_link_info *, const char *, const char *, |
unsigned long, unsigned long, unsigned long, bfd_boolean, |
int, bfd_boolean, unsigned int, struct bfd_section **, bfd_boolean); |
extern bfd_boolean bfd_xcoff_link_generate_rtinit |
(bfd *, const char *, const char *, bfd_boolean); |
/* XCOFF support routines for ar. */ |
extern bfd_boolean bfd_xcoff_ar_archive_set_magic |
(bfd *, char *); |
/* Externally visible COFF routines. */ |
#if defined(__STDC__) || defined(ALMOST_STDC) |
struct internal_syment; |
union internal_auxent; |
#endif |
extern bfd_boolean bfd_coff_get_syment |
(bfd *, struct bfd_symbol *, struct internal_syment *); |
extern bfd_boolean bfd_coff_get_auxent |
(bfd *, struct bfd_symbol *, int, union internal_auxent *); |
extern bfd_boolean bfd_coff_set_symbol_class |
(bfd *, struct bfd_symbol *, unsigned int); |
extern bfd_boolean bfd_m68k_coff_create_embedded_relocs |
(bfd *, struct bfd_link_info *, struct bfd_section *, struct bfd_section *, char **); |
/* ARM VFP11 erratum workaround support. */ |
typedef enum |
{ |
BFD_ARM_VFP11_FIX_DEFAULT, |
BFD_ARM_VFP11_FIX_NONE, |
BFD_ARM_VFP11_FIX_SCALAR, |
BFD_ARM_VFP11_FIX_VECTOR |
} bfd_arm_vfp11_fix; |
extern void bfd_elf32_arm_init_maps |
(bfd *); |
extern void bfd_elf32_arm_set_vfp11_fix |
(bfd *, struct bfd_link_info *); |
extern void bfd_elf32_arm_set_cortex_a8_fix |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean bfd_elf32_arm_vfp11_erratum_scan |
(bfd *, struct bfd_link_info *); |
extern void bfd_elf32_arm_vfp11_fix_veneer_locations |
(bfd *, struct bfd_link_info *); |
/* ARM Interworking support. Called from linker. */ |
extern bfd_boolean bfd_arm_allocate_interworking_sections |
(struct bfd_link_info *); |
extern bfd_boolean bfd_arm_process_before_allocation |
(bfd *, struct bfd_link_info *, int); |
extern bfd_boolean bfd_arm_get_bfd_for_interworking |
(bfd *, struct bfd_link_info *); |
/* PE ARM Interworking support. Called from linker. */ |
extern bfd_boolean bfd_arm_pe_allocate_interworking_sections |
(struct bfd_link_info *); |
extern bfd_boolean bfd_arm_pe_process_before_allocation |
(bfd *, struct bfd_link_info *, int); |
extern bfd_boolean bfd_arm_pe_get_bfd_for_interworking |
(bfd *, struct bfd_link_info *); |
/* ELF ARM Interworking support. Called from linker. */ |
extern bfd_boolean bfd_elf32_arm_allocate_interworking_sections |
(struct bfd_link_info *); |
extern bfd_boolean bfd_elf32_arm_process_before_allocation |
(bfd *, struct bfd_link_info *); |
void bfd_elf32_arm_set_target_relocs |
(bfd *, struct bfd_link_info *, int, char *, int, int, bfd_arm_vfp11_fix, |
int, int, int, int, int); |
extern bfd_boolean bfd_elf32_arm_get_bfd_for_interworking |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean bfd_elf32_arm_add_glue_sections_to_bfd |
(bfd *, struct bfd_link_info *); |
/* ELF ARM mapping symbol support */ |
#define BFD_ARM_SPECIAL_SYM_TYPE_MAP (1 << 0) |
#define BFD_ARM_SPECIAL_SYM_TYPE_TAG (1 << 1) |
#define BFD_ARM_SPECIAL_SYM_TYPE_OTHER (1 << 2) |
#define BFD_ARM_SPECIAL_SYM_TYPE_ANY (~0) |
extern bfd_boolean bfd_is_arm_special_symbol_name |
(const char * name, int type); |
extern void bfd_elf32_arm_set_byteswap_code (struct bfd_link_info *, int); |
/* ARM Note section processing. */ |
extern bfd_boolean bfd_arm_merge_machines |
(bfd *, bfd *); |
extern bfd_boolean bfd_arm_update_notes |
(bfd *, const char *); |
extern unsigned int bfd_arm_get_mach_from_notes |
(bfd *, const char *); |
/* ARM stub generation support. Called from the linker. */ |
extern int elf32_arm_setup_section_lists |
(bfd *, struct bfd_link_info *); |
extern void elf32_arm_next_input_section |
(struct bfd_link_info *, struct bfd_section *); |
extern bfd_boolean elf32_arm_size_stubs |
(bfd *, bfd *, struct bfd_link_info *, bfd_signed_vma, |
struct bfd_section * (*) (const char *, struct bfd_section *, unsigned int), |
void (*) (void)); |
extern bfd_boolean elf32_arm_build_stubs |
(struct bfd_link_info *); |
/* ARM unwind section editing support. */ |
extern bfd_boolean elf32_arm_fix_exidx_coverage |
(struct bfd_section **, unsigned int, struct bfd_link_info *, bfd_boolean); |
/* C6x unwind section editing support. */ |
extern bfd_boolean elf32_tic6x_fix_exidx_coverage |
(struct bfd_section **, unsigned int, struct bfd_link_info *, bfd_boolean); |
/* PowerPC @tls opcode transform/validate. */ |
extern unsigned int _bfd_elf_ppc_at_tls_transform |
(unsigned int, unsigned int); |
/* PowerPC @tprel opcode transform/validate. */ |
extern unsigned int _bfd_elf_ppc_at_tprel_transform |
(unsigned int, unsigned int); |
extern void bfd_elf64_aarch64_init_maps |
(bfd *); |
extern void bfd_elf32_aarch64_init_maps |
(bfd *); |
extern void bfd_elf64_aarch64_set_options |
(bfd *, struct bfd_link_info *, int, int, int); |
extern void bfd_elf32_aarch64_set_options |
(bfd *, struct bfd_link_info *, int, int, int); |
/* ELF AArch64 mapping symbol support. */ |
#define BFD_AARCH64_SPECIAL_SYM_TYPE_MAP (1 << 0) |
#define BFD_AARCH64_SPECIAL_SYM_TYPE_TAG (1 << 1) |
#define BFD_AARCH64_SPECIAL_SYM_TYPE_OTHER (1 << 2) |
#define BFD_AARCH64_SPECIAL_SYM_TYPE_ANY (~0) |
extern bfd_boolean bfd_is_aarch64_special_symbol_name |
(const char * name, int type); |
/* AArch64 stub generation support for ELF64. Called from the linker. */ |
extern int elf64_aarch64_setup_section_lists |
(bfd *, struct bfd_link_info *); |
extern void elf64_aarch64_next_input_section |
(struct bfd_link_info *, struct bfd_section *); |
extern bfd_boolean elf64_aarch64_size_stubs |
(bfd *, bfd *, struct bfd_link_info *, bfd_signed_vma, |
struct bfd_section * (*) (const char *, struct bfd_section *), |
void (*) (void)); |
extern bfd_boolean elf64_aarch64_build_stubs |
(struct bfd_link_info *); |
/* AArch64 stub generation support for ELF32. Called from the linker. */ |
extern int elf32_aarch64_setup_section_lists |
(bfd *, struct bfd_link_info *); |
extern void elf32_aarch64_next_input_section |
(struct bfd_link_info *, struct bfd_section *); |
extern bfd_boolean elf32_aarch64_size_stubs |
(bfd *, bfd *, struct bfd_link_info *, bfd_signed_vma, |
struct bfd_section * (*) (const char *, struct bfd_section *), |
void (*) (void)); |
extern bfd_boolean elf32_aarch64_build_stubs |
(struct bfd_link_info *); |
/* TI COFF load page support. */ |
extern void bfd_ticoff_set_section_load_page |
(struct bfd_section *, int); |
extern int bfd_ticoff_get_section_load_page |
(struct bfd_section *); |
/* H8/300 functions. */ |
extern bfd_vma bfd_h8300_pad_address |
(bfd *, bfd_vma); |
/* IA64 Itanium code generation. Called from linker. */ |
extern void bfd_elf32_ia64_after_parse |
(int); |
extern void bfd_elf64_ia64_after_parse |
(int); |
/* This structure is used for a comdat section, as in PE. A comdat |
section is associated with a particular symbol. When the linker |
sees a comdat section, it keeps only one of the sections with a |
given name and associated with a given symbol. */ |
struct coff_comdat_info |
{ |
/* The name of the symbol associated with a comdat section. */ |
const char *name; |
/* The local symbol table index of the symbol associated with a |
comdat section. This is only meaningful to the object file format |
specific code; it is not an index into the list returned by |
bfd_canonicalize_symtab. */ |
long symbol; |
}; |
extern struct coff_comdat_info * bfd_coff_get_comdat_section |
(bfd *, struct bfd_section *); |
/* Extracted from init.c. */ |
void bfd_init (void); |
/* Extracted from opncls.c. */ |
extern unsigned int bfd_use_reserved_id; |
bfd *bfd_fopen (const char *filename, const char *target, |
const char *mode, int fd); |
bfd *bfd_openr (const char *filename, const char *target); |
bfd *bfd_fdopenr (const char *filename, const char *target, int fd); |
bfd *bfd_openstreamr (const char *, const char *, void *); |
bfd *bfd_openr_iovec (const char *filename, const char *target, |
void *(*open_func) (struct bfd *nbfd, |
void *open_closure), |
void *open_closure, |
file_ptr (*pread_func) (struct bfd *nbfd, |
void *stream, |
void *buf, |
file_ptr nbytes, |
file_ptr offset), |
int (*close_func) (struct bfd *nbfd, |
void *stream), |
int (*stat_func) (struct bfd *abfd, |
void *stream, |
struct stat *sb)); |
bfd *bfd_openw (const char *filename, const char *target); |
bfd_boolean bfd_close (bfd *abfd); |
bfd_boolean bfd_close_all_done (bfd *); |
bfd *bfd_create (const char *filename, bfd *templ); |
bfd_boolean bfd_make_writable (bfd *abfd); |
bfd_boolean bfd_make_readable (bfd *abfd); |
void *bfd_alloc (bfd *abfd, bfd_size_type wanted); |
void *bfd_zalloc (bfd *abfd, bfd_size_type wanted); |
unsigned long bfd_calc_gnu_debuglink_crc32 |
(unsigned long crc, const unsigned char *buf, bfd_size_type len); |
char *bfd_get_debug_link_info (bfd *abfd, unsigned long *crc32_out); |
char *bfd_get_alt_debug_link_info (bfd *abfd, unsigned long *crc32_out); |
char *bfd_follow_gnu_debuglink (bfd *abfd, const char *dir); |
char *bfd_follow_gnu_debugaltlink (bfd *abfd, const char *dir); |
struct bfd_section *bfd_create_gnu_debuglink_section |
(bfd *abfd, const char *filename); |
bfd_boolean bfd_fill_in_gnu_debuglink_section |
(bfd *abfd, struct bfd_section *sect, const char *filename); |
/* Extracted from libbfd.c. */ |
/* Byte swapping macros for user section data. */ |
#define bfd_put_8(abfd, val, ptr) \ |
((void) (*((unsigned char *) (ptr)) = (val) & 0xff)) |
#define bfd_put_signed_8 \ |
bfd_put_8 |
#define bfd_get_8(abfd, ptr) \ |
(*(const unsigned char *) (ptr) & 0xff) |
#define bfd_get_signed_8(abfd, ptr) \ |
(((*(const unsigned char *) (ptr) & 0xff) ^ 0x80) - 0x80) |
#define bfd_put_16(abfd, val, ptr) \ |
BFD_SEND (abfd, bfd_putx16, ((val),(ptr))) |
#define bfd_put_signed_16 \ |
bfd_put_16 |
#define bfd_get_16(abfd, ptr) \ |
BFD_SEND (abfd, bfd_getx16, (ptr)) |
#define bfd_get_signed_16(abfd, ptr) \ |
BFD_SEND (abfd, bfd_getx_signed_16, (ptr)) |
#define bfd_put_32(abfd, val, ptr) \ |
BFD_SEND (abfd, bfd_putx32, ((val),(ptr))) |
#define bfd_put_signed_32 \ |
bfd_put_32 |
#define bfd_get_32(abfd, ptr) \ |
BFD_SEND (abfd, bfd_getx32, (ptr)) |
#define bfd_get_signed_32(abfd, ptr) \ |
BFD_SEND (abfd, bfd_getx_signed_32, (ptr)) |
#define bfd_put_64(abfd, val, ptr) \ |
BFD_SEND (abfd, bfd_putx64, ((val), (ptr))) |
#define bfd_put_signed_64 \ |
bfd_put_64 |
#define bfd_get_64(abfd, ptr) \ |
BFD_SEND (abfd, bfd_getx64, (ptr)) |
#define bfd_get_signed_64(abfd, ptr) \ |
BFD_SEND (abfd, bfd_getx_signed_64, (ptr)) |
#define bfd_get(bits, abfd, ptr) \ |
((bits) == 8 ? (bfd_vma) bfd_get_8 (abfd, ptr) \ |
: (bits) == 16 ? bfd_get_16 (abfd, ptr) \ |
: (bits) == 32 ? bfd_get_32 (abfd, ptr) \ |
: (bits) == 64 ? bfd_get_64 (abfd, ptr) \ |
: (abort (), (bfd_vma) - 1)) |
#define bfd_put(bits, abfd, val, ptr) \ |
((bits) == 8 ? bfd_put_8 (abfd, val, ptr) \ |
: (bits) == 16 ? bfd_put_16 (abfd, val, ptr) \ |
: (bits) == 32 ? bfd_put_32 (abfd, val, ptr) \ |
: (bits) == 64 ? bfd_put_64 (abfd, val, ptr) \ |
: (abort (), (void) 0)) |
/* Byte swapping macros for file header data. */ |
#define bfd_h_put_8(abfd, val, ptr) \ |
bfd_put_8 (abfd, val, ptr) |
#define bfd_h_put_signed_8(abfd, val, ptr) \ |
bfd_put_8 (abfd, val, ptr) |
#define bfd_h_get_8(abfd, ptr) \ |
bfd_get_8 (abfd, ptr) |
#define bfd_h_get_signed_8(abfd, ptr) \ |
bfd_get_signed_8 (abfd, ptr) |
#define bfd_h_put_16(abfd, val, ptr) \ |
BFD_SEND (abfd, bfd_h_putx16, (val, ptr)) |
#define bfd_h_put_signed_16 \ |
bfd_h_put_16 |
#define bfd_h_get_16(abfd, ptr) \ |
BFD_SEND (abfd, bfd_h_getx16, (ptr)) |
#define bfd_h_get_signed_16(abfd, ptr) \ |
BFD_SEND (abfd, bfd_h_getx_signed_16, (ptr)) |
#define bfd_h_put_32(abfd, val, ptr) \ |
BFD_SEND (abfd, bfd_h_putx32, (val, ptr)) |
#define bfd_h_put_signed_32 \ |
bfd_h_put_32 |
#define bfd_h_get_32(abfd, ptr) \ |
BFD_SEND (abfd, bfd_h_getx32, (ptr)) |
#define bfd_h_get_signed_32(abfd, ptr) \ |
BFD_SEND (abfd, bfd_h_getx_signed_32, (ptr)) |
#define bfd_h_put_64(abfd, val, ptr) \ |
BFD_SEND (abfd, bfd_h_putx64, (val, ptr)) |
#define bfd_h_put_signed_64 \ |
bfd_h_put_64 |
#define bfd_h_get_64(abfd, ptr) \ |
BFD_SEND (abfd, bfd_h_getx64, (ptr)) |
#define bfd_h_get_signed_64(abfd, ptr) \ |
BFD_SEND (abfd, bfd_h_getx_signed_64, (ptr)) |
/* Aliases for the above, which should eventually go away. */ |
#define H_PUT_64 bfd_h_put_64 |
#define H_PUT_32 bfd_h_put_32 |
#define H_PUT_16 bfd_h_put_16 |
#define H_PUT_8 bfd_h_put_8 |
#define H_PUT_S64 bfd_h_put_signed_64 |
#define H_PUT_S32 bfd_h_put_signed_32 |
#define H_PUT_S16 bfd_h_put_signed_16 |
#define H_PUT_S8 bfd_h_put_signed_8 |
#define H_GET_64 bfd_h_get_64 |
#define H_GET_32 bfd_h_get_32 |
#define H_GET_16 bfd_h_get_16 |
#define H_GET_8 bfd_h_get_8 |
#define H_GET_S64 bfd_h_get_signed_64 |
#define H_GET_S32 bfd_h_get_signed_32 |
#define H_GET_S16 bfd_h_get_signed_16 |
#define H_GET_S8 bfd_h_get_signed_8 |
/* Extracted from bfdio.c. */ |
long bfd_get_mtime (bfd *abfd); |
file_ptr bfd_get_size (bfd *abfd); |
void *bfd_mmap (bfd *abfd, void *addr, bfd_size_type len, |
int prot, int flags, file_ptr offset, |
void **map_addr, bfd_size_type *map_len); |
/* Extracted from bfdwin.c. */ |
/* Extracted from section.c. */ |
typedef struct bfd_section |
{ |
/* The name of the section; the name isn't a copy, the pointer is |
the same as that passed to bfd_make_section. */ |
const char *name; |
/* A unique sequence number. */ |
int id; |
/* Which section in the bfd; 0..n-1 as sections are created in a bfd. */ |
int index; |
/* The next section in the list belonging to the BFD, or NULL. */ |
struct bfd_section *next; |
/* The previous section in the list belonging to the BFD, or NULL. */ |
struct bfd_section *prev; |
/* The field flags contains attributes of the section. Some |
flags are read in from the object file, and some are |
synthesized from other information. */ |
flagword flags; |
#define SEC_NO_FLAGS 0x000 |
/* Tells the OS to allocate space for this section when loading. |
This is clear for a section containing debug information only. */ |
#define SEC_ALLOC 0x001 |
/* Tells the OS to load the section from the file when loading. |
This is clear for a .bss section. */ |
#define SEC_LOAD 0x002 |
/* The section contains data still to be relocated, so there is |
some relocation information too. */ |
#define SEC_RELOC 0x004 |
/* A signal to the OS that the section contains read only data. */ |
#define SEC_READONLY 0x008 |
/* The section contains code only. */ |
#define SEC_CODE 0x010 |
/* The section contains data only. */ |
#define SEC_DATA 0x020 |
/* The section will reside in ROM. */ |
#define SEC_ROM 0x040 |
/* The section contains constructor information. This section |
type is used by the linker to create lists of constructors and |
destructors used by <<g++>>. When a back end sees a symbol |
which should be used in a constructor list, it creates a new |
section for the type of name (e.g., <<__CTOR_LIST__>>), attaches |
the symbol to it, and builds a relocation. To build the lists |
of constructors, all the linker has to do is catenate all the |
sections called <<__CTOR_LIST__>> and relocate the data |
contained within - exactly the operations it would peform on |
standard data. */ |
#define SEC_CONSTRUCTOR 0x080 |
/* The section has contents - a data section could be |
<<SEC_ALLOC>> | <<SEC_HAS_CONTENTS>>; a debug section could be |
<<SEC_HAS_CONTENTS>> */ |
#define SEC_HAS_CONTENTS 0x100 |
/* An instruction to the linker to not output the section |
even if it has information which would normally be written. */ |
#define SEC_NEVER_LOAD 0x200 |
/* The section contains thread local data. */ |
#define SEC_THREAD_LOCAL 0x400 |
/* The section has GOT references. This flag is only for the |
linker, and is currently only used by the elf32-hppa back end. |
It will be set if global offset table references were detected |
in this section, which indicate to the linker that the section |
contains PIC code, and must be handled specially when doing a |
static link. */ |
#define SEC_HAS_GOT_REF 0x800 |
/* The section contains common symbols (symbols may be defined |
multiple times, the value of a symbol is the amount of |
space it requires, and the largest symbol value is the one |
used). Most targets have exactly one of these (which we |
translate to bfd_com_section_ptr), but ECOFF has two. */ |
#define SEC_IS_COMMON 0x1000 |
/* The section contains only debugging information. For |
example, this is set for ELF .debug and .stab sections. |
strip tests this flag to see if a section can be |
discarded. */ |
#define SEC_DEBUGGING 0x2000 |
/* The contents of this section are held in memory pointed to |
by the contents field. This is checked by bfd_get_section_contents, |
and the data is retrieved from memory if appropriate. */ |
#define SEC_IN_MEMORY 0x4000 |
/* The contents of this section are to be excluded by the |
linker for executable and shared objects unless those |
objects are to be further relocated. */ |
#define SEC_EXCLUDE 0x8000 |
/* The contents of this section are to be sorted based on the sum of |
the symbol and addend values specified by the associated relocation |
entries. Entries without associated relocation entries will be |
appended to the end of the section in an unspecified order. */ |
#define SEC_SORT_ENTRIES 0x10000 |
/* When linking, duplicate sections of the same name should be |
discarded, rather than being combined into a single section as |
is usually done. This is similar to how common symbols are |
handled. See SEC_LINK_DUPLICATES below. */ |
#define SEC_LINK_ONCE 0x20000 |
/* If SEC_LINK_ONCE is set, this bitfield describes how the linker |
should handle duplicate sections. */ |
#define SEC_LINK_DUPLICATES 0xc0000 |
/* This value for SEC_LINK_DUPLICATES means that duplicate |
sections with the same name should simply be discarded. */ |
#define SEC_LINK_DUPLICATES_DISCARD 0x0 |
/* This value for SEC_LINK_DUPLICATES means that the linker |
should warn if there are any duplicate sections, although |
it should still only link one copy. */ |
#define SEC_LINK_DUPLICATES_ONE_ONLY 0x40000 |
/* This value for SEC_LINK_DUPLICATES means that the linker |
should warn if any duplicate sections are a different size. */ |
#define SEC_LINK_DUPLICATES_SAME_SIZE 0x80000 |
/* This value for SEC_LINK_DUPLICATES means that the linker |
should warn if any duplicate sections contain different |
contents. */ |
#define SEC_LINK_DUPLICATES_SAME_CONTENTS \ |
(SEC_LINK_DUPLICATES_ONE_ONLY | SEC_LINK_DUPLICATES_SAME_SIZE) |
/* This section was created by the linker as part of dynamic |
relocation or other arcane processing. It is skipped when |
going through the first-pass output, trusting that someone |
else up the line will take care of it later. */ |
#define SEC_LINKER_CREATED 0x100000 |
/* This section should not be subject to garbage collection. |
Also set to inform the linker that this section should not be |
listed in the link map as discarded. */ |
#define SEC_KEEP 0x200000 |
/* This section contains "short" data, and should be placed |
"near" the GP. */ |
#define SEC_SMALL_DATA 0x400000 |
/* Attempt to merge identical entities in the section. |
Entity size is given in the entsize field. */ |
#define SEC_MERGE 0x800000 |
/* If given with SEC_MERGE, entities to merge are zero terminated |
strings where entsize specifies character size instead of fixed |
size entries. */ |
#define SEC_STRINGS 0x1000000 |
/* This section contains data about section groups. */ |
#define SEC_GROUP 0x2000000 |
/* The section is a COFF shared library section. This flag is |
only for the linker. If this type of section appears in |
the input file, the linker must copy it to the output file |
without changing the vma or size. FIXME: Although this |
was originally intended to be general, it really is COFF |
specific (and the flag was renamed to indicate this). It |
might be cleaner to have some more general mechanism to |
allow the back end to control what the linker does with |
sections. */ |
#define SEC_COFF_SHARED_LIBRARY 0x4000000 |
/* This input section should be copied to output in reverse order |
as an array of pointers. This is for ELF linker internal use |
only. */ |
#define SEC_ELF_REVERSE_COPY 0x4000000 |
/* This section contains data which may be shared with other |
executables or shared objects. This is for COFF only. */ |
#define SEC_COFF_SHARED 0x8000000 |
/* When a section with this flag is being linked, then if the size of |
the input section is less than a page, it should not cross a page |
boundary. If the size of the input section is one page or more, |
it should be aligned on a page boundary. This is for TI |
TMS320C54X only. */ |
#define SEC_TIC54X_BLOCK 0x10000000 |
/* Conditionally link this section; do not link if there are no |
references found to any symbol in the section. This is for TI |
TMS320C54X only. */ |
#define SEC_TIC54X_CLINK 0x20000000 |
/* Indicate that section has the no read flag set. This happens |
when memory read flag isn't set. */ |
#define SEC_COFF_NOREAD 0x40000000 |
/* End of section flags. */ |
/* Some internal packed boolean fields. */ |
/* See the vma field. */ |
unsigned int user_set_vma : 1; |
/* A mark flag used by some of the linker backends. */ |
unsigned int linker_mark : 1; |
/* Another mark flag used by some of the linker backends. Set for |
output sections that have an input section. */ |
unsigned int linker_has_input : 1; |
/* Mark flag used by some linker backends for garbage collection. */ |
unsigned int gc_mark : 1; |
/* Section compression status. */ |
unsigned int compress_status : 2; |
#define COMPRESS_SECTION_NONE 0 |
#define COMPRESS_SECTION_DONE 1 |
#define DECOMPRESS_SECTION_SIZED 2 |
/* The following flags are used by the ELF linker. */ |
/* Mark sections which have been allocated to segments. */ |
unsigned int segment_mark : 1; |
/* Type of sec_info information. */ |
unsigned int sec_info_type:3; |
#define SEC_INFO_TYPE_NONE 0 |
#define SEC_INFO_TYPE_STABS 1 |
#define SEC_INFO_TYPE_MERGE 2 |
#define SEC_INFO_TYPE_EH_FRAME 3 |
#define SEC_INFO_TYPE_JUST_SYMS 4 |
/* Nonzero if this section uses RELA relocations, rather than REL. */ |
unsigned int use_rela_p:1; |
/* Bits used by various backends. The generic code doesn't touch |
these fields. */ |
unsigned int sec_flg0:1; |
unsigned int sec_flg1:1; |
unsigned int sec_flg2:1; |
unsigned int sec_flg3:1; |
unsigned int sec_flg4:1; |
unsigned int sec_flg5:1; |
/* End of internal packed boolean fields. */ |
/* The virtual memory address of the section - where it will be |
at run time. The symbols are relocated against this. The |
user_set_vma flag is maintained by bfd; if it's not set, the |
backend can assign addresses (for example, in <<a.out>>, where |
the default address for <<.data>> is dependent on the specific |
target and various flags). */ |
bfd_vma vma; |
/* The load address of the section - where it would be in a |
rom image; really only used for writing section header |
information. */ |
bfd_vma lma; |
/* The size of the section in octets, as it will be output. |
Contains a value even if the section has no contents (e.g., the |
size of <<.bss>>). */ |
bfd_size_type size; |
/* For input sections, the original size on disk of the section, in |
octets. This field should be set for any section whose size is |
changed by linker relaxation. It is required for sections where |
the linker relaxation scheme doesn't cache altered section and |
reloc contents (stabs, eh_frame, SEC_MERGE, some coff relaxing |
targets), and thus the original size needs to be kept to read the |
section multiple times. For output sections, rawsize holds the |
section size calculated on a previous linker relaxation pass. */ |
bfd_size_type rawsize; |
/* The compressed size of the section in octets. */ |
bfd_size_type compressed_size; |
/* Relaxation table. */ |
struct relax_table *relax; |
/* Count of used relaxation table entries. */ |
int relax_count; |
/* If this section is going to be output, then this value is the |
offset in *bytes* into the output section of the first byte in the |
input section (byte ==> smallest addressable unit on the |
target). In most cases, if this was going to start at the |
100th octet (8-bit quantity) in the output section, this value |
would be 100. However, if the target byte size is 16 bits |
(bfd_octets_per_byte is "2"), this value would be 50. */ |
bfd_vma output_offset; |
/* The output section through which to map on output. */ |
struct bfd_section *output_section; |
/* The alignment requirement of the section, as an exponent of 2 - |
e.g., 3 aligns to 2^3 (or 8). */ |
unsigned int alignment_power; |
/* If an input section, a pointer to a vector of relocation |
records for the data in this section. */ |
struct reloc_cache_entry *relocation; |
/* If an output section, a pointer to a vector of pointers to |
relocation records for the data in this section. */ |
struct reloc_cache_entry **orelocation; |
/* The number of relocation records in one of the above. */ |
unsigned reloc_count; |
/* Information below is back end specific - and not always used |
or updated. */ |
/* File position of section data. */ |
file_ptr filepos; |
/* File position of relocation info. */ |
file_ptr rel_filepos; |
/* File position of line data. */ |
file_ptr line_filepos; |
/* Pointer to data for applications. */ |
void *userdata; |
/* If the SEC_IN_MEMORY flag is set, this points to the actual |
contents. */ |
unsigned char *contents; |
/* Attached line number information. */ |
alent *lineno; |
/* Number of line number records. */ |
unsigned int lineno_count; |
/* Entity size for merging purposes. */ |
unsigned int entsize; |
/* Points to the kept section if this section is a link-once section, |
and is discarded. */ |
struct bfd_section *kept_section; |
/* When a section is being output, this value changes as more |
linenumbers are written out. */ |
file_ptr moving_line_filepos; |
/* What the section number is in the target world. */ |
int target_index; |
void *used_by_bfd; |
/* If this is a constructor section then here is a list of the |
relocations created to relocate items within it. */ |
struct relent_chain *constructor_chain; |
/* The BFD which owns the section. */ |
bfd *owner; |
/* A symbol which points at this section only. */ |
struct bfd_symbol *symbol; |
struct bfd_symbol **symbol_ptr_ptr; |
/* Early in the link process, map_head and map_tail are used to build |
a list of input sections attached to an output section. Later, |
output sections use these fields for a list of bfd_link_order |
structs. */ |
union { |
struct bfd_link_order *link_order; |
struct bfd_section *s; |
} map_head, map_tail; |
} asection; |
/* Relax table contains information about instructions which can |
be removed by relaxation -- replacing a long address with a |
short address. */ |
struct relax_table { |
/* Address where bytes may be deleted. */ |
bfd_vma addr; |
/* Number of bytes to be deleted. */ |
int size; |
}; |
/* These sections are global, and are managed by BFD. The application |
and target back end are not permitted to change the values in |
these sections. */ |
extern asection _bfd_std_section[4]; |
#define BFD_ABS_SECTION_NAME "*ABS*" |
#define BFD_UND_SECTION_NAME "*UND*" |
#define BFD_COM_SECTION_NAME "*COM*" |
#define BFD_IND_SECTION_NAME "*IND*" |
/* Pointer to the common section. */ |
#define bfd_com_section_ptr (&_bfd_std_section[0]) |
/* Pointer to the undefined section. */ |
#define bfd_und_section_ptr (&_bfd_std_section[1]) |
/* Pointer to the absolute section. */ |
#define bfd_abs_section_ptr (&_bfd_std_section[2]) |
/* Pointer to the indirect section. */ |
#define bfd_ind_section_ptr (&_bfd_std_section[3]) |
#define bfd_is_und_section(sec) ((sec) == bfd_und_section_ptr) |
#define bfd_is_abs_section(sec) ((sec) == bfd_abs_section_ptr) |
#define bfd_is_ind_section(sec) ((sec) == bfd_ind_section_ptr) |
#define bfd_is_const_section(SEC) \ |
( ((SEC) == bfd_abs_section_ptr) \ |
|| ((SEC) == bfd_und_section_ptr) \ |
|| ((SEC) == bfd_com_section_ptr) \ |
|| ((SEC) == bfd_ind_section_ptr)) |
/* Macros to handle insertion and deletion of a bfd's sections. These |
only handle the list pointers, ie. do not adjust section_count, |
target_index etc. */ |
#define bfd_section_list_remove(ABFD, S) \ |
do \ |
{ \ |
asection *_s = S; \ |
asection *_next = _s->next; \ |
asection *_prev = _s->prev; \ |
if (_prev) \ |
_prev->next = _next; \ |
else \ |
(ABFD)->sections = _next; \ |
if (_next) \ |
_next->prev = _prev; \ |
else \ |
(ABFD)->section_last = _prev; \ |
} \ |
while (0) |
#define bfd_section_list_append(ABFD, S) \ |
do \ |
{ \ |
asection *_s = S; \ |
bfd *_abfd = ABFD; \ |
_s->next = NULL; \ |
if (_abfd->section_last) \ |
{ \ |
_s->prev = _abfd->section_last; \ |
_abfd->section_last->next = _s; \ |
} \ |
else \ |
{ \ |
_s->prev = NULL; \ |
_abfd->sections = _s; \ |
} \ |
_abfd->section_last = _s; \ |
} \ |
while (0) |
#define bfd_section_list_prepend(ABFD, S) \ |
do \ |
{ \ |
asection *_s = S; \ |
bfd *_abfd = ABFD; \ |
_s->prev = NULL; \ |
if (_abfd->sections) \ |
{ \ |
_s->next = _abfd->sections; \ |
_abfd->sections->prev = _s; \ |
} \ |
else \ |
{ \ |
_s->next = NULL; \ |
_abfd->section_last = _s; \ |
} \ |
_abfd->sections = _s; \ |
} \ |
while (0) |
#define bfd_section_list_insert_after(ABFD, A, S) \ |
do \ |
{ \ |
asection *_a = A; \ |
asection *_s = S; \ |
asection *_next = _a->next; \ |
_s->next = _next; \ |
_s->prev = _a; \ |
_a->next = _s; \ |
if (_next) \ |
_next->prev = _s; \ |
else \ |
(ABFD)->section_last = _s; \ |
} \ |
while (0) |
#define bfd_section_list_insert_before(ABFD, B, S) \ |
do \ |
{ \ |
asection *_b = B; \ |
asection *_s = S; \ |
asection *_prev = _b->prev; \ |
_s->prev = _prev; \ |
_s->next = _b; \ |
_b->prev = _s; \ |
if (_prev) \ |
_prev->next = _s; \ |
else \ |
(ABFD)->sections = _s; \ |
} \ |
while (0) |
#define bfd_section_removed_from_list(ABFD, S) \ |
((S)->next == NULL ? (ABFD)->section_last != (S) : (S)->next->prev != (S)) |
#define BFD_FAKE_SECTION(SEC, FLAGS, SYM, NAME, IDX) \ |
/* name, id, index, next, prev, flags, user_set_vma, */ \ |
{ NAME, IDX, 0, NULL, NULL, FLAGS, 0, \ |
\ |
/* linker_mark, linker_has_input, gc_mark, decompress_status, */ \ |
0, 0, 1, 0, \ |
\ |
/* segment_mark, sec_info_type, use_rela_p, */ \ |
0, 0, 0, \ |
\ |
/* sec_flg0, sec_flg1, sec_flg2, sec_flg3, sec_flg4, sec_flg5, */ \ |
0, 0, 0, 0, 0, 0, \ |
\ |
/* vma, lma, size, rawsize, compressed_size, relax, relax_count, */ \ |
0, 0, 0, 0, 0, 0, 0, \ |
\ |
/* output_offset, output_section, alignment_power, */ \ |
0, &SEC, 0, \ |
\ |
/* relocation, orelocation, reloc_count, filepos, rel_filepos, */ \ |
NULL, NULL, 0, 0, 0, \ |
\ |
/* line_filepos, userdata, contents, lineno, lineno_count, */ \ |
0, NULL, NULL, NULL, 0, \ |
\ |
/* entsize, kept_section, moving_line_filepos, */ \ |
0, NULL, 0, \ |
\ |
/* target_index, used_by_bfd, constructor_chain, owner, */ \ |
0, NULL, NULL, NULL, \ |
\ |
/* symbol, symbol_ptr_ptr, */ \ |
(struct bfd_symbol *) SYM, &SEC.symbol, \ |
\ |
/* map_head, map_tail */ \ |
{ NULL }, { NULL } \ |
} |
void bfd_section_list_clear (bfd *); |
asection *bfd_get_section_by_name (bfd *abfd, const char *name); |
asection *bfd_get_next_section_by_name (asection *sec); |
asection *bfd_get_linker_section (bfd *abfd, const char *name); |
asection *bfd_get_section_by_name_if |
(bfd *abfd, |
const char *name, |
bfd_boolean (*func) (bfd *abfd, asection *sect, void *obj), |
void *obj); |
char *bfd_get_unique_section_name |
(bfd *abfd, const char *templat, int *count); |
asection *bfd_make_section_old_way (bfd *abfd, const char *name); |
asection *bfd_make_section_anyway_with_flags |
(bfd *abfd, const char *name, flagword flags); |
asection *bfd_make_section_anyway (bfd *abfd, const char *name); |
asection *bfd_make_section_with_flags |
(bfd *, const char *name, flagword flags); |
asection *bfd_make_section (bfd *, const char *name); |
bfd_boolean bfd_set_section_flags |
(bfd *abfd, asection *sec, flagword flags); |
void bfd_rename_section |
(bfd *abfd, asection *sec, const char *newname); |
void bfd_map_over_sections |
(bfd *abfd, |
void (*func) (bfd *abfd, asection *sect, void *obj), |
void *obj); |
asection *bfd_sections_find_if |
(bfd *abfd, |
bfd_boolean (*operation) (bfd *abfd, asection *sect, void *obj), |
void *obj); |
bfd_boolean bfd_set_section_size |
(bfd *abfd, asection *sec, bfd_size_type val); |
bfd_boolean bfd_set_section_contents |
(bfd *abfd, asection *section, const void *data, |
file_ptr offset, bfd_size_type count); |
bfd_boolean bfd_get_section_contents |
(bfd *abfd, asection *section, void *location, file_ptr offset, |
bfd_size_type count); |
bfd_boolean bfd_malloc_and_get_section |
(bfd *abfd, asection *section, bfd_byte **buf); |
bfd_boolean bfd_copy_private_section_data |
(bfd *ibfd, asection *isec, bfd *obfd, asection *osec); |
#define bfd_copy_private_section_data(ibfd, isection, obfd, osection) \ |
BFD_SEND (obfd, _bfd_copy_private_section_data, \ |
(ibfd, isection, obfd, osection)) |
bfd_boolean bfd_generic_is_group_section (bfd *, const asection *sec); |
bfd_boolean bfd_generic_discard_group (bfd *abfd, asection *group); |
/* Extracted from archures.c. */ |
enum bfd_architecture |
{ |
bfd_arch_unknown, /* File arch not known. */ |
bfd_arch_obscure, /* Arch known, not one of these. */ |
bfd_arch_m68k, /* Motorola 68xxx */ |
#define bfd_mach_m68000 1 |
#define bfd_mach_m68008 2 |
#define bfd_mach_m68010 3 |
#define bfd_mach_m68020 4 |
#define bfd_mach_m68030 5 |
#define bfd_mach_m68040 6 |
#define bfd_mach_m68060 7 |
#define bfd_mach_cpu32 8 |
#define bfd_mach_fido 9 |
#define bfd_mach_mcf_isa_a_nodiv 10 |
#define bfd_mach_mcf_isa_a 11 |
#define bfd_mach_mcf_isa_a_mac 12 |
#define bfd_mach_mcf_isa_a_emac 13 |
#define bfd_mach_mcf_isa_aplus 14 |
#define bfd_mach_mcf_isa_aplus_mac 15 |
#define bfd_mach_mcf_isa_aplus_emac 16 |
#define bfd_mach_mcf_isa_b_nousp 17 |
#define bfd_mach_mcf_isa_b_nousp_mac 18 |
#define bfd_mach_mcf_isa_b_nousp_emac 19 |
#define bfd_mach_mcf_isa_b 20 |
#define bfd_mach_mcf_isa_b_mac 21 |
#define bfd_mach_mcf_isa_b_emac 22 |
#define bfd_mach_mcf_isa_b_float 23 |
#define bfd_mach_mcf_isa_b_float_mac 24 |
#define bfd_mach_mcf_isa_b_float_emac 25 |
#define bfd_mach_mcf_isa_c 26 |
#define bfd_mach_mcf_isa_c_mac 27 |
#define bfd_mach_mcf_isa_c_emac 28 |
#define bfd_mach_mcf_isa_c_nodiv 29 |
#define bfd_mach_mcf_isa_c_nodiv_mac 30 |
#define bfd_mach_mcf_isa_c_nodiv_emac 31 |
bfd_arch_vax, /* DEC Vax */ |
bfd_arch_i960, /* Intel 960 */ |
/* The order of the following is important. |
lower number indicates a machine type that |
only accepts a subset of the instructions |
available to machines with higher numbers. |
The exception is the "ca", which is |
incompatible with all other machines except |
"core". */ |
#define bfd_mach_i960_core 1 |
#define bfd_mach_i960_ka_sa 2 |
#define bfd_mach_i960_kb_sb 3 |
#define bfd_mach_i960_mc 4 |
#define bfd_mach_i960_xa 5 |
#define bfd_mach_i960_ca 6 |
#define bfd_mach_i960_jx 7 |
#define bfd_mach_i960_hx 8 |
bfd_arch_or32, /* OpenRISC 32 */ |
bfd_arch_sparc, /* SPARC */ |
#define bfd_mach_sparc 1 |
/* The difference between v8plus and v9 is that v9 is a true 64 bit env. */ |
#define bfd_mach_sparc_sparclet 2 |
#define bfd_mach_sparc_sparclite 3 |
#define bfd_mach_sparc_v8plus 4 |
#define bfd_mach_sparc_v8plusa 5 /* with ultrasparc add'ns. */ |
#define bfd_mach_sparc_sparclite_le 6 |
#define bfd_mach_sparc_v9 7 |
#define bfd_mach_sparc_v9a 8 /* with ultrasparc add'ns. */ |
#define bfd_mach_sparc_v8plusb 9 /* with cheetah add'ns. */ |
#define bfd_mach_sparc_v9b 10 /* with cheetah add'ns. */ |
/* Nonzero if MACH has the v9 instruction set. */ |
#define bfd_mach_sparc_v9_p(mach) \ |
((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9b \ |
&& (mach) != bfd_mach_sparc_sparclite_le) |
/* Nonzero if MACH is a 64 bit sparc architecture. */ |
#define bfd_mach_sparc_64bit_p(mach) \ |
((mach) >= bfd_mach_sparc_v9 && (mach) != bfd_mach_sparc_v8plusb) |
bfd_arch_spu, /* PowerPC SPU */ |
#define bfd_mach_spu 256 |
bfd_arch_mips, /* MIPS Rxxxx */ |
#define bfd_mach_mips3000 3000 |
#define bfd_mach_mips3900 3900 |
#define bfd_mach_mips4000 4000 |
#define bfd_mach_mips4010 4010 |
#define bfd_mach_mips4100 4100 |
#define bfd_mach_mips4111 4111 |
#define bfd_mach_mips4120 4120 |
#define bfd_mach_mips4300 4300 |
#define bfd_mach_mips4400 4400 |
#define bfd_mach_mips4600 4600 |
#define bfd_mach_mips4650 4650 |
#define bfd_mach_mips5000 5000 |
#define bfd_mach_mips5400 5400 |
#define bfd_mach_mips5500 5500 |
#define bfd_mach_mips5900 5900 |
#define bfd_mach_mips6000 6000 |
#define bfd_mach_mips7000 7000 |
#define bfd_mach_mips8000 8000 |
#define bfd_mach_mips9000 9000 |
#define bfd_mach_mips10000 10000 |
#define bfd_mach_mips12000 12000 |
#define bfd_mach_mips14000 14000 |
#define bfd_mach_mips16000 16000 |
#define bfd_mach_mips16 16 |
#define bfd_mach_mips5 5 |
#define bfd_mach_mips_loongson_2e 3001 |
#define bfd_mach_mips_loongson_2f 3002 |
#define bfd_mach_mips_loongson_3a 3003 |
#define bfd_mach_mips_sb1 12310201 /* octal 'SB', 01 */ |
#define bfd_mach_mips_octeon 6501 |
#define bfd_mach_mips_octeonp 6601 |
#define bfd_mach_mips_octeon2 6502 |
#define bfd_mach_mips_xlr 887682 /* decimal 'XLR' */ |
#define bfd_mach_mipsisa32 32 |
#define bfd_mach_mipsisa32r2 33 |
#define bfd_mach_mipsisa64 64 |
#define bfd_mach_mipsisa64r2 65 |
#define bfd_mach_mips_micromips 96 |
bfd_arch_i386, /* Intel 386 */ |
#define bfd_mach_i386_intel_syntax (1 << 0) |
#define bfd_mach_i386_i8086 (1 << 1) |
#define bfd_mach_i386_i386 (1 << 2) |
#define bfd_mach_x86_64 (1 << 3) |
#define bfd_mach_x64_32 (1 << 4) |
#define bfd_mach_i386_i386_intel_syntax (bfd_mach_i386_i386 | bfd_mach_i386_intel_syntax) |
#define bfd_mach_x86_64_intel_syntax (bfd_mach_x86_64 | bfd_mach_i386_intel_syntax) |
#define bfd_mach_x64_32_intel_syntax (bfd_mach_x64_32 | bfd_mach_i386_intel_syntax) |
bfd_arch_l1om, /* Intel L1OM */ |
#define bfd_mach_l1om (1 << 5) |
#define bfd_mach_l1om_intel_syntax (bfd_mach_l1om | bfd_mach_i386_intel_syntax) |
bfd_arch_k1om, /* Intel K1OM */ |
#define bfd_mach_k1om (1 << 6) |
#define bfd_mach_k1om_intel_syntax (bfd_mach_k1om | bfd_mach_i386_intel_syntax) |
#define bfd_mach_i386_nacl (1 << 7) |
#define bfd_mach_i386_i386_nacl (bfd_mach_i386_i386 | bfd_mach_i386_nacl) |
#define bfd_mach_x86_64_nacl (bfd_mach_x86_64 | bfd_mach_i386_nacl) |
#define bfd_mach_x64_32_nacl (bfd_mach_x64_32 | bfd_mach_i386_nacl) |
bfd_arch_we32k, /* AT&T WE32xxx */ |
bfd_arch_tahoe, /* CCI/Harris Tahoe */ |
bfd_arch_i860, /* Intel 860 */ |
bfd_arch_i370, /* IBM 360/370 Mainframes */ |
bfd_arch_romp, /* IBM ROMP PC/RT */ |
bfd_arch_convex, /* Convex */ |
bfd_arch_m88k, /* Motorola 88xxx */ |
bfd_arch_m98k, /* Motorola 98xxx */ |
bfd_arch_pyramid, /* Pyramid Technology */ |
bfd_arch_h8300, /* Renesas H8/300 (formerly Hitachi H8/300) */ |
#define bfd_mach_h8300 1 |
#define bfd_mach_h8300h 2 |
#define bfd_mach_h8300s 3 |
#define bfd_mach_h8300hn 4 |
#define bfd_mach_h8300sn 5 |
#define bfd_mach_h8300sx 6 |
#define bfd_mach_h8300sxn 7 |
bfd_arch_pdp11, /* DEC PDP-11 */ |
bfd_arch_plugin, |
bfd_arch_powerpc, /* PowerPC */ |
#define bfd_mach_ppc 32 |
#define bfd_mach_ppc64 64 |
#define bfd_mach_ppc_403 403 |
#define bfd_mach_ppc_403gc 4030 |
#define bfd_mach_ppc_405 405 |
#define bfd_mach_ppc_505 505 |
#define bfd_mach_ppc_601 601 |
#define bfd_mach_ppc_602 602 |
#define bfd_mach_ppc_603 603 |
#define bfd_mach_ppc_ec603e 6031 |
#define bfd_mach_ppc_604 604 |
#define bfd_mach_ppc_620 620 |
#define bfd_mach_ppc_630 630 |
#define bfd_mach_ppc_750 750 |
#define bfd_mach_ppc_860 860 |
#define bfd_mach_ppc_a35 35 |
#define bfd_mach_ppc_rs64ii 642 |
#define bfd_mach_ppc_rs64iii 643 |
#define bfd_mach_ppc_7400 7400 |
#define bfd_mach_ppc_e500 500 |
#define bfd_mach_ppc_e500mc 5001 |
#define bfd_mach_ppc_e500mc64 5005 |
#define bfd_mach_ppc_e5500 5006 |
#define bfd_mach_ppc_e6500 5007 |
#define bfd_mach_ppc_titan 83 |
#define bfd_mach_ppc_vle 84 |
bfd_arch_rs6000, /* IBM RS/6000 */ |
#define bfd_mach_rs6k 6000 |
#define bfd_mach_rs6k_rs1 6001 |
#define bfd_mach_rs6k_rsc 6003 |
#define bfd_mach_rs6k_rs2 6002 |
bfd_arch_hppa, /* HP PA RISC */ |
#define bfd_mach_hppa10 10 |
#define bfd_mach_hppa11 11 |
#define bfd_mach_hppa20 20 |
#define bfd_mach_hppa20w 25 |
bfd_arch_d10v, /* Mitsubishi D10V */ |
#define bfd_mach_d10v 1 |
#define bfd_mach_d10v_ts2 2 |
#define bfd_mach_d10v_ts3 3 |
bfd_arch_d30v, /* Mitsubishi D30V */ |
bfd_arch_dlx, /* DLX */ |
bfd_arch_m68hc11, /* Motorola 68HC11 */ |
bfd_arch_m68hc12, /* Motorola 68HC12 */ |
#define bfd_mach_m6812_default 0 |
#define bfd_mach_m6812 1 |
#define bfd_mach_m6812s 2 |
bfd_arch_m9s12x, /* Freescale S12X */ |
bfd_arch_m9s12xg, /* Freescale XGATE */ |
bfd_arch_z8k, /* Zilog Z8000 */ |
#define bfd_mach_z8001 1 |
#define bfd_mach_z8002 2 |
bfd_arch_h8500, /* Renesas H8/500 (formerly Hitachi H8/500) */ |
bfd_arch_sh, /* Renesas / SuperH SH (formerly Hitachi SH) */ |
#define bfd_mach_sh 1 |
#define bfd_mach_sh2 0x20 |
#define bfd_mach_sh_dsp 0x2d |
#define bfd_mach_sh2a 0x2a |
#define bfd_mach_sh2a_nofpu 0x2b |
#define bfd_mach_sh2a_nofpu_or_sh4_nommu_nofpu 0x2a1 |
#define bfd_mach_sh2a_nofpu_or_sh3_nommu 0x2a2 |
#define bfd_mach_sh2a_or_sh4 0x2a3 |
#define bfd_mach_sh2a_or_sh3e 0x2a4 |
#define bfd_mach_sh2e 0x2e |
#define bfd_mach_sh3 0x30 |
#define bfd_mach_sh3_nommu 0x31 |
#define bfd_mach_sh3_dsp 0x3d |
#define bfd_mach_sh3e 0x3e |
#define bfd_mach_sh4 0x40 |
#define bfd_mach_sh4_nofpu 0x41 |
#define bfd_mach_sh4_nommu_nofpu 0x42 |
#define bfd_mach_sh4a 0x4a |
#define bfd_mach_sh4a_nofpu 0x4b |
#define bfd_mach_sh4al_dsp 0x4d |
#define bfd_mach_sh5 0x50 |
bfd_arch_alpha, /* Dec Alpha */ |
#define bfd_mach_alpha_ev4 0x10 |
#define bfd_mach_alpha_ev5 0x20 |
#define bfd_mach_alpha_ev6 0x30 |
bfd_arch_arm, /* Advanced Risc Machines ARM. */ |
#define bfd_mach_arm_unknown 0 |
#define bfd_mach_arm_2 1 |
#define bfd_mach_arm_2a 2 |
#define bfd_mach_arm_3 3 |
#define bfd_mach_arm_3M 4 |
#define bfd_mach_arm_4 5 |
#define bfd_mach_arm_4T 6 |
#define bfd_mach_arm_5 7 |
#define bfd_mach_arm_5T 8 |
#define bfd_mach_arm_5TE 9 |
#define bfd_mach_arm_XScale 10 |
#define bfd_mach_arm_ep9312 11 |
#define bfd_mach_arm_iWMMXt 12 |
#define bfd_mach_arm_iWMMXt2 13 |
bfd_arch_ns32k, /* National Semiconductors ns32000 */ |
bfd_arch_w65, /* WDC 65816 */ |
bfd_arch_tic30, /* Texas Instruments TMS320C30 */ |
bfd_arch_tic4x, /* Texas Instruments TMS320C3X/4X */ |
#define bfd_mach_tic3x 30 |
#define bfd_mach_tic4x 40 |
bfd_arch_tic54x, /* Texas Instruments TMS320C54X */ |
bfd_arch_tic6x, /* Texas Instruments TMS320C6X */ |
bfd_arch_tic80, /* TI TMS320c80 (MVP) */ |
bfd_arch_v850, /* NEC V850 */ |
bfd_arch_v850_rh850,/* NEC V850 (using RH850 ABI) */ |
#define bfd_mach_v850 1 |
#define bfd_mach_v850e 'E' |
#define bfd_mach_v850e1 '1' |
#define bfd_mach_v850e2 0x4532 |
#define bfd_mach_v850e2v3 0x45325633 |
#define bfd_mach_v850e3v5 0x45335635 /* ('E'|'3'|'V'|'5') */ |
bfd_arch_arc, /* ARC Cores */ |
#define bfd_mach_arc_5 5 |
#define bfd_mach_arc_6 6 |
#define bfd_mach_arc_7 7 |
#define bfd_mach_arc_8 8 |
bfd_arch_m32c, /* Renesas M16C/M32C. */ |
#define bfd_mach_m16c 0x75 |
#define bfd_mach_m32c 0x78 |
bfd_arch_m32r, /* Renesas M32R (formerly Mitsubishi M32R/D) */ |
#define bfd_mach_m32r 1 /* For backwards compatibility. */ |
#define bfd_mach_m32rx 'x' |
#define bfd_mach_m32r2 '2' |
bfd_arch_mn10200, /* Matsushita MN10200 */ |
bfd_arch_mn10300, /* Matsushita MN10300 */ |
#define bfd_mach_mn10300 300 |
#define bfd_mach_am33 330 |
#define bfd_mach_am33_2 332 |
bfd_arch_fr30, |
#define bfd_mach_fr30 0x46523330 |
bfd_arch_frv, |
#define bfd_mach_frv 1 |
#define bfd_mach_frvsimple 2 |
#define bfd_mach_fr300 300 |
#define bfd_mach_fr400 400 |
#define bfd_mach_fr450 450 |
#define bfd_mach_frvtomcat 499 /* fr500 prototype */ |
#define bfd_mach_fr500 500 |
#define bfd_mach_fr550 550 |
bfd_arch_moxie, /* The moxie processor */ |
#define bfd_mach_moxie 1 |
bfd_arch_mcore, |
bfd_arch_mep, |
#define bfd_mach_mep 1 |
#define bfd_mach_mep_h1 0x6831 |
#define bfd_mach_mep_c5 0x6335 |
bfd_arch_metag, |
#define bfd_mach_metag 1 |
bfd_arch_ia64, /* HP/Intel ia64 */ |
#define bfd_mach_ia64_elf64 64 |
#define bfd_mach_ia64_elf32 32 |
bfd_arch_ip2k, /* Ubicom IP2K microcontrollers. */ |
#define bfd_mach_ip2022 1 |
#define bfd_mach_ip2022ext 2 |
bfd_arch_iq2000, /* Vitesse IQ2000. */ |
#define bfd_mach_iq2000 1 |
#define bfd_mach_iq10 2 |
bfd_arch_epiphany, /* Adapteva EPIPHANY */ |
#define bfd_mach_epiphany16 1 |
#define bfd_mach_epiphany32 2 |
bfd_arch_mt, |
#define bfd_mach_ms1 1 |
#define bfd_mach_mrisc2 2 |
#define bfd_mach_ms2 3 |
bfd_arch_pj, |
bfd_arch_avr, /* Atmel AVR microcontrollers. */ |
#define bfd_mach_avr1 1 |
#define bfd_mach_avr2 2 |
#define bfd_mach_avr25 25 |
#define bfd_mach_avr3 3 |
#define bfd_mach_avr31 31 |
#define bfd_mach_avr35 35 |
#define bfd_mach_avr4 4 |
#define bfd_mach_avr5 5 |
#define bfd_mach_avr51 51 |
#define bfd_mach_avr6 6 |
#define bfd_mach_avrxmega1 101 |
#define bfd_mach_avrxmega2 102 |
#define bfd_mach_avrxmega3 103 |
#define bfd_mach_avrxmega4 104 |
#define bfd_mach_avrxmega5 105 |
#define bfd_mach_avrxmega6 106 |
#define bfd_mach_avrxmega7 107 |
bfd_arch_bfin, /* ADI Blackfin */ |
#define bfd_mach_bfin 1 |
bfd_arch_cr16, /* National Semiconductor CompactRISC (ie CR16). */ |
#define bfd_mach_cr16 1 |
bfd_arch_cr16c, /* National Semiconductor CompactRISC. */ |
#define bfd_mach_cr16c 1 |
bfd_arch_crx, /* National Semiconductor CRX. */ |
#define bfd_mach_crx 1 |
bfd_arch_cris, /* Axis CRIS */ |
#define bfd_mach_cris_v0_v10 255 |
#define bfd_mach_cris_v32 32 |
#define bfd_mach_cris_v10_v32 1032 |
bfd_arch_rl78, |
#define bfd_mach_rl78 0x75 |
bfd_arch_rx, /* Renesas RX. */ |
#define bfd_mach_rx 0x75 |
bfd_arch_s390, /* IBM s390 */ |
#define bfd_mach_s390_31 31 |
#define bfd_mach_s390_64 64 |
bfd_arch_score, /* Sunplus score */ |
#define bfd_mach_score3 3 |
#define bfd_mach_score7 7 |
bfd_arch_openrisc, /* OpenRISC */ |
bfd_arch_mmix, /* Donald Knuth's educational processor. */ |
bfd_arch_xstormy16, |
#define bfd_mach_xstormy16 1 |
bfd_arch_msp430, /* Texas Instruments MSP430 architecture. */ |
#define bfd_mach_msp11 11 |
#define bfd_mach_msp110 110 |
#define bfd_mach_msp12 12 |
#define bfd_mach_msp13 13 |
#define bfd_mach_msp14 14 |
#define bfd_mach_msp15 15 |
#define bfd_mach_msp16 16 |
#define bfd_mach_msp20 20 |
#define bfd_mach_msp21 21 |
#define bfd_mach_msp22 22 |
#define bfd_mach_msp23 23 |
#define bfd_mach_msp24 24 |
#define bfd_mach_msp26 26 |
#define bfd_mach_msp31 31 |
#define bfd_mach_msp32 32 |
#define bfd_mach_msp33 33 |
#define bfd_mach_msp41 41 |
#define bfd_mach_msp42 42 |
#define bfd_mach_msp43 43 |
#define bfd_mach_msp44 44 |
#define bfd_mach_msp430x 45 |
#define bfd_mach_msp46 46 |
#define bfd_mach_msp47 47 |
#define bfd_mach_msp54 54 |
bfd_arch_xc16x, /* Infineon's XC16X Series. */ |
#define bfd_mach_xc16x 1 |
#define bfd_mach_xc16xl 2 |
#define bfd_mach_xc16xs 3 |
bfd_arch_xgate, /* Freescale XGATE */ |
#define bfd_mach_xgate 1 |
bfd_arch_xtensa, /* Tensilica's Xtensa cores. */ |
#define bfd_mach_xtensa 1 |
bfd_arch_z80, |
#define bfd_mach_z80strict 1 /* No undocumented opcodes. */ |
#define bfd_mach_z80 3 /* With ixl, ixh, iyl, and iyh. */ |
#define bfd_mach_z80full 7 /* All undocumented instructions. */ |
#define bfd_mach_r800 11 /* R800: successor with multiplication. */ |
bfd_arch_lm32, /* Lattice Mico32 */ |
#define bfd_mach_lm32 1 |
bfd_arch_microblaze,/* Xilinx MicroBlaze. */ |
bfd_arch_tilepro, /* Tilera TILEPro */ |
bfd_arch_tilegx, /* Tilera TILE-Gx */ |
#define bfd_mach_tilepro 1 |
#define bfd_mach_tilegx 1 |
#define bfd_mach_tilegx32 2 |
bfd_arch_aarch64, /* AArch64 */ |
#define bfd_mach_aarch64 0 |
#define bfd_mach_aarch64_ilp32 32 |
bfd_arch_nios2, |
#define bfd_mach_nios2 0 |
bfd_arch_last |
}; |
typedef struct bfd_arch_info |
{ |
int bits_per_word; |
int bits_per_address; |
int bits_per_byte; |
enum bfd_architecture arch; |
unsigned long mach; |
const char *arch_name; |
const char *printable_name; |
unsigned int section_align_power; |
/* TRUE if this is the default machine for the architecture. |
The default arch should be the first entry for an arch so that |
all the entries for that arch can be accessed via <<next>>. */ |
bfd_boolean the_default; |
const struct bfd_arch_info * (*compatible) |
(const struct bfd_arch_info *a, const struct bfd_arch_info *b); |
bfd_boolean (*scan) (const struct bfd_arch_info *, const char *); |
/* Allocate via bfd_malloc and return a fill buffer of size COUNT. If |
IS_BIGENDIAN is TRUE, the order of bytes is big endian. If CODE is |
TRUE, the buffer contains code. */ |
void *(*fill) (bfd_size_type count, bfd_boolean is_bigendian, |
bfd_boolean code); |
const struct bfd_arch_info *next; |
} |
bfd_arch_info_type; |
const char *bfd_printable_name (bfd *abfd); |
const bfd_arch_info_type *bfd_scan_arch (const char *string); |
const char **bfd_arch_list (void); |
const bfd_arch_info_type *bfd_arch_get_compatible |
(const bfd *abfd, const bfd *bbfd, bfd_boolean accept_unknowns); |
void bfd_set_arch_info (bfd *abfd, const bfd_arch_info_type *arg); |
enum bfd_architecture bfd_get_arch (bfd *abfd); |
unsigned long bfd_get_mach (bfd *abfd); |
unsigned int bfd_arch_bits_per_byte (bfd *abfd); |
unsigned int bfd_arch_bits_per_address (bfd *abfd); |
const bfd_arch_info_type *bfd_get_arch_info (bfd *abfd); |
const bfd_arch_info_type *bfd_lookup_arch |
(enum bfd_architecture arch, unsigned long machine); |
const char *bfd_printable_arch_mach |
(enum bfd_architecture arch, unsigned long machine); |
unsigned int bfd_octets_per_byte (bfd *abfd); |
unsigned int bfd_arch_mach_octets_per_byte |
(enum bfd_architecture arch, unsigned long machine); |
/* Extracted from reloc.c. */ |
typedef enum bfd_reloc_status |
{ |
/* No errors detected. */ |
bfd_reloc_ok, |
/* The relocation was performed, but there was an overflow. */ |
bfd_reloc_overflow, |
/* The address to relocate was not within the section supplied. */ |
bfd_reloc_outofrange, |
/* Used by special functions. */ |
bfd_reloc_continue, |
/* Unsupported relocation size requested. */ |
bfd_reloc_notsupported, |
/* Unused. */ |
bfd_reloc_other, |
/* The symbol to relocate against was undefined. */ |
bfd_reloc_undefined, |
/* The relocation was performed, but may not be ok - presently |
generated only when linking i960 coff files with i960 b.out |
symbols. If this type is returned, the error_message argument |
to bfd_perform_relocation will be set. */ |
bfd_reloc_dangerous |
} |
bfd_reloc_status_type; |
typedef struct reloc_cache_entry |
{ |
/* A pointer into the canonical table of pointers. */ |
struct bfd_symbol **sym_ptr_ptr; |
/* offset in section. */ |
bfd_size_type address; |
/* addend for relocation value. */ |
bfd_vma addend; |
/* Pointer to how to perform the required relocation. */ |
reloc_howto_type *howto; |
} |
arelent; |
enum complain_overflow |
{ |
/* Do not complain on overflow. */ |
complain_overflow_dont, |
/* Complain if the value overflows when considered as a signed |
number one bit larger than the field. ie. A bitfield of N bits |
is allowed to represent -2**n to 2**n-1. */ |
complain_overflow_bitfield, |
/* Complain if the value overflows when considered as a signed |
number. */ |
complain_overflow_signed, |
/* Complain if the value overflows when considered as an |
unsigned number. */ |
complain_overflow_unsigned |
}; |
struct reloc_howto_struct |
{ |
/* The type field has mainly a documentary use - the back end can |
do what it wants with it, though normally the back end's |
external idea of what a reloc number is stored |
in this field. For example, a PC relative word relocation |
in a coff environment has the type 023 - because that's |
what the outside world calls a R_PCRWORD reloc. */ |
unsigned int type; |
/* The value the final relocation is shifted right by. This drops |
unwanted data from the relocation. */ |
unsigned int rightshift; |
/* The size of the item to be relocated. This is *not* a |
power-of-two measure. To get the number of bytes operated |
on by a type of relocation, use bfd_get_reloc_size. */ |
int size; |
/* The number of bits in the item to be relocated. This is used |
when doing overflow checking. */ |
unsigned int bitsize; |
/* The relocation is relative to the field being relocated. */ |
bfd_boolean pc_relative; |
/* The bit position of the reloc value in the destination. |
The relocated value is left shifted by this amount. */ |
unsigned int bitpos; |
/* What type of overflow error should be checked for when |
relocating. */ |
enum complain_overflow complain_on_overflow; |
/* If this field is non null, then the supplied function is |
called rather than the normal function. This allows really |
strange relocation methods to be accommodated (e.g., i960 callj |
instructions). */ |
bfd_reloc_status_type (*special_function) |
(bfd *, arelent *, struct bfd_symbol *, void *, asection *, |
bfd *, char **); |
/* The textual name of the relocation type. */ |
char *name; |
/* Some formats record a relocation addend in the section contents |
rather than with the relocation. For ELF formats this is the |
distinction between USE_REL and USE_RELA (though the code checks |
for USE_REL == 1/0). The value of this field is TRUE if the |
addend is recorded with the section contents; when performing a |
partial link (ld -r) the section contents (the data) will be |
modified. The value of this field is FALSE if addends are |
recorded with the relocation (in arelent.addend); when performing |
a partial link the relocation will be modified. |
All relocations for all ELF USE_RELA targets should set this field |
to FALSE (values of TRUE should be looked on with suspicion). |
However, the converse is not true: not all relocations of all ELF |
USE_REL targets set this field to TRUE. Why this is so is peculiar |
to each particular target. For relocs that aren't used in partial |
links (e.g. GOT stuff) it doesn't matter what this is set to. */ |
bfd_boolean partial_inplace; |
/* src_mask selects the part of the instruction (or data) to be used |
in the relocation sum. If the target relocations don't have an |
addend in the reloc, eg. ELF USE_REL, src_mask will normally equal |
dst_mask to extract the addend from the section contents. If |
relocations do have an addend in the reloc, eg. ELF USE_RELA, this |
field should be zero. Non-zero values for ELF USE_RELA targets are |
bogus as in those cases the value in the dst_mask part of the |
section contents should be treated as garbage. */ |
bfd_vma src_mask; |
/* dst_mask selects which parts of the instruction (or data) are |
replaced with a relocated value. */ |
bfd_vma dst_mask; |
/* When some formats create PC relative instructions, they leave |
the value of the pc of the place being relocated in the offset |
slot of the instruction, so that a PC relative relocation can |
be made just by adding in an ordinary offset (e.g., sun3 a.out). |
Some formats leave the displacement part of an instruction |
empty (e.g., m88k bcs); this flag signals the fact. */ |
bfd_boolean pcrel_offset; |
}; |
#define HOWTO(C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC) \ |
{ (unsigned) C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC } |
#define NEWHOWTO(FUNCTION, NAME, SIZE, REL, IN) \ |
HOWTO (0, 0, SIZE, 0, REL, 0, complain_overflow_dont, FUNCTION, \ |
NAME, FALSE, 0, 0, IN) |
#define EMPTY_HOWTO(C) \ |
HOWTO ((C), 0, 0, 0, FALSE, 0, complain_overflow_dont, NULL, \ |
NULL, FALSE, 0, 0, FALSE) |
#define HOWTO_PREPARE(relocation, symbol) \ |
{ \ |
if (symbol != NULL) \ |
{ \ |
if (bfd_is_com_section (symbol->section)) \ |
{ \ |
relocation = 0; \ |
} \ |
else \ |
{ \ |
relocation = symbol->value; \ |
} \ |
} \ |
} |
unsigned int bfd_get_reloc_size (reloc_howto_type *); |
typedef struct relent_chain |
{ |
arelent relent; |
struct relent_chain *next; |
} |
arelent_chain; |
bfd_reloc_status_type bfd_check_overflow |
(enum complain_overflow how, |
unsigned int bitsize, |
unsigned int rightshift, |
unsigned int addrsize, |
bfd_vma relocation); |
bfd_reloc_status_type bfd_perform_relocation |
(bfd *abfd, |
arelent *reloc_entry, |
void *data, |
asection *input_section, |
bfd *output_bfd, |
char **error_message); |
bfd_reloc_status_type bfd_install_relocation |
(bfd *abfd, |
arelent *reloc_entry, |
void *data, bfd_vma data_start, |
asection *input_section, |
char **error_message); |
enum bfd_reloc_code_real { |
_dummy_first_bfd_reloc_code_real, |
/* Basic absolute relocations of N bits. */ |
BFD_RELOC_64, |
BFD_RELOC_32, |
BFD_RELOC_26, |
BFD_RELOC_24, |
BFD_RELOC_16, |
BFD_RELOC_14, |
BFD_RELOC_8, |
/* PC-relative relocations. Sometimes these are relative to the address |
of the relocation itself; sometimes they are relative to the start of |
the section containing the relocation. It depends on the specific target. |
The 24-bit relocation is used in some Intel 960 configurations. */ |
BFD_RELOC_64_PCREL, |
BFD_RELOC_32_PCREL, |
BFD_RELOC_24_PCREL, |
BFD_RELOC_16_PCREL, |
BFD_RELOC_12_PCREL, |
BFD_RELOC_8_PCREL, |
/* Section relative relocations. Some targets need this for DWARF2. */ |
BFD_RELOC_32_SECREL, |
/* For ELF. */ |
BFD_RELOC_32_GOT_PCREL, |
BFD_RELOC_16_GOT_PCREL, |
BFD_RELOC_8_GOT_PCREL, |
BFD_RELOC_32_GOTOFF, |
BFD_RELOC_16_GOTOFF, |
BFD_RELOC_LO16_GOTOFF, |
BFD_RELOC_HI16_GOTOFF, |
BFD_RELOC_HI16_S_GOTOFF, |
BFD_RELOC_8_GOTOFF, |
BFD_RELOC_64_PLT_PCREL, |
BFD_RELOC_32_PLT_PCREL, |
BFD_RELOC_24_PLT_PCREL, |
BFD_RELOC_16_PLT_PCREL, |
BFD_RELOC_8_PLT_PCREL, |
BFD_RELOC_64_PLTOFF, |
BFD_RELOC_32_PLTOFF, |
BFD_RELOC_16_PLTOFF, |
BFD_RELOC_LO16_PLTOFF, |
BFD_RELOC_HI16_PLTOFF, |
BFD_RELOC_HI16_S_PLTOFF, |
BFD_RELOC_8_PLTOFF, |
/* Size relocations. */ |
BFD_RELOC_SIZE32, |
BFD_RELOC_SIZE64, |
/* Relocations used by 68K ELF. */ |
BFD_RELOC_68K_GLOB_DAT, |
BFD_RELOC_68K_JMP_SLOT, |
BFD_RELOC_68K_RELATIVE, |
BFD_RELOC_68K_TLS_GD32, |
BFD_RELOC_68K_TLS_GD16, |
BFD_RELOC_68K_TLS_GD8, |
BFD_RELOC_68K_TLS_LDM32, |
BFD_RELOC_68K_TLS_LDM16, |
BFD_RELOC_68K_TLS_LDM8, |
BFD_RELOC_68K_TLS_LDO32, |
BFD_RELOC_68K_TLS_LDO16, |
BFD_RELOC_68K_TLS_LDO8, |
BFD_RELOC_68K_TLS_IE32, |
BFD_RELOC_68K_TLS_IE16, |
BFD_RELOC_68K_TLS_IE8, |
BFD_RELOC_68K_TLS_LE32, |
BFD_RELOC_68K_TLS_LE16, |
BFD_RELOC_68K_TLS_LE8, |
/* Linkage-table relative. */ |
BFD_RELOC_32_BASEREL, |
BFD_RELOC_16_BASEREL, |
BFD_RELOC_LO16_BASEREL, |
BFD_RELOC_HI16_BASEREL, |
BFD_RELOC_HI16_S_BASEREL, |
BFD_RELOC_8_BASEREL, |
BFD_RELOC_RVA, |
/* Absolute 8-bit relocation, but used to form an address like 0xFFnn. */ |
BFD_RELOC_8_FFnn, |
/* These PC-relative relocations are stored as word displacements -- |
i.e., byte displacements shifted right two bits. The 30-bit word |
displacement (<<32_PCREL_S2>> -- 32 bits, shifted 2) is used on the |
SPARC. (SPARC tools generally refer to this as <<WDISP30>>.) The |
signed 16-bit displacement is used on the MIPS, and the 23-bit |
displacement is used on the Alpha. */ |
BFD_RELOC_32_PCREL_S2, |
BFD_RELOC_16_PCREL_S2, |
BFD_RELOC_23_PCREL_S2, |
/* High 22 bits and low 10 bits of 32-bit value, placed into lower bits of |
the target word. These are used on the SPARC. */ |
BFD_RELOC_HI22, |
BFD_RELOC_LO10, |
/* For systems that allocate a Global Pointer register, these are |
displacements off that register. These relocation types are |
handled specially, because the value the register will have is |
decided relatively late. */ |
BFD_RELOC_GPREL16, |
BFD_RELOC_GPREL32, |
/* Reloc types used for i960/b.out. */ |
BFD_RELOC_I960_CALLJ, |
/* SPARC ELF relocations. There is probably some overlap with other |
relocation types already defined. */ |
BFD_RELOC_NONE, |
BFD_RELOC_SPARC_WDISP22, |
BFD_RELOC_SPARC22, |
BFD_RELOC_SPARC13, |
BFD_RELOC_SPARC_GOT10, |
BFD_RELOC_SPARC_GOT13, |
BFD_RELOC_SPARC_GOT22, |
BFD_RELOC_SPARC_PC10, |
BFD_RELOC_SPARC_PC22, |
BFD_RELOC_SPARC_WPLT30, |
BFD_RELOC_SPARC_COPY, |
BFD_RELOC_SPARC_GLOB_DAT, |
BFD_RELOC_SPARC_JMP_SLOT, |
BFD_RELOC_SPARC_RELATIVE, |
BFD_RELOC_SPARC_UA16, |
BFD_RELOC_SPARC_UA32, |
BFD_RELOC_SPARC_UA64, |
BFD_RELOC_SPARC_GOTDATA_HIX22, |
BFD_RELOC_SPARC_GOTDATA_LOX10, |
BFD_RELOC_SPARC_GOTDATA_OP_HIX22, |
BFD_RELOC_SPARC_GOTDATA_OP_LOX10, |
BFD_RELOC_SPARC_GOTDATA_OP, |
BFD_RELOC_SPARC_JMP_IREL, |
BFD_RELOC_SPARC_IRELATIVE, |
/* I think these are specific to SPARC a.out (e.g., Sun 4). */ |
BFD_RELOC_SPARC_BASE13, |
BFD_RELOC_SPARC_BASE22, |
/* SPARC64 relocations */ |
#define BFD_RELOC_SPARC_64 BFD_RELOC_64 |
BFD_RELOC_SPARC_10, |
BFD_RELOC_SPARC_11, |
BFD_RELOC_SPARC_OLO10, |
BFD_RELOC_SPARC_HH22, |
BFD_RELOC_SPARC_HM10, |
BFD_RELOC_SPARC_LM22, |
BFD_RELOC_SPARC_PC_HH22, |
BFD_RELOC_SPARC_PC_HM10, |
BFD_RELOC_SPARC_PC_LM22, |
BFD_RELOC_SPARC_WDISP16, |
BFD_RELOC_SPARC_WDISP19, |
BFD_RELOC_SPARC_7, |
BFD_RELOC_SPARC_6, |
BFD_RELOC_SPARC_5, |
#define BFD_RELOC_SPARC_DISP64 BFD_RELOC_64_PCREL |
BFD_RELOC_SPARC_PLT32, |
BFD_RELOC_SPARC_PLT64, |
BFD_RELOC_SPARC_HIX22, |
BFD_RELOC_SPARC_LOX10, |
BFD_RELOC_SPARC_H44, |
BFD_RELOC_SPARC_M44, |
BFD_RELOC_SPARC_L44, |
BFD_RELOC_SPARC_REGISTER, |
BFD_RELOC_SPARC_H34, |
BFD_RELOC_SPARC_SIZE32, |
BFD_RELOC_SPARC_SIZE64, |
BFD_RELOC_SPARC_WDISP10, |
/* SPARC little endian relocation */ |
BFD_RELOC_SPARC_REV32, |
/* SPARC TLS relocations */ |
BFD_RELOC_SPARC_TLS_GD_HI22, |
BFD_RELOC_SPARC_TLS_GD_LO10, |
BFD_RELOC_SPARC_TLS_GD_ADD, |
BFD_RELOC_SPARC_TLS_GD_CALL, |
BFD_RELOC_SPARC_TLS_LDM_HI22, |
BFD_RELOC_SPARC_TLS_LDM_LO10, |
BFD_RELOC_SPARC_TLS_LDM_ADD, |
BFD_RELOC_SPARC_TLS_LDM_CALL, |
BFD_RELOC_SPARC_TLS_LDO_HIX22, |
BFD_RELOC_SPARC_TLS_LDO_LOX10, |
BFD_RELOC_SPARC_TLS_LDO_ADD, |
BFD_RELOC_SPARC_TLS_IE_HI22, |
BFD_RELOC_SPARC_TLS_IE_LO10, |
BFD_RELOC_SPARC_TLS_IE_LD, |
BFD_RELOC_SPARC_TLS_IE_LDX, |
BFD_RELOC_SPARC_TLS_IE_ADD, |
BFD_RELOC_SPARC_TLS_LE_HIX22, |
BFD_RELOC_SPARC_TLS_LE_LOX10, |
BFD_RELOC_SPARC_TLS_DTPMOD32, |
BFD_RELOC_SPARC_TLS_DTPMOD64, |
BFD_RELOC_SPARC_TLS_DTPOFF32, |
BFD_RELOC_SPARC_TLS_DTPOFF64, |
BFD_RELOC_SPARC_TLS_TPOFF32, |
BFD_RELOC_SPARC_TLS_TPOFF64, |
/* SPU Relocations. */ |
BFD_RELOC_SPU_IMM7, |
BFD_RELOC_SPU_IMM8, |
BFD_RELOC_SPU_IMM10, |
BFD_RELOC_SPU_IMM10W, |
BFD_RELOC_SPU_IMM16, |
BFD_RELOC_SPU_IMM16W, |
BFD_RELOC_SPU_IMM18, |
BFD_RELOC_SPU_PCREL9a, |
BFD_RELOC_SPU_PCREL9b, |
BFD_RELOC_SPU_PCREL16, |
BFD_RELOC_SPU_LO16, |
BFD_RELOC_SPU_HI16, |
BFD_RELOC_SPU_PPU32, |
BFD_RELOC_SPU_PPU64, |
BFD_RELOC_SPU_ADD_PIC, |
/* Alpha ECOFF and ELF relocations. Some of these treat the symbol or |
"addend" in some special way. |
For GPDISP_HI16 ("gpdisp") relocations, the symbol is ignored when |
writing; when reading, it will be the absolute section symbol. The |
addend is the displacement in bytes of the "lda" instruction from |
the "ldah" instruction (which is at the address of this reloc). */ |
BFD_RELOC_ALPHA_GPDISP_HI16, |
/* For GPDISP_LO16 ("ignore") relocations, the symbol is handled as |
with GPDISP_HI16 relocs. The addend is ignored when writing the |
relocations out, and is filled in with the file's GP value on |
reading, for convenience. */ |
BFD_RELOC_ALPHA_GPDISP_LO16, |
/* The ELF GPDISP relocation is exactly the same as the GPDISP_HI16 |
relocation except that there is no accompanying GPDISP_LO16 |
relocation. */ |
BFD_RELOC_ALPHA_GPDISP, |
/* The Alpha LITERAL/LITUSE relocs are produced by a symbol reference; |
the assembler turns it into a LDQ instruction to load the address of |
the symbol, and then fills in a register in the real instruction. |
The LITERAL reloc, at the LDQ instruction, refers to the .lita |
section symbol. The addend is ignored when writing, but is filled |
in with the file's GP value on reading, for convenience, as with the |
GPDISP_LO16 reloc. |
The ELF_LITERAL reloc is somewhere between 16_GOTOFF and GPDISP_LO16. |
It should refer to the symbol to be referenced, as with 16_GOTOFF, |
but it generates output not based on the position within the .got |
section, but relative to the GP value chosen for the file during the |
final link stage. |
The LITUSE reloc, on the instruction using the loaded address, gives |
information to the linker that it might be able to use to optimize |
away some literal section references. The symbol is ignored (read |
as the absolute section symbol), and the "addend" indicates the type |
of instruction using the register: |
1 - "memory" fmt insn |
2 - byte-manipulation (byte offset reg) |
3 - jsr (target of branch) */ |
BFD_RELOC_ALPHA_LITERAL, |
BFD_RELOC_ALPHA_ELF_LITERAL, |
BFD_RELOC_ALPHA_LITUSE, |
/* The HINT relocation indicates a value that should be filled into the |
"hint" field of a jmp/jsr/ret instruction, for possible branch- |
prediction logic which may be provided on some processors. */ |
BFD_RELOC_ALPHA_HINT, |
/* The LINKAGE relocation outputs a linkage pair in the object file, |
which is filled by the linker. */ |
BFD_RELOC_ALPHA_LINKAGE, |
/* The CODEADDR relocation outputs a STO_CA in the object file, |
which is filled by the linker. */ |
BFD_RELOC_ALPHA_CODEADDR, |
/* The GPREL_HI/LO relocations together form a 32-bit offset from the |
GP register. */ |
BFD_RELOC_ALPHA_GPREL_HI16, |
BFD_RELOC_ALPHA_GPREL_LO16, |
/* Like BFD_RELOC_23_PCREL_S2, except that the source and target must |
share a common GP, and the target address is adjusted for |
STO_ALPHA_STD_GPLOAD. */ |
BFD_RELOC_ALPHA_BRSGP, |
/* The NOP relocation outputs a NOP if the longword displacement |
between two procedure entry points is < 2^21. */ |
BFD_RELOC_ALPHA_NOP, |
/* The BSR relocation outputs a BSR if the longword displacement |
between two procedure entry points is < 2^21. */ |
BFD_RELOC_ALPHA_BSR, |
/* The LDA relocation outputs a LDA if the longword displacement |
between two procedure entry points is < 2^16. */ |
BFD_RELOC_ALPHA_LDA, |
/* The BOH relocation outputs a BSR if the longword displacement |
between two procedure entry points is < 2^21, or else a hint. */ |
BFD_RELOC_ALPHA_BOH, |
/* Alpha thread-local storage relocations. */ |
BFD_RELOC_ALPHA_TLSGD, |
BFD_RELOC_ALPHA_TLSLDM, |
BFD_RELOC_ALPHA_DTPMOD64, |
BFD_RELOC_ALPHA_GOTDTPREL16, |
BFD_RELOC_ALPHA_DTPREL64, |
BFD_RELOC_ALPHA_DTPREL_HI16, |
BFD_RELOC_ALPHA_DTPREL_LO16, |
BFD_RELOC_ALPHA_DTPREL16, |
BFD_RELOC_ALPHA_GOTTPREL16, |
BFD_RELOC_ALPHA_TPREL64, |
BFD_RELOC_ALPHA_TPREL_HI16, |
BFD_RELOC_ALPHA_TPREL_LO16, |
BFD_RELOC_ALPHA_TPREL16, |
/* The MIPS jump instruction. */ |
BFD_RELOC_MIPS_JMP, |
BFD_RELOC_MICROMIPS_JMP, |
/* The MIPS16 jump instruction. */ |
BFD_RELOC_MIPS16_JMP, |
/* MIPS16 GP relative reloc. */ |
BFD_RELOC_MIPS16_GPREL, |
/* High 16 bits of 32-bit value; simple reloc. */ |
BFD_RELOC_HI16, |
/* High 16 bits of 32-bit value but the low 16 bits will be sign |
extended and added to form the final result. If the low 16 |
bits form a negative number, we need to add one to the high value |
to compensate for the borrow when the low bits are added. */ |
BFD_RELOC_HI16_S, |
/* Low 16 bits. */ |
BFD_RELOC_LO16, |
/* High 16 bits of 32-bit pc-relative value */ |
BFD_RELOC_HI16_PCREL, |
/* High 16 bits of 32-bit pc-relative value, adjusted */ |
BFD_RELOC_HI16_S_PCREL, |
/* Low 16 bits of pc-relative value */ |
BFD_RELOC_LO16_PCREL, |
/* Equivalent of BFD_RELOC_MIPS_*, but with the MIPS16 layout of |
16-bit immediate fields */ |
BFD_RELOC_MIPS16_GOT16, |
BFD_RELOC_MIPS16_CALL16, |
/* MIPS16 high 16 bits of 32-bit value. */ |
BFD_RELOC_MIPS16_HI16, |
/* MIPS16 high 16 bits of 32-bit value but the low 16 bits will be sign |
extended and added to form the final result. If the low 16 |
bits form a negative number, we need to add one to the high value |
to compensate for the borrow when the low bits are added. */ |
BFD_RELOC_MIPS16_HI16_S, |
/* MIPS16 low 16 bits. */ |
BFD_RELOC_MIPS16_LO16, |
/* MIPS16 TLS relocations */ |
BFD_RELOC_MIPS16_TLS_GD, |
BFD_RELOC_MIPS16_TLS_LDM, |
BFD_RELOC_MIPS16_TLS_DTPREL_HI16, |
BFD_RELOC_MIPS16_TLS_DTPREL_LO16, |
BFD_RELOC_MIPS16_TLS_GOTTPREL, |
BFD_RELOC_MIPS16_TLS_TPREL_HI16, |
BFD_RELOC_MIPS16_TLS_TPREL_LO16, |
/* Relocation against a MIPS literal section. */ |
BFD_RELOC_MIPS_LITERAL, |
BFD_RELOC_MICROMIPS_LITERAL, |
/* microMIPS PC-relative relocations. */ |
BFD_RELOC_MICROMIPS_7_PCREL_S1, |
BFD_RELOC_MICROMIPS_10_PCREL_S1, |
BFD_RELOC_MICROMIPS_16_PCREL_S1, |
/* microMIPS versions of generic BFD relocs. */ |
BFD_RELOC_MICROMIPS_GPREL16, |
BFD_RELOC_MICROMIPS_HI16, |
BFD_RELOC_MICROMIPS_HI16_S, |
BFD_RELOC_MICROMIPS_LO16, |
/* MIPS ELF relocations. */ |
BFD_RELOC_MIPS_GOT16, |
BFD_RELOC_MICROMIPS_GOT16, |
BFD_RELOC_MIPS_CALL16, |
BFD_RELOC_MICROMIPS_CALL16, |
BFD_RELOC_MIPS_GOT_HI16, |
BFD_RELOC_MICROMIPS_GOT_HI16, |
BFD_RELOC_MIPS_GOT_LO16, |
BFD_RELOC_MICROMIPS_GOT_LO16, |
BFD_RELOC_MIPS_CALL_HI16, |
BFD_RELOC_MICROMIPS_CALL_HI16, |
BFD_RELOC_MIPS_CALL_LO16, |
BFD_RELOC_MICROMIPS_CALL_LO16, |
BFD_RELOC_MIPS_SUB, |
BFD_RELOC_MICROMIPS_SUB, |
BFD_RELOC_MIPS_GOT_PAGE, |
BFD_RELOC_MICROMIPS_GOT_PAGE, |
BFD_RELOC_MIPS_GOT_OFST, |
BFD_RELOC_MICROMIPS_GOT_OFST, |
BFD_RELOC_MIPS_GOT_DISP, |
BFD_RELOC_MICROMIPS_GOT_DISP, |
BFD_RELOC_MIPS_SHIFT5, |
BFD_RELOC_MIPS_SHIFT6, |
BFD_RELOC_MIPS_INSERT_A, |
BFD_RELOC_MIPS_INSERT_B, |
BFD_RELOC_MIPS_DELETE, |
BFD_RELOC_MIPS_HIGHEST, |
BFD_RELOC_MICROMIPS_HIGHEST, |
BFD_RELOC_MIPS_HIGHER, |
BFD_RELOC_MICROMIPS_HIGHER, |
BFD_RELOC_MIPS_SCN_DISP, |
BFD_RELOC_MICROMIPS_SCN_DISP, |
BFD_RELOC_MIPS_REL16, |
BFD_RELOC_MIPS_RELGOT, |
BFD_RELOC_MIPS_JALR, |
BFD_RELOC_MICROMIPS_JALR, |
BFD_RELOC_MIPS_TLS_DTPMOD32, |
BFD_RELOC_MIPS_TLS_DTPREL32, |
BFD_RELOC_MIPS_TLS_DTPMOD64, |
BFD_RELOC_MIPS_TLS_DTPREL64, |
BFD_RELOC_MIPS_TLS_GD, |
BFD_RELOC_MICROMIPS_TLS_GD, |
BFD_RELOC_MIPS_TLS_LDM, |
BFD_RELOC_MICROMIPS_TLS_LDM, |
BFD_RELOC_MIPS_TLS_DTPREL_HI16, |
BFD_RELOC_MICROMIPS_TLS_DTPREL_HI16, |
BFD_RELOC_MIPS_TLS_DTPREL_LO16, |
BFD_RELOC_MICROMIPS_TLS_DTPREL_LO16, |
BFD_RELOC_MIPS_TLS_GOTTPREL, |
BFD_RELOC_MICROMIPS_TLS_GOTTPREL, |
BFD_RELOC_MIPS_TLS_TPREL32, |
BFD_RELOC_MIPS_TLS_TPREL64, |
BFD_RELOC_MIPS_TLS_TPREL_HI16, |
BFD_RELOC_MICROMIPS_TLS_TPREL_HI16, |
BFD_RELOC_MIPS_TLS_TPREL_LO16, |
BFD_RELOC_MICROMIPS_TLS_TPREL_LO16, |
BFD_RELOC_MIPS_EH, |
/* MIPS ELF relocations (VxWorks and PLT extensions). */ |
BFD_RELOC_MIPS_COPY, |
BFD_RELOC_MIPS_JUMP_SLOT, |
/* Moxie ELF relocations. */ |
BFD_RELOC_MOXIE_10_PCREL, |
/* Fujitsu Frv Relocations. */ |
BFD_RELOC_FRV_LABEL16, |
BFD_RELOC_FRV_LABEL24, |
BFD_RELOC_FRV_LO16, |
BFD_RELOC_FRV_HI16, |
BFD_RELOC_FRV_GPREL12, |
BFD_RELOC_FRV_GPRELU12, |
BFD_RELOC_FRV_GPREL32, |
BFD_RELOC_FRV_GPRELHI, |
BFD_RELOC_FRV_GPRELLO, |
BFD_RELOC_FRV_GOT12, |
BFD_RELOC_FRV_GOTHI, |
BFD_RELOC_FRV_GOTLO, |
BFD_RELOC_FRV_FUNCDESC, |
BFD_RELOC_FRV_FUNCDESC_GOT12, |
BFD_RELOC_FRV_FUNCDESC_GOTHI, |
BFD_RELOC_FRV_FUNCDESC_GOTLO, |
BFD_RELOC_FRV_FUNCDESC_VALUE, |
BFD_RELOC_FRV_FUNCDESC_GOTOFF12, |
BFD_RELOC_FRV_FUNCDESC_GOTOFFHI, |
BFD_RELOC_FRV_FUNCDESC_GOTOFFLO, |
BFD_RELOC_FRV_GOTOFF12, |
BFD_RELOC_FRV_GOTOFFHI, |
BFD_RELOC_FRV_GOTOFFLO, |
BFD_RELOC_FRV_GETTLSOFF, |
BFD_RELOC_FRV_TLSDESC_VALUE, |
BFD_RELOC_FRV_GOTTLSDESC12, |
BFD_RELOC_FRV_GOTTLSDESCHI, |
BFD_RELOC_FRV_GOTTLSDESCLO, |
BFD_RELOC_FRV_TLSMOFF12, |
BFD_RELOC_FRV_TLSMOFFHI, |
BFD_RELOC_FRV_TLSMOFFLO, |
BFD_RELOC_FRV_GOTTLSOFF12, |
BFD_RELOC_FRV_GOTTLSOFFHI, |
BFD_RELOC_FRV_GOTTLSOFFLO, |
BFD_RELOC_FRV_TLSOFF, |
BFD_RELOC_FRV_TLSDESC_RELAX, |
BFD_RELOC_FRV_GETTLSOFF_RELAX, |
BFD_RELOC_FRV_TLSOFF_RELAX, |
BFD_RELOC_FRV_TLSMOFF, |
/* This is a 24bit GOT-relative reloc for the mn10300. */ |
BFD_RELOC_MN10300_GOTOFF24, |
/* This is a 32bit GOT-relative reloc for the mn10300, offset by two bytes |
in the instruction. */ |
BFD_RELOC_MN10300_GOT32, |
/* This is a 24bit GOT-relative reloc for the mn10300, offset by two bytes |
in the instruction. */ |
BFD_RELOC_MN10300_GOT24, |
/* This is a 16bit GOT-relative reloc for the mn10300, offset by two bytes |
in the instruction. */ |
BFD_RELOC_MN10300_GOT16, |
/* Copy symbol at runtime. */ |
BFD_RELOC_MN10300_COPY, |
/* Create GOT entry. */ |
BFD_RELOC_MN10300_GLOB_DAT, |
/* Create PLT entry. */ |
BFD_RELOC_MN10300_JMP_SLOT, |
/* Adjust by program base. */ |
BFD_RELOC_MN10300_RELATIVE, |
/* Together with another reloc targeted at the same location, |
allows for a value that is the difference of two symbols |
in the same section. */ |
BFD_RELOC_MN10300_SYM_DIFF, |
/* The addend of this reloc is an alignment power that must |
be honoured at the offset's location, regardless of linker |
relaxation. */ |
BFD_RELOC_MN10300_ALIGN, |
/* Various TLS-related relocations. */ |
BFD_RELOC_MN10300_TLS_GD, |
BFD_RELOC_MN10300_TLS_LD, |
BFD_RELOC_MN10300_TLS_LDO, |
BFD_RELOC_MN10300_TLS_GOTIE, |
BFD_RELOC_MN10300_TLS_IE, |
BFD_RELOC_MN10300_TLS_LE, |
BFD_RELOC_MN10300_TLS_DTPMOD, |
BFD_RELOC_MN10300_TLS_DTPOFF, |
BFD_RELOC_MN10300_TLS_TPOFF, |
/* This is a 32bit pcrel reloc for the mn10300, offset by two bytes in the |
instruction. */ |
BFD_RELOC_MN10300_32_PCREL, |
/* This is a 16bit pcrel reloc for the mn10300, offset by two bytes in the |
instruction. */ |
BFD_RELOC_MN10300_16_PCREL, |
/* i386/elf relocations */ |
BFD_RELOC_386_GOT32, |
BFD_RELOC_386_PLT32, |
BFD_RELOC_386_COPY, |
BFD_RELOC_386_GLOB_DAT, |
BFD_RELOC_386_JUMP_SLOT, |
BFD_RELOC_386_RELATIVE, |
BFD_RELOC_386_GOTOFF, |
BFD_RELOC_386_GOTPC, |
BFD_RELOC_386_TLS_TPOFF, |
BFD_RELOC_386_TLS_IE, |
BFD_RELOC_386_TLS_GOTIE, |
BFD_RELOC_386_TLS_LE, |
BFD_RELOC_386_TLS_GD, |
BFD_RELOC_386_TLS_LDM, |
BFD_RELOC_386_TLS_LDO_32, |
BFD_RELOC_386_TLS_IE_32, |
BFD_RELOC_386_TLS_LE_32, |
BFD_RELOC_386_TLS_DTPMOD32, |
BFD_RELOC_386_TLS_DTPOFF32, |
BFD_RELOC_386_TLS_TPOFF32, |
BFD_RELOC_386_TLS_GOTDESC, |
BFD_RELOC_386_TLS_DESC_CALL, |
BFD_RELOC_386_TLS_DESC, |
BFD_RELOC_386_IRELATIVE, |
/* x86-64/elf relocations */ |
BFD_RELOC_X86_64_GOT32, |
BFD_RELOC_X86_64_PLT32, |
BFD_RELOC_X86_64_COPY, |
BFD_RELOC_X86_64_GLOB_DAT, |
BFD_RELOC_X86_64_JUMP_SLOT, |
BFD_RELOC_X86_64_RELATIVE, |
BFD_RELOC_X86_64_GOTPCREL, |
BFD_RELOC_X86_64_32S, |
BFD_RELOC_X86_64_DTPMOD64, |
BFD_RELOC_X86_64_DTPOFF64, |
BFD_RELOC_X86_64_TPOFF64, |
BFD_RELOC_X86_64_TLSGD, |
BFD_RELOC_X86_64_TLSLD, |
BFD_RELOC_X86_64_DTPOFF32, |
BFD_RELOC_X86_64_GOTTPOFF, |
BFD_RELOC_X86_64_TPOFF32, |
BFD_RELOC_X86_64_GOTOFF64, |
BFD_RELOC_X86_64_GOTPC32, |
BFD_RELOC_X86_64_GOT64, |
BFD_RELOC_X86_64_GOTPCREL64, |
BFD_RELOC_X86_64_GOTPC64, |
BFD_RELOC_X86_64_GOTPLT64, |
BFD_RELOC_X86_64_PLTOFF64, |
BFD_RELOC_X86_64_GOTPC32_TLSDESC, |
BFD_RELOC_X86_64_TLSDESC_CALL, |
BFD_RELOC_X86_64_TLSDESC, |
BFD_RELOC_X86_64_IRELATIVE, |
BFD_RELOC_X86_64_PC32_BND, |
BFD_RELOC_X86_64_PLT32_BND, |
/* ns32k relocations */ |
BFD_RELOC_NS32K_IMM_8, |
BFD_RELOC_NS32K_IMM_16, |
BFD_RELOC_NS32K_IMM_32, |
BFD_RELOC_NS32K_IMM_8_PCREL, |
BFD_RELOC_NS32K_IMM_16_PCREL, |
BFD_RELOC_NS32K_IMM_32_PCREL, |
BFD_RELOC_NS32K_DISP_8, |
BFD_RELOC_NS32K_DISP_16, |
BFD_RELOC_NS32K_DISP_32, |
BFD_RELOC_NS32K_DISP_8_PCREL, |
BFD_RELOC_NS32K_DISP_16_PCREL, |
BFD_RELOC_NS32K_DISP_32_PCREL, |
/* PDP11 relocations */ |
BFD_RELOC_PDP11_DISP_8_PCREL, |
BFD_RELOC_PDP11_DISP_6_PCREL, |
/* Picojava relocs. Not all of these appear in object files. */ |
BFD_RELOC_PJ_CODE_HI16, |
BFD_RELOC_PJ_CODE_LO16, |
BFD_RELOC_PJ_CODE_DIR16, |
BFD_RELOC_PJ_CODE_DIR32, |
BFD_RELOC_PJ_CODE_REL16, |
BFD_RELOC_PJ_CODE_REL32, |
/* Power(rs6000) and PowerPC relocations. */ |
BFD_RELOC_PPC_B26, |
BFD_RELOC_PPC_BA26, |
BFD_RELOC_PPC_TOC16, |
BFD_RELOC_PPC_B16, |
BFD_RELOC_PPC_B16_BRTAKEN, |
BFD_RELOC_PPC_B16_BRNTAKEN, |
BFD_RELOC_PPC_BA16, |
BFD_RELOC_PPC_BA16_BRTAKEN, |
BFD_RELOC_PPC_BA16_BRNTAKEN, |
BFD_RELOC_PPC_COPY, |
BFD_RELOC_PPC_GLOB_DAT, |
BFD_RELOC_PPC_JMP_SLOT, |
BFD_RELOC_PPC_RELATIVE, |
BFD_RELOC_PPC_LOCAL24PC, |
BFD_RELOC_PPC_EMB_NADDR32, |
BFD_RELOC_PPC_EMB_NADDR16, |
BFD_RELOC_PPC_EMB_NADDR16_LO, |
BFD_RELOC_PPC_EMB_NADDR16_HI, |
BFD_RELOC_PPC_EMB_NADDR16_HA, |
BFD_RELOC_PPC_EMB_SDAI16, |
BFD_RELOC_PPC_EMB_SDA2I16, |
BFD_RELOC_PPC_EMB_SDA2REL, |
BFD_RELOC_PPC_EMB_SDA21, |
BFD_RELOC_PPC_EMB_MRKREF, |
BFD_RELOC_PPC_EMB_RELSEC16, |
BFD_RELOC_PPC_EMB_RELST_LO, |
BFD_RELOC_PPC_EMB_RELST_HI, |
BFD_RELOC_PPC_EMB_RELST_HA, |
BFD_RELOC_PPC_EMB_BIT_FLD, |
BFD_RELOC_PPC_EMB_RELSDA, |
BFD_RELOC_PPC_VLE_REL8, |
BFD_RELOC_PPC_VLE_REL15, |
BFD_RELOC_PPC_VLE_REL24, |
BFD_RELOC_PPC_VLE_LO16A, |
BFD_RELOC_PPC_VLE_LO16D, |
BFD_RELOC_PPC_VLE_HI16A, |
BFD_RELOC_PPC_VLE_HI16D, |
BFD_RELOC_PPC_VLE_HA16A, |
BFD_RELOC_PPC_VLE_HA16D, |
BFD_RELOC_PPC_VLE_SDA21, |
BFD_RELOC_PPC_VLE_SDA21_LO, |
BFD_RELOC_PPC_VLE_SDAREL_LO16A, |
BFD_RELOC_PPC_VLE_SDAREL_LO16D, |
BFD_RELOC_PPC_VLE_SDAREL_HI16A, |
BFD_RELOC_PPC_VLE_SDAREL_HI16D, |
BFD_RELOC_PPC_VLE_SDAREL_HA16A, |
BFD_RELOC_PPC_VLE_SDAREL_HA16D, |
BFD_RELOC_PPC64_HIGHER, |
BFD_RELOC_PPC64_HIGHER_S, |
BFD_RELOC_PPC64_HIGHEST, |
BFD_RELOC_PPC64_HIGHEST_S, |
BFD_RELOC_PPC64_TOC16_LO, |
BFD_RELOC_PPC64_TOC16_HI, |
BFD_RELOC_PPC64_TOC16_HA, |
BFD_RELOC_PPC64_TOC, |
BFD_RELOC_PPC64_PLTGOT16, |
BFD_RELOC_PPC64_PLTGOT16_LO, |
BFD_RELOC_PPC64_PLTGOT16_HI, |
BFD_RELOC_PPC64_PLTGOT16_HA, |
BFD_RELOC_PPC64_ADDR16_DS, |
BFD_RELOC_PPC64_ADDR16_LO_DS, |
BFD_RELOC_PPC64_GOT16_DS, |
BFD_RELOC_PPC64_GOT16_LO_DS, |
BFD_RELOC_PPC64_PLT16_LO_DS, |
BFD_RELOC_PPC64_SECTOFF_DS, |
BFD_RELOC_PPC64_SECTOFF_LO_DS, |
BFD_RELOC_PPC64_TOC16_DS, |
BFD_RELOC_PPC64_TOC16_LO_DS, |
BFD_RELOC_PPC64_PLTGOT16_DS, |
BFD_RELOC_PPC64_PLTGOT16_LO_DS, |
BFD_RELOC_PPC64_ADDR16_HIGH, |
BFD_RELOC_PPC64_ADDR16_HIGHA, |
/* PowerPC and PowerPC64 thread-local storage relocations. */ |
BFD_RELOC_PPC_TLS, |
BFD_RELOC_PPC_TLSGD, |
BFD_RELOC_PPC_TLSLD, |
BFD_RELOC_PPC_DTPMOD, |
BFD_RELOC_PPC_TPREL16, |
BFD_RELOC_PPC_TPREL16_LO, |
BFD_RELOC_PPC_TPREL16_HI, |
BFD_RELOC_PPC_TPREL16_HA, |
BFD_RELOC_PPC_TPREL, |
BFD_RELOC_PPC_DTPREL16, |
BFD_RELOC_PPC_DTPREL16_LO, |
BFD_RELOC_PPC_DTPREL16_HI, |
BFD_RELOC_PPC_DTPREL16_HA, |
BFD_RELOC_PPC_DTPREL, |
BFD_RELOC_PPC_GOT_TLSGD16, |
BFD_RELOC_PPC_GOT_TLSGD16_LO, |
BFD_RELOC_PPC_GOT_TLSGD16_HI, |
BFD_RELOC_PPC_GOT_TLSGD16_HA, |
BFD_RELOC_PPC_GOT_TLSLD16, |
BFD_RELOC_PPC_GOT_TLSLD16_LO, |
BFD_RELOC_PPC_GOT_TLSLD16_HI, |
BFD_RELOC_PPC_GOT_TLSLD16_HA, |
BFD_RELOC_PPC_GOT_TPREL16, |
BFD_RELOC_PPC_GOT_TPREL16_LO, |
BFD_RELOC_PPC_GOT_TPREL16_HI, |
BFD_RELOC_PPC_GOT_TPREL16_HA, |
BFD_RELOC_PPC_GOT_DTPREL16, |
BFD_RELOC_PPC_GOT_DTPREL16_LO, |
BFD_RELOC_PPC_GOT_DTPREL16_HI, |
BFD_RELOC_PPC_GOT_DTPREL16_HA, |
BFD_RELOC_PPC64_TPREL16_DS, |
BFD_RELOC_PPC64_TPREL16_LO_DS, |
BFD_RELOC_PPC64_TPREL16_HIGHER, |
BFD_RELOC_PPC64_TPREL16_HIGHERA, |
BFD_RELOC_PPC64_TPREL16_HIGHEST, |
BFD_RELOC_PPC64_TPREL16_HIGHESTA, |
BFD_RELOC_PPC64_DTPREL16_DS, |
BFD_RELOC_PPC64_DTPREL16_LO_DS, |
BFD_RELOC_PPC64_DTPREL16_HIGHER, |
BFD_RELOC_PPC64_DTPREL16_HIGHERA, |
BFD_RELOC_PPC64_DTPREL16_HIGHEST, |
BFD_RELOC_PPC64_DTPREL16_HIGHESTA, |
BFD_RELOC_PPC64_TPREL16_HIGH, |
BFD_RELOC_PPC64_TPREL16_HIGHA, |
BFD_RELOC_PPC64_DTPREL16_HIGH, |
BFD_RELOC_PPC64_DTPREL16_HIGHA, |
/* IBM 370/390 relocations */ |
BFD_RELOC_I370_D12, |
/* The type of reloc used to build a constructor table - at the moment |
probably a 32 bit wide absolute relocation, but the target can choose. |
It generally does map to one of the other relocation types. */ |
BFD_RELOC_CTOR, |
/* ARM 26 bit pc-relative branch. The lowest two bits must be zero and are |
not stored in the instruction. */ |
BFD_RELOC_ARM_PCREL_BRANCH, |
/* ARM 26 bit pc-relative branch. The lowest bit must be zero and is |
not stored in the instruction. The 2nd lowest bit comes from a 1 bit |
field in the instruction. */ |
BFD_RELOC_ARM_PCREL_BLX, |
/* Thumb 22 bit pc-relative branch. The lowest bit must be zero and is |
not stored in the instruction. The 2nd lowest bit comes from a 1 bit |
field in the instruction. */ |
BFD_RELOC_THUMB_PCREL_BLX, |
/* ARM 26-bit pc-relative branch for an unconditional BL or BLX instruction. */ |
BFD_RELOC_ARM_PCREL_CALL, |
/* ARM 26-bit pc-relative branch for B or conditional BL instruction. */ |
BFD_RELOC_ARM_PCREL_JUMP, |
/* Thumb 7-, 9-, 12-, 20-, 23-, and 25-bit pc-relative branches. |
The lowest bit must be zero and is not stored in the instruction. |
Note that the corresponding ELF R_ARM_THM_JUMPnn constant has an |
"nn" one smaller in all cases. Note further that BRANCH23 |
corresponds to R_ARM_THM_CALL. */ |
BFD_RELOC_THUMB_PCREL_BRANCH7, |
BFD_RELOC_THUMB_PCREL_BRANCH9, |
BFD_RELOC_THUMB_PCREL_BRANCH12, |
BFD_RELOC_THUMB_PCREL_BRANCH20, |
BFD_RELOC_THUMB_PCREL_BRANCH23, |
BFD_RELOC_THUMB_PCREL_BRANCH25, |
/* 12-bit immediate offset, used in ARM-format ldr and str instructions. */ |
BFD_RELOC_ARM_OFFSET_IMM, |
/* 5-bit immediate offset, used in Thumb-format ldr and str instructions. */ |
BFD_RELOC_ARM_THUMB_OFFSET, |
/* Pc-relative or absolute relocation depending on target. Used for |
entries in .init_array sections. */ |
BFD_RELOC_ARM_TARGET1, |
/* Read-only segment base relative address. */ |
BFD_RELOC_ARM_ROSEGREL32, |
/* Data segment base relative address. */ |
BFD_RELOC_ARM_SBREL32, |
/* This reloc is used for references to RTTI data from exception handling |
tables. The actual definition depends on the target. It may be a |
pc-relative or some form of GOT-indirect relocation. */ |
BFD_RELOC_ARM_TARGET2, |
/* 31-bit PC relative address. */ |
BFD_RELOC_ARM_PREL31, |
/* Low and High halfword relocations for MOVW and MOVT instructions. */ |
BFD_RELOC_ARM_MOVW, |
BFD_RELOC_ARM_MOVT, |
BFD_RELOC_ARM_MOVW_PCREL, |
BFD_RELOC_ARM_MOVT_PCREL, |
BFD_RELOC_ARM_THUMB_MOVW, |
BFD_RELOC_ARM_THUMB_MOVT, |
BFD_RELOC_ARM_THUMB_MOVW_PCREL, |
BFD_RELOC_ARM_THUMB_MOVT_PCREL, |
/* Relocations for setting up GOTs and PLTs for shared libraries. */ |
BFD_RELOC_ARM_JUMP_SLOT, |
BFD_RELOC_ARM_GLOB_DAT, |
BFD_RELOC_ARM_GOT32, |
BFD_RELOC_ARM_PLT32, |
BFD_RELOC_ARM_RELATIVE, |
BFD_RELOC_ARM_GOTOFF, |
BFD_RELOC_ARM_GOTPC, |
BFD_RELOC_ARM_GOT_PREL, |
/* ARM thread-local storage relocations. */ |
BFD_RELOC_ARM_TLS_GD32, |
BFD_RELOC_ARM_TLS_LDO32, |
BFD_RELOC_ARM_TLS_LDM32, |
BFD_RELOC_ARM_TLS_DTPOFF32, |
BFD_RELOC_ARM_TLS_DTPMOD32, |
BFD_RELOC_ARM_TLS_TPOFF32, |
BFD_RELOC_ARM_TLS_IE32, |
BFD_RELOC_ARM_TLS_LE32, |
BFD_RELOC_ARM_TLS_GOTDESC, |
BFD_RELOC_ARM_TLS_CALL, |
BFD_RELOC_ARM_THM_TLS_CALL, |
BFD_RELOC_ARM_TLS_DESCSEQ, |
BFD_RELOC_ARM_THM_TLS_DESCSEQ, |
BFD_RELOC_ARM_TLS_DESC, |
/* ARM group relocations. */ |
BFD_RELOC_ARM_ALU_PC_G0_NC, |
BFD_RELOC_ARM_ALU_PC_G0, |
BFD_RELOC_ARM_ALU_PC_G1_NC, |
BFD_RELOC_ARM_ALU_PC_G1, |
BFD_RELOC_ARM_ALU_PC_G2, |
BFD_RELOC_ARM_LDR_PC_G0, |
BFD_RELOC_ARM_LDR_PC_G1, |
BFD_RELOC_ARM_LDR_PC_G2, |
BFD_RELOC_ARM_LDRS_PC_G0, |
BFD_RELOC_ARM_LDRS_PC_G1, |
BFD_RELOC_ARM_LDRS_PC_G2, |
BFD_RELOC_ARM_LDC_PC_G0, |
BFD_RELOC_ARM_LDC_PC_G1, |
BFD_RELOC_ARM_LDC_PC_G2, |
BFD_RELOC_ARM_ALU_SB_G0_NC, |
BFD_RELOC_ARM_ALU_SB_G0, |
BFD_RELOC_ARM_ALU_SB_G1_NC, |
BFD_RELOC_ARM_ALU_SB_G1, |
BFD_RELOC_ARM_ALU_SB_G2, |
BFD_RELOC_ARM_LDR_SB_G0, |
BFD_RELOC_ARM_LDR_SB_G1, |
BFD_RELOC_ARM_LDR_SB_G2, |
BFD_RELOC_ARM_LDRS_SB_G0, |
BFD_RELOC_ARM_LDRS_SB_G1, |
BFD_RELOC_ARM_LDRS_SB_G2, |
BFD_RELOC_ARM_LDC_SB_G0, |
BFD_RELOC_ARM_LDC_SB_G1, |
BFD_RELOC_ARM_LDC_SB_G2, |
/* Annotation of BX instructions. */ |
BFD_RELOC_ARM_V4BX, |
/* ARM support for STT_GNU_IFUNC. */ |
BFD_RELOC_ARM_IRELATIVE, |
/* These relocs are only used within the ARM assembler. They are not |
(at present) written to any object files. */ |
BFD_RELOC_ARM_IMMEDIATE, |
BFD_RELOC_ARM_ADRL_IMMEDIATE, |
BFD_RELOC_ARM_T32_IMMEDIATE, |
BFD_RELOC_ARM_T32_ADD_IMM, |
BFD_RELOC_ARM_T32_IMM12, |
BFD_RELOC_ARM_T32_ADD_PC12, |
BFD_RELOC_ARM_SHIFT_IMM, |
BFD_RELOC_ARM_SMC, |
BFD_RELOC_ARM_HVC, |
BFD_RELOC_ARM_SWI, |
BFD_RELOC_ARM_MULTI, |
BFD_RELOC_ARM_CP_OFF_IMM, |
BFD_RELOC_ARM_CP_OFF_IMM_S2, |
BFD_RELOC_ARM_T32_CP_OFF_IMM, |
BFD_RELOC_ARM_T32_CP_OFF_IMM_S2, |
BFD_RELOC_ARM_ADR_IMM, |
BFD_RELOC_ARM_LDR_IMM, |
BFD_RELOC_ARM_LITERAL, |
BFD_RELOC_ARM_IN_POOL, |
BFD_RELOC_ARM_OFFSET_IMM8, |
BFD_RELOC_ARM_T32_OFFSET_U8, |
BFD_RELOC_ARM_T32_OFFSET_IMM, |
BFD_RELOC_ARM_HWLITERAL, |
BFD_RELOC_ARM_THUMB_ADD, |
BFD_RELOC_ARM_THUMB_IMM, |
BFD_RELOC_ARM_THUMB_SHIFT, |
/* Renesas / SuperH SH relocs. Not all of these appear in object files. */ |
BFD_RELOC_SH_PCDISP8BY2, |
BFD_RELOC_SH_PCDISP12BY2, |
BFD_RELOC_SH_IMM3, |
BFD_RELOC_SH_IMM3U, |
BFD_RELOC_SH_DISP12, |
BFD_RELOC_SH_DISP12BY2, |
BFD_RELOC_SH_DISP12BY4, |
BFD_RELOC_SH_DISP12BY8, |
BFD_RELOC_SH_DISP20, |
BFD_RELOC_SH_DISP20BY8, |
BFD_RELOC_SH_IMM4, |
BFD_RELOC_SH_IMM4BY2, |
BFD_RELOC_SH_IMM4BY4, |
BFD_RELOC_SH_IMM8, |
BFD_RELOC_SH_IMM8BY2, |
BFD_RELOC_SH_IMM8BY4, |
BFD_RELOC_SH_PCRELIMM8BY2, |
BFD_RELOC_SH_PCRELIMM8BY4, |
BFD_RELOC_SH_SWITCH16, |
BFD_RELOC_SH_SWITCH32, |
BFD_RELOC_SH_USES, |
BFD_RELOC_SH_COUNT, |
BFD_RELOC_SH_ALIGN, |
BFD_RELOC_SH_CODE, |
BFD_RELOC_SH_DATA, |
BFD_RELOC_SH_LABEL, |
BFD_RELOC_SH_LOOP_START, |
BFD_RELOC_SH_LOOP_END, |
BFD_RELOC_SH_COPY, |
BFD_RELOC_SH_GLOB_DAT, |
BFD_RELOC_SH_JMP_SLOT, |
BFD_RELOC_SH_RELATIVE, |
BFD_RELOC_SH_GOTPC, |
BFD_RELOC_SH_GOT_LOW16, |
BFD_RELOC_SH_GOT_MEDLOW16, |
BFD_RELOC_SH_GOT_MEDHI16, |
BFD_RELOC_SH_GOT_HI16, |
BFD_RELOC_SH_GOTPLT_LOW16, |
BFD_RELOC_SH_GOTPLT_MEDLOW16, |
BFD_RELOC_SH_GOTPLT_MEDHI16, |
BFD_RELOC_SH_GOTPLT_HI16, |
BFD_RELOC_SH_PLT_LOW16, |
BFD_RELOC_SH_PLT_MEDLOW16, |
BFD_RELOC_SH_PLT_MEDHI16, |
BFD_RELOC_SH_PLT_HI16, |
BFD_RELOC_SH_GOTOFF_LOW16, |
BFD_RELOC_SH_GOTOFF_MEDLOW16, |
BFD_RELOC_SH_GOTOFF_MEDHI16, |
BFD_RELOC_SH_GOTOFF_HI16, |
BFD_RELOC_SH_GOTPC_LOW16, |
BFD_RELOC_SH_GOTPC_MEDLOW16, |
BFD_RELOC_SH_GOTPC_MEDHI16, |
BFD_RELOC_SH_GOTPC_HI16, |
BFD_RELOC_SH_COPY64, |
BFD_RELOC_SH_GLOB_DAT64, |
BFD_RELOC_SH_JMP_SLOT64, |
BFD_RELOC_SH_RELATIVE64, |
BFD_RELOC_SH_GOT10BY4, |
BFD_RELOC_SH_GOT10BY8, |
BFD_RELOC_SH_GOTPLT10BY4, |
BFD_RELOC_SH_GOTPLT10BY8, |
BFD_RELOC_SH_GOTPLT32, |
BFD_RELOC_SH_SHMEDIA_CODE, |
BFD_RELOC_SH_IMMU5, |
BFD_RELOC_SH_IMMS6, |
BFD_RELOC_SH_IMMS6BY32, |
BFD_RELOC_SH_IMMU6, |
BFD_RELOC_SH_IMMS10, |
BFD_RELOC_SH_IMMS10BY2, |
BFD_RELOC_SH_IMMS10BY4, |
BFD_RELOC_SH_IMMS10BY8, |
BFD_RELOC_SH_IMMS16, |
BFD_RELOC_SH_IMMU16, |
BFD_RELOC_SH_IMM_LOW16, |
BFD_RELOC_SH_IMM_LOW16_PCREL, |
BFD_RELOC_SH_IMM_MEDLOW16, |
BFD_RELOC_SH_IMM_MEDLOW16_PCREL, |
BFD_RELOC_SH_IMM_MEDHI16, |
BFD_RELOC_SH_IMM_MEDHI16_PCREL, |
BFD_RELOC_SH_IMM_HI16, |
BFD_RELOC_SH_IMM_HI16_PCREL, |
BFD_RELOC_SH_PT_16, |
BFD_RELOC_SH_TLS_GD_32, |
BFD_RELOC_SH_TLS_LD_32, |
BFD_RELOC_SH_TLS_LDO_32, |
BFD_RELOC_SH_TLS_IE_32, |
BFD_RELOC_SH_TLS_LE_32, |
BFD_RELOC_SH_TLS_DTPMOD32, |
BFD_RELOC_SH_TLS_DTPOFF32, |
BFD_RELOC_SH_TLS_TPOFF32, |
BFD_RELOC_SH_GOT20, |
BFD_RELOC_SH_GOTOFF20, |
BFD_RELOC_SH_GOTFUNCDESC, |
BFD_RELOC_SH_GOTFUNCDESC20, |
BFD_RELOC_SH_GOTOFFFUNCDESC, |
BFD_RELOC_SH_GOTOFFFUNCDESC20, |
BFD_RELOC_SH_FUNCDESC, |
/* ARC Cores relocs. |
ARC 22 bit pc-relative branch. The lowest two bits must be zero and are |
not stored in the instruction. The high 20 bits are installed in bits 26 |
through 7 of the instruction. */ |
BFD_RELOC_ARC_B22_PCREL, |
/* ARC 26 bit absolute branch. The lowest two bits must be zero and are not |
stored in the instruction. The high 24 bits are installed in bits 23 |
through 0. */ |
BFD_RELOC_ARC_B26, |
/* ADI Blackfin 16 bit immediate absolute reloc. */ |
BFD_RELOC_BFIN_16_IMM, |
/* ADI Blackfin 16 bit immediate absolute reloc higher 16 bits. */ |
BFD_RELOC_BFIN_16_HIGH, |
/* ADI Blackfin 'a' part of LSETUP. */ |
BFD_RELOC_BFIN_4_PCREL, |
/* ADI Blackfin. */ |
BFD_RELOC_BFIN_5_PCREL, |
/* ADI Blackfin 16 bit immediate absolute reloc lower 16 bits. */ |
BFD_RELOC_BFIN_16_LOW, |
/* ADI Blackfin. */ |
BFD_RELOC_BFIN_10_PCREL, |
/* ADI Blackfin 'b' part of LSETUP. */ |
BFD_RELOC_BFIN_11_PCREL, |
/* ADI Blackfin. */ |
BFD_RELOC_BFIN_12_PCREL_JUMP, |
/* ADI Blackfin Short jump, pcrel. */ |
BFD_RELOC_BFIN_12_PCREL_JUMP_S, |
/* ADI Blackfin Call.x not implemented. */ |
BFD_RELOC_BFIN_24_PCREL_CALL_X, |
/* ADI Blackfin Long Jump pcrel. */ |
BFD_RELOC_BFIN_24_PCREL_JUMP_L, |
/* ADI Blackfin FD-PIC relocations. */ |
BFD_RELOC_BFIN_GOT17M4, |
BFD_RELOC_BFIN_GOTHI, |
BFD_RELOC_BFIN_GOTLO, |
BFD_RELOC_BFIN_FUNCDESC, |
BFD_RELOC_BFIN_FUNCDESC_GOT17M4, |
BFD_RELOC_BFIN_FUNCDESC_GOTHI, |
BFD_RELOC_BFIN_FUNCDESC_GOTLO, |
BFD_RELOC_BFIN_FUNCDESC_VALUE, |
BFD_RELOC_BFIN_FUNCDESC_GOTOFF17M4, |
BFD_RELOC_BFIN_FUNCDESC_GOTOFFHI, |
BFD_RELOC_BFIN_FUNCDESC_GOTOFFLO, |
BFD_RELOC_BFIN_GOTOFF17M4, |
BFD_RELOC_BFIN_GOTOFFHI, |
BFD_RELOC_BFIN_GOTOFFLO, |
/* ADI Blackfin GOT relocation. */ |
BFD_RELOC_BFIN_GOT, |
/* ADI Blackfin PLTPC relocation. */ |
BFD_RELOC_BFIN_PLTPC, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_PUSH, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_CONST, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_ADD, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_SUB, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_MULT, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_DIV, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_MOD, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_LSHIFT, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_RSHIFT, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_AND, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_OR, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_XOR, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_LAND, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_LOR, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_LEN, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_NEG, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_COMP, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_PAGE, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_HWPAGE, |
/* ADI Blackfin arithmetic relocation. */ |
BFD_ARELOC_BFIN_ADDR, |
/* Mitsubishi D10V relocs. |
This is a 10-bit reloc with the right 2 bits |
assumed to be 0. */ |
BFD_RELOC_D10V_10_PCREL_R, |
/* Mitsubishi D10V relocs. |
This is a 10-bit reloc with the right 2 bits |
assumed to be 0. This is the same as the previous reloc |
except it is in the left container, i.e., |
shifted left 15 bits. */ |
BFD_RELOC_D10V_10_PCREL_L, |
/* This is an 18-bit reloc with the right 2 bits |
assumed to be 0. */ |
BFD_RELOC_D10V_18, |
/* This is an 18-bit reloc with the right 2 bits |
assumed to be 0. */ |
BFD_RELOC_D10V_18_PCREL, |
/* Mitsubishi D30V relocs. |
This is a 6-bit absolute reloc. */ |
BFD_RELOC_D30V_6, |
/* This is a 6-bit pc-relative reloc with |
the right 3 bits assumed to be 0. */ |
BFD_RELOC_D30V_9_PCREL, |
/* This is a 6-bit pc-relative reloc with |
the right 3 bits assumed to be 0. Same |
as the previous reloc but on the right side |
of the container. */ |
BFD_RELOC_D30V_9_PCREL_R, |
/* This is a 12-bit absolute reloc with the |
right 3 bitsassumed to be 0. */ |
BFD_RELOC_D30V_15, |
/* This is a 12-bit pc-relative reloc with |
the right 3 bits assumed to be 0. */ |
BFD_RELOC_D30V_15_PCREL, |
/* This is a 12-bit pc-relative reloc with |
the right 3 bits assumed to be 0. Same |
as the previous reloc but on the right side |
of the container. */ |
BFD_RELOC_D30V_15_PCREL_R, |
/* This is an 18-bit absolute reloc with |
the right 3 bits assumed to be 0. */ |
BFD_RELOC_D30V_21, |
/* This is an 18-bit pc-relative reloc with |
the right 3 bits assumed to be 0. */ |
BFD_RELOC_D30V_21_PCREL, |
/* This is an 18-bit pc-relative reloc with |
the right 3 bits assumed to be 0. Same |
as the previous reloc but on the right side |
of the container. */ |
BFD_RELOC_D30V_21_PCREL_R, |
/* This is a 32-bit absolute reloc. */ |
BFD_RELOC_D30V_32, |
/* This is a 32-bit pc-relative reloc. */ |
BFD_RELOC_D30V_32_PCREL, |
/* DLX relocs */ |
BFD_RELOC_DLX_HI16_S, |
/* DLX relocs */ |
BFD_RELOC_DLX_LO16, |
/* DLX relocs */ |
BFD_RELOC_DLX_JMP26, |
/* Renesas M16C/M32C Relocations. */ |
BFD_RELOC_M32C_HI8, |
BFD_RELOC_M32C_RL_JUMP, |
BFD_RELOC_M32C_RL_1ADDR, |
BFD_RELOC_M32C_RL_2ADDR, |
/* Renesas M32R (formerly Mitsubishi M32R) relocs. |
This is a 24 bit absolute address. */ |
BFD_RELOC_M32R_24, |
/* This is a 10-bit pc-relative reloc with the right 2 bits assumed to be 0. */ |
BFD_RELOC_M32R_10_PCREL, |
/* This is an 18-bit reloc with the right 2 bits assumed to be 0. */ |
BFD_RELOC_M32R_18_PCREL, |
/* This is a 26-bit reloc with the right 2 bits assumed to be 0. */ |
BFD_RELOC_M32R_26_PCREL, |
/* This is a 16-bit reloc containing the high 16 bits of an address |
used when the lower 16 bits are treated as unsigned. */ |
BFD_RELOC_M32R_HI16_ULO, |
/* This is a 16-bit reloc containing the high 16 bits of an address |
used when the lower 16 bits are treated as signed. */ |
BFD_RELOC_M32R_HI16_SLO, |
/* This is a 16-bit reloc containing the lower 16 bits of an address. */ |
BFD_RELOC_M32R_LO16, |
/* This is a 16-bit reloc containing the small data area offset for use in |
add3, load, and store instructions. */ |
BFD_RELOC_M32R_SDA16, |
/* For PIC. */ |
BFD_RELOC_M32R_GOT24, |
BFD_RELOC_M32R_26_PLTREL, |
BFD_RELOC_M32R_COPY, |
BFD_RELOC_M32R_GLOB_DAT, |
BFD_RELOC_M32R_JMP_SLOT, |
BFD_RELOC_M32R_RELATIVE, |
BFD_RELOC_M32R_GOTOFF, |
BFD_RELOC_M32R_GOTOFF_HI_ULO, |
BFD_RELOC_M32R_GOTOFF_HI_SLO, |
BFD_RELOC_M32R_GOTOFF_LO, |
BFD_RELOC_M32R_GOTPC24, |
BFD_RELOC_M32R_GOT16_HI_ULO, |
BFD_RELOC_M32R_GOT16_HI_SLO, |
BFD_RELOC_M32R_GOT16_LO, |
BFD_RELOC_M32R_GOTPC_HI_ULO, |
BFD_RELOC_M32R_GOTPC_HI_SLO, |
BFD_RELOC_M32R_GOTPC_LO, |
/* This is a 9-bit reloc */ |
BFD_RELOC_V850_9_PCREL, |
/* This is a 22-bit reloc */ |
BFD_RELOC_V850_22_PCREL, |
/* This is a 16 bit offset from the short data area pointer. */ |
BFD_RELOC_V850_SDA_16_16_OFFSET, |
/* This is a 16 bit offset (of which only 15 bits are used) from the |
short data area pointer. */ |
BFD_RELOC_V850_SDA_15_16_OFFSET, |
/* This is a 16 bit offset from the zero data area pointer. */ |
BFD_RELOC_V850_ZDA_16_16_OFFSET, |
/* This is a 16 bit offset (of which only 15 bits are used) from the |
zero data area pointer. */ |
BFD_RELOC_V850_ZDA_15_16_OFFSET, |
/* This is an 8 bit offset (of which only 6 bits are used) from the |
tiny data area pointer. */ |
BFD_RELOC_V850_TDA_6_8_OFFSET, |
/* This is an 8bit offset (of which only 7 bits are used) from the tiny |
data area pointer. */ |
BFD_RELOC_V850_TDA_7_8_OFFSET, |
/* This is a 7 bit offset from the tiny data area pointer. */ |
BFD_RELOC_V850_TDA_7_7_OFFSET, |
/* This is a 16 bit offset from the tiny data area pointer. */ |
BFD_RELOC_V850_TDA_16_16_OFFSET, |
/* This is a 5 bit offset (of which only 4 bits are used) from the tiny |
data area pointer. */ |
BFD_RELOC_V850_TDA_4_5_OFFSET, |
/* This is a 4 bit offset from the tiny data area pointer. */ |
BFD_RELOC_V850_TDA_4_4_OFFSET, |
/* This is a 16 bit offset from the short data area pointer, with the |
bits placed non-contiguously in the instruction. */ |
BFD_RELOC_V850_SDA_16_16_SPLIT_OFFSET, |
/* This is a 16 bit offset from the zero data area pointer, with the |
bits placed non-contiguously in the instruction. */ |
BFD_RELOC_V850_ZDA_16_16_SPLIT_OFFSET, |
/* This is a 6 bit offset from the call table base pointer. */ |
BFD_RELOC_V850_CALLT_6_7_OFFSET, |
/* This is a 16 bit offset from the call table base pointer. */ |
BFD_RELOC_V850_CALLT_16_16_OFFSET, |
/* Used for relaxing indirect function calls. */ |
BFD_RELOC_V850_LONGCALL, |
/* Used for relaxing indirect jumps. */ |
BFD_RELOC_V850_LONGJUMP, |
/* Used to maintain alignment whilst relaxing. */ |
BFD_RELOC_V850_ALIGN, |
/* This is a variation of BFD_RELOC_LO16 that can be used in v850e ld.bu |
instructions. */ |
BFD_RELOC_V850_LO16_SPLIT_OFFSET, |
/* This is a 16-bit reloc. */ |
BFD_RELOC_V850_16_PCREL, |
/* This is a 17-bit reloc. */ |
BFD_RELOC_V850_17_PCREL, |
/* This is a 23-bit reloc. */ |
BFD_RELOC_V850_23, |
/* This is a 32-bit reloc. */ |
BFD_RELOC_V850_32_PCREL, |
/* This is a 32-bit reloc. */ |
BFD_RELOC_V850_32_ABS, |
/* This is a 16-bit reloc. */ |
BFD_RELOC_V850_16_SPLIT_OFFSET, |
/* This is a 16-bit reloc. */ |
BFD_RELOC_V850_16_S1, |
/* Low 16 bits. 16 bit shifted by 1. */ |
BFD_RELOC_V850_LO16_S1, |
/* This is a 16 bit offset from the call table base pointer. */ |
BFD_RELOC_V850_CALLT_15_16_OFFSET, |
/* DSO relocations. */ |
BFD_RELOC_V850_32_GOTPCREL, |
/* DSO relocations. */ |
BFD_RELOC_V850_16_GOT, |
/* DSO relocations. */ |
BFD_RELOC_V850_32_GOT, |
/* DSO relocations. */ |
BFD_RELOC_V850_22_PLT_PCREL, |
/* DSO relocations. */ |
BFD_RELOC_V850_32_PLT_PCREL, |
/* DSO relocations. */ |
BFD_RELOC_V850_COPY, |
/* DSO relocations. */ |
BFD_RELOC_V850_GLOB_DAT, |
/* DSO relocations. */ |
BFD_RELOC_V850_JMP_SLOT, |
/* DSO relocations. */ |
BFD_RELOC_V850_RELATIVE, |
/* DSO relocations. */ |
BFD_RELOC_V850_16_GOTOFF, |
/* DSO relocations. */ |
BFD_RELOC_V850_32_GOTOFF, |
/* start code. */ |
BFD_RELOC_V850_CODE, |
/* start data in text. */ |
BFD_RELOC_V850_DATA, |
/* This is a 8bit DP reloc for the tms320c30, where the most |
significant 8 bits of a 24 bit word are placed into the least |
significant 8 bits of the opcode. */ |
BFD_RELOC_TIC30_LDP, |
/* This is a 7bit reloc for the tms320c54x, where the least |
significant 7 bits of a 16 bit word are placed into the least |
significant 7 bits of the opcode. */ |
BFD_RELOC_TIC54X_PARTLS7, |
/* This is a 9bit DP reloc for the tms320c54x, where the most |
significant 9 bits of a 16 bit word are placed into the least |
significant 9 bits of the opcode. */ |
BFD_RELOC_TIC54X_PARTMS9, |
/* This is an extended address 23-bit reloc for the tms320c54x. */ |
BFD_RELOC_TIC54X_23, |
/* This is a 16-bit reloc for the tms320c54x, where the least |
significant 16 bits of a 23-bit extended address are placed into |
the opcode. */ |
BFD_RELOC_TIC54X_16_OF_23, |
/* This is a reloc for the tms320c54x, where the most |
significant 7 bits of a 23-bit extended address are placed into |
the opcode. */ |
BFD_RELOC_TIC54X_MS7_OF_23, |
/* TMS320C6000 relocations. */ |
BFD_RELOC_C6000_PCR_S21, |
BFD_RELOC_C6000_PCR_S12, |
BFD_RELOC_C6000_PCR_S10, |
BFD_RELOC_C6000_PCR_S7, |
BFD_RELOC_C6000_ABS_S16, |
BFD_RELOC_C6000_ABS_L16, |
BFD_RELOC_C6000_ABS_H16, |
BFD_RELOC_C6000_SBR_U15_B, |
BFD_RELOC_C6000_SBR_U15_H, |
BFD_RELOC_C6000_SBR_U15_W, |
BFD_RELOC_C6000_SBR_S16, |
BFD_RELOC_C6000_SBR_L16_B, |
BFD_RELOC_C6000_SBR_L16_H, |
BFD_RELOC_C6000_SBR_L16_W, |
BFD_RELOC_C6000_SBR_H16_B, |
BFD_RELOC_C6000_SBR_H16_H, |
BFD_RELOC_C6000_SBR_H16_W, |
BFD_RELOC_C6000_SBR_GOT_U15_W, |
BFD_RELOC_C6000_SBR_GOT_L16_W, |
BFD_RELOC_C6000_SBR_GOT_H16_W, |
BFD_RELOC_C6000_DSBT_INDEX, |
BFD_RELOC_C6000_PREL31, |
BFD_RELOC_C6000_COPY, |
BFD_RELOC_C6000_JUMP_SLOT, |
BFD_RELOC_C6000_EHTYPE, |
BFD_RELOC_C6000_PCR_H16, |
BFD_RELOC_C6000_PCR_L16, |
BFD_RELOC_C6000_ALIGN, |
BFD_RELOC_C6000_FPHEAD, |
BFD_RELOC_C6000_NOCMP, |
/* This is a 48 bit reloc for the FR30 that stores 32 bits. */ |
BFD_RELOC_FR30_48, |
/* This is a 32 bit reloc for the FR30 that stores 20 bits split up into |
two sections. */ |
BFD_RELOC_FR30_20, |
/* This is a 16 bit reloc for the FR30 that stores a 6 bit word offset in |
4 bits. */ |
BFD_RELOC_FR30_6_IN_4, |
/* This is a 16 bit reloc for the FR30 that stores an 8 bit byte offset |
into 8 bits. */ |
BFD_RELOC_FR30_8_IN_8, |
/* This is a 16 bit reloc for the FR30 that stores a 9 bit short offset |
into 8 bits. */ |
BFD_RELOC_FR30_9_IN_8, |
/* This is a 16 bit reloc for the FR30 that stores a 10 bit word offset |
into 8 bits. */ |
BFD_RELOC_FR30_10_IN_8, |
/* This is a 16 bit reloc for the FR30 that stores a 9 bit pc relative |
short offset into 8 bits. */ |
BFD_RELOC_FR30_9_PCREL, |
/* This is a 16 bit reloc for the FR30 that stores a 12 bit pc relative |
short offset into 11 bits. */ |
BFD_RELOC_FR30_12_PCREL, |
/* Motorola Mcore relocations. */ |
BFD_RELOC_MCORE_PCREL_IMM8BY4, |
BFD_RELOC_MCORE_PCREL_IMM11BY2, |
BFD_RELOC_MCORE_PCREL_IMM4BY2, |
BFD_RELOC_MCORE_PCREL_32, |
BFD_RELOC_MCORE_PCREL_JSR_IMM11BY2, |
BFD_RELOC_MCORE_RVA, |
/* Toshiba Media Processor Relocations. */ |
BFD_RELOC_MEP_8, |
BFD_RELOC_MEP_16, |
BFD_RELOC_MEP_32, |
BFD_RELOC_MEP_PCREL8A2, |
BFD_RELOC_MEP_PCREL12A2, |
BFD_RELOC_MEP_PCREL17A2, |
BFD_RELOC_MEP_PCREL24A2, |
BFD_RELOC_MEP_PCABS24A2, |
BFD_RELOC_MEP_LOW16, |
BFD_RELOC_MEP_HI16U, |
BFD_RELOC_MEP_HI16S, |
BFD_RELOC_MEP_GPREL, |
BFD_RELOC_MEP_TPREL, |
BFD_RELOC_MEP_TPREL7, |
BFD_RELOC_MEP_TPREL7A2, |
BFD_RELOC_MEP_TPREL7A4, |
BFD_RELOC_MEP_UIMM24, |
BFD_RELOC_MEP_ADDR24A4, |
BFD_RELOC_MEP_GNU_VTINHERIT, |
BFD_RELOC_MEP_GNU_VTENTRY, |
/* Imagination Technologies Meta relocations. */ |
BFD_RELOC_METAG_HIADDR16, |
BFD_RELOC_METAG_LOADDR16, |
BFD_RELOC_METAG_RELBRANCH, |
BFD_RELOC_METAG_GETSETOFF, |
BFD_RELOC_METAG_HIOG, |
BFD_RELOC_METAG_LOOG, |
BFD_RELOC_METAG_REL8, |
BFD_RELOC_METAG_REL16, |
BFD_RELOC_METAG_HI16_GOTOFF, |
BFD_RELOC_METAG_LO16_GOTOFF, |
BFD_RELOC_METAG_GETSET_GOTOFF, |
BFD_RELOC_METAG_GETSET_GOT, |
BFD_RELOC_METAG_HI16_GOTPC, |
BFD_RELOC_METAG_LO16_GOTPC, |
BFD_RELOC_METAG_HI16_PLT, |
BFD_RELOC_METAG_LO16_PLT, |
BFD_RELOC_METAG_RELBRANCH_PLT, |
BFD_RELOC_METAG_GOTOFF, |
BFD_RELOC_METAG_PLT, |
BFD_RELOC_METAG_COPY, |
BFD_RELOC_METAG_JMP_SLOT, |
BFD_RELOC_METAG_RELATIVE, |
BFD_RELOC_METAG_GLOB_DAT, |
BFD_RELOC_METAG_TLS_GD, |
BFD_RELOC_METAG_TLS_LDM, |
BFD_RELOC_METAG_TLS_LDO_HI16, |
BFD_RELOC_METAG_TLS_LDO_LO16, |
BFD_RELOC_METAG_TLS_LDO, |
BFD_RELOC_METAG_TLS_IE, |
BFD_RELOC_METAG_TLS_IENONPIC, |
BFD_RELOC_METAG_TLS_IENONPIC_HI16, |
BFD_RELOC_METAG_TLS_IENONPIC_LO16, |
BFD_RELOC_METAG_TLS_TPOFF, |
BFD_RELOC_METAG_TLS_DTPMOD, |
BFD_RELOC_METAG_TLS_DTPOFF, |
BFD_RELOC_METAG_TLS_LE, |
BFD_RELOC_METAG_TLS_LE_HI16, |
BFD_RELOC_METAG_TLS_LE_LO16, |
/* These are relocations for the GETA instruction. */ |
BFD_RELOC_MMIX_GETA, |
BFD_RELOC_MMIX_GETA_1, |
BFD_RELOC_MMIX_GETA_2, |
BFD_RELOC_MMIX_GETA_3, |
/* These are relocations for a conditional branch instruction. */ |
BFD_RELOC_MMIX_CBRANCH, |
BFD_RELOC_MMIX_CBRANCH_J, |
BFD_RELOC_MMIX_CBRANCH_1, |
BFD_RELOC_MMIX_CBRANCH_2, |
BFD_RELOC_MMIX_CBRANCH_3, |
/* These are relocations for the PUSHJ instruction. */ |
BFD_RELOC_MMIX_PUSHJ, |
BFD_RELOC_MMIX_PUSHJ_1, |
BFD_RELOC_MMIX_PUSHJ_2, |
BFD_RELOC_MMIX_PUSHJ_3, |
BFD_RELOC_MMIX_PUSHJ_STUBBABLE, |
/* These are relocations for the JMP instruction. */ |
BFD_RELOC_MMIX_JMP, |
BFD_RELOC_MMIX_JMP_1, |
BFD_RELOC_MMIX_JMP_2, |
BFD_RELOC_MMIX_JMP_3, |
/* This is a relocation for a relative address as in a GETA instruction or |
a branch. */ |
BFD_RELOC_MMIX_ADDR19, |
/* This is a relocation for a relative address as in a JMP instruction. */ |
BFD_RELOC_MMIX_ADDR27, |
/* This is a relocation for an instruction field that may be a general |
register or a value 0..255. */ |
BFD_RELOC_MMIX_REG_OR_BYTE, |
/* This is a relocation for an instruction field that may be a general |
register. */ |
BFD_RELOC_MMIX_REG, |
/* This is a relocation for two instruction fields holding a register and |
an offset, the equivalent of the relocation. */ |
BFD_RELOC_MMIX_BASE_PLUS_OFFSET, |
/* This relocation is an assertion that the expression is not allocated as |
a global register. It does not modify contents. */ |
BFD_RELOC_MMIX_LOCAL, |
/* This is a 16 bit reloc for the AVR that stores 8 bit pc relative |
short offset into 7 bits. */ |
BFD_RELOC_AVR_7_PCREL, |
/* This is a 16 bit reloc for the AVR that stores 13 bit pc relative |
short offset into 12 bits. */ |
BFD_RELOC_AVR_13_PCREL, |
/* This is a 16 bit reloc for the AVR that stores 17 bit value (usually |
program memory address) into 16 bits. */ |
BFD_RELOC_AVR_16_PM, |
/* This is a 16 bit reloc for the AVR that stores 8 bit value (usually |
data memory address) into 8 bit immediate value of LDI insn. */ |
BFD_RELOC_AVR_LO8_LDI, |
/* This is a 16 bit reloc for the AVR that stores 8 bit value (high 8 bit |
of data memory address) into 8 bit immediate value of LDI insn. */ |
BFD_RELOC_AVR_HI8_LDI, |
/* This is a 16 bit reloc for the AVR that stores 8 bit value (most high 8 bit |
of program memory address) into 8 bit immediate value of LDI insn. */ |
BFD_RELOC_AVR_HH8_LDI, |
/* This is a 16 bit reloc for the AVR that stores 8 bit value (most high 8 bit |
of 32 bit value) into 8 bit immediate value of LDI insn. */ |
BFD_RELOC_AVR_MS8_LDI, |
/* This is a 16 bit reloc for the AVR that stores negated 8 bit value |
(usually data memory address) into 8 bit immediate value of SUBI insn. */ |
BFD_RELOC_AVR_LO8_LDI_NEG, |
/* This is a 16 bit reloc for the AVR that stores negated 8 bit value |
(high 8 bit of data memory address) into 8 bit immediate value of |
SUBI insn. */ |
BFD_RELOC_AVR_HI8_LDI_NEG, |
/* This is a 16 bit reloc for the AVR that stores negated 8 bit value |
(most high 8 bit of program memory address) into 8 bit immediate value |
of LDI or SUBI insn. */ |
BFD_RELOC_AVR_HH8_LDI_NEG, |
/* This is a 16 bit reloc for the AVR that stores negated 8 bit value (msb |
of 32 bit value) into 8 bit immediate value of LDI insn. */ |
BFD_RELOC_AVR_MS8_LDI_NEG, |
/* This is a 16 bit reloc for the AVR that stores 8 bit value (usually |
command address) into 8 bit immediate value of LDI insn. */ |
BFD_RELOC_AVR_LO8_LDI_PM, |
/* This is a 16 bit reloc for the AVR that stores 8 bit value |
(command address) into 8 bit immediate value of LDI insn. If the address |
is beyond the 128k boundary, the linker inserts a jump stub for this reloc |
in the lower 128k. */ |
BFD_RELOC_AVR_LO8_LDI_GS, |
/* This is a 16 bit reloc for the AVR that stores 8 bit value (high 8 bit |
of command address) into 8 bit immediate value of LDI insn. */ |
BFD_RELOC_AVR_HI8_LDI_PM, |
/* This is a 16 bit reloc for the AVR that stores 8 bit value (high 8 bit |
of command address) into 8 bit immediate value of LDI insn. If the address |
is beyond the 128k boundary, the linker inserts a jump stub for this reloc |
below 128k. */ |
BFD_RELOC_AVR_HI8_LDI_GS, |
/* This is a 16 bit reloc for the AVR that stores 8 bit value (most high 8 bit |
of command address) into 8 bit immediate value of LDI insn. */ |
BFD_RELOC_AVR_HH8_LDI_PM, |
/* This is a 16 bit reloc for the AVR that stores negated 8 bit value |
(usually command address) into 8 bit immediate value of SUBI insn. */ |
BFD_RELOC_AVR_LO8_LDI_PM_NEG, |
/* This is a 16 bit reloc for the AVR that stores negated 8 bit value |
(high 8 bit of 16 bit command address) into 8 bit immediate value |
of SUBI insn. */ |
BFD_RELOC_AVR_HI8_LDI_PM_NEG, |
/* This is a 16 bit reloc for the AVR that stores negated 8 bit value |
(high 6 bit of 22 bit command address) into 8 bit immediate |
value of SUBI insn. */ |
BFD_RELOC_AVR_HH8_LDI_PM_NEG, |
/* This is a 32 bit reloc for the AVR that stores 23 bit value |
into 22 bits. */ |
BFD_RELOC_AVR_CALL, |
/* This is a 16 bit reloc for the AVR that stores all needed bits |
for absolute addressing with ldi with overflow check to linktime */ |
BFD_RELOC_AVR_LDI, |
/* This is a 6 bit reloc for the AVR that stores offset for ldd/std |
instructions */ |
BFD_RELOC_AVR_6, |
/* This is a 6 bit reloc for the AVR that stores offset for adiw/sbiw |
instructions */ |
BFD_RELOC_AVR_6_ADIW, |
/* This is a 8 bit reloc for the AVR that stores bits 0..7 of a symbol |
in .byte lo8(symbol) */ |
BFD_RELOC_AVR_8_LO, |
/* This is a 8 bit reloc for the AVR that stores bits 8..15 of a symbol |
in .byte hi8(symbol) */ |
BFD_RELOC_AVR_8_HI, |
/* This is a 8 bit reloc for the AVR that stores bits 16..23 of a symbol |
in .byte hlo8(symbol) */ |
BFD_RELOC_AVR_8_HLO, |
/* Renesas RL78 Relocations. */ |
BFD_RELOC_RL78_NEG8, |
BFD_RELOC_RL78_NEG16, |
BFD_RELOC_RL78_NEG24, |
BFD_RELOC_RL78_NEG32, |
BFD_RELOC_RL78_16_OP, |
BFD_RELOC_RL78_24_OP, |
BFD_RELOC_RL78_32_OP, |
BFD_RELOC_RL78_8U, |
BFD_RELOC_RL78_16U, |
BFD_RELOC_RL78_24U, |
BFD_RELOC_RL78_DIR3U_PCREL, |
BFD_RELOC_RL78_DIFF, |
BFD_RELOC_RL78_GPRELB, |
BFD_RELOC_RL78_GPRELW, |
BFD_RELOC_RL78_GPRELL, |
BFD_RELOC_RL78_SYM, |
BFD_RELOC_RL78_OP_SUBTRACT, |
BFD_RELOC_RL78_OP_NEG, |
BFD_RELOC_RL78_OP_AND, |
BFD_RELOC_RL78_OP_SHRA, |
BFD_RELOC_RL78_ABS8, |
BFD_RELOC_RL78_ABS16, |
BFD_RELOC_RL78_ABS16_REV, |
BFD_RELOC_RL78_ABS32, |
BFD_RELOC_RL78_ABS32_REV, |
BFD_RELOC_RL78_ABS16U, |
BFD_RELOC_RL78_ABS16UW, |
BFD_RELOC_RL78_ABS16UL, |
BFD_RELOC_RL78_RELAX, |
BFD_RELOC_RL78_HI16, |
BFD_RELOC_RL78_HI8, |
BFD_RELOC_RL78_LO16, |
BFD_RELOC_RL78_CODE, |
/* Renesas RX Relocations. */ |
BFD_RELOC_RX_NEG8, |
BFD_RELOC_RX_NEG16, |
BFD_RELOC_RX_NEG24, |
BFD_RELOC_RX_NEG32, |
BFD_RELOC_RX_16_OP, |
BFD_RELOC_RX_24_OP, |
BFD_RELOC_RX_32_OP, |
BFD_RELOC_RX_8U, |
BFD_RELOC_RX_16U, |
BFD_RELOC_RX_24U, |
BFD_RELOC_RX_DIR3U_PCREL, |
BFD_RELOC_RX_DIFF, |
BFD_RELOC_RX_GPRELB, |
BFD_RELOC_RX_GPRELW, |
BFD_RELOC_RX_GPRELL, |
BFD_RELOC_RX_SYM, |
BFD_RELOC_RX_OP_SUBTRACT, |
BFD_RELOC_RX_OP_NEG, |
BFD_RELOC_RX_ABS8, |
BFD_RELOC_RX_ABS16, |
BFD_RELOC_RX_ABS16_REV, |
BFD_RELOC_RX_ABS32, |
BFD_RELOC_RX_ABS32_REV, |
BFD_RELOC_RX_ABS16U, |
BFD_RELOC_RX_ABS16UW, |
BFD_RELOC_RX_ABS16UL, |
BFD_RELOC_RX_RELAX, |
/* Direct 12 bit. */ |
BFD_RELOC_390_12, |
/* 12 bit GOT offset. */ |
BFD_RELOC_390_GOT12, |
/* 32 bit PC relative PLT address. */ |
BFD_RELOC_390_PLT32, |
/* Copy symbol at runtime. */ |
BFD_RELOC_390_COPY, |
/* Create GOT entry. */ |
BFD_RELOC_390_GLOB_DAT, |
/* Create PLT entry. */ |
BFD_RELOC_390_JMP_SLOT, |
/* Adjust by program base. */ |
BFD_RELOC_390_RELATIVE, |
/* 32 bit PC relative offset to GOT. */ |
BFD_RELOC_390_GOTPC, |
/* 16 bit GOT offset. */ |
BFD_RELOC_390_GOT16, |
/* PC relative 12 bit shifted by 1. */ |
BFD_RELOC_390_PC12DBL, |
/* 12 bit PC rel. PLT shifted by 1. */ |
BFD_RELOC_390_PLT12DBL, |
/* PC relative 16 bit shifted by 1. */ |
BFD_RELOC_390_PC16DBL, |
/* 16 bit PC rel. PLT shifted by 1. */ |
BFD_RELOC_390_PLT16DBL, |
/* PC relative 24 bit shifted by 1. */ |
BFD_RELOC_390_PC24DBL, |
/* 24 bit PC rel. PLT shifted by 1. */ |
BFD_RELOC_390_PLT24DBL, |
/* PC relative 32 bit shifted by 1. */ |
BFD_RELOC_390_PC32DBL, |
/* 32 bit PC rel. PLT shifted by 1. */ |
BFD_RELOC_390_PLT32DBL, |
/* 32 bit PC rel. GOT shifted by 1. */ |
BFD_RELOC_390_GOTPCDBL, |
/* 64 bit GOT offset. */ |
BFD_RELOC_390_GOT64, |
/* 64 bit PC relative PLT address. */ |
BFD_RELOC_390_PLT64, |
/* 32 bit rel. offset to GOT entry. */ |
BFD_RELOC_390_GOTENT, |
/* 64 bit offset to GOT. */ |
BFD_RELOC_390_GOTOFF64, |
/* 12-bit offset to symbol-entry within GOT, with PLT handling. */ |
BFD_RELOC_390_GOTPLT12, |
/* 16-bit offset to symbol-entry within GOT, with PLT handling. */ |
BFD_RELOC_390_GOTPLT16, |
/* 32-bit offset to symbol-entry within GOT, with PLT handling. */ |
BFD_RELOC_390_GOTPLT32, |
/* 64-bit offset to symbol-entry within GOT, with PLT handling. */ |
BFD_RELOC_390_GOTPLT64, |
/* 32-bit rel. offset to symbol-entry within GOT, with PLT handling. */ |
BFD_RELOC_390_GOTPLTENT, |
/* 16-bit rel. offset from the GOT to a PLT entry. */ |
BFD_RELOC_390_PLTOFF16, |
/* 32-bit rel. offset from the GOT to a PLT entry. */ |
BFD_RELOC_390_PLTOFF32, |
/* 64-bit rel. offset from the GOT to a PLT entry. */ |
BFD_RELOC_390_PLTOFF64, |
/* s390 tls relocations. */ |
BFD_RELOC_390_TLS_LOAD, |
BFD_RELOC_390_TLS_GDCALL, |
BFD_RELOC_390_TLS_LDCALL, |
BFD_RELOC_390_TLS_GD32, |
BFD_RELOC_390_TLS_GD64, |
BFD_RELOC_390_TLS_GOTIE12, |
BFD_RELOC_390_TLS_GOTIE32, |
BFD_RELOC_390_TLS_GOTIE64, |
BFD_RELOC_390_TLS_LDM32, |
BFD_RELOC_390_TLS_LDM64, |
BFD_RELOC_390_TLS_IE32, |
BFD_RELOC_390_TLS_IE64, |
BFD_RELOC_390_TLS_IEENT, |
BFD_RELOC_390_TLS_LE32, |
BFD_RELOC_390_TLS_LE64, |
BFD_RELOC_390_TLS_LDO32, |
BFD_RELOC_390_TLS_LDO64, |
BFD_RELOC_390_TLS_DTPMOD, |
BFD_RELOC_390_TLS_DTPOFF, |
BFD_RELOC_390_TLS_TPOFF, |
/* Long displacement extension. */ |
BFD_RELOC_390_20, |
BFD_RELOC_390_GOT20, |
BFD_RELOC_390_GOTPLT20, |
BFD_RELOC_390_TLS_GOTIE20, |
/* STT_GNU_IFUNC relocation. */ |
BFD_RELOC_390_IRELATIVE, |
/* Score relocations |
Low 16 bit for load/store */ |
BFD_RELOC_SCORE_GPREL15, |
/* This is a 24-bit reloc with the right 1 bit assumed to be 0 */ |
BFD_RELOC_SCORE_DUMMY2, |
BFD_RELOC_SCORE_JMP, |
/* This is a 19-bit reloc with the right 1 bit assumed to be 0 */ |
BFD_RELOC_SCORE_BRANCH, |
/* This is a 32-bit reloc for 48-bit instructions. */ |
BFD_RELOC_SCORE_IMM30, |
/* This is a 32-bit reloc for 48-bit instructions. */ |
BFD_RELOC_SCORE_IMM32, |
/* This is a 11-bit reloc with the right 1 bit assumed to be 0 */ |
BFD_RELOC_SCORE16_JMP, |
/* This is a 8-bit reloc with the right 1 bit assumed to be 0 */ |
BFD_RELOC_SCORE16_BRANCH, |
/* This is a 9-bit reloc with the right 1 bit assumed to be 0 */ |
BFD_RELOC_SCORE_BCMP, |
/* Undocumented Score relocs */ |
BFD_RELOC_SCORE_GOT15, |
BFD_RELOC_SCORE_GOT_LO16, |
BFD_RELOC_SCORE_CALL15, |
BFD_RELOC_SCORE_DUMMY_HI16, |
/* Scenix IP2K - 9-bit register number / data address */ |
BFD_RELOC_IP2K_FR9, |
/* Scenix IP2K - 4-bit register/data bank number */ |
BFD_RELOC_IP2K_BANK, |
/* Scenix IP2K - low 13 bits of instruction word address */ |
BFD_RELOC_IP2K_ADDR16CJP, |
/* Scenix IP2K - high 3 bits of instruction word address */ |
BFD_RELOC_IP2K_PAGE3, |
/* Scenix IP2K - ext/low/high 8 bits of data address */ |
BFD_RELOC_IP2K_LO8DATA, |
BFD_RELOC_IP2K_HI8DATA, |
BFD_RELOC_IP2K_EX8DATA, |
/* Scenix IP2K - low/high 8 bits of instruction word address */ |
BFD_RELOC_IP2K_LO8INSN, |
BFD_RELOC_IP2K_HI8INSN, |
/* Scenix IP2K - even/odd PC modifier to modify snb pcl.0 */ |
BFD_RELOC_IP2K_PC_SKIP, |
/* Scenix IP2K - 16 bit word address in text section. */ |
BFD_RELOC_IP2K_TEXT, |
/* Scenix IP2K - 7-bit sp or dp offset */ |
BFD_RELOC_IP2K_FR_OFFSET, |
/* Scenix VPE4K coprocessor - data/insn-space addressing */ |
BFD_RELOC_VPE4KMATH_DATA, |
BFD_RELOC_VPE4KMATH_INSN, |
/* These two relocations are used by the linker to determine which of |
the entries in a C++ virtual function table are actually used. When |
the --gc-sections option is given, the linker will zero out the entries |
that are not used, so that the code for those functions need not be |
included in the output. |
VTABLE_INHERIT is a zero-space relocation used to describe to the |
linker the inheritance tree of a C++ virtual function table. The |
relocation's symbol should be the parent class' vtable, and the |
relocation should be located at the child vtable. |
VTABLE_ENTRY is a zero-space relocation that describes the use of a |
virtual function table entry. The reloc's symbol should refer to the |
table of the class mentioned in the code. Off of that base, an offset |
describes the entry that is being used. For Rela hosts, this offset |
is stored in the reloc's addend. For Rel hosts, we are forced to put |
this offset in the reloc's section offset. */ |
BFD_RELOC_VTABLE_INHERIT, |
BFD_RELOC_VTABLE_ENTRY, |
/* Intel IA64 Relocations. */ |
BFD_RELOC_IA64_IMM14, |
BFD_RELOC_IA64_IMM22, |
BFD_RELOC_IA64_IMM64, |
BFD_RELOC_IA64_DIR32MSB, |
BFD_RELOC_IA64_DIR32LSB, |
BFD_RELOC_IA64_DIR64MSB, |
BFD_RELOC_IA64_DIR64LSB, |
BFD_RELOC_IA64_GPREL22, |
BFD_RELOC_IA64_GPREL64I, |
BFD_RELOC_IA64_GPREL32MSB, |
BFD_RELOC_IA64_GPREL32LSB, |
BFD_RELOC_IA64_GPREL64MSB, |
BFD_RELOC_IA64_GPREL64LSB, |
BFD_RELOC_IA64_LTOFF22, |
BFD_RELOC_IA64_LTOFF64I, |
BFD_RELOC_IA64_PLTOFF22, |
BFD_RELOC_IA64_PLTOFF64I, |
BFD_RELOC_IA64_PLTOFF64MSB, |
BFD_RELOC_IA64_PLTOFF64LSB, |
BFD_RELOC_IA64_FPTR64I, |
BFD_RELOC_IA64_FPTR32MSB, |
BFD_RELOC_IA64_FPTR32LSB, |
BFD_RELOC_IA64_FPTR64MSB, |
BFD_RELOC_IA64_FPTR64LSB, |
BFD_RELOC_IA64_PCREL21B, |
BFD_RELOC_IA64_PCREL21BI, |
BFD_RELOC_IA64_PCREL21M, |
BFD_RELOC_IA64_PCREL21F, |
BFD_RELOC_IA64_PCREL22, |
BFD_RELOC_IA64_PCREL60B, |
BFD_RELOC_IA64_PCREL64I, |
BFD_RELOC_IA64_PCREL32MSB, |
BFD_RELOC_IA64_PCREL32LSB, |
BFD_RELOC_IA64_PCREL64MSB, |
BFD_RELOC_IA64_PCREL64LSB, |
BFD_RELOC_IA64_LTOFF_FPTR22, |
BFD_RELOC_IA64_LTOFF_FPTR64I, |
BFD_RELOC_IA64_LTOFF_FPTR32MSB, |
BFD_RELOC_IA64_LTOFF_FPTR32LSB, |
BFD_RELOC_IA64_LTOFF_FPTR64MSB, |
BFD_RELOC_IA64_LTOFF_FPTR64LSB, |
BFD_RELOC_IA64_SEGREL32MSB, |
BFD_RELOC_IA64_SEGREL32LSB, |
BFD_RELOC_IA64_SEGREL64MSB, |
BFD_RELOC_IA64_SEGREL64LSB, |
BFD_RELOC_IA64_SECREL32MSB, |
BFD_RELOC_IA64_SECREL32LSB, |
BFD_RELOC_IA64_SECREL64MSB, |
BFD_RELOC_IA64_SECREL64LSB, |
BFD_RELOC_IA64_REL32MSB, |
BFD_RELOC_IA64_REL32LSB, |
BFD_RELOC_IA64_REL64MSB, |
BFD_RELOC_IA64_REL64LSB, |
BFD_RELOC_IA64_LTV32MSB, |
BFD_RELOC_IA64_LTV32LSB, |
BFD_RELOC_IA64_LTV64MSB, |
BFD_RELOC_IA64_LTV64LSB, |
BFD_RELOC_IA64_IPLTMSB, |
BFD_RELOC_IA64_IPLTLSB, |
BFD_RELOC_IA64_COPY, |
BFD_RELOC_IA64_LTOFF22X, |
BFD_RELOC_IA64_LDXMOV, |
BFD_RELOC_IA64_TPREL14, |
BFD_RELOC_IA64_TPREL22, |
BFD_RELOC_IA64_TPREL64I, |
BFD_RELOC_IA64_TPREL64MSB, |
BFD_RELOC_IA64_TPREL64LSB, |
BFD_RELOC_IA64_LTOFF_TPREL22, |
BFD_RELOC_IA64_DTPMOD64MSB, |
BFD_RELOC_IA64_DTPMOD64LSB, |
BFD_RELOC_IA64_LTOFF_DTPMOD22, |
BFD_RELOC_IA64_DTPREL14, |
BFD_RELOC_IA64_DTPREL22, |
BFD_RELOC_IA64_DTPREL64I, |
BFD_RELOC_IA64_DTPREL32MSB, |
BFD_RELOC_IA64_DTPREL32LSB, |
BFD_RELOC_IA64_DTPREL64MSB, |
BFD_RELOC_IA64_DTPREL64LSB, |
BFD_RELOC_IA64_LTOFF_DTPREL22, |
/* Motorola 68HC11 reloc. |
This is the 8 bit high part of an absolute address. */ |
BFD_RELOC_M68HC11_HI8, |
/* Motorola 68HC11 reloc. |
This is the 8 bit low part of an absolute address. */ |
BFD_RELOC_M68HC11_LO8, |
/* Motorola 68HC11 reloc. |
This is the 3 bit of a value. */ |
BFD_RELOC_M68HC11_3B, |
/* Motorola 68HC11 reloc. |
This reloc marks the beginning of a jump/call instruction. |
It is used for linker relaxation to correctly identify beginning |
of instruction and change some branches to use PC-relative |
addressing mode. */ |
BFD_RELOC_M68HC11_RL_JUMP, |
/* Motorola 68HC11 reloc. |
This reloc marks a group of several instructions that gcc generates |
and for which the linker relaxation pass can modify and/or remove |
some of them. */ |
BFD_RELOC_M68HC11_RL_GROUP, |
/* Motorola 68HC11 reloc. |
This is the 16-bit lower part of an address. It is used for 'call' |
instruction to specify the symbol address without any special |
transformation (due to memory bank window). */ |
BFD_RELOC_M68HC11_LO16, |
/* Motorola 68HC11 reloc. |
This is a 8-bit reloc that specifies the page number of an address. |
It is used by 'call' instruction to specify the page number of |
the symbol. */ |
BFD_RELOC_M68HC11_PAGE, |
/* Motorola 68HC11 reloc. |
This is a 24-bit reloc that represents the address with a 16-bit |
value and a 8-bit page number. The symbol address is transformed |
to follow the 16K memory bank of 68HC12 (seen as mapped in the window). */ |
BFD_RELOC_M68HC11_24, |
/* Motorola 68HC12 reloc. |
This is the 5 bits of a value. */ |
BFD_RELOC_M68HC12_5B, |
/* Freescale XGATE reloc. |
This reloc marks the beginning of a bra/jal instruction. */ |
BFD_RELOC_XGATE_RL_JUMP, |
/* Freescale XGATE reloc. |
This reloc marks a group of several instructions that gcc generates |
and for which the linker relaxation pass can modify and/or remove |
some of them. */ |
BFD_RELOC_XGATE_RL_GROUP, |
/* Freescale XGATE reloc. |
This is the 16-bit lower part of an address. It is used for the '16-bit' |
instructions. */ |
BFD_RELOC_XGATE_LO16, |
/* Freescale XGATE reloc. */ |
BFD_RELOC_XGATE_GPAGE, |
/* Freescale XGATE reloc. */ |
BFD_RELOC_XGATE_24, |
/* Freescale XGATE reloc. |
This is a 9-bit pc-relative reloc. */ |
BFD_RELOC_XGATE_PCREL_9, |
/* Freescale XGATE reloc. |
This is a 10-bit pc-relative reloc. */ |
BFD_RELOC_XGATE_PCREL_10, |
/* Freescale XGATE reloc. |
This is the 16-bit lower part of an address. It is used for the '16-bit' |
instructions. */ |
BFD_RELOC_XGATE_IMM8_LO, |
/* Freescale XGATE reloc. |
This is the 16-bit higher part of an address. It is used for the '16-bit' |
instructions. */ |
BFD_RELOC_XGATE_IMM8_HI, |
/* Freescale XGATE reloc. |
This is a 3-bit pc-relative reloc. */ |
BFD_RELOC_XGATE_IMM3, |
/* Freescale XGATE reloc. |
This is a 4-bit pc-relative reloc. */ |
BFD_RELOC_XGATE_IMM4, |
/* Freescale XGATE reloc. |
This is a 5-bit pc-relative reloc. */ |
BFD_RELOC_XGATE_IMM5, |
/* Motorola 68HC12 reloc. |
This is the 9 bits of a value. */ |
BFD_RELOC_M68HC12_9B, |
/* Motorola 68HC12 reloc. |
This is the 16 bits of a value. */ |
BFD_RELOC_M68HC12_16B, |
/* Motorola 68HC12/XGATE reloc. |
This is a PCREL9 branch. */ |
BFD_RELOC_M68HC12_9_PCREL, |
/* Motorola 68HC12/XGATE reloc. |
This is a PCREL10 branch. */ |
BFD_RELOC_M68HC12_10_PCREL, |
/* Motorola 68HC12/XGATE reloc. |
This is the 8 bit low part of an absolute address and immediately precedes |
a matching HI8XG part. */ |
BFD_RELOC_M68HC12_LO8XG, |
/* Motorola 68HC12/XGATE reloc. |
This is the 8 bit high part of an absolute address and immediately follows |
a matching LO8XG part. */ |
BFD_RELOC_M68HC12_HI8XG, |
/* NS CR16C Relocations. */ |
BFD_RELOC_16C_NUM08, |
BFD_RELOC_16C_NUM08_C, |
BFD_RELOC_16C_NUM16, |
BFD_RELOC_16C_NUM16_C, |
BFD_RELOC_16C_NUM32, |
BFD_RELOC_16C_NUM32_C, |
BFD_RELOC_16C_DISP04, |
BFD_RELOC_16C_DISP04_C, |
BFD_RELOC_16C_DISP08, |
BFD_RELOC_16C_DISP08_C, |
BFD_RELOC_16C_DISP16, |
BFD_RELOC_16C_DISP16_C, |
BFD_RELOC_16C_DISP24, |
BFD_RELOC_16C_DISP24_C, |
BFD_RELOC_16C_DISP24a, |
BFD_RELOC_16C_DISP24a_C, |
BFD_RELOC_16C_REG04, |
BFD_RELOC_16C_REG04_C, |
BFD_RELOC_16C_REG04a, |
BFD_RELOC_16C_REG04a_C, |
BFD_RELOC_16C_REG14, |
BFD_RELOC_16C_REG14_C, |
BFD_RELOC_16C_REG16, |
BFD_RELOC_16C_REG16_C, |
BFD_RELOC_16C_REG20, |
BFD_RELOC_16C_REG20_C, |
BFD_RELOC_16C_ABS20, |
BFD_RELOC_16C_ABS20_C, |
BFD_RELOC_16C_ABS24, |
BFD_RELOC_16C_ABS24_C, |
BFD_RELOC_16C_IMM04, |
BFD_RELOC_16C_IMM04_C, |
BFD_RELOC_16C_IMM16, |
BFD_RELOC_16C_IMM16_C, |
BFD_RELOC_16C_IMM20, |
BFD_RELOC_16C_IMM20_C, |
BFD_RELOC_16C_IMM24, |
BFD_RELOC_16C_IMM24_C, |
BFD_RELOC_16C_IMM32, |
BFD_RELOC_16C_IMM32_C, |
/* NS CR16 Relocations. */ |
BFD_RELOC_CR16_NUM8, |
BFD_RELOC_CR16_NUM16, |
BFD_RELOC_CR16_NUM32, |
BFD_RELOC_CR16_NUM32a, |
BFD_RELOC_CR16_REGREL0, |
BFD_RELOC_CR16_REGREL4, |
BFD_RELOC_CR16_REGREL4a, |
BFD_RELOC_CR16_REGREL14, |
BFD_RELOC_CR16_REGREL14a, |
BFD_RELOC_CR16_REGREL16, |
BFD_RELOC_CR16_REGREL20, |
BFD_RELOC_CR16_REGREL20a, |
BFD_RELOC_CR16_ABS20, |
BFD_RELOC_CR16_ABS24, |
BFD_RELOC_CR16_IMM4, |
BFD_RELOC_CR16_IMM8, |
BFD_RELOC_CR16_IMM16, |
BFD_RELOC_CR16_IMM20, |
BFD_RELOC_CR16_IMM24, |
BFD_RELOC_CR16_IMM32, |
BFD_RELOC_CR16_IMM32a, |
BFD_RELOC_CR16_DISP4, |
BFD_RELOC_CR16_DISP8, |
BFD_RELOC_CR16_DISP16, |
BFD_RELOC_CR16_DISP20, |
BFD_RELOC_CR16_DISP24, |
BFD_RELOC_CR16_DISP24a, |
BFD_RELOC_CR16_SWITCH8, |
BFD_RELOC_CR16_SWITCH16, |
BFD_RELOC_CR16_SWITCH32, |
BFD_RELOC_CR16_GOT_REGREL20, |
BFD_RELOC_CR16_GOTC_REGREL20, |
BFD_RELOC_CR16_GLOB_DAT, |
/* NS CRX Relocations. */ |
BFD_RELOC_CRX_REL4, |
BFD_RELOC_CRX_REL8, |
BFD_RELOC_CRX_REL8_CMP, |
BFD_RELOC_CRX_REL16, |
BFD_RELOC_CRX_REL24, |
BFD_RELOC_CRX_REL32, |
BFD_RELOC_CRX_REGREL12, |
BFD_RELOC_CRX_REGREL22, |
BFD_RELOC_CRX_REGREL28, |
BFD_RELOC_CRX_REGREL32, |
BFD_RELOC_CRX_ABS16, |
BFD_RELOC_CRX_ABS32, |
BFD_RELOC_CRX_NUM8, |
BFD_RELOC_CRX_NUM16, |
BFD_RELOC_CRX_NUM32, |
BFD_RELOC_CRX_IMM16, |
BFD_RELOC_CRX_IMM32, |
BFD_RELOC_CRX_SWITCH8, |
BFD_RELOC_CRX_SWITCH16, |
BFD_RELOC_CRX_SWITCH32, |
/* These relocs are only used within the CRIS assembler. They are not |
(at present) written to any object files. */ |
BFD_RELOC_CRIS_BDISP8, |
BFD_RELOC_CRIS_UNSIGNED_5, |
BFD_RELOC_CRIS_SIGNED_6, |
BFD_RELOC_CRIS_UNSIGNED_6, |
BFD_RELOC_CRIS_SIGNED_8, |
BFD_RELOC_CRIS_UNSIGNED_8, |
BFD_RELOC_CRIS_SIGNED_16, |
BFD_RELOC_CRIS_UNSIGNED_16, |
BFD_RELOC_CRIS_LAPCQ_OFFSET, |
BFD_RELOC_CRIS_UNSIGNED_4, |
/* Relocs used in ELF shared libraries for CRIS. */ |
BFD_RELOC_CRIS_COPY, |
BFD_RELOC_CRIS_GLOB_DAT, |
BFD_RELOC_CRIS_JUMP_SLOT, |
BFD_RELOC_CRIS_RELATIVE, |
/* 32-bit offset to symbol-entry within GOT. */ |
BFD_RELOC_CRIS_32_GOT, |
/* 16-bit offset to symbol-entry within GOT. */ |
BFD_RELOC_CRIS_16_GOT, |
/* 32-bit offset to symbol-entry within GOT, with PLT handling. */ |
BFD_RELOC_CRIS_32_GOTPLT, |
/* 16-bit offset to symbol-entry within GOT, with PLT handling. */ |
BFD_RELOC_CRIS_16_GOTPLT, |
/* 32-bit offset to symbol, relative to GOT. */ |
BFD_RELOC_CRIS_32_GOTREL, |
/* 32-bit offset to symbol with PLT entry, relative to GOT. */ |
BFD_RELOC_CRIS_32_PLT_GOTREL, |
/* 32-bit offset to symbol with PLT entry, relative to this relocation. */ |
BFD_RELOC_CRIS_32_PLT_PCREL, |
/* Relocs used in TLS code for CRIS. */ |
BFD_RELOC_CRIS_32_GOT_GD, |
BFD_RELOC_CRIS_16_GOT_GD, |
BFD_RELOC_CRIS_32_GD, |
BFD_RELOC_CRIS_DTP, |
BFD_RELOC_CRIS_32_DTPREL, |
BFD_RELOC_CRIS_16_DTPREL, |
BFD_RELOC_CRIS_32_GOT_TPREL, |
BFD_RELOC_CRIS_16_GOT_TPREL, |
BFD_RELOC_CRIS_32_TPREL, |
BFD_RELOC_CRIS_16_TPREL, |
BFD_RELOC_CRIS_DTPMOD, |
BFD_RELOC_CRIS_32_IE, |
/* Intel i860 Relocations. */ |
BFD_RELOC_860_COPY, |
BFD_RELOC_860_GLOB_DAT, |
BFD_RELOC_860_JUMP_SLOT, |
BFD_RELOC_860_RELATIVE, |
BFD_RELOC_860_PC26, |
BFD_RELOC_860_PLT26, |
BFD_RELOC_860_PC16, |
BFD_RELOC_860_LOW0, |
BFD_RELOC_860_SPLIT0, |
BFD_RELOC_860_LOW1, |
BFD_RELOC_860_SPLIT1, |
BFD_RELOC_860_LOW2, |
BFD_RELOC_860_SPLIT2, |
BFD_RELOC_860_LOW3, |
BFD_RELOC_860_LOGOT0, |
BFD_RELOC_860_SPGOT0, |
BFD_RELOC_860_LOGOT1, |
BFD_RELOC_860_SPGOT1, |
BFD_RELOC_860_LOGOTOFF0, |
BFD_RELOC_860_SPGOTOFF0, |
BFD_RELOC_860_LOGOTOFF1, |
BFD_RELOC_860_SPGOTOFF1, |
BFD_RELOC_860_LOGOTOFF2, |
BFD_RELOC_860_LOGOTOFF3, |
BFD_RELOC_860_LOPC, |
BFD_RELOC_860_HIGHADJ, |
BFD_RELOC_860_HAGOT, |
BFD_RELOC_860_HAGOTOFF, |
BFD_RELOC_860_HAPC, |
BFD_RELOC_860_HIGH, |
BFD_RELOC_860_HIGOT, |
BFD_RELOC_860_HIGOTOFF, |
/* OpenRISC Relocations. */ |
BFD_RELOC_OPENRISC_ABS_26, |
BFD_RELOC_OPENRISC_REL_26, |
/* H8 elf Relocations. */ |
BFD_RELOC_H8_DIR16A8, |
BFD_RELOC_H8_DIR16R8, |
BFD_RELOC_H8_DIR24A8, |
BFD_RELOC_H8_DIR24R8, |
BFD_RELOC_H8_DIR32A16, |
BFD_RELOC_H8_DISP32A16, |
/* Sony Xstormy16 Relocations. */ |
BFD_RELOC_XSTORMY16_REL_12, |
BFD_RELOC_XSTORMY16_12, |
BFD_RELOC_XSTORMY16_24, |
BFD_RELOC_XSTORMY16_FPTR16, |
/* Self-describing complex relocations. */ |
BFD_RELOC_RELC, |
/* Infineon Relocations. */ |
BFD_RELOC_XC16X_PAG, |
BFD_RELOC_XC16X_POF, |
BFD_RELOC_XC16X_SEG, |
BFD_RELOC_XC16X_SOF, |
/* Relocations used by VAX ELF. */ |
BFD_RELOC_VAX_GLOB_DAT, |
BFD_RELOC_VAX_JMP_SLOT, |
BFD_RELOC_VAX_RELATIVE, |
/* Morpho MT - 16 bit immediate relocation. */ |
BFD_RELOC_MT_PC16, |
/* Morpho MT - Hi 16 bits of an address. */ |
BFD_RELOC_MT_HI16, |
/* Morpho MT - Low 16 bits of an address. */ |
BFD_RELOC_MT_LO16, |
/* Morpho MT - Used to tell the linker which vtable entries are used. */ |
BFD_RELOC_MT_GNU_VTINHERIT, |
/* Morpho MT - Used to tell the linker which vtable entries are used. */ |
BFD_RELOC_MT_GNU_VTENTRY, |
/* Morpho MT - 8 bit immediate relocation. */ |
BFD_RELOC_MT_PCINSN8, |
/* msp430 specific relocation codes */ |
BFD_RELOC_MSP430_10_PCREL, |
BFD_RELOC_MSP430_16_PCREL, |
BFD_RELOC_MSP430_16, |
BFD_RELOC_MSP430_16_PCREL_BYTE, |
BFD_RELOC_MSP430_16_BYTE, |
BFD_RELOC_MSP430_2X_PCREL, |
BFD_RELOC_MSP430_RL_PCREL, |
BFD_RELOC_MSP430_ABS8, |
BFD_RELOC_MSP430X_PCR20_EXT_SRC, |
BFD_RELOC_MSP430X_PCR20_EXT_DST, |
BFD_RELOC_MSP430X_PCR20_EXT_ODST, |
BFD_RELOC_MSP430X_ABS20_EXT_SRC, |
BFD_RELOC_MSP430X_ABS20_EXT_DST, |
BFD_RELOC_MSP430X_ABS20_EXT_ODST, |
BFD_RELOC_MSP430X_ABS20_ADR_SRC, |
BFD_RELOC_MSP430X_ABS20_ADR_DST, |
BFD_RELOC_MSP430X_PCR16, |
BFD_RELOC_MSP430X_PCR20_CALL, |
BFD_RELOC_MSP430X_ABS16, |
BFD_RELOC_MSP430_ABS_HI16, |
BFD_RELOC_MSP430_PREL31, |
BFD_RELOC_MSP430_SYM_DIFF, |
/* Relocations used by the Altera Nios II core. */ |
BFD_RELOC_NIOS2_S16, |
BFD_RELOC_NIOS2_U16, |
BFD_RELOC_NIOS2_CALL26, |
BFD_RELOC_NIOS2_IMM5, |
BFD_RELOC_NIOS2_CACHE_OPX, |
BFD_RELOC_NIOS2_IMM6, |
BFD_RELOC_NIOS2_IMM8, |
BFD_RELOC_NIOS2_HI16, |
BFD_RELOC_NIOS2_LO16, |
BFD_RELOC_NIOS2_HIADJ16, |
BFD_RELOC_NIOS2_GPREL, |
BFD_RELOC_NIOS2_UJMP, |
BFD_RELOC_NIOS2_CJMP, |
BFD_RELOC_NIOS2_CALLR, |
BFD_RELOC_NIOS2_ALIGN, |
BFD_RELOC_NIOS2_GOT16, |
BFD_RELOC_NIOS2_CALL16, |
BFD_RELOC_NIOS2_GOTOFF_LO, |
BFD_RELOC_NIOS2_GOTOFF_HA, |
BFD_RELOC_NIOS2_PCREL_LO, |
BFD_RELOC_NIOS2_PCREL_HA, |
BFD_RELOC_NIOS2_TLS_GD16, |
BFD_RELOC_NIOS2_TLS_LDM16, |
BFD_RELOC_NIOS2_TLS_LDO16, |
BFD_RELOC_NIOS2_TLS_IE16, |
BFD_RELOC_NIOS2_TLS_LE16, |
BFD_RELOC_NIOS2_TLS_DTPMOD, |
BFD_RELOC_NIOS2_TLS_DTPREL, |
BFD_RELOC_NIOS2_TLS_TPREL, |
BFD_RELOC_NIOS2_COPY, |
BFD_RELOC_NIOS2_GLOB_DAT, |
BFD_RELOC_NIOS2_JUMP_SLOT, |
BFD_RELOC_NIOS2_RELATIVE, |
BFD_RELOC_NIOS2_GOTOFF, |
/* IQ2000 Relocations. */ |
BFD_RELOC_IQ2000_OFFSET_16, |
BFD_RELOC_IQ2000_OFFSET_21, |
BFD_RELOC_IQ2000_UHI16, |
/* Special Xtensa relocation used only by PLT entries in ELF shared |
objects to indicate that the runtime linker should set the value |
to one of its own internal functions or data structures. */ |
BFD_RELOC_XTENSA_RTLD, |
/* Xtensa relocations for ELF shared objects. */ |
BFD_RELOC_XTENSA_GLOB_DAT, |
BFD_RELOC_XTENSA_JMP_SLOT, |
BFD_RELOC_XTENSA_RELATIVE, |
/* Xtensa relocation used in ELF object files for symbols that may require |
PLT entries. Otherwise, this is just a generic 32-bit relocation. */ |
BFD_RELOC_XTENSA_PLT, |
/* Xtensa relocations to mark the difference of two local symbols. |
These are only needed to support linker relaxation and can be ignored |
when not relaxing. The field is set to the value of the difference |
assuming no relaxation. The relocation encodes the position of the |
first symbol so the linker can determine whether to adjust the field |
value. */ |
BFD_RELOC_XTENSA_DIFF8, |
BFD_RELOC_XTENSA_DIFF16, |
BFD_RELOC_XTENSA_DIFF32, |
/* Generic Xtensa relocations for instruction operands. Only the slot |
number is encoded in the relocation. The relocation applies to the |
last PC-relative immediate operand, or if there are no PC-relative |
immediates, to the last immediate operand. */ |
BFD_RELOC_XTENSA_SLOT0_OP, |
BFD_RELOC_XTENSA_SLOT1_OP, |
BFD_RELOC_XTENSA_SLOT2_OP, |
BFD_RELOC_XTENSA_SLOT3_OP, |
BFD_RELOC_XTENSA_SLOT4_OP, |
BFD_RELOC_XTENSA_SLOT5_OP, |
BFD_RELOC_XTENSA_SLOT6_OP, |
BFD_RELOC_XTENSA_SLOT7_OP, |
BFD_RELOC_XTENSA_SLOT8_OP, |
BFD_RELOC_XTENSA_SLOT9_OP, |
BFD_RELOC_XTENSA_SLOT10_OP, |
BFD_RELOC_XTENSA_SLOT11_OP, |
BFD_RELOC_XTENSA_SLOT12_OP, |
BFD_RELOC_XTENSA_SLOT13_OP, |
BFD_RELOC_XTENSA_SLOT14_OP, |
/* Alternate Xtensa relocations. Only the slot is encoded in the |
relocation. The meaning of these relocations is opcode-specific. */ |
BFD_RELOC_XTENSA_SLOT0_ALT, |
BFD_RELOC_XTENSA_SLOT1_ALT, |
BFD_RELOC_XTENSA_SLOT2_ALT, |
BFD_RELOC_XTENSA_SLOT3_ALT, |
BFD_RELOC_XTENSA_SLOT4_ALT, |
BFD_RELOC_XTENSA_SLOT5_ALT, |
BFD_RELOC_XTENSA_SLOT6_ALT, |
BFD_RELOC_XTENSA_SLOT7_ALT, |
BFD_RELOC_XTENSA_SLOT8_ALT, |
BFD_RELOC_XTENSA_SLOT9_ALT, |
BFD_RELOC_XTENSA_SLOT10_ALT, |
BFD_RELOC_XTENSA_SLOT11_ALT, |
BFD_RELOC_XTENSA_SLOT12_ALT, |
BFD_RELOC_XTENSA_SLOT13_ALT, |
BFD_RELOC_XTENSA_SLOT14_ALT, |
/* Xtensa relocations for backward compatibility. These have all been |
replaced by BFD_RELOC_XTENSA_SLOT0_OP. */ |
BFD_RELOC_XTENSA_OP0, |
BFD_RELOC_XTENSA_OP1, |
BFD_RELOC_XTENSA_OP2, |
/* Xtensa relocation to mark that the assembler expanded the |
instructions from an original target. The expansion size is |
encoded in the reloc size. */ |
BFD_RELOC_XTENSA_ASM_EXPAND, |
/* Xtensa relocation to mark that the linker should simplify |
assembler-expanded instructions. This is commonly used |
internally by the linker after analysis of a |
BFD_RELOC_XTENSA_ASM_EXPAND. */ |
BFD_RELOC_XTENSA_ASM_SIMPLIFY, |
/* Xtensa TLS relocations. */ |
BFD_RELOC_XTENSA_TLSDESC_FN, |
BFD_RELOC_XTENSA_TLSDESC_ARG, |
BFD_RELOC_XTENSA_TLS_DTPOFF, |
BFD_RELOC_XTENSA_TLS_TPOFF, |
BFD_RELOC_XTENSA_TLS_FUNC, |
BFD_RELOC_XTENSA_TLS_ARG, |
BFD_RELOC_XTENSA_TLS_CALL, |
/* 8 bit signed offset in (ix+d) or (iy+d). */ |
BFD_RELOC_Z80_DISP8, |
/* DJNZ offset. */ |
BFD_RELOC_Z8K_DISP7, |
/* CALR offset. */ |
BFD_RELOC_Z8K_CALLR, |
/* 4 bit value. */ |
BFD_RELOC_Z8K_IMM4L, |
/* Lattice Mico32 relocations. */ |
BFD_RELOC_LM32_CALL, |
BFD_RELOC_LM32_BRANCH, |
BFD_RELOC_LM32_16_GOT, |
BFD_RELOC_LM32_GOTOFF_HI16, |
BFD_RELOC_LM32_GOTOFF_LO16, |
BFD_RELOC_LM32_COPY, |
BFD_RELOC_LM32_GLOB_DAT, |
BFD_RELOC_LM32_JMP_SLOT, |
BFD_RELOC_LM32_RELATIVE, |
/* Difference between two section addreses. Must be followed by a |
BFD_RELOC_MACH_O_PAIR. */ |
BFD_RELOC_MACH_O_SECTDIFF, |
/* Like BFD_RELOC_MACH_O_SECTDIFF but with a local symbol. */ |
BFD_RELOC_MACH_O_LOCAL_SECTDIFF, |
/* Pair of relocation. Contains the first symbol. */ |
BFD_RELOC_MACH_O_PAIR, |
/* PCREL relocations. They are marked as branch to create PLT entry if |
required. */ |
BFD_RELOC_MACH_O_X86_64_BRANCH32, |
BFD_RELOC_MACH_O_X86_64_BRANCH8, |
/* Used when referencing a GOT entry. */ |
BFD_RELOC_MACH_O_X86_64_GOT, |
/* Used when loading a GOT entry with movq. It is specially marked so that |
the linker could optimize the movq to a leaq if possible. */ |
BFD_RELOC_MACH_O_X86_64_GOT_LOAD, |
/* Symbol will be substracted. Must be followed by a BFD_RELOC_64. */ |
BFD_RELOC_MACH_O_X86_64_SUBTRACTOR32, |
/* Symbol will be substracted. Must be followed by a BFD_RELOC_64. */ |
BFD_RELOC_MACH_O_X86_64_SUBTRACTOR64, |
/* Same as BFD_RELOC_32_PCREL but with an implicit -1 addend. */ |
BFD_RELOC_MACH_O_X86_64_PCREL32_1, |
/* Same as BFD_RELOC_32_PCREL but with an implicit -2 addend. */ |
BFD_RELOC_MACH_O_X86_64_PCREL32_2, |
/* Same as BFD_RELOC_32_PCREL but with an implicit -4 addend. */ |
BFD_RELOC_MACH_O_X86_64_PCREL32_4, |
/* This is a 32 bit reloc for the microblaze that stores the |
low 16 bits of a value */ |
BFD_RELOC_MICROBLAZE_32_LO, |
/* This is a 32 bit pc-relative reloc for the microblaze that |
stores the low 16 bits of a value */ |
BFD_RELOC_MICROBLAZE_32_LO_PCREL, |
/* This is a 32 bit reloc for the microblaze that stores a |
value relative to the read-only small data area anchor */ |
BFD_RELOC_MICROBLAZE_32_ROSDA, |
/* This is a 32 bit reloc for the microblaze that stores a |
value relative to the read-write small data area anchor */ |
BFD_RELOC_MICROBLAZE_32_RWSDA, |
/* This is a 32 bit reloc for the microblaze to handle |
expressions of the form "Symbol Op Symbol" */ |
BFD_RELOC_MICROBLAZE_32_SYM_OP_SYM, |
/* This is a 64 bit reloc that stores the 32 bit pc relative |
value in two words (with an imm instruction). No relocation is |
done here - only used for relaxing */ |
BFD_RELOC_MICROBLAZE_64_NONE, |
/* This is a 64 bit reloc that stores the 32 bit pc relative |
value in two words (with an imm instruction). The relocation is |
PC-relative GOT offset */ |
BFD_RELOC_MICROBLAZE_64_GOTPC, |
/* This is a 64 bit reloc that stores the 32 bit pc relative |
value in two words (with an imm instruction). The relocation is |
GOT offset */ |
BFD_RELOC_MICROBLAZE_64_GOT, |
/* This is a 64 bit reloc that stores the 32 bit pc relative |
value in two words (with an imm instruction). The relocation is |
PC-relative offset into PLT */ |
BFD_RELOC_MICROBLAZE_64_PLT, |
/* This is a 64 bit reloc that stores the 32 bit GOT relative |
value in two words (with an imm instruction). The relocation is |
relative offset from _GLOBAL_OFFSET_TABLE_ */ |
BFD_RELOC_MICROBLAZE_64_GOTOFF, |
/* This is a 32 bit reloc that stores the 32 bit GOT relative |
value in a word. The relocation is relative offset from */ |
BFD_RELOC_MICROBLAZE_32_GOTOFF, |
/* This is used to tell the dynamic linker to copy the value out of |
the dynamic object into the runtime process image. */ |
BFD_RELOC_MICROBLAZE_COPY, |
/* Unused Reloc */ |
BFD_RELOC_MICROBLAZE_64_TLS, |
/* This is a 64 bit reloc that stores the 32 bit GOT relative value |
of the GOT TLS GD info entry in two words (with an imm instruction). The |
relocation is GOT offset. */ |
BFD_RELOC_MICROBLAZE_64_TLSGD, |
/* This is a 64 bit reloc that stores the 32 bit GOT relative value |
of the GOT TLS LD info entry in two words (with an imm instruction). The |
relocation is GOT offset. */ |
BFD_RELOC_MICROBLAZE_64_TLSLD, |
/* This is a 32 bit reloc that stores the Module ID to GOT(n). */ |
BFD_RELOC_MICROBLAZE_32_TLSDTPMOD, |
/* This is a 32 bit reloc that stores TLS offset to GOT(n+1). */ |
BFD_RELOC_MICROBLAZE_32_TLSDTPREL, |
/* This is a 32 bit reloc for storing TLS offset to two words (uses imm |
instruction) */ |
BFD_RELOC_MICROBLAZE_64_TLSDTPREL, |
/* This is a 64 bit reloc that stores 32-bit thread pointer relative offset |
to two words (uses imm instruction). */ |
BFD_RELOC_MICROBLAZE_64_TLSGOTTPREL, |
/* This is a 64 bit reloc that stores 32-bit thread pointer relative offset |
to two words (uses imm instruction). */ |
BFD_RELOC_MICROBLAZE_64_TLSTPREL, |
/* AArch64 pseudo relocation code to mark the start of the AArch64 |
relocation enumerators. N.B. the order of the enumerators is |
important as several tables in the AArch64 bfd backend are indexed |
by these enumerators; make sure they are all synced. */ |
BFD_RELOC_AARCH64_RELOC_START, |
/* AArch64 null relocation code. */ |
BFD_RELOC_AARCH64_NONE, |
/* Basic absolute relocations of N bits. These are equivalent to |
BFD_RELOC_N and they were added to assist the indexing of the howto |
table. */ |
BFD_RELOC_AARCH64_64, |
BFD_RELOC_AARCH64_32, |
BFD_RELOC_AARCH64_16, |
/* PC-relative relocations. These are equivalent to BFD_RELOC_N_PCREL |
and they were added to assist the indexing of the howto table. */ |
BFD_RELOC_AARCH64_64_PCREL, |
BFD_RELOC_AARCH64_32_PCREL, |
BFD_RELOC_AARCH64_16_PCREL, |
/* AArch64 MOV[NZK] instruction with most significant bits 0 to 15 |
of an unsigned address/value. */ |
BFD_RELOC_AARCH64_MOVW_G0, |
/* AArch64 MOV[NZK] instruction with less significant bits 0 to 15 of |
an address/value. No overflow checking. */ |
BFD_RELOC_AARCH64_MOVW_G0_NC, |
/* AArch64 MOV[NZK] instruction with most significant bits 16 to 31 |
of an unsigned address/value. */ |
BFD_RELOC_AARCH64_MOVW_G1, |
/* AArch64 MOV[NZK] instruction with less significant bits 16 to 31 |
of an address/value. No overflow checking. */ |
BFD_RELOC_AARCH64_MOVW_G1_NC, |
/* AArch64 MOV[NZK] instruction with most significant bits 32 to 47 |
of an unsigned address/value. */ |
BFD_RELOC_AARCH64_MOVW_G2, |
/* AArch64 MOV[NZK] instruction with less significant bits 32 to 47 |
of an address/value. No overflow checking. */ |
BFD_RELOC_AARCH64_MOVW_G2_NC, |
/* AArch64 MOV[NZK] instruction with most signficant bits 48 to 64 |
of a signed or unsigned address/value. */ |
BFD_RELOC_AARCH64_MOVW_G3, |
/* AArch64 MOV[NZ] instruction with most significant bits 0 to 15 |
of a signed value. Changes instruction to MOVZ or MOVN depending on the |
value's sign. */ |
BFD_RELOC_AARCH64_MOVW_G0_S, |
/* AArch64 MOV[NZ] instruction with most significant bits 16 to 31 |
of a signed value. Changes instruction to MOVZ or MOVN depending on the |
value's sign. */ |
BFD_RELOC_AARCH64_MOVW_G1_S, |
/* AArch64 MOV[NZ] instruction with most significant bits 32 to 47 |
of a signed value. Changes instruction to MOVZ or MOVN depending on the |
value's sign. */ |
BFD_RELOC_AARCH64_MOVW_G2_S, |
/* AArch64 Load Literal instruction, holding a 19 bit pc-relative word |
offset. The lowest two bits must be zero and are not stored in the |
instruction, giving a 21 bit signed byte offset. */ |
BFD_RELOC_AARCH64_LD_LO19_PCREL, |
/* AArch64 ADR instruction, holding a simple 21 bit pc-relative byte offset. */ |
BFD_RELOC_AARCH64_ADR_LO21_PCREL, |
/* AArch64 ADRP instruction, with bits 12 to 32 of a pc-relative page |
offset, giving a 4KB aligned page base address. */ |
BFD_RELOC_AARCH64_ADR_HI21_PCREL, |
/* AArch64 ADRP instruction, with bits 12 to 32 of a pc-relative page |
offset, giving a 4KB aligned page base address, but with no overflow |
checking. */ |
BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL, |
/* AArch64 ADD immediate instruction, holding bits 0 to 11 of the address. |
Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ |
BFD_RELOC_AARCH64_ADD_LO12, |
/* AArch64 8-bit load/store instruction, holding bits 0 to 11 of the |
address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ |
BFD_RELOC_AARCH64_LDST8_LO12, |
/* AArch64 14 bit pc-relative test bit and branch. |
The lowest two bits must be zero and are not stored in the instruction, |
giving a 16 bit signed byte offset. */ |
BFD_RELOC_AARCH64_TSTBR14, |
/* AArch64 19 bit pc-relative conditional branch and compare & branch. |
The lowest two bits must be zero and are not stored in the instruction, |
giving a 21 bit signed byte offset. */ |
BFD_RELOC_AARCH64_BRANCH19, |
/* AArch64 26 bit pc-relative unconditional branch. |
The lowest two bits must be zero and are not stored in the instruction, |
giving a 28 bit signed byte offset. */ |
BFD_RELOC_AARCH64_JUMP26, |
/* AArch64 26 bit pc-relative unconditional branch and link. |
The lowest two bits must be zero and are not stored in the instruction, |
giving a 28 bit signed byte offset. */ |
BFD_RELOC_AARCH64_CALL26, |
/* AArch64 16-bit load/store instruction, holding bits 0 to 11 of the |
address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ |
BFD_RELOC_AARCH64_LDST16_LO12, |
/* AArch64 32-bit load/store instruction, holding bits 0 to 11 of the |
address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ |
BFD_RELOC_AARCH64_LDST32_LO12, |
/* AArch64 64-bit load/store instruction, holding bits 0 to 11 of the |
address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ |
BFD_RELOC_AARCH64_LDST64_LO12, |
/* AArch64 128-bit load/store instruction, holding bits 0 to 11 of the |
address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ |
BFD_RELOC_AARCH64_LDST128_LO12, |
/* AArch64 Load Literal instruction, holding a 19 bit PC relative word |
offset of the global offset table entry for a symbol. The lowest two |
bits must be zero and are not stored in the instruction, giving a 21 |
bit signed byte offset. This relocation type requires signed overflow |
checking. */ |
BFD_RELOC_AARCH64_GOT_LD_PREL19, |
/* Get to the page base of the global offset table entry for a symbol as |
part of an ADRP instruction using a 21 bit PC relative value.Used in |
conjunction with BFD_RELOC_AARCH64_LD64_GOT_LO12_NC. */ |
BFD_RELOC_AARCH64_ADR_GOT_PAGE, |
/* Unsigned 12 bit byte offset for 64 bit load/store from the page of |
the GOT entry for this symbol. Used in conjunction with |
BFD_RELOC_AARCH64_ADR_GOTPAGE. Valid in LP64 ABI only. */ |
BFD_RELOC_AARCH64_LD64_GOT_LO12_NC, |
/* Unsigned 12 bit byte offset for 32 bit load/store from the page of |
the GOT entry for this symbol. Used in conjunction with |
BFD_RELOC_AARCH64_ADR_GOTPAGE. Valid in ILP32 ABI only. */ |
BFD_RELOC_AARCH64_LD32_GOT_LO12_NC, |
/* Get to the page base of the global offset table entry for a symbols |
tls_index structure as part of an adrp instruction using a 21 bit PC |
relative value. Used in conjunction with |
BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC. */ |
BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21, |
/* Unsigned 12 bit byte offset to global offset table entry for a symbols |
tls_index structure. Used in conjunction with |
BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21. */ |
BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC, |
/* AArch64 TLS INITIAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1, |
/* AArch64 TLS INITIAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC, |
/* AArch64 TLS INITIAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, |
/* AArch64 TLS INITIAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, |
/* AArch64 TLS INITIAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSIE_LD32_GOTTPREL_LO12_NC, |
/* AArch64 TLS INITIAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19, |
/* AArch64 TLS LOCAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2, |
/* AArch64 TLS LOCAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1, |
/* AArch64 TLS LOCAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC, |
/* AArch64 TLS LOCAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0, |
/* AArch64 TLS LOCAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC, |
/* AArch64 TLS LOCAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12, |
/* AArch64 TLS LOCAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12, |
/* AArch64 TLS LOCAL EXEC relocation. */ |
BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC, |
/* AArch64 TLS DESC relocation. */ |
BFD_RELOC_AARCH64_TLSDESC_LD_PREL19, |
/* AArch64 TLS DESC relocation. */ |
BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21, |
/* AArch64 TLS DESC relocation. */ |
BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21, |
/* AArch64 TLS DESC relocation. */ |
BFD_RELOC_AARCH64_TLSDESC_LD64_LO12_NC, |
/* AArch64 TLS DESC relocation. */ |
BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC, |
/* AArch64 TLS DESC relocation. */ |
BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC, |
/* AArch64 TLS DESC relocation. */ |
BFD_RELOC_AARCH64_TLSDESC_OFF_G1, |
/* AArch64 TLS DESC relocation. */ |
BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC, |
/* AArch64 TLS DESC relocation. */ |
BFD_RELOC_AARCH64_TLSDESC_LDR, |
/* AArch64 TLS DESC relocation. */ |
BFD_RELOC_AARCH64_TLSDESC_ADD, |
/* AArch64 TLS DESC relocation. */ |
BFD_RELOC_AARCH64_TLSDESC_CALL, |
/* AArch64 TLS relocation. */ |
BFD_RELOC_AARCH64_COPY, |
/* AArch64 TLS relocation. */ |
BFD_RELOC_AARCH64_GLOB_DAT, |
/* AArch64 TLS relocation. */ |
BFD_RELOC_AARCH64_JUMP_SLOT, |
/* AArch64 TLS relocation. */ |
BFD_RELOC_AARCH64_RELATIVE, |
/* AArch64 TLS relocation. */ |
BFD_RELOC_AARCH64_TLS_DTPMOD, |
/* AArch64 TLS relocation. */ |
BFD_RELOC_AARCH64_TLS_DTPREL, |
/* AArch64 TLS relocation. */ |
BFD_RELOC_AARCH64_TLS_TPREL, |
/* AArch64 TLS relocation. */ |
BFD_RELOC_AARCH64_TLSDESC, |
/* AArch64 support for STT_GNU_IFUNC. */ |
BFD_RELOC_AARCH64_IRELATIVE, |
/* AArch64 pseudo relocation code to mark the end of the AArch64 |
relocation enumerators that have direct mapping to ELF reloc codes. |
There are a few more enumerators after this one; those are mainly |
used by the AArch64 assembler for the internal fixup or to select |
one of the above enumerators. */ |
BFD_RELOC_AARCH64_RELOC_END, |
/* AArch64 pseudo relocation code to be used internally by the AArch64 |
assembler and not (currently) written to any object files. */ |
BFD_RELOC_AARCH64_GAS_INTERNAL_FIXUP, |
/* AArch64 unspecified load/store instruction, holding bits 0 to 11 of the |
address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ |
BFD_RELOC_AARCH64_LDST_LO12, |
/* AArch64 pseudo relocation code to be used internally by the AArch64 |
assembler and not (currently) written to any object files. */ |
BFD_RELOC_AARCH64_LD_GOT_LO12_NC, |
/* AArch64 pseudo relocation code to be used internally by the AArch64 |
assembler and not (currently) written to any object files. */ |
BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_LO12_NC, |
/* AArch64 pseudo relocation code to be used internally by the AArch64 |
assembler and not (currently) written to any object files. */ |
BFD_RELOC_AARCH64_TLSDESC_LD_LO12_NC, |
/* Tilera TILEPro Relocations. */ |
BFD_RELOC_TILEPRO_COPY, |
BFD_RELOC_TILEPRO_GLOB_DAT, |
BFD_RELOC_TILEPRO_JMP_SLOT, |
BFD_RELOC_TILEPRO_RELATIVE, |
BFD_RELOC_TILEPRO_BROFF_X1, |
BFD_RELOC_TILEPRO_JOFFLONG_X1, |
BFD_RELOC_TILEPRO_JOFFLONG_X1_PLT, |
BFD_RELOC_TILEPRO_IMM8_X0, |
BFD_RELOC_TILEPRO_IMM8_Y0, |
BFD_RELOC_TILEPRO_IMM8_X1, |
BFD_RELOC_TILEPRO_IMM8_Y1, |
BFD_RELOC_TILEPRO_DEST_IMM8_X1, |
BFD_RELOC_TILEPRO_MT_IMM15_X1, |
BFD_RELOC_TILEPRO_MF_IMM15_X1, |
BFD_RELOC_TILEPRO_IMM16_X0, |
BFD_RELOC_TILEPRO_IMM16_X1, |
BFD_RELOC_TILEPRO_IMM16_X0_LO, |
BFD_RELOC_TILEPRO_IMM16_X1_LO, |
BFD_RELOC_TILEPRO_IMM16_X0_HI, |
BFD_RELOC_TILEPRO_IMM16_X1_HI, |
BFD_RELOC_TILEPRO_IMM16_X0_HA, |
BFD_RELOC_TILEPRO_IMM16_X1_HA, |
BFD_RELOC_TILEPRO_IMM16_X0_PCREL, |
BFD_RELOC_TILEPRO_IMM16_X1_PCREL, |
BFD_RELOC_TILEPRO_IMM16_X0_LO_PCREL, |
BFD_RELOC_TILEPRO_IMM16_X1_LO_PCREL, |
BFD_RELOC_TILEPRO_IMM16_X0_HI_PCREL, |
BFD_RELOC_TILEPRO_IMM16_X1_HI_PCREL, |
BFD_RELOC_TILEPRO_IMM16_X0_HA_PCREL, |
BFD_RELOC_TILEPRO_IMM16_X1_HA_PCREL, |
BFD_RELOC_TILEPRO_IMM16_X0_GOT, |
BFD_RELOC_TILEPRO_IMM16_X1_GOT, |
BFD_RELOC_TILEPRO_IMM16_X0_GOT_LO, |
BFD_RELOC_TILEPRO_IMM16_X1_GOT_LO, |
BFD_RELOC_TILEPRO_IMM16_X0_GOT_HI, |
BFD_RELOC_TILEPRO_IMM16_X1_GOT_HI, |
BFD_RELOC_TILEPRO_IMM16_X0_GOT_HA, |
BFD_RELOC_TILEPRO_IMM16_X1_GOT_HA, |
BFD_RELOC_TILEPRO_MMSTART_X0, |
BFD_RELOC_TILEPRO_MMEND_X0, |
BFD_RELOC_TILEPRO_MMSTART_X1, |
BFD_RELOC_TILEPRO_MMEND_X1, |
BFD_RELOC_TILEPRO_SHAMT_X0, |
BFD_RELOC_TILEPRO_SHAMT_X1, |
BFD_RELOC_TILEPRO_SHAMT_Y0, |
BFD_RELOC_TILEPRO_SHAMT_Y1, |
BFD_RELOC_TILEPRO_TLS_GD_CALL, |
BFD_RELOC_TILEPRO_IMM8_X0_TLS_GD_ADD, |
BFD_RELOC_TILEPRO_IMM8_X1_TLS_GD_ADD, |
BFD_RELOC_TILEPRO_IMM8_Y0_TLS_GD_ADD, |
BFD_RELOC_TILEPRO_IMM8_Y1_TLS_GD_ADD, |
BFD_RELOC_TILEPRO_TLS_IE_LOAD, |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD, |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD, |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD_LO, |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD_LO, |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD_HI, |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD_HI, |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD_HA, |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD_HA, |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE, |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE, |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE_LO, |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE_LO, |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE_HI, |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE_HI, |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE_HA, |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE_HA, |
BFD_RELOC_TILEPRO_TLS_DTPMOD32, |
BFD_RELOC_TILEPRO_TLS_DTPOFF32, |
BFD_RELOC_TILEPRO_TLS_TPOFF32, |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE, |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE, |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_LO, |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_LO, |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_HI, |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_HI, |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_HA, |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_HA, |
/* Tilera TILE-Gx Relocations. */ |
BFD_RELOC_TILEGX_HW0, |
BFD_RELOC_TILEGX_HW1, |
BFD_RELOC_TILEGX_HW2, |
BFD_RELOC_TILEGX_HW3, |
BFD_RELOC_TILEGX_HW0_LAST, |
BFD_RELOC_TILEGX_HW1_LAST, |
BFD_RELOC_TILEGX_HW2_LAST, |
BFD_RELOC_TILEGX_COPY, |
BFD_RELOC_TILEGX_GLOB_DAT, |
BFD_RELOC_TILEGX_JMP_SLOT, |
BFD_RELOC_TILEGX_RELATIVE, |
BFD_RELOC_TILEGX_BROFF_X1, |
BFD_RELOC_TILEGX_JUMPOFF_X1, |
BFD_RELOC_TILEGX_JUMPOFF_X1_PLT, |
BFD_RELOC_TILEGX_IMM8_X0, |
BFD_RELOC_TILEGX_IMM8_Y0, |
BFD_RELOC_TILEGX_IMM8_X1, |
BFD_RELOC_TILEGX_IMM8_Y1, |
BFD_RELOC_TILEGX_DEST_IMM8_X1, |
BFD_RELOC_TILEGX_MT_IMM14_X1, |
BFD_RELOC_TILEGX_MF_IMM14_X1, |
BFD_RELOC_TILEGX_MMSTART_X0, |
BFD_RELOC_TILEGX_MMEND_X0, |
BFD_RELOC_TILEGX_SHAMT_X0, |
BFD_RELOC_TILEGX_SHAMT_X1, |
BFD_RELOC_TILEGX_SHAMT_Y0, |
BFD_RELOC_TILEGX_SHAMT_Y1, |
BFD_RELOC_TILEGX_IMM16_X0_HW0, |
BFD_RELOC_TILEGX_IMM16_X1_HW0, |
BFD_RELOC_TILEGX_IMM16_X0_HW1, |
BFD_RELOC_TILEGX_IMM16_X1_HW1, |
BFD_RELOC_TILEGX_IMM16_X0_HW2, |
BFD_RELOC_TILEGX_IMM16_X1_HW2, |
BFD_RELOC_TILEGX_IMM16_X0_HW3, |
BFD_RELOC_TILEGX_IMM16_X1_HW3, |
BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST, |
BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST, |
BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST, |
BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST, |
BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST, |
BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST, |
BFD_RELOC_TILEGX_IMM16_X0_HW0_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW0_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW1_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW1_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW2_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW2_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW3_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW3_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW0_GOT, |
BFD_RELOC_TILEGX_IMM16_X1_HW0_GOT, |
BFD_RELOC_TILEGX_IMM16_X0_HW0_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW0_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW1_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW1_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW2_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW2_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_GOT, |
BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_GOT, |
BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_GOT, |
BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_GOT, |
BFD_RELOC_TILEGX_IMM16_X0_HW3_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW3_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_GD, |
BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_GD, |
BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_LE, |
BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_LE, |
BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_LE, |
BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_TLS_LE, |
BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_LE, |
BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_LE, |
BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_GD, |
BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_TLS_GD, |
BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_GD, |
BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_GD, |
BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_IE, |
BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_IE, |
BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL, |
BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_IE, |
BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_TLS_IE, |
BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_IE, |
BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_IE, |
BFD_RELOC_TILEGX_TLS_DTPMOD64, |
BFD_RELOC_TILEGX_TLS_DTPOFF64, |
BFD_RELOC_TILEGX_TLS_TPOFF64, |
BFD_RELOC_TILEGX_TLS_DTPMOD32, |
BFD_RELOC_TILEGX_TLS_DTPOFF32, |
BFD_RELOC_TILEGX_TLS_TPOFF32, |
BFD_RELOC_TILEGX_TLS_GD_CALL, |
BFD_RELOC_TILEGX_IMM8_X0_TLS_GD_ADD, |
BFD_RELOC_TILEGX_IMM8_X1_TLS_GD_ADD, |
BFD_RELOC_TILEGX_IMM8_Y0_TLS_GD_ADD, |
BFD_RELOC_TILEGX_IMM8_Y1_TLS_GD_ADD, |
BFD_RELOC_TILEGX_TLS_IE_LOAD, |
BFD_RELOC_TILEGX_IMM8_X0_TLS_ADD, |
BFD_RELOC_TILEGX_IMM8_X1_TLS_ADD, |
BFD_RELOC_TILEGX_IMM8_Y0_TLS_ADD, |
BFD_RELOC_TILEGX_IMM8_Y1_TLS_ADD, |
/* Adapteva EPIPHANY - 8 bit signed pc-relative displacement */ |
BFD_RELOC_EPIPHANY_SIMM8, |
/* Adapteva EPIPHANY - 24 bit signed pc-relative displacement */ |
BFD_RELOC_EPIPHANY_SIMM24, |
/* Adapteva EPIPHANY - 16 most-significant bits of absolute address */ |
BFD_RELOC_EPIPHANY_HIGH, |
/* Adapteva EPIPHANY - 16 least-significant bits of absolute address */ |
BFD_RELOC_EPIPHANY_LOW, |
/* Adapteva EPIPHANY - 11 bit signed number - add/sub immediate */ |
BFD_RELOC_EPIPHANY_SIMM11, |
/* Adapteva EPIPHANY - 11 bit sign-magnitude number (ld/st displacement) */ |
BFD_RELOC_EPIPHANY_IMM11, |
/* Adapteva EPIPHANY - 8 bit immediate for 16 bit mov instruction. */ |
BFD_RELOC_EPIPHANY_IMM8, |
BFD_RELOC_UNUSED }; |
typedef enum bfd_reloc_code_real bfd_reloc_code_real_type; |
reloc_howto_type *bfd_reloc_type_lookup |
(bfd *abfd, bfd_reloc_code_real_type code); |
reloc_howto_type *bfd_reloc_name_lookup |
(bfd *abfd, const char *reloc_name); |
const char *bfd_get_reloc_code_name (bfd_reloc_code_real_type code); |
/* Extracted from syms.c. */ |
typedef struct bfd_symbol |
{ |
/* A pointer to the BFD which owns the symbol. This information |
is necessary so that a back end can work out what additional |
information (invisible to the application writer) is carried |
with the symbol. |
This field is *almost* redundant, since you can use section->owner |
instead, except that some symbols point to the global sections |
bfd_{abs,com,und}_section. This could be fixed by making |
these globals be per-bfd (or per-target-flavor). FIXME. */ |
struct bfd *the_bfd; /* Use bfd_asymbol_bfd(sym) to access this field. */ |
/* The text of the symbol. The name is left alone, and not copied; the |
application may not alter it. */ |
const char *name; |
/* The value of the symbol. This really should be a union of a |
numeric value with a pointer, since some flags indicate that |
a pointer to another symbol is stored here. */ |
symvalue value; |
/* Attributes of a symbol. */ |
#define BSF_NO_FLAGS 0x00 |
/* The symbol has local scope; <<static>> in <<C>>. The value |
is the offset into the section of the data. */ |
#define BSF_LOCAL (1 << 0) |
/* The symbol has global scope; initialized data in <<C>>. The |
value is the offset into the section of the data. */ |
#define BSF_GLOBAL (1 << 1) |
/* The symbol has global scope and is exported. The value is |
the offset into the section of the data. */ |
#define BSF_EXPORT BSF_GLOBAL /* No real difference. */ |
/* A normal C symbol would be one of: |
<<BSF_LOCAL>>, <<BSF_COMMON>>, <<BSF_UNDEFINED>> or |
<<BSF_GLOBAL>>. */ |
/* The symbol is a debugging record. The value has an arbitrary |
meaning, unless BSF_DEBUGGING_RELOC is also set. */ |
#define BSF_DEBUGGING (1 << 2) |
/* The symbol denotes a function entry point. Used in ELF, |
perhaps others someday. */ |
#define BSF_FUNCTION (1 << 3) |
/* Used by the linker. */ |
#define BSF_KEEP (1 << 5) |
#define BSF_KEEP_G (1 << 6) |
/* A weak global symbol, overridable without warnings by |
a regular global symbol of the same name. */ |
#define BSF_WEAK (1 << 7) |
/* This symbol was created to point to a section, e.g. ELF's |
STT_SECTION symbols. */ |
#define BSF_SECTION_SYM (1 << 8) |
/* The symbol used to be a common symbol, but now it is |
allocated. */ |
#define BSF_OLD_COMMON (1 << 9) |
/* In some files the type of a symbol sometimes alters its |
location in an output file - ie in coff a <<ISFCN>> symbol |
which is also <<C_EXT>> symbol appears where it was |
declared and not at the end of a section. This bit is set |
by the target BFD part to convey this information. */ |
#define BSF_NOT_AT_END (1 << 10) |
/* Signal that the symbol is the label of constructor section. */ |
#define BSF_CONSTRUCTOR (1 << 11) |
/* Signal that the symbol is a warning symbol. The name is a |
warning. The name of the next symbol is the one to warn about; |
if a reference is made to a symbol with the same name as the next |
symbol, a warning is issued by the linker. */ |
#define BSF_WARNING (1 << 12) |
/* Signal that the symbol is indirect. This symbol is an indirect |
pointer to the symbol with the same name as the next symbol. */ |
#define BSF_INDIRECT (1 << 13) |
/* BSF_FILE marks symbols that contain a file name. This is used |
for ELF STT_FILE symbols. */ |
#define BSF_FILE (1 << 14) |
/* Symbol is from dynamic linking information. */ |
#define BSF_DYNAMIC (1 << 15) |
/* The symbol denotes a data object. Used in ELF, and perhaps |
others someday. */ |
#define BSF_OBJECT (1 << 16) |
/* This symbol is a debugging symbol. The value is the offset |
into the section of the data. BSF_DEBUGGING should be set |
as well. */ |
#define BSF_DEBUGGING_RELOC (1 << 17) |
/* This symbol is thread local. Used in ELF. */ |
#define BSF_THREAD_LOCAL (1 << 18) |
/* This symbol represents a complex relocation expression, |
with the expression tree serialized in the symbol name. */ |
#define BSF_RELC (1 << 19) |
/* This symbol represents a signed complex relocation expression, |
with the expression tree serialized in the symbol name. */ |
#define BSF_SRELC (1 << 20) |
/* This symbol was created by bfd_get_synthetic_symtab. */ |
#define BSF_SYNTHETIC (1 << 21) |
/* This symbol is an indirect code object. Unrelated to BSF_INDIRECT. |
The dynamic linker will compute the value of this symbol by |
calling the function that it points to. BSF_FUNCTION must |
also be also set. */ |
#define BSF_GNU_INDIRECT_FUNCTION (1 << 22) |
/* This symbol is a globally unique data object. The dynamic linker |
will make sure that in the entire process there is just one symbol |
with this name and type in use. BSF_OBJECT must also be set. */ |
#define BSF_GNU_UNIQUE (1 << 23) |
flagword flags; |
/* A pointer to the section to which this symbol is |
relative. This will always be non NULL, there are special |
sections for undefined and absolute symbols. */ |
struct bfd_section *section; |
/* Back end special data. */ |
union |
{ |
void *p; |
bfd_vma i; |
} |
udata; |
} |
asymbol; |
#define bfd_get_symtab_upper_bound(abfd) \ |
BFD_SEND (abfd, _bfd_get_symtab_upper_bound, (abfd)) |
bfd_boolean bfd_is_local_label (bfd *abfd, asymbol *sym); |
bfd_boolean bfd_is_local_label_name (bfd *abfd, const char *name); |
#define bfd_is_local_label_name(abfd, name) \ |
BFD_SEND (abfd, _bfd_is_local_label_name, (abfd, name)) |
bfd_boolean bfd_is_target_special_symbol (bfd *abfd, asymbol *sym); |
#define bfd_is_target_special_symbol(abfd, sym) \ |
BFD_SEND (abfd, _bfd_is_target_special_symbol, (abfd, sym)) |
#define bfd_canonicalize_symtab(abfd, location) \ |
BFD_SEND (abfd, _bfd_canonicalize_symtab, (abfd, location)) |
bfd_boolean bfd_set_symtab |
(bfd *abfd, asymbol **location, unsigned int count); |
void bfd_print_symbol_vandf (bfd *abfd, void *file, asymbol *symbol); |
#define bfd_make_empty_symbol(abfd) \ |
BFD_SEND (abfd, _bfd_make_empty_symbol, (abfd)) |
asymbol *_bfd_generic_make_empty_symbol (bfd *); |
#define bfd_make_debug_symbol(abfd,ptr,size) \ |
BFD_SEND (abfd, _bfd_make_debug_symbol, (abfd, ptr, size)) |
int bfd_decode_symclass (asymbol *symbol); |
bfd_boolean bfd_is_undefined_symclass (int symclass); |
void bfd_symbol_info (asymbol *symbol, symbol_info *ret); |
bfd_boolean bfd_copy_private_symbol_data |
(bfd *ibfd, asymbol *isym, bfd *obfd, asymbol *osym); |
#define bfd_copy_private_symbol_data(ibfd, isymbol, obfd, osymbol) \ |
BFD_SEND (obfd, _bfd_copy_private_symbol_data, \ |
(ibfd, isymbol, obfd, osymbol)) |
/* Extracted from bfd.c. */ |
enum bfd_direction |
{ |
no_direction = 0, |
read_direction = 1, |
write_direction = 2, |
both_direction = 3 |
}; |
struct bfd |
{ |
/* A unique identifier of the BFD */ |
unsigned int id; |
/* The filename the application opened the BFD with. */ |
const char *filename; |
/* A pointer to the target jump table. */ |
const struct bfd_target *xvec; |
/* The IOSTREAM, and corresponding IO vector that provide access |
to the file backing the BFD. */ |
void *iostream; |
const struct bfd_iovec *iovec; |
/* The caching routines use these to maintain a |
least-recently-used list of BFDs. */ |
struct bfd *lru_prev, *lru_next; |
/* When a file is closed by the caching routines, BFD retains |
state information on the file here... */ |
ufile_ptr where; |
/* File modified time, if mtime_set is TRUE. */ |
long mtime; |
/* Reserved for an unimplemented file locking extension. */ |
int ifd; |
/* The format which belongs to the BFD. (object, core, etc.) */ |
bfd_format format; |
/* The direction with which the BFD was opened. */ |
enum bfd_direction direction; |
/* Format_specific flags. */ |
flagword flags; |
/* Values that may appear in the flags field of a BFD. These also |
appear in the object_flags field of the bfd_target structure, where |
they indicate the set of flags used by that backend (not all flags |
are meaningful for all object file formats) (FIXME: at the moment, |
the object_flags values have mostly just been copied from backend |
to another, and are not necessarily correct). */ |
#define BFD_NO_FLAGS 0x00 |
/* BFD contains relocation entries. */ |
#define HAS_RELOC 0x01 |
/* BFD is directly executable. */ |
#define EXEC_P 0x02 |
/* BFD has line number information (basically used for F_LNNO in a |
COFF header). */ |
#define HAS_LINENO 0x04 |
/* BFD has debugging information. */ |
#define HAS_DEBUG 0x08 |
/* BFD has symbols. */ |
#define HAS_SYMS 0x10 |
/* BFD has local symbols (basically used for F_LSYMS in a COFF |
header). */ |
#define HAS_LOCALS 0x20 |
/* BFD is a dynamic object. */ |
#define DYNAMIC 0x40 |
/* Text section is write protected (if D_PAGED is not set, this is |
like an a.out NMAGIC file) (the linker sets this by default, but |
clears it for -r or -N). */ |
#define WP_TEXT 0x80 |
/* BFD is dynamically paged (this is like an a.out ZMAGIC file) (the |
linker sets this by default, but clears it for -r or -n or -N). */ |
#define D_PAGED 0x100 |
/* BFD is relaxable (this means that bfd_relax_section may be able to |
do something) (sometimes bfd_relax_section can do something even if |
this is not set). */ |
#define BFD_IS_RELAXABLE 0x200 |
/* This may be set before writing out a BFD to request using a |
traditional format. For example, this is used to request that when |
writing out an a.out object the symbols not be hashed to eliminate |
duplicates. */ |
#define BFD_TRADITIONAL_FORMAT 0x400 |
/* This flag indicates that the BFD contents are actually cached |
in memory. If this is set, iostream points to a bfd_in_memory |
struct. */ |
#define BFD_IN_MEMORY 0x800 |
/* The sections in this BFD specify a memory page. */ |
#define HAS_LOAD_PAGE 0x1000 |
/* This BFD has been created by the linker and doesn't correspond |
to any input file. */ |
#define BFD_LINKER_CREATED 0x2000 |
/* This may be set before writing out a BFD to request that it |
be written using values for UIDs, GIDs, timestamps, etc. that |
will be consistent from run to run. */ |
#define BFD_DETERMINISTIC_OUTPUT 0x4000 |
/* Compress sections in this BFD. */ |
#define BFD_COMPRESS 0x8000 |
/* Decompress sections in this BFD. */ |
#define BFD_DECOMPRESS 0x10000 |
/* BFD is a dummy, for plugins. */ |
#define BFD_PLUGIN 0x20000 |
/* Flags bits to be saved in bfd_preserve_save. */ |
#define BFD_FLAGS_SAVED \ |
(BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_PLUGIN) |
/* Flags bits which are for BFD use only. */ |
#define BFD_FLAGS_FOR_BFD_USE_MASK \ |
(BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \ |
| BFD_PLUGIN | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT) |
/* Currently my_archive is tested before adding origin to |
anything. I believe that this can become always an add of |
origin, with origin set to 0 for non archive files. */ |
ufile_ptr origin; |
/* The origin in the archive of the proxy entry. This will |
normally be the same as origin, except for thin archives, |
when it will contain the current offset of the proxy in the |
thin archive rather than the offset of the bfd in its actual |
container. */ |
ufile_ptr proxy_origin; |
/* A hash table for section names. */ |
struct bfd_hash_table section_htab; |
/* Pointer to linked list of sections. */ |
struct bfd_section *sections; |
/* The last section on the section list. */ |
struct bfd_section *section_last; |
/* The number of sections. */ |
unsigned int section_count; |
/* Stuff only useful for object files: |
The start address. */ |
bfd_vma start_address; |
/* Used for input and output. */ |
unsigned int symcount; |
/* Symbol table for output BFD (with symcount entries). |
Also used by the linker to cache input BFD symbols. */ |
struct bfd_symbol **outsymbols; |
/* Used for slurped dynamic symbol tables. */ |
unsigned int dynsymcount; |
/* Pointer to structure which contains architecture information. */ |
const struct bfd_arch_info *arch_info; |
/* Stuff only useful for archives. */ |
void *arelt_data; |
struct bfd *my_archive; /* The containing archive BFD. */ |
struct bfd *archive_next; /* The next BFD in the archive. */ |
struct bfd *archive_head; /* The first BFD in the archive. */ |
struct bfd *nested_archives; /* List of nested archive in a flattened |
thin archive. */ |
/* A chain of BFD structures involved in a link. */ |
struct bfd *link_next; |
/* A field used by _bfd_generic_link_add_archive_symbols. This will |
be used only for archive elements. */ |
int archive_pass; |
/* Used by the back end to hold private data. */ |
union |
{ |
struct aout_data_struct *aout_data; |
struct artdata *aout_ar_data; |
struct _oasys_data *oasys_obj_data; |
struct _oasys_ar_data *oasys_ar_data; |
struct coff_tdata *coff_obj_data; |
struct pe_tdata *pe_obj_data; |
struct xcoff_tdata *xcoff_obj_data; |
struct ecoff_tdata *ecoff_obj_data; |
struct ieee_data_struct *ieee_data; |
struct ieee_ar_data_struct *ieee_ar_data; |
struct srec_data_struct *srec_data; |
struct verilog_data_struct *verilog_data; |
struct ihex_data_struct *ihex_data; |
struct tekhex_data_struct *tekhex_data; |
struct elf_obj_tdata *elf_obj_data; |
struct nlm_obj_tdata *nlm_obj_data; |
struct bout_data_struct *bout_data; |
struct mmo_data_struct *mmo_data; |
struct sun_core_struct *sun_core_data; |
struct sco5_core_struct *sco5_core_data; |
struct trad_core_struct *trad_core_data; |
struct som_data_struct *som_data; |
struct hpux_core_struct *hpux_core_data; |
struct hppabsd_core_struct *hppabsd_core_data; |
struct sgi_core_struct *sgi_core_data; |
struct lynx_core_struct *lynx_core_data; |
struct osf_core_struct *osf_core_data; |
struct cisco_core_struct *cisco_core_data; |
struct versados_data_struct *versados_data; |
struct netbsd_core_struct *netbsd_core_data; |
struct mach_o_data_struct *mach_o_data; |
struct mach_o_fat_data_struct *mach_o_fat_data; |
struct plugin_data_struct *plugin_data; |
struct bfd_pef_data_struct *pef_data; |
struct bfd_pef_xlib_data_struct *pef_xlib_data; |
struct bfd_sym_data_struct *sym_data; |
void *any; |
} |
tdata; |
/* Used by the application to hold private data. */ |
void *usrdata; |
/* Where all the allocated stuff under this BFD goes. This is a |
struct objalloc *, but we use void * to avoid requiring the inclusion |
of objalloc.h. */ |
void *memory; |
/* Is the file descriptor being cached? That is, can it be closed as |
needed, and re-opened when accessed later? */ |
unsigned int cacheable : 1; |
/* Marks whether there was a default target specified when the |
BFD was opened. This is used to select which matching algorithm |
to use to choose the back end. */ |
unsigned int target_defaulted : 1; |
/* ... and here: (``once'' means at least once). */ |
unsigned int opened_once : 1; |
/* Set if we have a locally maintained mtime value, rather than |
getting it from the file each time. */ |
unsigned int mtime_set : 1; |
/* Flag set if symbols from this BFD should not be exported. */ |
unsigned int no_export : 1; |
/* Remember when output has begun, to stop strange things |
from happening. */ |
unsigned int output_has_begun : 1; |
/* Have archive map. */ |
unsigned int has_armap : 1; |
/* Set if this is a thin archive. */ |
unsigned int is_thin_archive : 1; |
/* Set if only required symbols should be added in the link hash table for |
this object. Used by VMS linkers. */ |
unsigned int selective_search : 1; |
}; |
typedef enum bfd_error |
{ |
bfd_error_no_error = 0, |
bfd_error_system_call, |
bfd_error_invalid_target, |
bfd_error_wrong_format, |
bfd_error_wrong_object_format, |
bfd_error_invalid_operation, |
bfd_error_no_memory, |
bfd_error_no_symbols, |
bfd_error_no_armap, |
bfd_error_no_more_archived_files, |
bfd_error_malformed_archive, |
bfd_error_missing_dso, |
bfd_error_file_not_recognized, |
bfd_error_file_ambiguously_recognized, |
bfd_error_no_contents, |
bfd_error_nonrepresentable_section, |
bfd_error_no_debug_section, |
bfd_error_bad_value, |
bfd_error_file_truncated, |
bfd_error_file_too_big, |
bfd_error_on_input, |
bfd_error_invalid_error_code |
} |
bfd_error_type; |
bfd_error_type bfd_get_error (void); |
void bfd_set_error (bfd_error_type error_tag, ...); |
const char *bfd_errmsg (bfd_error_type error_tag); |
void bfd_perror (const char *message); |
typedef void (*bfd_error_handler_type) (const char *, ...); |
bfd_error_handler_type bfd_set_error_handler (bfd_error_handler_type); |
void bfd_set_error_program_name (const char *); |
bfd_error_handler_type bfd_get_error_handler (void); |
typedef void (*bfd_assert_handler_type) (const char *bfd_formatmsg, |
const char *bfd_version, |
const char *bfd_file, |
int bfd_line); |
bfd_assert_handler_type bfd_set_assert_handler (bfd_assert_handler_type); |
bfd_assert_handler_type bfd_get_assert_handler (void); |
long bfd_get_reloc_upper_bound (bfd *abfd, asection *sect); |
long bfd_canonicalize_reloc |
(bfd *abfd, asection *sec, arelent **loc, asymbol **syms); |
void bfd_set_reloc |
(bfd *abfd, asection *sec, arelent **rel, unsigned int count); |
bfd_boolean bfd_set_file_flags (bfd *abfd, flagword flags); |
int bfd_get_arch_size (bfd *abfd); |
int bfd_get_sign_extend_vma (bfd *abfd); |
bfd_boolean bfd_set_start_address (bfd *abfd, bfd_vma vma); |
unsigned int bfd_get_gp_size (bfd *abfd); |
void bfd_set_gp_size (bfd *abfd, unsigned int i); |
bfd_vma bfd_scan_vma (const char *string, const char **end, int base); |
bfd_boolean bfd_copy_private_header_data (bfd *ibfd, bfd *obfd); |
#define bfd_copy_private_header_data(ibfd, obfd) \ |
BFD_SEND (obfd, _bfd_copy_private_header_data, \ |
(ibfd, obfd)) |
bfd_boolean bfd_copy_private_bfd_data (bfd *ibfd, bfd *obfd); |
#define bfd_copy_private_bfd_data(ibfd, obfd) \ |
BFD_SEND (obfd, _bfd_copy_private_bfd_data, \ |
(ibfd, obfd)) |
bfd_boolean bfd_merge_private_bfd_data (bfd *ibfd, bfd *obfd); |
#define bfd_merge_private_bfd_data(ibfd, obfd) \ |
BFD_SEND (obfd, _bfd_merge_private_bfd_data, \ |
(ibfd, obfd)) |
bfd_boolean bfd_set_private_flags (bfd *abfd, flagword flags); |
#define bfd_set_private_flags(abfd, flags) \ |
BFD_SEND (abfd, _bfd_set_private_flags, (abfd, flags)) |
#define bfd_sizeof_headers(abfd, info) \ |
BFD_SEND (abfd, _bfd_sizeof_headers, (abfd, info)) |
#define bfd_find_nearest_line(abfd, sec, syms, off, file, func, line) \ |
BFD_SEND (abfd, _bfd_find_nearest_line, \ |
(abfd, sec, syms, off, file, func, line)) |
#define bfd_find_nearest_line_discriminator(abfd, sec, syms, off, file, func, \ |
line, disc) \ |
BFD_SEND (abfd, _bfd_find_nearest_line_discriminator, \ |
(abfd, sec, syms, off, file, func, line, disc)) |
#define bfd_find_line(abfd, syms, sym, file, line) \ |
BFD_SEND (abfd, _bfd_find_line, \ |
(abfd, syms, sym, file, line)) |
#define bfd_find_inliner_info(abfd, file, func, line) \ |
BFD_SEND (abfd, _bfd_find_inliner_info, \ |
(abfd, file, func, line)) |
#define bfd_debug_info_start(abfd) \ |
BFD_SEND (abfd, _bfd_debug_info_start, (abfd)) |
#define bfd_debug_info_end(abfd) \ |
BFD_SEND (abfd, _bfd_debug_info_end, (abfd)) |
#define bfd_debug_info_accumulate(abfd, section) \ |
BFD_SEND (abfd, _bfd_debug_info_accumulate, (abfd, section)) |
#define bfd_stat_arch_elt(abfd, stat) \ |
BFD_SEND (abfd, _bfd_stat_arch_elt,(abfd, stat)) |
#define bfd_update_armap_timestamp(abfd) \ |
BFD_SEND (abfd, _bfd_update_armap_timestamp, (abfd)) |
#define bfd_set_arch_mach(abfd, arch, mach)\ |
BFD_SEND ( abfd, _bfd_set_arch_mach, (abfd, arch, mach)) |
#define bfd_relax_section(abfd, section, link_info, again) \ |
BFD_SEND (abfd, _bfd_relax_section, (abfd, section, link_info, again)) |
#define bfd_gc_sections(abfd, link_info) \ |
BFD_SEND (abfd, _bfd_gc_sections, (abfd, link_info)) |
#define bfd_lookup_section_flags(link_info, flag_info, section) \ |
BFD_SEND (abfd, _bfd_lookup_section_flags, (link_info, flag_info, section)) |
#define bfd_merge_sections(abfd, link_info) \ |
BFD_SEND (abfd, _bfd_merge_sections, (abfd, link_info)) |
#define bfd_is_group_section(abfd, sec) \ |
BFD_SEND (abfd, _bfd_is_group_section, (abfd, sec)) |
#define bfd_discard_group(abfd, sec) \ |
BFD_SEND (abfd, _bfd_discard_group, (abfd, sec)) |
#define bfd_link_hash_table_create(abfd) \ |
BFD_SEND (abfd, _bfd_link_hash_table_create, (abfd)) |
#define bfd_link_hash_table_free(abfd, hash) \ |
BFD_SEND (abfd, _bfd_link_hash_table_free, (hash)) |
#define bfd_link_add_symbols(abfd, info) \ |
BFD_SEND (abfd, _bfd_link_add_symbols, (abfd, info)) |
#define bfd_link_just_syms(abfd, sec, info) \ |
BFD_SEND (abfd, _bfd_link_just_syms, (sec, info)) |
#define bfd_final_link(abfd, info) \ |
BFD_SEND (abfd, _bfd_final_link, (abfd, info)) |
#define bfd_free_cached_info(abfd) \ |
BFD_SEND (abfd, _bfd_free_cached_info, (abfd)) |
#define bfd_get_dynamic_symtab_upper_bound(abfd) \ |
BFD_SEND (abfd, _bfd_get_dynamic_symtab_upper_bound, (abfd)) |
#define bfd_print_private_bfd_data(abfd, file)\ |
BFD_SEND (abfd, _bfd_print_private_bfd_data, (abfd, file)) |
#define bfd_canonicalize_dynamic_symtab(abfd, asymbols) \ |
BFD_SEND (abfd, _bfd_canonicalize_dynamic_symtab, (abfd, asymbols)) |
#define bfd_get_synthetic_symtab(abfd, count, syms, dyncount, dynsyms, ret) \ |
BFD_SEND (abfd, _bfd_get_synthetic_symtab, (abfd, count, syms, \ |
dyncount, dynsyms, ret)) |
#define bfd_get_dynamic_reloc_upper_bound(abfd) \ |
BFD_SEND (abfd, _bfd_get_dynamic_reloc_upper_bound, (abfd)) |
#define bfd_canonicalize_dynamic_reloc(abfd, arels, asyms) \ |
BFD_SEND (abfd, _bfd_canonicalize_dynamic_reloc, (abfd, arels, asyms)) |
extern bfd_byte *bfd_get_relocated_section_contents |
(bfd *, struct bfd_link_info *, struct bfd_link_order *, bfd_byte *, |
bfd_boolean, asymbol **); |
bfd_boolean bfd_alt_mach_code (bfd *abfd, int alternative); |
bfd_vma bfd_emul_get_maxpagesize (const char *); |
void bfd_emul_set_maxpagesize (const char *, bfd_vma); |
bfd_vma bfd_emul_get_commonpagesize (const char *); |
void bfd_emul_set_commonpagesize (const char *, bfd_vma); |
char *bfd_demangle (bfd *, const char *, int); |
/* Extracted from archive.c. */ |
symindex bfd_get_next_mapent |
(bfd *abfd, symindex previous, carsym **sym); |
bfd_boolean bfd_set_archive_head (bfd *output, bfd *new_head); |
bfd *bfd_openr_next_archived_file (bfd *archive, bfd *previous); |
/* Extracted from corefile.c. */ |
const char *bfd_core_file_failing_command (bfd *abfd); |
int bfd_core_file_failing_signal (bfd *abfd); |
int bfd_core_file_pid (bfd *abfd); |
bfd_boolean core_file_matches_executable_p |
(bfd *core_bfd, bfd *exec_bfd); |
bfd_boolean generic_core_file_matches_executable_p |
(bfd *core_bfd, bfd *exec_bfd); |
/* Extracted from targets.c. */ |
#define BFD_SEND(bfd, message, arglist) \ |
((*((bfd)->xvec->message)) arglist) |
#ifdef DEBUG_BFD_SEND |
#undef BFD_SEND |
#define BFD_SEND(bfd, message, arglist) \ |
(((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \ |
((*((bfd)->xvec->message)) arglist) : \ |
(bfd_assert (__FILE__,__LINE__), NULL)) |
#endif |
#define BFD_SEND_FMT(bfd, message, arglist) \ |
(((bfd)->xvec->message[(int) ((bfd)->format)]) arglist) |
#ifdef DEBUG_BFD_SEND |
#undef BFD_SEND_FMT |
#define BFD_SEND_FMT(bfd, message, arglist) \ |
(((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \ |
(((bfd)->xvec->message[(int) ((bfd)->format)]) arglist) : \ |
(bfd_assert (__FILE__,__LINE__), NULL)) |
#endif |
enum bfd_flavour |
{ |
bfd_target_unknown_flavour, |
bfd_target_aout_flavour, |
bfd_target_coff_flavour, |
bfd_target_ecoff_flavour, |
bfd_target_xcoff_flavour, |
bfd_target_elf_flavour, |
bfd_target_ieee_flavour, |
bfd_target_nlm_flavour, |
bfd_target_oasys_flavour, |
bfd_target_tekhex_flavour, |
bfd_target_srec_flavour, |
bfd_target_verilog_flavour, |
bfd_target_ihex_flavour, |
bfd_target_som_flavour, |
bfd_target_os9k_flavour, |
bfd_target_versados_flavour, |
bfd_target_msdos_flavour, |
bfd_target_ovax_flavour, |
bfd_target_evax_flavour, |
bfd_target_mmo_flavour, |
bfd_target_mach_o_flavour, |
bfd_target_pef_flavour, |
bfd_target_pef_xlib_flavour, |
bfd_target_sym_flavour |
}; |
enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN }; |
/* Forward declaration. */ |
typedef struct bfd_link_info _bfd_link_info; |
/* Forward declaration. */ |
typedef struct flag_info flag_info; |
typedef struct bfd_target |
{ |
/* Identifies the kind of target, e.g., SunOS4, Ultrix, etc. */ |
char *name; |
/* The "flavour" of a back end is a general indication about |
the contents of a file. */ |
enum bfd_flavour flavour; |
/* The order of bytes within the data area of a file. */ |
enum bfd_endian byteorder; |
/* The order of bytes within the header parts of a file. */ |
enum bfd_endian header_byteorder; |
/* A mask of all the flags which an executable may have set - |
from the set <<BFD_NO_FLAGS>>, <<HAS_RELOC>>, ...<<D_PAGED>>. */ |
flagword object_flags; |
/* A mask of all the flags which a section may have set - from |
the set <<SEC_NO_FLAGS>>, <<SEC_ALLOC>>, ...<<SET_NEVER_LOAD>>. */ |
flagword section_flags; |
/* The character normally found at the front of a symbol. |
(if any), perhaps `_'. */ |
char symbol_leading_char; |
/* The pad character for file names within an archive header. */ |
char ar_pad_char; |
/* The maximum number of characters in an archive header. */ |
unsigned char ar_max_namelen; |
/* How well this target matches, used to select between various |
possible targets when more than one target matches. */ |
unsigned char match_priority; |
/* Entries for byte swapping for data. These are different from the |
other entry points, since they don't take a BFD as the first argument. |
Certain other handlers could do the same. */ |
bfd_uint64_t (*bfd_getx64) (const void *); |
bfd_int64_t (*bfd_getx_signed_64) (const void *); |
void (*bfd_putx64) (bfd_uint64_t, void *); |
bfd_vma (*bfd_getx32) (const void *); |
bfd_signed_vma (*bfd_getx_signed_32) (const void *); |
void (*bfd_putx32) (bfd_vma, void *); |
bfd_vma (*bfd_getx16) (const void *); |
bfd_signed_vma (*bfd_getx_signed_16) (const void *); |
void (*bfd_putx16) (bfd_vma, void *); |
/* Byte swapping for the headers. */ |
bfd_uint64_t (*bfd_h_getx64) (const void *); |
bfd_int64_t (*bfd_h_getx_signed_64) (const void *); |
void (*bfd_h_putx64) (bfd_uint64_t, void *); |
bfd_vma (*bfd_h_getx32) (const void *); |
bfd_signed_vma (*bfd_h_getx_signed_32) (const void *); |
void (*bfd_h_putx32) (bfd_vma, void *); |
bfd_vma (*bfd_h_getx16) (const void *); |
bfd_signed_vma (*bfd_h_getx_signed_16) (const void *); |
void (*bfd_h_putx16) (bfd_vma, void *); |
/* Format dependent routines: these are vectors of entry points |
within the target vector structure, one for each format to check. */ |
/* Check the format of a file being read. Return a <<bfd_target *>> or zero. */ |
const struct bfd_target *(*_bfd_check_format[bfd_type_end]) (bfd *); |
/* Set the format of a file being written. */ |
bfd_boolean (*_bfd_set_format[bfd_type_end]) (bfd *); |
/* Write cached information into a file being written, at <<bfd_close>>. */ |
bfd_boolean (*_bfd_write_contents[bfd_type_end]) (bfd *); |
/* Generic entry points. */ |
#define BFD_JUMP_TABLE_GENERIC(NAME) \ |
NAME##_close_and_cleanup, \ |
NAME##_bfd_free_cached_info, \ |
NAME##_new_section_hook, \ |
NAME##_get_section_contents, \ |
NAME##_get_section_contents_in_window |
/* Called when the BFD is being closed to do any necessary cleanup. */ |
bfd_boolean (*_close_and_cleanup) (bfd *); |
/* Ask the BFD to free all cached information. */ |
bfd_boolean (*_bfd_free_cached_info) (bfd *); |
/* Called when a new section is created. */ |
bfd_boolean (*_new_section_hook) (bfd *, sec_ptr); |
/* Read the contents of a section. */ |
bfd_boolean (*_bfd_get_section_contents) |
(bfd *, sec_ptr, void *, file_ptr, bfd_size_type); |
bfd_boolean (*_bfd_get_section_contents_in_window) |
(bfd *, sec_ptr, bfd_window *, file_ptr, bfd_size_type); |
/* Entry points to copy private data. */ |
#define BFD_JUMP_TABLE_COPY(NAME) \ |
NAME##_bfd_copy_private_bfd_data, \ |
NAME##_bfd_merge_private_bfd_data, \ |
_bfd_generic_init_private_section_data, \ |
NAME##_bfd_copy_private_section_data, \ |
NAME##_bfd_copy_private_symbol_data, \ |
NAME##_bfd_copy_private_header_data, \ |
NAME##_bfd_set_private_flags, \ |
NAME##_bfd_print_private_bfd_data |
/* Called to copy BFD general private data from one object file |
to another. */ |
bfd_boolean (*_bfd_copy_private_bfd_data) (bfd *, bfd *); |
/* Called to merge BFD general private data from one object file |
to a common output file when linking. */ |
bfd_boolean (*_bfd_merge_private_bfd_data) (bfd *, bfd *); |
/* Called to initialize BFD private section data from one object file |
to another. */ |
#define bfd_init_private_section_data(ibfd, isec, obfd, osec, link_info) \ |
BFD_SEND (obfd, _bfd_init_private_section_data, (ibfd, isec, obfd, osec, link_info)) |
bfd_boolean (*_bfd_init_private_section_data) |
(bfd *, sec_ptr, bfd *, sec_ptr, struct bfd_link_info *); |
/* Called to copy BFD private section data from one object file |
to another. */ |
bfd_boolean (*_bfd_copy_private_section_data) |
(bfd *, sec_ptr, bfd *, sec_ptr); |
/* Called to copy BFD private symbol data from one symbol |
to another. */ |
bfd_boolean (*_bfd_copy_private_symbol_data) |
(bfd *, asymbol *, bfd *, asymbol *); |
/* Called to copy BFD private header data from one object file |
to another. */ |
bfd_boolean (*_bfd_copy_private_header_data) |
(bfd *, bfd *); |
/* Called to set private backend flags. */ |
bfd_boolean (*_bfd_set_private_flags) (bfd *, flagword); |
/* Called to print private BFD data. */ |
bfd_boolean (*_bfd_print_private_bfd_data) (bfd *, void *); |
/* Core file entry points. */ |
#define BFD_JUMP_TABLE_CORE(NAME) \ |
NAME##_core_file_failing_command, \ |
NAME##_core_file_failing_signal, \ |
NAME##_core_file_matches_executable_p, \ |
NAME##_core_file_pid |
char * (*_core_file_failing_command) (bfd *); |
int (*_core_file_failing_signal) (bfd *); |
bfd_boolean (*_core_file_matches_executable_p) (bfd *, bfd *); |
int (*_core_file_pid) (bfd *); |
/* Archive entry points. */ |
#define BFD_JUMP_TABLE_ARCHIVE(NAME) \ |
NAME##_slurp_armap, \ |
NAME##_slurp_extended_name_table, \ |
NAME##_construct_extended_name_table, \ |
NAME##_truncate_arname, \ |
NAME##_write_armap, \ |
NAME##_read_ar_hdr, \ |
NAME##_write_ar_hdr, \ |
NAME##_openr_next_archived_file, \ |
NAME##_get_elt_at_index, \ |
NAME##_generic_stat_arch_elt, \ |
NAME##_update_armap_timestamp |
bfd_boolean (*_bfd_slurp_armap) (bfd *); |
bfd_boolean (*_bfd_slurp_extended_name_table) (bfd *); |
bfd_boolean (*_bfd_construct_extended_name_table) |
(bfd *, char **, bfd_size_type *, const char **); |
void (*_bfd_truncate_arname) (bfd *, const char *, char *); |
bfd_boolean (*write_armap) |
(bfd *, unsigned int, struct orl *, unsigned int, int); |
void * (*_bfd_read_ar_hdr_fn) (bfd *); |
bfd_boolean (*_bfd_write_ar_hdr_fn) (bfd *, bfd *); |
bfd * (*openr_next_archived_file) (bfd *, bfd *); |
#define bfd_get_elt_at_index(b,i) BFD_SEND (b, _bfd_get_elt_at_index, (b,i)) |
bfd * (*_bfd_get_elt_at_index) (bfd *, symindex); |
int (*_bfd_stat_arch_elt) (bfd *, struct stat *); |
bfd_boolean (*_bfd_update_armap_timestamp) (bfd *); |
/* Entry points used for symbols. */ |
#define BFD_JUMP_TABLE_SYMBOLS(NAME) \ |
NAME##_get_symtab_upper_bound, \ |
NAME##_canonicalize_symtab, \ |
NAME##_make_empty_symbol, \ |
NAME##_print_symbol, \ |
NAME##_get_symbol_info, \ |
NAME##_bfd_is_local_label_name, \ |
NAME##_bfd_is_target_special_symbol, \ |
NAME##_get_lineno, \ |
NAME##_find_nearest_line, \ |
_bfd_generic_find_nearest_line_discriminator, \ |
_bfd_generic_find_line, \ |
NAME##_find_inliner_info, \ |
NAME##_bfd_make_debug_symbol, \ |
NAME##_read_minisymbols, \ |
NAME##_minisymbol_to_symbol |
long (*_bfd_get_symtab_upper_bound) (bfd *); |
long (*_bfd_canonicalize_symtab) |
(bfd *, struct bfd_symbol **); |
struct bfd_symbol * |
(*_bfd_make_empty_symbol) (bfd *); |
void (*_bfd_print_symbol) |
(bfd *, void *, struct bfd_symbol *, bfd_print_symbol_type); |
#define bfd_print_symbol(b,p,s,e) BFD_SEND (b, _bfd_print_symbol, (b,p,s,e)) |
void (*_bfd_get_symbol_info) |
(bfd *, struct bfd_symbol *, symbol_info *); |
#define bfd_get_symbol_info(b,p,e) BFD_SEND (b, _bfd_get_symbol_info, (b,p,e)) |
bfd_boolean (*_bfd_is_local_label_name) (bfd *, const char *); |
bfd_boolean (*_bfd_is_target_special_symbol) (bfd *, asymbol *); |
alent * (*_get_lineno) (bfd *, struct bfd_symbol *); |
bfd_boolean (*_bfd_find_nearest_line) |
(bfd *, struct bfd_section *, struct bfd_symbol **, bfd_vma, |
const char **, const char **, unsigned int *); |
bfd_boolean (*_bfd_find_nearest_line_discriminator) |
(bfd *, struct bfd_section *, struct bfd_symbol **, bfd_vma, |
const char **, const char **, unsigned int *, unsigned int *); |
bfd_boolean (*_bfd_find_line) |
(bfd *, struct bfd_symbol **, struct bfd_symbol *, |
const char **, unsigned int *); |
bfd_boolean (*_bfd_find_inliner_info) |
(bfd *, const char **, const char **, unsigned int *); |
/* Back-door to allow format-aware applications to create debug symbols |
while using BFD for everything else. Currently used by the assembler |
when creating COFF files. */ |
asymbol * (*_bfd_make_debug_symbol) |
(bfd *, void *, unsigned long size); |
#define bfd_read_minisymbols(b, d, m, s) \ |
BFD_SEND (b, _read_minisymbols, (b, d, m, s)) |
long (*_read_minisymbols) |
(bfd *, bfd_boolean, void **, unsigned int *); |
#define bfd_minisymbol_to_symbol(b, d, m, f) \ |
BFD_SEND (b, _minisymbol_to_symbol, (b, d, m, f)) |
asymbol * (*_minisymbol_to_symbol) |
(bfd *, bfd_boolean, const void *, asymbol *); |
/* Routines for relocs. */ |
#define BFD_JUMP_TABLE_RELOCS(NAME) \ |
NAME##_get_reloc_upper_bound, \ |
NAME##_canonicalize_reloc, \ |
NAME##_bfd_reloc_type_lookup, \ |
NAME##_bfd_reloc_name_lookup |
long (*_get_reloc_upper_bound) (bfd *, sec_ptr); |
long (*_bfd_canonicalize_reloc) |
(bfd *, sec_ptr, arelent **, struct bfd_symbol **); |
/* See documentation on reloc types. */ |
reloc_howto_type * |
(*reloc_type_lookup) (bfd *, bfd_reloc_code_real_type); |
reloc_howto_type * |
(*reloc_name_lookup) (bfd *, const char *); |
/* Routines used when writing an object file. */ |
#define BFD_JUMP_TABLE_WRITE(NAME) \ |
NAME##_set_arch_mach, \ |
NAME##_set_section_contents |
bfd_boolean (*_bfd_set_arch_mach) |
(bfd *, enum bfd_architecture, unsigned long); |
bfd_boolean (*_bfd_set_section_contents) |
(bfd *, sec_ptr, const void *, file_ptr, bfd_size_type); |
/* Routines used by the linker. */ |
#define BFD_JUMP_TABLE_LINK(NAME) \ |
NAME##_sizeof_headers, \ |
NAME##_bfd_get_relocated_section_contents, \ |
NAME##_bfd_relax_section, \ |
NAME##_bfd_link_hash_table_create, \ |
NAME##_bfd_link_hash_table_free, \ |
NAME##_bfd_link_add_symbols, \ |
NAME##_bfd_link_just_syms, \ |
NAME##_bfd_copy_link_hash_symbol_type, \ |
NAME##_bfd_final_link, \ |
NAME##_bfd_link_split_section, \ |
NAME##_bfd_gc_sections, \ |
NAME##_bfd_lookup_section_flags, \ |
NAME##_bfd_merge_sections, \ |
NAME##_bfd_is_group_section, \ |
NAME##_bfd_discard_group, \ |
NAME##_section_already_linked, \ |
NAME##_bfd_define_common_symbol |
int (*_bfd_sizeof_headers) (bfd *, struct bfd_link_info *); |
bfd_byte * (*_bfd_get_relocated_section_contents) |
(bfd *, struct bfd_link_info *, struct bfd_link_order *, |
bfd_byte *, bfd_boolean, struct bfd_symbol **); |
bfd_boolean (*_bfd_relax_section) |
(bfd *, struct bfd_section *, struct bfd_link_info *, bfd_boolean *); |
/* Create a hash table for the linker. Different backends store |
different information in this table. */ |
struct bfd_link_hash_table * |
(*_bfd_link_hash_table_create) (bfd *); |
/* Release the memory associated with the linker hash table. */ |
void (*_bfd_link_hash_table_free) (struct bfd_link_hash_table *); |
/* Add symbols from this object file into the hash table. */ |
bfd_boolean (*_bfd_link_add_symbols) (bfd *, struct bfd_link_info *); |
/* Indicate that we are only retrieving symbol values from this section. */ |
void (*_bfd_link_just_syms) (asection *, struct bfd_link_info *); |
/* Copy the symbol type of a linker hash table entry. */ |
#define bfd_copy_link_hash_symbol_type(b, t, f) \ |
BFD_SEND (b, _bfd_copy_link_hash_symbol_type, (b, t, f)) |
void (*_bfd_copy_link_hash_symbol_type) |
(bfd *, struct bfd_link_hash_entry *, struct bfd_link_hash_entry *); |
/* Do a link based on the link_order structures attached to each |
section of the BFD. */ |
bfd_boolean (*_bfd_final_link) (bfd *, struct bfd_link_info *); |
/* Should this section be split up into smaller pieces during linking. */ |
bfd_boolean (*_bfd_link_split_section) (bfd *, struct bfd_section *); |
/* Remove sections that are not referenced from the output. */ |
bfd_boolean (*_bfd_gc_sections) (bfd *, struct bfd_link_info *); |
/* Sets the bitmask of allowed and disallowed section flags. */ |
bfd_boolean (*_bfd_lookup_section_flags) (struct bfd_link_info *, |
struct flag_info *, |
asection *); |
/* Attempt to merge SEC_MERGE sections. */ |
bfd_boolean (*_bfd_merge_sections) (bfd *, struct bfd_link_info *); |
/* Is this section a member of a group? */ |
bfd_boolean (*_bfd_is_group_section) (bfd *, const struct bfd_section *); |
/* Discard members of a group. */ |
bfd_boolean (*_bfd_discard_group) (bfd *, struct bfd_section *); |
/* Check if SEC has been already linked during a reloceatable or |
final link. */ |
bfd_boolean (*_section_already_linked) (bfd *, asection *, |
struct bfd_link_info *); |
/* Define a common symbol. */ |
bfd_boolean (*_bfd_define_common_symbol) (bfd *, struct bfd_link_info *, |
struct bfd_link_hash_entry *); |
/* Routines to handle dynamic symbols and relocs. */ |
#define BFD_JUMP_TABLE_DYNAMIC(NAME) \ |
NAME##_get_dynamic_symtab_upper_bound, \ |
NAME##_canonicalize_dynamic_symtab, \ |
NAME##_get_synthetic_symtab, \ |
NAME##_get_dynamic_reloc_upper_bound, \ |
NAME##_canonicalize_dynamic_reloc |
/* Get the amount of memory required to hold the dynamic symbols. */ |
long (*_bfd_get_dynamic_symtab_upper_bound) (bfd *); |
/* Read in the dynamic symbols. */ |
long (*_bfd_canonicalize_dynamic_symtab) |
(bfd *, struct bfd_symbol **); |
/* Create synthetized symbols. */ |
long (*_bfd_get_synthetic_symtab) |
(bfd *, long, struct bfd_symbol **, long, struct bfd_symbol **, |
struct bfd_symbol **); |
/* Get the amount of memory required to hold the dynamic relocs. */ |
long (*_bfd_get_dynamic_reloc_upper_bound) (bfd *); |
/* Read in the dynamic relocs. */ |
long (*_bfd_canonicalize_dynamic_reloc) |
(bfd *, arelent **, struct bfd_symbol **); |
/* Opposite endian version of this target. */ |
const struct bfd_target * alternative_target; |
/* Data for use by back-end routines, which isn't |
generic enough to belong in this structure. */ |
const void *backend_data; |
} bfd_target; |
bfd_boolean bfd_set_default_target (const char *name); |
const bfd_target *bfd_find_target (const char *target_name, bfd *abfd); |
const bfd_target *bfd_get_target_info (const char *target_name, |
bfd *abfd, |
bfd_boolean *is_bigendian, |
int *underscoring, |
const char **def_target_arch); |
const char ** bfd_target_list (void); |
const bfd_target *bfd_search_for_target |
(int (*search_func) (const bfd_target *, void *), |
void *); |
/* Extracted from format.c. */ |
bfd_boolean bfd_check_format (bfd *abfd, bfd_format format); |
bfd_boolean bfd_check_format_matches |
(bfd *abfd, bfd_format format, char ***matching); |
bfd_boolean bfd_set_format (bfd *abfd, bfd_format format); |
const char *bfd_format_string (bfd_format format); |
/* Extracted from linker.c. */ |
bfd_boolean bfd_link_split_section (bfd *abfd, asection *sec); |
#define bfd_link_split_section(abfd, sec) \ |
BFD_SEND (abfd, _bfd_link_split_section, (abfd, sec)) |
bfd_boolean bfd_section_already_linked (bfd *abfd, |
asection *sec, |
struct bfd_link_info *info); |
#define bfd_section_already_linked(abfd, sec, info) \ |
BFD_SEND (abfd, _section_already_linked, (abfd, sec, info)) |
bfd_boolean bfd_generic_define_common_symbol |
(bfd *output_bfd, struct bfd_link_info *info, |
struct bfd_link_hash_entry *h); |
#define bfd_define_common_symbol(output_bfd, info, h) \ |
BFD_SEND (output_bfd, _bfd_define_common_symbol, (output_bfd, info, h)) |
struct bfd_elf_version_tree * bfd_find_version_for_sym |
(struct bfd_elf_version_tree *verdefs, |
const char *sym_name, bfd_boolean *hide); |
bfd_boolean bfd_hide_sym_by_version |
(struct bfd_elf_version_tree *verdefs, const char *sym_name); |
/* Extracted from simple.c. */ |
bfd_byte *bfd_simple_get_relocated_section_contents |
(bfd *abfd, asection *sec, bfd_byte *outbuf, asymbol **symbol_table); |
/* Extracted from compress.c. */ |
bfd_boolean bfd_compress_section_contents |
(bfd *abfd, asection *section, bfd_byte *uncompressed_buffer, |
bfd_size_type uncompressed_size); |
bfd_boolean bfd_get_full_section_contents |
(bfd *abfd, asection *section, bfd_byte **ptr); |
void bfd_cache_section_contents |
(asection *sec, void *contents); |
bfd_boolean bfd_is_section_compressed |
(bfd *abfd, asection *section); |
bfd_boolean bfd_init_section_decompress_status |
(bfd *abfd, asection *section); |
bfd_boolean bfd_init_section_compress_status |
(bfd *abfd, asection *section); |
#ifdef __cplusplus |
} |
#endif |
#endif |
/contrib/toolchain/binutils/bfd/bfd_stdint.h |
---|
0,0 → 1,47 |
/* generated for gcc.exe (GCC) 4.8.1 */ |
#ifndef GCC_GENERATED_STDINT_H |
#define GCC_GENERATED_STDINT_H 1 |
#include <sys/types.h> |
#include <stdint.h> |
/* glibc uses these symbols as guards to prevent redefinitions. */ |
#ifdef __int8_t_defined |
#define _INT8_T |
#define _INT16_T |
#define _INT32_T |
#endif |
#ifdef __uint32_t_defined |
#define _UINT32_T |
#endif |
/* Some systems have guard macros to prevent redefinitions, define them. */ |
#ifndef _INT8_T |
#define _INT8_T |
#endif |
#ifndef _INT16_T |
#define _INT16_T |
#endif |
#ifndef _INT32_T |
#define _INT32_T |
#endif |
#ifndef _UINT8_T |
#define _UINT8_T |
#endif |
#ifndef _UINT16_T |
#define _UINT16_T |
#endif |
#ifndef _UINT32_T |
#define _UINT32_T |
#endif |
/* system headers have good uint64_t and int64_t */ |
#ifndef _INT64_T |
#define _INT64_T |
#endif |
#ifndef _UINT64_T |
#define _UINT64_T |
#endif |
#endif /* GCC_GENERATED_STDINT_H */ |
/contrib/toolchain/binutils/bfd/bfdio.c |
---|
0,0 → 1,621 |
/* Low-level I/O routines for BFDs. |
Copyright 1990-2013 Free Software Foundation, Inc. |
Written by Cygnus Support. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include <limits.h> |
#include "bfd.h" |
#include "libbfd.h" |
#ifndef S_IXUSR |
#define S_IXUSR 0100 /* Execute by owner. */ |
#endif |
#ifndef S_IXGRP |
#define S_IXGRP 0010 /* Execute by group. */ |
#endif |
#ifndef S_IXOTH |
#define S_IXOTH 0001 /* Execute by others. */ |
#endif |
#ifndef FD_CLOEXEC |
#define FD_CLOEXEC 1 |
#endif |
file_ptr |
real_ftell (FILE *file) |
{ |
#if defined (HAVE_FTELLO64) |
return ftello64 (file); |
#elif defined (HAVE_FTELLO) |
return ftello (file); |
#else |
return ftell (file); |
#endif |
} |
int |
real_fseek (FILE *file, file_ptr offset, int whence) |
{ |
#if defined (HAVE_FSEEKO64) |
return fseeko64 (file, offset, whence); |
#elif defined (HAVE_FSEEKO) |
return fseeko (file, offset, whence); |
#else |
return fseek (file, offset, whence); |
#endif |
} |
/* Mark FILE as close-on-exec. Return FILE. FILE may be NULL, in |
which case nothing is done. */ |
static FILE * |
close_on_exec (FILE *file) |
{ |
#if defined (HAVE_FILENO) && defined (F_GETFD) |
if (file) |
{ |
int fd = fileno (file); |
int old = fcntl (fd, F_GETFD, 0); |
if (old >= 0) |
fcntl (fd, F_SETFD, old | FD_CLOEXEC); |
} |
#endif |
return file; |
} |
FILE * |
real_fopen (const char *filename, const char *modes) |
{ |
#ifdef VMS |
char *vms_attr; |
/* On VMS, fopen allows file attributes as optional arguments. |
We need to use them but we'd better to use the common prototype. |
In fopen-vms.h, they are separated from the mode with a comma. |
Split here. */ |
vms_attr = strchr (modes, ','); |
if (vms_attr == NULL) |
{ |
/* No attributes. */ |
return close_on_exec (fopen (filename, modes)); |
} |
else |
{ |
/* Attributes found. Split. */ |
size_t modes_len = strlen (modes) + 1; |
char attrs[modes_len + 1]; |
char *at[3]; |
int i; |
memcpy (attrs, modes, modes_len); |
at[0] = attrs; |
for (i = 0; i < 2; i++) |
{ |
at[i + 1] = strchr (at[i], ','); |
BFD_ASSERT (at[i + 1] != NULL); |
*(at[i + 1]++) = 0; /* Replace ',' with a nul, and skip it. */ |
} |
return close_on_exec (fopen (filename, at[0], at[1], at[2])); |
} |
#else /* !VMS */ |
#if defined (HAVE_FOPEN64) |
return close_on_exec (fopen64 (filename, modes)); |
#else |
return close_on_exec (fopen (filename, modes)); |
#endif |
#endif /* !VMS */ |
} |
/* |
INTERNAL_DEFINITION |
struct bfd_iovec |
DESCRIPTION |
The <<struct bfd_iovec>> contains the internal file I/O class. |
Each <<BFD>> has an instance of this class and all file I/O is |
routed through it (it is assumed that the instance implements |
all methods listed below). |
.struct bfd_iovec |
.{ |
. {* To avoid problems with macros, a "b" rather than "f" |
. prefix is prepended to each method name. *} |
. {* Attempt to read/write NBYTES on ABFD's IOSTREAM storing/fetching |
. bytes starting at PTR. Return the number of bytes actually |
. transfered (a read past end-of-file returns less than NBYTES), |
. or -1 (setting <<bfd_error>>) if an error occurs. *} |
. file_ptr (*bread) (struct bfd *abfd, void *ptr, file_ptr nbytes); |
. file_ptr (*bwrite) (struct bfd *abfd, const void *ptr, |
. file_ptr nbytes); |
. {* Return the current IOSTREAM file offset, or -1 (setting <<bfd_error>> |
. if an error occurs. *} |
. file_ptr (*btell) (struct bfd *abfd); |
. {* For the following, on successful completion a value of 0 is returned. |
. Otherwise, a value of -1 is returned (and <<bfd_error>> is set). *} |
. int (*bseek) (struct bfd *abfd, file_ptr offset, int whence); |
. int (*bclose) (struct bfd *abfd); |
. int (*bflush) (struct bfd *abfd); |
. int (*bstat) (struct bfd *abfd, struct stat *sb); |
. {* Mmap a part of the files. ADDR, LEN, PROT, FLAGS and OFFSET are the usual |
. mmap parameter, except that LEN and OFFSET do not need to be page |
. aligned. Returns (void *)-1 on failure, mmapped address on success. |
. Also write in MAP_ADDR the address of the page aligned buffer and in |
. MAP_LEN the size mapped (a page multiple). Use unmap with MAP_ADDR and |
. MAP_LEN to unmap. *} |
. void *(*bmmap) (struct bfd *abfd, void *addr, bfd_size_type len, |
. int prot, int flags, file_ptr offset, |
. void **map_addr, bfd_size_type *map_len); |
.}; |
.extern const struct bfd_iovec _bfd_memory_iovec; |
*/ |
/* Return value is amount read. */ |
bfd_size_type |
bfd_bread (void *ptr, bfd_size_type size, bfd *abfd) |
{ |
size_t nread; |
/* If this is an archive element, don't read past the end of |
this element. */ |
if (abfd->arelt_data != NULL) |
{ |
bfd_size_type maxbytes = arelt_size (abfd); |
if (abfd->where + size > maxbytes) |
{ |
if (abfd->where >= maxbytes) |
return 0; |
size = maxbytes - abfd->where; |
} |
} |
if (abfd->iovec) |
nread = abfd->iovec->bread (abfd, ptr, size); |
else |
nread = 0; |
if (nread != (size_t) -1) |
abfd->where += nread; |
return nread; |
} |
bfd_size_type |
bfd_bwrite (const void *ptr, bfd_size_type size, bfd *abfd) |
{ |
size_t nwrote; |
if (abfd->iovec) |
nwrote = abfd->iovec->bwrite (abfd, ptr, size); |
else |
nwrote = 0; |
if (nwrote != (size_t) -1) |
abfd->where += nwrote; |
if (nwrote != size) |
{ |
#ifdef ENOSPC |
errno = ENOSPC; |
#endif |
bfd_set_error (bfd_error_system_call); |
} |
return nwrote; |
} |
file_ptr |
bfd_tell (bfd *abfd) |
{ |
file_ptr ptr; |
if (abfd->iovec) |
{ |
bfd *parent_bfd = abfd; |
ptr = abfd->iovec->btell (abfd); |
while (parent_bfd->my_archive != NULL) |
{ |
ptr -= parent_bfd->origin; |
parent_bfd = parent_bfd->my_archive; |
} |
} |
else |
ptr = 0; |
abfd->where = ptr; |
return ptr; |
} |
int |
bfd_flush (bfd *abfd) |
{ |
if (abfd->iovec) |
return abfd->iovec->bflush (abfd); |
return 0; |
} |
/* Returns 0 for success, negative value for failure (in which case |
bfd_get_error can retrieve the error code). */ |
int |
bfd_stat (bfd *abfd, struct stat *statbuf) |
{ |
int result; |
if (abfd->iovec) |
result = abfd->iovec->bstat (abfd, statbuf); |
else |
result = -1; |
if (result < 0) |
bfd_set_error (bfd_error_system_call); |
return result; |
} |
/* Returns 0 for success, nonzero for failure (in which case bfd_get_error |
can retrieve the error code). */ |
int |
bfd_seek (bfd *abfd, file_ptr position, int direction) |
{ |
int result; |
file_ptr file_position; |
/* For the time being, a BFD may not seek to it's end. The problem |
is that we don't easily have a way to recognize the end of an |
element in an archive. */ |
BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR); |
if (direction == SEEK_CUR && position == 0) |
return 0; |
if (abfd->format != bfd_archive && abfd->my_archive == 0) |
{ |
if (direction == SEEK_SET && (bfd_vma) position == abfd->where) |
return 0; |
} |
else |
{ |
/* We need something smarter to optimize access to archives. |
Currently, anything inside an archive is read via the file |
handle for the archive. Which means that a bfd_seek on one |
component affects the `current position' in the archive, as |
well as in any other component. |
It might be sufficient to put a spike through the cache |
abstraction, and look to the archive for the file position, |
but I think we should try for something cleaner. |
In the meantime, no optimization for archives. */ |
} |
file_position = position; |
if (direction == SEEK_SET) |
{ |
bfd *parent_bfd = abfd; |
while (parent_bfd->my_archive != NULL) |
{ |
file_position += parent_bfd->origin; |
parent_bfd = parent_bfd->my_archive; |
} |
} |
if (abfd->iovec) |
result = abfd->iovec->bseek (abfd, file_position, direction); |
else |
result = -1; |
if (result != 0) |
{ |
int hold_errno = errno; |
/* Force redetermination of `where' field. */ |
bfd_tell (abfd); |
/* An EINVAL error probably means that the file offset was |
absurd. */ |
if (hold_errno == EINVAL) |
bfd_set_error (bfd_error_file_truncated); |
else |
{ |
bfd_set_error (bfd_error_system_call); |
errno = hold_errno; |
} |
} |
else |
{ |
/* Adjust `where' field. */ |
if (direction == SEEK_SET) |
abfd->where = position; |
else |
abfd->where += position; |
} |
return result; |
} |
/* |
FUNCTION |
bfd_get_mtime |
SYNOPSIS |
long bfd_get_mtime (bfd *abfd); |
DESCRIPTION |
Return the file modification time (as read from the file system, or |
from the archive header for archive members). |
*/ |
long |
bfd_get_mtime (bfd *abfd) |
{ |
struct stat buf; |
if (abfd->mtime_set) |
return abfd->mtime; |
if (abfd->iovec == NULL) |
return 0; |
if (abfd->iovec->bstat (abfd, &buf) != 0) |
return 0; |
abfd->mtime = buf.st_mtime; /* Save value in case anyone wants it */ |
return buf.st_mtime; |
} |
/* |
FUNCTION |
bfd_get_size |
SYNOPSIS |
file_ptr bfd_get_size (bfd *abfd); |
DESCRIPTION |
Return the file size (as read from file system) for the file |
associated with BFD @var{abfd}. |
The initial motivation for, and use of, this routine is not |
so we can get the exact size of the object the BFD applies to, since |
that might not be generally possible (archive members for example). |
It would be ideal if someone could eventually modify |
it so that such results were guaranteed. |
Instead, we want to ask questions like "is this NNN byte sized |
object I'm about to try read from file offset YYY reasonable?" |
As as example of where we might do this, some object formats |
use string tables for which the first <<sizeof (long)>> bytes of the |
table contain the size of the table itself, including the size bytes. |
If an application tries to read what it thinks is one of these |
string tables, without some way to validate the size, and for |
some reason the size is wrong (byte swapping error, wrong location |
for the string table, etc.), the only clue is likely to be a read |
error when it tries to read the table, or a "virtual memory |
exhausted" error when it tries to allocate 15 bazillon bytes |
of space for the 15 bazillon byte table it is about to read. |
This function at least allows us to answer the question, "is the |
size reasonable?". |
*/ |
file_ptr |
bfd_get_size (bfd *abfd) |
{ |
struct stat buf; |
if (abfd->iovec == NULL) |
return 0; |
if (abfd->iovec->bstat (abfd, &buf) != 0) |
return 0; |
return buf.st_size; |
} |
/* |
FUNCTION |
bfd_mmap |
SYNOPSIS |
void *bfd_mmap (bfd *abfd, void *addr, bfd_size_type len, |
int prot, int flags, file_ptr offset, |
void **map_addr, bfd_size_type *map_len); |
DESCRIPTION |
Return mmap()ed region of the file, if possible and implemented. |
LEN and OFFSET do not need to be page aligned. The page aligned |
address and length are written to MAP_ADDR and MAP_LEN. |
*/ |
void * |
bfd_mmap (bfd *abfd, void *addr, bfd_size_type len, |
int prot, int flags, file_ptr offset, |
void **map_addr, bfd_size_type *map_len) |
{ |
void *ret = (void *)-1; |
if (abfd->iovec == NULL) |
return ret; |
return abfd->iovec->bmmap (abfd, addr, len, prot, flags, offset, |
map_addr, map_len); |
} |
/* Memory file I/O operations. */ |
static file_ptr |
memory_bread (bfd *abfd, void *ptr, file_ptr size) |
{ |
struct bfd_in_memory *bim; |
bfd_size_type get; |
bim = (struct bfd_in_memory *) abfd->iostream; |
get = size; |
if (abfd->where + get > bim->size) |
{ |
if (bim->size < (bfd_size_type) abfd->where) |
get = 0; |
else |
get = bim->size - abfd->where; |
bfd_set_error (bfd_error_file_truncated); |
} |
memcpy (ptr, bim->buffer + abfd->where, (size_t) get); |
return get; |
} |
static file_ptr |
memory_bwrite (bfd *abfd, const void *ptr, file_ptr size) |
{ |
struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream; |
if (abfd->where + size > bim->size) |
{ |
bfd_size_type newsize, oldsize; |
oldsize = (bim->size + 127) & ~(bfd_size_type) 127; |
bim->size = abfd->where + size; |
/* Round up to cut down on memory fragmentation */ |
newsize = (bim->size + 127) & ~(bfd_size_type) 127; |
if (newsize > oldsize) |
{ |
bim->buffer = (bfd_byte *) bfd_realloc_or_free (bim->buffer, newsize); |
if (bim->buffer == NULL) |
{ |
bim->size = 0; |
return 0; |
} |
if (newsize > bim->size) |
memset (bim->buffer + bim->size, 0, newsize - bim->size); |
} |
} |
memcpy (bim->buffer + abfd->where, ptr, (size_t) size); |
return size; |
} |
static file_ptr |
memory_btell (bfd *abfd) |
{ |
return abfd->where; |
} |
static int |
memory_bseek (bfd *abfd, file_ptr position, int direction) |
{ |
file_ptr nwhere; |
struct bfd_in_memory *bim; |
bim = (struct bfd_in_memory *) abfd->iostream; |
if (direction == SEEK_SET) |
nwhere = position; |
else |
nwhere = abfd->where + position; |
if (nwhere < 0) |
{ |
abfd->where = 0; |
errno = EINVAL; |
return -1; |
} |
if ((bfd_size_type)nwhere > bim->size) |
{ |
if (abfd->direction == write_direction |
|| abfd->direction == both_direction) |
{ |
bfd_size_type newsize, oldsize; |
oldsize = (bim->size + 127) & ~(bfd_size_type) 127; |
bim->size = nwhere; |
/* Round up to cut down on memory fragmentation */ |
newsize = (bim->size + 127) & ~(bfd_size_type) 127; |
if (newsize > oldsize) |
{ |
bim->buffer = (bfd_byte *) bfd_realloc_or_free (bim->buffer, newsize); |
if (bim->buffer == NULL) |
{ |
errno = EINVAL; |
bim->size = 0; |
return -1; |
} |
memset (bim->buffer + oldsize, 0, newsize - oldsize); |
} |
} |
else |
{ |
abfd->where = bim->size; |
errno = EINVAL; |
bfd_set_error (bfd_error_file_truncated); |
return -1; |
} |
} |
return 0; |
} |
static int |
memory_bclose (struct bfd *abfd) |
{ |
struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream; |
if (bim->buffer != NULL) |
free (bim->buffer); |
free (bim); |
abfd->iostream = NULL; |
return 0; |
} |
static int |
memory_bflush (bfd *abfd ATTRIBUTE_UNUSED) |
{ |
return 0; |
} |
static int |
memory_bstat (bfd *abfd, struct stat *statbuf) |
{ |
struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream; |
memset (statbuf, 0, sizeof (*statbuf)); |
statbuf->st_size = bim->size; |
return 0; |
} |
static void * |
memory_bmmap (bfd *abfd ATTRIBUTE_UNUSED, void *addr ATTRIBUTE_UNUSED, |
bfd_size_type len ATTRIBUTE_UNUSED, int prot ATTRIBUTE_UNUSED, |
int flags ATTRIBUTE_UNUSED, file_ptr offset ATTRIBUTE_UNUSED, |
void **map_addr ATTRIBUTE_UNUSED, |
bfd_size_type *map_len ATTRIBUTE_UNUSED) |
{ |
return (void *)-1; |
} |
const struct bfd_iovec _bfd_memory_iovec = |
{ |
&memory_bread, &memory_bwrite, &memory_btell, &memory_bseek, |
&memory_bclose, &memory_bflush, &memory_bstat, &memory_bmmap |
}; |
/contrib/toolchain/binutils/bfd/bfdver.h |
---|
0,0 → 1,4 |
#define BFD_VERSION_DATE 20131202 |
#define BFD_VERSION 224000000 |
#define BFD_VERSION_STRING "(GNU Binutils) " "2.24" |
#define REPORT_BUGS_TO "<http://www.sourceware.org/bugzilla/>" |
/contrib/toolchain/binutils/bfd/binary.c |
---|
0,0 → 1,369 |
/* BFD back-end for binary objects. |
Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, |
2004, 2005, 2006, 2007, 2009, 2011 Free Software Foundation, Inc. |
Written by Ian Lance Taylor, Cygnus Support, <ian@cygnus.com> |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* This is a BFD backend which may be used to write binary objects. |
It may only be used for output, not input. The intention is that |
this may be used as an output format for objcopy in order to |
generate raw binary data. |
This is very simple. The only complication is that the real data |
will start at some address X, and in some cases we will not want to |
include X zeroes just to get to that point. Since the start |
address is not meaningful for this object file format, we use it |
instead to indicate the number of zeroes to skip at the start of |
the file. objcopy cooperates by specially setting the start |
address to zero by default. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "safe-ctype.h" |
#include "libbfd.h" |
/* Any bfd we create by reading a binary file has three symbols: |
a start symbol, an end symbol, and an absolute length symbol. */ |
#define BIN_SYMS 3 |
/* Create a binary object. Invoked via bfd_set_format. */ |
static bfd_boolean |
binary_mkobject (bfd *abfd ATTRIBUTE_UNUSED) |
{ |
return TRUE; |
} |
/* Any file may be considered to be a binary file, provided the target |
was not defaulted. That is, it must be explicitly specified as |
being binary. */ |
static const bfd_target * |
binary_object_p (bfd *abfd) |
{ |
struct stat statbuf; |
asection *sec; |
flagword flags; |
if (abfd->target_defaulted) |
{ |
bfd_set_error (bfd_error_wrong_format); |
return NULL; |
} |
abfd->symcount = BIN_SYMS; |
/* Find the file size. */ |
if (bfd_stat (abfd, &statbuf) < 0) |
{ |
bfd_set_error (bfd_error_system_call); |
return NULL; |
} |
/* One data section. */ |
flags = SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS; |
sec = bfd_make_section_with_flags (abfd, ".data", flags); |
if (sec == NULL) |
return NULL; |
sec->vma = 0; |
sec->size = statbuf.st_size; |
sec->filepos = 0; |
abfd->tdata.any = (void *) sec; |
return abfd->xvec; |
} |
#define binary_close_and_cleanup _bfd_generic_close_and_cleanup |
#define binary_bfd_free_cached_info _bfd_generic_bfd_free_cached_info |
#define binary_new_section_hook _bfd_generic_new_section_hook |
/* Get contents of the only section. */ |
static bfd_boolean |
binary_get_section_contents (bfd *abfd, |
asection *section ATTRIBUTE_UNUSED, |
void * location, |
file_ptr offset, |
bfd_size_type count) |
{ |
if (bfd_seek (abfd, offset, SEEK_SET) != 0 |
|| bfd_bread (location, count, abfd) != count) |
return FALSE; |
return TRUE; |
} |
/* Return the amount of memory needed to read the symbol table. */ |
static long |
binary_get_symtab_upper_bound (bfd *abfd ATTRIBUTE_UNUSED) |
{ |
return (BIN_SYMS + 1) * sizeof (asymbol *); |
} |
/* Create a symbol name based on the bfd's filename. */ |
static char * |
mangle_name (bfd *abfd, char *suffix) |
{ |
bfd_size_type size; |
char *buf; |
char *p; |
size = (strlen (bfd_get_filename (abfd)) |
+ strlen (suffix) |
+ sizeof "_binary__"); |
buf = (char *) bfd_alloc (abfd, size); |
if (buf == NULL) |
return ""; |
sprintf (buf, "_binary_%s_%s", bfd_get_filename (abfd), suffix); |
/* Change any non-alphanumeric characters to underscores. */ |
for (p = buf; *p; p++) |
if (! ISALNUM (*p)) |
*p = '_'; |
return buf; |
} |
/* Return the symbol table. */ |
static long |
binary_canonicalize_symtab (bfd *abfd, asymbol **alocation) |
{ |
asection *sec = (asection *) abfd->tdata.any; |
asymbol *syms; |
unsigned int i; |
bfd_size_type amt = BIN_SYMS * sizeof (asymbol); |
syms = (asymbol *) bfd_alloc (abfd, amt); |
if (syms == NULL) |
return -1; |
/* Start symbol. */ |
syms[0].the_bfd = abfd; |
syms[0].name = mangle_name (abfd, "start"); |
syms[0].value = 0; |
syms[0].flags = BSF_GLOBAL; |
syms[0].section = sec; |
syms[0].udata.p = NULL; |
/* End symbol. */ |
syms[1].the_bfd = abfd; |
syms[1].name = mangle_name (abfd, "end"); |
syms[1].value = sec->size; |
syms[1].flags = BSF_GLOBAL; |
syms[1].section = sec; |
syms[1].udata.p = NULL; |
/* Size symbol. */ |
syms[2].the_bfd = abfd; |
syms[2].name = mangle_name (abfd, "size"); |
syms[2].value = sec->size; |
syms[2].flags = BSF_GLOBAL; |
syms[2].section = bfd_abs_section_ptr; |
syms[2].udata.p = NULL; |
for (i = 0; i < BIN_SYMS; i++) |
*alocation++ = syms++; |
*alocation = NULL; |
return BIN_SYMS; |
} |
#define binary_make_empty_symbol _bfd_generic_make_empty_symbol |
#define binary_print_symbol _bfd_nosymbols_print_symbol |
/* Get information about a symbol. */ |
static void |
binary_get_symbol_info (bfd *ignore_abfd ATTRIBUTE_UNUSED, |
asymbol *symbol, |
symbol_info *ret) |
{ |
bfd_symbol_info (symbol, ret); |
} |
#define binary_bfd_is_local_label_name bfd_generic_is_local_label_name |
#define binary_get_lineno _bfd_nosymbols_get_lineno |
#define binary_find_nearest_line _bfd_nosymbols_find_nearest_line |
#define binary_find_inliner_info _bfd_nosymbols_find_inliner_info |
#define binary_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol |
#define binary_read_minisymbols _bfd_generic_read_minisymbols |
#define binary_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol |
#define binary_bfd_is_target_special_symbol ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) |
/* Set the architecture of a binary file. */ |
#define binary_set_arch_mach _bfd_generic_set_arch_mach |
/* Write section contents of a binary file. */ |
static bfd_boolean |
binary_set_section_contents (bfd *abfd, |
asection *sec, |
const void * data, |
file_ptr offset, |
bfd_size_type size) |
{ |
if (size == 0) |
return TRUE; |
if (! abfd->output_has_begun) |
{ |
bfd_boolean found_low; |
bfd_vma low; |
asection *s; |
/* The lowest section LMA sets the virtual address of the start |
of the file. We use this to set the file position of all the |
sections. */ |
found_low = FALSE; |
low = 0; |
for (s = abfd->sections; s != NULL; s = s->next) |
if (((s->flags |
& (SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC | SEC_NEVER_LOAD)) |
== (SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC)) |
&& (s->size > 0) |
&& (! found_low || s->lma < low)) |
{ |
low = s->lma; |
found_low = TRUE; |
} |
for (s = abfd->sections; s != NULL; s = s->next) |
{ |
s->filepos = s->lma - low; |
/* Skip following warning check for sections that will not |
occupy file space. */ |
if ((s->flags |
& (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_NEVER_LOAD)) |
!= (SEC_HAS_CONTENTS | SEC_ALLOC) |
|| (s->size == 0)) |
continue; |
/* If attempting to generate a binary file from a bfd with |
LMA's all over the place, huge (sparse?) binary files may |
result. This condition attempts to detect this situation |
and print a warning. Better heuristics would be nice to |
have. */ |
if (s->filepos < 0) |
(*_bfd_error_handler) |
(_("Warning: Writing section `%s' to huge (ie negative) file offset 0x%lx."), |
bfd_get_section_name (abfd, s), |
(unsigned long) s->filepos); |
} |
abfd->output_has_begun = TRUE; |
} |
/* We don't want to output anything for a section that is neither |
loaded nor allocated. The contents of such a section are not |
meaningful in the binary format. */ |
if ((sec->flags & (SEC_LOAD | SEC_ALLOC)) == 0) |
return TRUE; |
if ((sec->flags & SEC_NEVER_LOAD) != 0) |
return TRUE; |
return _bfd_generic_set_section_contents (abfd, sec, data, offset, size); |
} |
/* No space is required for header information. */ |
static int |
binary_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED, |
struct bfd_link_info *info ATTRIBUTE_UNUSED) |
{ |
return 0; |
} |
#define binary_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents |
#define binary_bfd_relax_section bfd_generic_relax_section |
#define binary_bfd_gc_sections bfd_generic_gc_sections |
#define binary_bfd_lookup_section_flags bfd_generic_lookup_section_flags |
#define binary_bfd_merge_sections bfd_generic_merge_sections |
#define binary_bfd_is_group_section bfd_generic_is_group_section |
#define binary_bfd_discard_group bfd_generic_discard_group |
#define binary_section_already_linked _bfd_generic_section_already_linked |
#define binary_bfd_define_common_symbol bfd_generic_define_common_symbol |
#define binary_bfd_link_hash_table_create _bfd_generic_link_hash_table_create |
#define binary_bfd_link_hash_table_free _bfd_generic_link_hash_table_free |
#define binary_bfd_link_just_syms _bfd_generic_link_just_syms |
#define binary_bfd_copy_link_hash_symbol_type \ |
_bfd_generic_copy_link_hash_symbol_type |
#define binary_bfd_link_add_symbols _bfd_generic_link_add_symbols |
#define binary_bfd_final_link _bfd_generic_final_link |
#define binary_bfd_link_split_section _bfd_generic_link_split_section |
#define binary_get_section_contents_in_window _bfd_generic_get_section_contents_in_window |
const bfd_target binary_vec = |
{ |
"binary", /* name */ |
bfd_target_unknown_flavour, /* flavour */ |
BFD_ENDIAN_UNKNOWN, /* byteorder */ |
BFD_ENDIAN_UNKNOWN, /* header_byteorder */ |
EXEC_P, /* object_flags */ |
(SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_DATA |
| SEC_ROM | SEC_HAS_CONTENTS), /* section_flags */ |
0, /* symbol_leading_char */ |
' ', /* ar_pad_char */ |
16, /* ar_max_namelen */ |
255, /* match priority. */ |
bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ |
bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ |
{ /* bfd_check_format */ |
_bfd_dummy_target, |
binary_object_p, |
_bfd_dummy_target, |
_bfd_dummy_target, |
}, |
{ /* bfd_set_format */ |
bfd_false, |
binary_mkobject, |
bfd_false, |
bfd_false, |
}, |
{ /* bfd_write_contents */ |
bfd_false, |
bfd_true, |
bfd_false, |
bfd_false, |
}, |
BFD_JUMP_TABLE_GENERIC (binary), |
BFD_JUMP_TABLE_COPY (_bfd_generic), |
BFD_JUMP_TABLE_CORE (_bfd_nocore), |
BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), |
BFD_JUMP_TABLE_SYMBOLS (binary), |
BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), |
BFD_JUMP_TABLE_WRITE (binary), |
BFD_JUMP_TABLE_LINK (binary), |
BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), |
NULL, |
NULL |
}; |
/contrib/toolchain/binutils/bfd/cache.c |
---|
0,0 → 1,645 |
/* BFD library -- caching of file descriptors. |
Copyright 1990, 1991, 1992, 1993, 1994, 1996, 2000, 2001, 2002, |
2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc. |
Hacked by Steve Chamberlain of Cygnus Support (steve@cygnus.com). |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* |
SECTION |
File caching |
The file caching mechanism is embedded within BFD and allows |
the application to open as many BFDs as it wants without |
regard to the underlying operating system's file descriptor |
limit (often as low as 20 open files). The module in |
<<cache.c>> maintains a least recently used list of |
<<bfd_cache_max_open>> files, and exports the name |
<<bfd_cache_lookup>>, which runs around and makes sure that |
the required BFD is open. If not, then it chooses a file to |
close, closes it and opens the one wanted, returning its file |
handle. |
SUBSECTION |
Caching functions |
*/ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
#include "libiberty.h" |
#include "bfd_stdint.h" |
#ifdef HAVE_MMAP |
#include <sys/mman.h> |
#endif |
/* In some cases we can optimize cache operation when reopening files. |
For instance, a flush is entirely unnecessary if the file is already |
closed, so a flush would use CACHE_NO_OPEN. Similarly, a seek using |
SEEK_SET or SEEK_END need not first seek to the current position. |
For stat we ignore seek errors, just in case the file has changed |
while we weren't looking. If it has, then it's possible that the |
file is shorter and we don't want a seek error to prevent us doing |
the stat. */ |
enum cache_flag { |
CACHE_NORMAL = 0, |
CACHE_NO_OPEN = 1, |
CACHE_NO_SEEK = 2, |
CACHE_NO_SEEK_ERROR = 4 |
}; |
/* The maximum number of files which the cache will keep open at |
one time. When needed call bfd_cache_max_open to initialize. */ |
static int max_open_files = 0; |
/* Set max_open_files, if not already set, to 12.5% of the allowed open |
file descriptors, but at least 10, and return the value. */ |
static int |
bfd_cache_max_open (void) |
{ |
if (max_open_files == 0) |
{ |
int max; |
#ifdef HAVE_GETRLIMIT |
struct rlimit rlim; |
if (getrlimit (RLIMIT_NOFILE, &rlim) == 0 |
&& rlim.rlim_cur != RLIM_INFINITY) |
max = rlim.rlim_cur / 8; |
else |
#endif /* HAVE_GETRLIMIT */ |
#ifdef _SC_OPEN_MAX |
max = sysconf (_SC_OPEN_MAX) / 8; |
#else |
max = 10; |
#endif /* _SC_OPEN_MAX */ |
max_open_files = max < 10 ? 10 : max; |
} |
return max_open_files; |
} |
/* The number of BFD files we have open. */ |
static int open_files; |
/* Zero, or a pointer to the topmost BFD on the chain. This is |
used by the <<bfd_cache_lookup>> macro in @file{libbfd.h} to |
determine when it can avoid a function call. */ |
static bfd *bfd_last_cache = NULL; |
/* Insert a BFD into the cache. */ |
static void |
insert (bfd *abfd) |
{ |
if (bfd_last_cache == NULL) |
{ |
abfd->lru_next = abfd; |
abfd->lru_prev = abfd; |
} |
else |
{ |
abfd->lru_next = bfd_last_cache; |
abfd->lru_prev = bfd_last_cache->lru_prev; |
abfd->lru_prev->lru_next = abfd; |
abfd->lru_next->lru_prev = abfd; |
} |
bfd_last_cache = abfd; |
} |
/* Remove a BFD from the cache. */ |
static void |
snip (bfd *abfd) |
{ |
abfd->lru_prev->lru_next = abfd->lru_next; |
abfd->lru_next->lru_prev = abfd->lru_prev; |
if (abfd == bfd_last_cache) |
{ |
bfd_last_cache = abfd->lru_next; |
if (abfd == bfd_last_cache) |
bfd_last_cache = NULL; |
} |
} |
/* Close a BFD and remove it from the cache. */ |
static bfd_boolean |
bfd_cache_delete (bfd *abfd) |
{ |
bfd_boolean ret; |
if (fclose ((FILE *) abfd->iostream) == 0) |
ret = TRUE; |
else |
{ |
ret = FALSE; |
bfd_set_error (bfd_error_system_call); |
} |
snip (abfd); |
abfd->iostream = NULL; |
--open_files; |
return ret; |
} |
/* We need to open a new file, and the cache is full. Find the least |
recently used cacheable BFD and close it. */ |
static bfd_boolean |
close_one (void) |
{ |
register bfd *to_kill; |
if (bfd_last_cache == NULL) |
to_kill = NULL; |
else |
{ |
for (to_kill = bfd_last_cache->lru_prev; |
! to_kill->cacheable; |
to_kill = to_kill->lru_prev) |
{ |
if (to_kill == bfd_last_cache) |
{ |
to_kill = NULL; |
break; |
} |
} |
} |
if (to_kill == NULL) |
{ |
/* There are no open cacheable BFD's. */ |
return TRUE; |
} |
to_kill->where = real_ftell ((FILE *) to_kill->iostream); |
return bfd_cache_delete (to_kill); |
} |
/* Check to see if the required BFD is the same as the last one |
looked up. If so, then it can use the stream in the BFD with |
impunity, since it can't have changed since the last lookup; |
otherwise, it has to perform the complicated lookup function. */ |
#define bfd_cache_lookup(x, flag) \ |
((x) == bfd_last_cache \ |
? (FILE *) (bfd_last_cache->iostream) \ |
: bfd_cache_lookup_worker (x, flag)) |
/* Called when the macro <<bfd_cache_lookup>> fails to find a |
quick answer. Find a file descriptor for @var{abfd}. If |
necessary, it open it. If there are already more than |
<<bfd_cache_max_open>> files open, it tries to close one first, to |
avoid running out of file descriptors. It will return NULL |
if it is unable to (re)open the @var{abfd}. */ |
static FILE * |
bfd_cache_lookup_worker (bfd *abfd, enum cache_flag flag) |
{ |
bfd *orig_bfd = abfd; |
if ((abfd->flags & BFD_IN_MEMORY) != 0) |
abort (); |
while (abfd->my_archive) |
abfd = abfd->my_archive; |
if (abfd->iostream != NULL) |
{ |
/* Move the file to the start of the cache. */ |
if (abfd != bfd_last_cache) |
{ |
snip (abfd); |
insert (abfd); |
} |
return (FILE *) abfd->iostream; |
} |
if (flag & CACHE_NO_OPEN) |
return NULL; |
if (bfd_open_file (abfd) == NULL) |
; |
else if (!(flag & CACHE_NO_SEEK) |
&& real_fseek ((FILE *) abfd->iostream, abfd->where, SEEK_SET) != 0 |
&& !(flag & CACHE_NO_SEEK_ERROR)) |
bfd_set_error (bfd_error_system_call); |
else |
return (FILE *) abfd->iostream; |
(*_bfd_error_handler) (_("reopening %B: %s\n"), |
orig_bfd, bfd_errmsg (bfd_get_error ())); |
return NULL; |
} |
static file_ptr |
cache_btell (struct bfd *abfd) |
{ |
FILE *f = bfd_cache_lookup (abfd, CACHE_NO_OPEN); |
if (f == NULL) |
return abfd->where; |
return real_ftell (f); |
} |
static int |
cache_bseek (struct bfd *abfd, file_ptr offset, int whence) |
{ |
FILE *f = bfd_cache_lookup (abfd, whence != SEEK_CUR ? CACHE_NO_SEEK : CACHE_NORMAL); |
if (f == NULL) |
return -1; |
return real_fseek (f, offset, whence); |
} |
/* Note that archive entries don't have streams; they share their parent's. |
This allows someone to play with the iostream behind BFD's back. |
Also, note that the origin pointer points to the beginning of a file's |
contents (0 for non-archive elements). For archive entries this is the |
first octet in the file, NOT the beginning of the archive header. */ |
static file_ptr |
cache_bread_1 (struct bfd *abfd, void *buf, file_ptr nbytes) |
{ |
FILE *f; |
file_ptr nread; |
/* FIXME - this looks like an optimization, but it's really to cover |
up for a feature of some OSs (not solaris - sigh) that |
ld/pe-dll.c takes advantage of (apparently) when it creates BFDs |
internally and tries to link against them. BFD seems to be smart |
enough to realize there are no symbol records in the "file" that |
doesn't exist but attempts to read them anyway. On Solaris, |
attempting to read zero bytes from a NULL file results in a core |
dump, but on other platforms it just returns zero bytes read. |
This makes it to something reasonable. - DJ */ |
if (nbytes == 0) |
return 0; |
f = bfd_cache_lookup (abfd, CACHE_NORMAL); |
if (f == NULL) |
return 0; |
#if defined (__VAX) && defined (VMS) |
/* Apparently fread on Vax VMS does not keep the record length |
information. */ |
nread = read (fileno (f), buf, nbytes); |
/* Set bfd_error if we did not read as much data as we expected. If |
the read failed due to an error set the bfd_error_system_call, |
else set bfd_error_file_truncated. */ |
if (nread == (file_ptr)-1) |
{ |
bfd_set_error (bfd_error_system_call); |
return -1; |
} |
#else |
nread = fread (buf, 1, nbytes, f); |
/* Set bfd_error if we did not read as much data as we expected. If |
the read failed due to an error set the bfd_error_system_call, |
else set bfd_error_file_truncated. */ |
if (nread < nbytes && ferror (f)) |
{ |
bfd_set_error (bfd_error_system_call); |
return -1; |
} |
#endif |
if (nread < nbytes) |
/* This may or may not be an error, but in case the calling code |
bails out because of it, set the right error code. */ |
bfd_set_error (bfd_error_file_truncated); |
return nread; |
} |
static file_ptr |
cache_bread (struct bfd *abfd, void *buf, file_ptr nbytes) |
{ |
file_ptr nread = 0; |
/* Some filesystems are unable to handle reads that are too large |
(for instance, NetApp shares with oplocks turned off). To avoid |
hitting this limitation, we read the buffer in chunks of 8MB max. */ |
while (nread < nbytes) |
{ |
const file_ptr max_chunk_size = 0x800000; |
file_ptr chunk_size = nbytes - nread; |
file_ptr chunk_nread; |
if (chunk_size > max_chunk_size) |
chunk_size = max_chunk_size; |
chunk_nread = cache_bread_1 (abfd, (char *) buf + nread, chunk_size); |
/* Update the nread count. |
We just have to be careful of the case when cache_bread_1 returns |
a negative count: If this is our first read, then set nread to |
that negative count in order to return that negative value to the |
caller. Otherwise, don't add it to our total count, or we would |
end up returning a smaller number of bytes read than we actually |
did. */ |
if (nread == 0 || chunk_nread > 0) |
nread += chunk_nread; |
if (chunk_nread < chunk_size) |
break; |
} |
return nread; |
} |
static file_ptr |
cache_bwrite (struct bfd *abfd, const void *where, file_ptr nbytes) |
{ |
file_ptr nwrite; |
FILE *f = bfd_cache_lookup (abfd, CACHE_NORMAL); |
if (f == NULL) |
return 0; |
nwrite = fwrite (where, 1, nbytes, f); |
if (nwrite < nbytes && ferror (f)) |
{ |
bfd_set_error (bfd_error_system_call); |
return -1; |
} |
return nwrite; |
} |
static int |
cache_bclose (struct bfd *abfd) |
{ |
return bfd_cache_close (abfd) - 1; |
} |
static int |
cache_bflush (struct bfd *abfd) |
{ |
int sts; |
FILE *f = bfd_cache_lookup (abfd, CACHE_NO_OPEN); |
if (f == NULL) |
return 0; |
sts = fflush (f); |
if (sts < 0) |
bfd_set_error (bfd_error_system_call); |
return sts; |
} |
static int |
cache_bstat (struct bfd *abfd, struct stat *sb) |
{ |
int sts; |
FILE *f = bfd_cache_lookup (abfd, CACHE_NO_SEEK_ERROR); |
if (f == NULL) |
return -1; |
sts = fstat (fileno (f), sb); |
if (sts < 0) |
bfd_set_error (bfd_error_system_call); |
return sts; |
} |
static void * |
cache_bmmap (struct bfd *abfd ATTRIBUTE_UNUSED, |
void *addr ATTRIBUTE_UNUSED, |
bfd_size_type len ATTRIBUTE_UNUSED, |
int prot ATTRIBUTE_UNUSED, |
int flags ATTRIBUTE_UNUSED, |
file_ptr offset ATTRIBUTE_UNUSED, |
void **map_addr ATTRIBUTE_UNUSED, |
bfd_size_type *map_len ATTRIBUTE_UNUSED) |
{ |
void *ret = (void *) -1; |
if ((abfd->flags & BFD_IN_MEMORY) != 0) |
abort (); |
#ifdef HAVE_MMAP |
else |
{ |
static uintptr_t pagesize_m1; |
FILE *f; |
file_ptr pg_offset; |
bfd_size_type pg_len; |
f = bfd_cache_lookup (abfd, CACHE_NO_SEEK_ERROR); |
if (f == NULL) |
return ret; |
if (pagesize_m1 == 0) |
pagesize_m1 = getpagesize () - 1; |
/* Handle archive members. */ |
if (abfd->my_archive != NULL) |
offset += abfd->origin; |
/* Align. */ |
pg_offset = offset & ~pagesize_m1; |
pg_len = (len + (offset - pg_offset) + pagesize_m1) & ~pagesize_m1; |
ret = mmap (addr, pg_len, prot, flags, fileno (f), pg_offset); |
if (ret == (void *) -1) |
bfd_set_error (bfd_error_system_call); |
else |
{ |
*map_addr = ret; |
*map_len = pg_len; |
ret = (char *) ret + (offset & pagesize_m1); |
} |
} |
#endif |
return ret; |
} |
static const struct bfd_iovec cache_iovec = |
{ |
&cache_bread, &cache_bwrite, &cache_btell, &cache_bseek, |
&cache_bclose, &cache_bflush, &cache_bstat, &cache_bmmap |
}; |
/* |
INTERNAL_FUNCTION |
bfd_cache_init |
SYNOPSIS |
bfd_boolean bfd_cache_init (bfd *abfd); |
DESCRIPTION |
Add a newly opened BFD to the cache. |
*/ |
bfd_boolean |
bfd_cache_init (bfd *abfd) |
{ |
BFD_ASSERT (abfd->iostream != NULL); |
if (open_files >= bfd_cache_max_open ()) |
{ |
if (! close_one ()) |
return FALSE; |
} |
abfd->iovec = &cache_iovec; |
insert (abfd); |
++open_files; |
return TRUE; |
} |
/* |
INTERNAL_FUNCTION |
bfd_cache_close |
SYNOPSIS |
bfd_boolean bfd_cache_close (bfd *abfd); |
DESCRIPTION |
Remove the BFD @var{abfd} from the cache. If the attached file is open, |
then close it too. |
RETURNS |
<<FALSE>> is returned if closing the file fails, <<TRUE>> is |
returned if all is well. |
*/ |
bfd_boolean |
bfd_cache_close (bfd *abfd) |
{ |
if (abfd->iovec != &cache_iovec) |
return TRUE; |
if (abfd->iostream == NULL) |
/* Previously closed. */ |
return TRUE; |
return bfd_cache_delete (abfd); |
} |
/* |
FUNCTION |
bfd_cache_close_all |
SYNOPSIS |
bfd_boolean bfd_cache_close_all (void); |
DESCRIPTION |
Remove all BFDs from the cache. If the attached file is open, |
then close it too. |
RETURNS |
<<FALSE>> is returned if closing one of the file fails, <<TRUE>> is |
returned if all is well. |
*/ |
bfd_boolean |
bfd_cache_close_all () |
{ |
bfd_boolean ret = TRUE; |
while (bfd_last_cache != NULL) |
ret &= bfd_cache_close (bfd_last_cache); |
return ret; |
} |
/* |
INTERNAL_FUNCTION |
bfd_open_file |
SYNOPSIS |
FILE* bfd_open_file (bfd *abfd); |
DESCRIPTION |
Call the OS to open a file for @var{abfd}. Return the <<FILE *>> |
(possibly <<NULL>>) that results from this operation. Set up the |
BFD so that future accesses know the file is open. If the <<FILE *>> |
returned is <<NULL>>, then it won't have been put in the |
cache, so it won't have to be removed from it. |
*/ |
FILE * |
bfd_open_file (bfd *abfd) |
{ |
abfd->cacheable = TRUE; /* Allow it to be closed later. */ |
if (open_files >= bfd_cache_max_open ()) |
{ |
if (! close_one ()) |
return NULL; |
} |
switch (abfd->direction) |
{ |
case read_direction: |
case no_direction: |
abfd->iostream = real_fopen (abfd->filename, FOPEN_RB); |
break; |
case both_direction: |
case write_direction: |
if (abfd->opened_once) |
{ |
abfd->iostream = real_fopen (abfd->filename, FOPEN_RUB); |
if (abfd->iostream == NULL) |
abfd->iostream = real_fopen (abfd->filename, FOPEN_WUB); |
} |
else |
{ |
/* Create the file. |
Some operating systems won't let us overwrite a running |
binary. For them, we want to unlink the file first. |
However, gcc 2.95 will create temporary files using |
O_EXCL and tight permissions to prevent other users from |
substituting other .o files during the compilation. gcc |
will then tell the assembler to use the newly created |
file as an output file. If we unlink the file here, we |
open a brief window when another user could still |
substitute a file. |
So we unlink the output file if and only if it has |
non-zero size. */ |
#ifndef __MSDOS__ |
/* Don't do this for MSDOS: it doesn't care about overwriting |
a running binary, but if this file is already open by |
another BFD, we will be in deep trouble if we delete an |
open file. In fact, objdump does just that if invoked with |
the --info option. */ |
struct stat s; |
if (stat (abfd->filename, &s) == 0 && s.st_size != 0) |
unlink_if_ordinary (abfd->filename); |
#endif |
abfd->iostream = real_fopen (abfd->filename, FOPEN_WUB); |
abfd->opened_once = TRUE; |
} |
break; |
} |
if (abfd->iostream == NULL) |
bfd_set_error (bfd_error_system_call); |
else |
{ |
if (! bfd_cache_init (abfd)) |
return NULL; |
} |
return (FILE *) abfd->iostream; |
} |
/contrib/toolchain/binutils/bfd/coff-i386.c |
---|
0,0 → 1,681 |
/* BFD back-end for Intel 386 COFF files. |
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, |
2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011, 2012 |
Free Software Foundation, Inc. |
Written by Cygnus Support. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
#include "coff/i386.h" |
#include "coff/internal.h" |
#ifdef COFF_WITH_PE |
#include "coff/pe.h" |
#endif |
#ifdef COFF_GO32_EXE |
#include "coff/go32exe.h" |
#endif |
#ifndef bfd_pe_print_pdata |
#define bfd_pe_print_pdata NULL |
#endif |
#include "libcoff.h" |
static reloc_howto_type *coff_i386_rtype_to_howto |
(bfd *, asection *, struct internal_reloc *, |
struct coff_link_hash_entry *, struct internal_syment *, |
bfd_vma *); |
static reloc_howto_type *coff_i386_reloc_type_lookup |
(bfd *, bfd_reloc_code_real_type); |
#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2) |
/* The page size is a guess based on ELF. */ |
#define COFF_PAGE_SIZE 0x1000 |
/* For some reason when using i386 COFF the value stored in the .text |
section for a reference to a common symbol is the value itself plus |
any desired offset. Ian Taylor, Cygnus Support. */ |
/* If we are producing relocatable output, we need to do some |
adjustments to the object file that are not done by the |
bfd_perform_relocation function. This function is called by every |
reloc type to make any required adjustments. */ |
static bfd_reloc_status_type |
coff_i386_reloc (bfd *abfd, |
arelent *reloc_entry, |
asymbol *symbol, |
void * data, |
asection *input_section ATTRIBUTE_UNUSED, |
bfd *output_bfd, |
char **error_message ATTRIBUTE_UNUSED) |
{ |
symvalue diff; |
#ifndef COFF_WITH_PE |
if (output_bfd == (bfd *) NULL) |
return bfd_reloc_continue; |
#endif |
if (bfd_is_com_section (symbol->section)) |
{ |
#ifndef COFF_WITH_PE |
/* We are relocating a common symbol. The current value in the |
object file is ORIG + OFFSET, where ORIG is the value of the |
common symbol as seen by the object file when it was compiled |
(this may be zero if the symbol was undefined) and OFFSET is |
the offset into the common symbol (normally zero, but may be |
non-zero when referring to a field in a common structure). |
ORIG is the negative of reloc_entry->addend, which is set by |
the CALC_ADDEND macro below. We want to replace the value in |
the object file with NEW + OFFSET, where NEW is the value of |
the common symbol which we are going to put in the final |
object file. NEW is symbol->value. */ |
diff = symbol->value + reloc_entry->addend; |
#else |
/* In PE mode, we do not offset the common symbol. */ |
diff = reloc_entry->addend; |
#endif |
} |
else |
{ |
/* For some reason bfd_perform_relocation always effectively |
ignores the addend for a COFF target when producing |
relocatable output. This seems to be always wrong for 386 |
COFF, so we handle the addend here instead. */ |
#ifdef COFF_WITH_PE |
if (output_bfd == (bfd *) NULL) |
{ |
reloc_howto_type *howto = reloc_entry->howto; |
/* Although PC relative relocations are very similar between |
PE and non-PE formats, but they are off by 1 << howto->size |
bytes. For the external relocation, PE is very different |
from others. See md_apply_fix3 () in gas/config/tc-i386.c. |
When we link PE and non-PE object files together to |
generate a non-PE executable, we have to compensate it |
here. */ |
if (howto->pc_relative && howto->pcrel_offset) |
diff = -(1 << howto->size); |
else if (symbol->flags & BSF_WEAK) |
diff = reloc_entry->addend - symbol->value; |
else |
diff = -reloc_entry->addend; |
} |
else |
#endif |
diff = reloc_entry->addend; |
} |
#ifdef COFF_WITH_PE |
/* FIXME: How should this case be handled? */ |
if (reloc_entry->howto->type == R_IMAGEBASE |
&& output_bfd != NULL |
&& bfd_get_flavour(output_bfd) == bfd_target_coff_flavour) |
diff -= pe_data (output_bfd)->pe_opthdr.ImageBase; |
#endif |
#define DOIT(x) \ |
x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask)) |
if (diff != 0) |
{ |
reloc_howto_type *howto = reloc_entry->howto; |
unsigned char *addr = (unsigned char *) data + reloc_entry->address; |
switch (howto->size) |
{ |
case 0: |
{ |
char x = bfd_get_8 (abfd, addr); |
DOIT (x); |
bfd_put_8 (abfd, x, addr); |
} |
break; |
case 1: |
{ |
short x = bfd_get_16 (abfd, addr); |
DOIT (x); |
bfd_put_16 (abfd, (bfd_vma) x, addr); |
} |
break; |
case 2: |
{ |
long x = bfd_get_32 (abfd, addr); |
DOIT (x); |
bfd_put_32 (abfd, (bfd_vma) x, addr); |
} |
break; |
default: |
abort (); |
} |
} |
/* Now let bfd_perform_relocation finish everything up. */ |
return bfd_reloc_continue; |
} |
#ifdef COFF_WITH_PE |
/* Return TRUE if this relocation should appear in the output .reloc |
section. */ |
static bfd_boolean in_reloc_p (bfd * abfd ATTRIBUTE_UNUSED, |
reloc_howto_type *howto) |
{ |
return ! howto->pc_relative && howto->type != R_IMAGEBASE |
&& howto->type != R_SECREL32; |
} |
#endif /* COFF_WITH_PE */ |
#ifndef PCRELOFFSET |
#define PCRELOFFSET FALSE |
#endif |
static reloc_howto_type howto_table[] = |
{ |
EMPTY_HOWTO (0), |
EMPTY_HOWTO (1), |
EMPTY_HOWTO (2), |
EMPTY_HOWTO (3), |
EMPTY_HOWTO (4), |
EMPTY_HOWTO (5), |
HOWTO (R_DIR32, /* type */ |
0, /* rightshift */ |
2, /* size (0 = byte, 1 = short, 2 = long) */ |
32, /* bitsize */ |
FALSE, /* pc_relative */ |
0, /* bitpos */ |
complain_overflow_bitfield, /* complain_on_overflow */ |
coff_i386_reloc, /* special_function */ |
"dir32", /* name */ |
TRUE, /* partial_inplace */ |
0xffffffff, /* src_mask */ |
0xffffffff, /* dst_mask */ |
TRUE), /* pcrel_offset */ |
/* PE IMAGE_REL_I386_DIR32NB relocation (7). */ |
HOWTO (R_IMAGEBASE, /* type */ |
0, /* rightshift */ |
2, /* size (0 = byte, 1 = short, 2 = long) */ |
32, /* bitsize */ |
FALSE, /* pc_relative */ |
0, /* bitpos */ |
complain_overflow_bitfield, /* complain_on_overflow */ |
coff_i386_reloc, /* special_function */ |
"rva32", /* name */ |
TRUE, /* partial_inplace */ |
0xffffffff, /* src_mask */ |
0xffffffff, /* dst_mask */ |
FALSE), /* pcrel_offset */ |
EMPTY_HOWTO (010), |
EMPTY_HOWTO (011), |
EMPTY_HOWTO (012), |
#ifdef COFF_WITH_PE |
/* 32-bit longword section relative relocation (013). */ |
HOWTO (R_SECREL32, /* type */ |
0, /* rightshift */ |
2, /* size (0 = byte, 1 = short, 2 = long) */ |
32, /* bitsize */ |
FALSE, /* pc_relative */ |
0, /* bitpos */ |
complain_overflow_bitfield, /* complain_on_overflow */ |
coff_i386_reloc, /* special_function */ |
"secrel32", /* name */ |
TRUE, /* partial_inplace */ |
0xffffffff, /* src_mask */ |
0xffffffff, /* dst_mask */ |
TRUE), /* pcrel_offset */ |
#else |
EMPTY_HOWTO (013), |
#endif |
EMPTY_HOWTO (014), |
EMPTY_HOWTO (015), |
EMPTY_HOWTO (016), |
/* Byte relocation (017). */ |
HOWTO (R_RELBYTE, /* type */ |
0, /* rightshift */ |
0, /* size (0 = byte, 1 = short, 2 = long) */ |
8, /* bitsize */ |
FALSE, /* pc_relative */ |
0, /* bitpos */ |
complain_overflow_bitfield, /* complain_on_overflow */ |
coff_i386_reloc, /* special_function */ |
"8", /* name */ |
TRUE, /* partial_inplace */ |
0x000000ff, /* src_mask */ |
0x000000ff, /* dst_mask */ |
PCRELOFFSET), /* pcrel_offset */ |
/* 16-bit word relocation (020). */ |
HOWTO (R_RELWORD, /* type */ |
0, /* rightshift */ |
1, /* size (0 = byte, 1 = short, 2 = long) */ |
16, /* bitsize */ |
FALSE, /* pc_relative */ |
0, /* bitpos */ |
complain_overflow_bitfield, /* complain_on_overflow */ |
coff_i386_reloc, /* special_function */ |
"16", /* name */ |
TRUE, /* partial_inplace */ |
0x0000ffff, /* src_mask */ |
0x0000ffff, /* dst_mask */ |
PCRELOFFSET), /* pcrel_offset */ |
/* 32-bit longword relocation (021). */ |
HOWTO (R_RELLONG, /* type */ |
0, /* rightshift */ |
2, /* size (0 = byte, 1 = short, 2 = long) */ |
32, /* bitsize */ |
FALSE, /* pc_relative */ |
0, /* bitpos */ |
complain_overflow_bitfield, /* complain_on_overflow */ |
coff_i386_reloc, /* special_function */ |
"32", /* name */ |
TRUE, /* partial_inplace */ |
0xffffffff, /* src_mask */ |
0xffffffff, /* dst_mask */ |
PCRELOFFSET), /* pcrel_offset */ |
/* Byte PC relative relocation (022). */ |
HOWTO (R_PCRBYTE, /* type */ |
0, /* rightshift */ |
0, /* size (0 = byte, 1 = short, 2 = long) */ |
8, /* bitsize */ |
TRUE, /* pc_relative */ |
0, /* bitpos */ |
complain_overflow_signed, /* complain_on_overflow */ |
coff_i386_reloc, /* special_function */ |
"DISP8", /* name */ |
TRUE, /* partial_inplace */ |
0x000000ff, /* src_mask */ |
0x000000ff, /* dst_mask */ |
PCRELOFFSET), /* pcrel_offset */ |
/* 16-bit word PC relative relocation (023). */ |
HOWTO (R_PCRWORD, /* type */ |
0, /* rightshift */ |
1, /* size (0 = byte, 1 = short, 2 = long) */ |
16, /* bitsize */ |
TRUE, /* pc_relative */ |
0, /* bitpos */ |
complain_overflow_signed, /* complain_on_overflow */ |
coff_i386_reloc, /* special_function */ |
"DISP16", /* name */ |
TRUE, /* partial_inplace */ |
0x0000ffff, /* src_mask */ |
0x0000ffff, /* dst_mask */ |
PCRELOFFSET), /* pcrel_offset */ |
/* 32-bit longword PC relative relocation (024). */ |
HOWTO (R_PCRLONG, /* type */ |
0, /* rightshift */ |
2, /* size (0 = byte, 1 = short, 2 = long) */ |
32, /* bitsize */ |
TRUE, /* pc_relative */ |
0, /* bitpos */ |
complain_overflow_signed, /* complain_on_overflow */ |
coff_i386_reloc, /* special_function */ |
"DISP32", /* name */ |
TRUE, /* partial_inplace */ |
0xffffffff, /* src_mask */ |
0xffffffff, /* dst_mask */ |
PCRELOFFSET) /* pcrel_offset */ |
}; |
/* Turn a howto into a reloc nunmber */ |
#define SELECT_RELOC(x,howto) { x.r_type = howto->type; } |
#define BADMAG(x) I386BADMAG(x) |
#define I386 1 /* Customize coffcode.h */ |
#define RTYPE2HOWTO(cache_ptr, dst) \ |
((cache_ptr)->howto = \ |
((dst)->r_type < sizeof (howto_table) / sizeof (howto_table[0]) \ |
? howto_table + (dst)->r_type \ |
: NULL)) |
/* For 386 COFF a STYP_NOLOAD | STYP_BSS section is part of a shared |
library. On some other COFF targets STYP_BSS is normally |
STYP_NOLOAD. */ |
#define BSS_NOLOAD_IS_SHARED_LIBRARY |
/* Compute the addend of a reloc. If the reloc is to a common symbol, |
the object file contains the value of the common symbol. By the |
time this is called, the linker may be using a different symbol |
from a different object file with a different value. Therefore, we |
hack wildly to locate the original symbol from this file so that we |
can make the correct adjustment. This macro sets coffsym to the |
symbol from the original file, and uses it to set the addend value |
correctly. If this is not a common symbol, the usual addend |
calculation is done, except that an additional tweak is needed for |
PC relative relocs. |
FIXME: This macro refers to symbols and asect; these are from the |
calling function, not the macro arguments. */ |
#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr) \ |
{ \ |
coff_symbol_type *coffsym = (coff_symbol_type *) NULL; \ |
if (ptr && bfd_asymbol_bfd (ptr) != abfd) \ |
coffsym = (obj_symbols (abfd) \ |
+ (cache_ptr->sym_ptr_ptr - symbols)); \ |
else if (ptr) \ |
coffsym = coff_symbol_from (abfd, ptr); \ |
if (coffsym != (coff_symbol_type *) NULL \ |
&& coffsym->native->u.syment.n_scnum == 0) \ |
cache_ptr->addend = - coffsym->native->u.syment.n_value; \ |
else if (ptr && bfd_asymbol_bfd (ptr) == abfd \ |
&& ptr->section != (asection *) NULL) \ |
cache_ptr->addend = - (ptr->section->vma + ptr->value); \ |
else \ |
cache_ptr->addend = 0; \ |
if (ptr && howto_table[reloc.r_type].pc_relative) \ |
cache_ptr->addend += asect->vma; \ |
} |
/* We use the special COFF backend linker. For normal i386 COFF, we |
can use the generic relocate_section routine. For PE, we need our |
own routine. */ |
#ifndef COFF_WITH_PE |
#define coff_relocate_section _bfd_coff_generic_relocate_section |
#else /* COFF_WITH_PE */ |
/* The PE relocate section routine. The only difference between this |
and the regular routine is that we don't want to do anything for a |
relocatable link. */ |
static bfd_boolean |
coff_pe_i386_relocate_section (bfd *output_bfd, |
struct bfd_link_info *info, |
bfd *input_bfd, |
asection *input_section, |
bfd_byte *contents, |
struct internal_reloc *relocs, |
struct internal_syment *syms, |
asection **sections) |
{ |
if (info->relocatable) |
return TRUE; |
return _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd, |
input_section, contents, |
relocs, syms, sections); |
} |
#define coff_relocate_section coff_pe_i386_relocate_section |
#endif /* COFF_WITH_PE */ |
/* Convert an rtype to howto for the COFF backend linker. */ |
static reloc_howto_type * |
coff_i386_rtype_to_howto (bfd *abfd ATTRIBUTE_UNUSED, |
asection *sec, |
struct internal_reloc *rel, |
struct coff_link_hash_entry *h, |
struct internal_syment *sym, |
bfd_vma *addendp) |
{ |
reloc_howto_type *howto; |
if (rel->r_type >= sizeof (howto_table) / sizeof (howto_table[0])) |
{ |
bfd_set_error (bfd_error_bad_value); |
return NULL; |
} |
howto = howto_table + rel->r_type; |
#ifdef COFF_WITH_PE |
/* Cancel out code in _bfd_coff_generic_relocate_section. */ |
*addendp = 0; |
#endif |
if (howto->pc_relative) |
*addendp += sec->vma; |
if (sym != NULL && sym->n_scnum == 0 && sym->n_value != 0) |
{ |
/* This is a common symbol. The section contents include the |
size (sym->n_value) as an addend. The relocate_section |
function will be adding in the final value of the symbol. We |
need to subtract out the current size in order to get the |
correct result. */ |
BFD_ASSERT (h != NULL); |
#ifndef COFF_WITH_PE |
/* I think we *do* want to bypass this. If we don't, I have |
seen some data parameters get the wrong relocation address. |
If I link two versions with and without this section bypassed |
and then do a binary comparison, the addresses which are |
different can be looked up in the map. The case in which |
this section has been bypassed has addresses which correspond |
to values I can find in the map. */ |
*addendp -= sym->n_value; |
#endif |
} |
#ifndef COFF_WITH_PE |
/* If the output symbol is common (in which case this must be a |
relocatable link), we need to add in the final size of the |
common symbol. */ |
if (h != NULL && h->root.type == bfd_link_hash_common) |
*addendp += h->root.u.c.size; |
#endif |
#ifdef COFF_WITH_PE |
if (howto->pc_relative) |
{ |
*addendp -= 4; |
/* If the symbol is defined, then the generic code is going to |
add back the symbol value in order to cancel out an |
adjustment it made to the addend. However, we set the addend |
to 0 at the start of this function. We need to adjust here, |
to avoid the adjustment the generic code will make. FIXME: |
This is getting a bit hackish. */ |
if (sym != NULL && sym->n_scnum != 0) |
*addendp -= sym->n_value; |
} |
if (rel->r_type == R_IMAGEBASE |
&& (bfd_get_flavour(sec->output_section->owner) |
== bfd_target_coff_flavour)) |
{ |
*addendp -= pe_data(sec->output_section->owner)->pe_opthdr.ImageBase; |
} |
BFD_ASSERT (sym != NULL); |
if (rel->r_type == R_SECREL32 && sym != NULL) |
{ |
bfd_vma osect_vma; |
if (h && (h->root.type == bfd_link_hash_defined |
|| h->root.type == bfd_link_hash_defweak)) |
osect_vma = h->root.u.def.section->output_section->vma; |
else |
{ |
asection *s; |
int i; |
/* Sigh, the only way to get the section to offset against |
is to find it the hard way. */ |
for (s = abfd->sections, i = 1; i < sym->n_scnum; i++) |
s = s->next; |
osect_vma = s->output_section->vma; |
} |
*addendp -= osect_vma; |
} |
#endif |
return howto; |
} |
#define coff_bfd_reloc_type_lookup coff_i386_reloc_type_lookup |
#define coff_bfd_reloc_name_lookup coff_i386_reloc_name_lookup |
static reloc_howto_type * |
coff_i386_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, |
bfd_reloc_code_real_type code) |
{ |
switch (code) |
{ |
case BFD_RELOC_RVA: |
return howto_table + R_IMAGEBASE; |
case BFD_RELOC_32: |
return howto_table + R_DIR32; |
case BFD_RELOC_32_PCREL: |
return howto_table + R_PCRLONG; |
case BFD_RELOC_16: |
return howto_table + R_RELWORD; |
case BFD_RELOC_16_PCREL: |
return howto_table + R_PCRWORD; |
case BFD_RELOC_8: |
return howto_table + R_RELBYTE; |
case BFD_RELOC_8_PCREL: |
return howto_table + R_PCRBYTE; |
#ifdef COFF_WITH_PE |
case BFD_RELOC_32_SECREL: |
return howto_table + R_SECREL32; |
#endif |
default: |
BFD_FAIL (); |
return 0; |
} |
} |
static reloc_howto_type * |
coff_i386_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, |
const char *r_name) |
{ |
unsigned int i; |
for (i = 0; i < sizeof (howto_table) / sizeof (howto_table[0]); i++) |
if (howto_table[i].name != NULL |
&& strcasecmp (howto_table[i].name, r_name) == 0) |
return &howto_table[i]; |
return NULL; |
} |
#define coff_rtype_to_howto coff_i386_rtype_to_howto |
#ifdef TARGET_UNDERSCORE |
/* If i386 gcc uses underscores for symbol names, then it does not use |
a leading dot for local labels, so if TARGET_UNDERSCORE is defined |
we treat all symbols starting with L as local. */ |
static bfd_boolean |
coff_i386_is_local_label_name (bfd *abfd, const char *name) |
{ |
if (name[0] == 'L') |
return TRUE; |
return _bfd_coff_is_local_label_name (abfd, name); |
} |
#define coff_bfd_is_local_label_name coff_i386_is_local_label_name |
#endif /* TARGET_UNDERSCORE */ |
#include "coffcode.h" |
#define _bfd_generic_find_nearest_line_discriminator \ |
coff_find_nearest_line_discriminator |
const bfd_target |
#ifdef TARGET_SYM |
TARGET_SYM = |
#else |
i386coff_vec = |
#endif |
{ |
#ifdef TARGET_NAME |
TARGET_NAME, |
#else |
"coff-i386", /* name */ |
#endif |
bfd_target_coff_flavour, |
BFD_ENDIAN_LITTLE, /* data byte order is little */ |
BFD_ENDIAN_LITTLE, /* header byte order is little */ |
(HAS_RELOC | EXEC_P | /* object flags */ |
HAS_LINENO | HAS_DEBUG | |
HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED | BFD_COMPRESS | BFD_DECOMPRESS ), |
(SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC /* section flags */ |
#ifdef COFF_WITH_PE |
| SEC_LINK_ONCE | SEC_LINK_DUPLICATES | SEC_READONLY | SEC_DEBUGGING |
#endif |
| SEC_CODE | SEC_DATA | SEC_EXCLUDE ), |
#ifdef TARGET_UNDERSCORE |
TARGET_UNDERSCORE, /* leading underscore */ |
#else |
0, /* leading underscore */ |
#endif |
'/', /* ar_pad_char */ |
15, /* ar_max_namelen */ |
0, /* match priority. */ |
bfd_getl64, bfd_getl_signed_64, bfd_putl64, |
bfd_getl32, bfd_getl_signed_32, bfd_putl32, |
bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ |
bfd_getl64, bfd_getl_signed_64, bfd_putl64, |
bfd_getl32, bfd_getl_signed_32, bfd_putl32, |
bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ |
/* Note that we allow an object file to be treated as a core file as well. */ |
/* bfd_check_format */ |
#ifdef COFF_CHECK_FORMAT |
{_bfd_dummy_target, COFF_CHECK_FORMAT, |
bfd_generic_archive_p, COFF_CHECK_FORMAT}, |
#else |
{_bfd_dummy_target, coff_object_p, bfd_generic_archive_p, coff_object_p}, |
#endif |
{bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ |
bfd_false}, |
{bfd_false, coff_write_object_contents, /* bfd_write_contents */ |
_bfd_write_archive_contents, bfd_false}, |
BFD_JUMP_TABLE_GENERIC (coff), |
BFD_JUMP_TABLE_COPY (coff), |
BFD_JUMP_TABLE_CORE (_bfd_nocore), |
BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), |
BFD_JUMP_TABLE_SYMBOLS (coff), |
BFD_JUMP_TABLE_RELOCS (coff), |
BFD_JUMP_TABLE_WRITE (coff), |
BFD_JUMP_TABLE_LINK (coff), |
BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), |
NULL, |
COFF_SWAP_TABLE |
}; |
/contrib/toolchain/binutils/bfd/coffcode.h |
---|
0,0 → 1,5846 |
/* Support for the generic parts of most COFF variants, for BFD. |
Copyright 1990-2013 Free Software Foundation, Inc. |
Written by Cygnus Support. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* Most of this hacked by Steve Chamberlain, |
sac@cygnus.com. */ |
/* |
SECTION |
coff backends |
BFD supports a number of different flavours of coff format. |
The major differences between formats are the sizes and |
alignments of fields in structures on disk, and the occasional |
extra field. |
Coff in all its varieties is implemented with a few common |
files and a number of implementation specific files. For |
example, The 88k bcs coff format is implemented in the file |
@file{coff-m88k.c}. This file @code{#include}s |
@file{coff/m88k.h} which defines the external structure of the |
coff format for the 88k, and @file{coff/internal.h} which |
defines the internal structure. @file{coff-m88k.c} also |
defines the relocations used by the 88k format |
@xref{Relocations}. |
The Intel i960 processor version of coff is implemented in |
@file{coff-i960.c}. This file has the same structure as |
@file{coff-m88k.c}, except that it includes @file{coff/i960.h} |
rather than @file{coff-m88k.h}. |
SUBSECTION |
Porting to a new version of coff |
The recommended method is to select from the existing |
implementations the version of coff which is most like the one |
you want to use. For example, we'll say that i386 coff is |
the one you select, and that your coff flavour is called foo. |
Copy @file{i386coff.c} to @file{foocoff.c}, copy |
@file{../include/coff/i386.h} to @file{../include/coff/foo.h}, |
and add the lines to @file{targets.c} and @file{Makefile.in} |
so that your new back end is used. Alter the shapes of the |
structures in @file{../include/coff/foo.h} so that they match |
what you need. You will probably also have to add |
@code{#ifdef}s to the code in @file{coff/internal.h} and |
@file{coffcode.h} if your version of coff is too wild. |
You can verify that your new BFD backend works quite simply by |
building @file{objdump} from the @file{binutils} directory, |
and making sure that its version of what's going on and your |
host system's idea (assuming it has the pretty standard coff |
dump utility, usually called @code{att-dump} or just |
@code{dump}) are the same. Then clean up your code, and send |
what you've done to Cygnus. Then your stuff will be in the |
next release, and you won't have to keep integrating it. |
SUBSECTION |
How the coff backend works |
SUBSUBSECTION |
File layout |
The Coff backend is split into generic routines that are |
applicable to any Coff target and routines that are specific |
to a particular target. The target-specific routines are |
further split into ones which are basically the same for all |
Coff targets except that they use the external symbol format |
or use different values for certain constants. |
The generic routines are in @file{coffgen.c}. These routines |
work for any Coff target. They use some hooks into the target |
specific code; the hooks are in a @code{bfd_coff_backend_data} |
structure, one of which exists for each target. |
The essentially similar target-specific routines are in |
@file{coffcode.h}. This header file includes executable C code. |
The various Coff targets first include the appropriate Coff |
header file, make any special defines that are needed, and |
then include @file{coffcode.h}. |
Some of the Coff targets then also have additional routines in |
the target source file itself. |
For example, @file{coff-i960.c} includes |
@file{coff/internal.h} and @file{coff/i960.h}. It then |
defines a few constants, such as @code{I960}, and includes |
@file{coffcode.h}. Since the i960 has complex relocation |
types, @file{coff-i960.c} also includes some code to |
manipulate the i960 relocs. This code is not in |
@file{coffcode.h} because it would not be used by any other |
target. |
SUBSUBSECTION |
Coff long section names |
In the standard Coff object format, section names are limited to |
the eight bytes available in the @code{s_name} field of the |
@code{SCNHDR} section header structure. The format requires the |
field to be NUL-padded, but not necessarily NUL-terminated, so |
the longest section names permitted are a full eight characters. |
The Microsoft PE variants of the Coff object file format add |
an extension to support the use of long section names. This |
extension is defined in section 4 of the Microsoft PE/COFF |
specification (rev 8.1). If a section name is too long to fit |
into the section header's @code{s_name} field, it is instead |
placed into the string table, and the @code{s_name} field is |
filled with a slash ("/") followed by the ASCII decimal |
representation of the offset of the full name relative to the |
string table base. |
Note that this implies that the extension can only be used in object |
files, as executables do not contain a string table. The standard |
specifies that long section names from objects emitted into executable |
images are to be truncated. |
However, as a GNU extension, BFD can generate executable images |
that contain a string table and long section names. This |
would appear to be technically valid, as the standard only says |
that Coff debugging information is deprecated, not forbidden, |
and in practice it works, although some tools that parse PE files |
expecting the MS standard format may become confused; @file{PEview} is |
one known example. |
The functionality is supported in BFD by code implemented under |
the control of the macro @code{COFF_LONG_SECTION_NAMES}. If not |
defined, the format does not support long section names in any way. |
If defined, it is used to initialise a flag, |
@code{_bfd_coff_long_section_names}, and a hook function pointer, |
@code{_bfd_coff_set_long_section_names}, in the Coff backend data |
structure. The flag controls the generation of long section names |
in output BFDs at runtime; if it is false, as it will be by default |
when generating an executable image, long section names are truncated; |
if true, the long section names extension is employed. The hook |
points to a function that allows the value of the flag to be altered |
at runtime, on formats that support long section names at all; on |
other formats it points to a stub that returns an error indication. |
With input BFDs, the flag is set according to whether any long section |
names are detected while reading the section headers. For a completely |
new BFD, the flag is set to the default for the target format. This |
information can be used by a client of the BFD library when deciding |
what output format to generate, and means that a BFD that is opened |
for read and subsequently converted to a writeable BFD and modified |
in-place will retain whatever format it had on input. |
If @code{COFF_LONG_SECTION_NAMES} is simply defined (blank), or is |
defined to the value "1", then long section names are enabled by |
default; if it is defined to the value zero, they are disabled by |
default (but still accepted in input BFDs). The header @file{coffcode.h} |
defines a macro, @code{COFF_DEFAULT_LONG_SECTION_NAMES}, which is |
used in the backends to initialise the backend data structure fields |
appropriately; see the comments for further detail. |
SUBSUBSECTION |
Bit twiddling |
Each flavour of coff supported in BFD has its own header file |
describing the external layout of the structures. There is also |
an internal description of the coff layout, in |
@file{coff/internal.h}. A major function of the |
coff backend is swapping the bytes and twiddling the bits to |
translate the external form of the structures into the normal |
internal form. This is all performed in the |
@code{bfd_swap}_@i{thing}_@i{direction} routines. Some |
elements are different sizes between different versions of |
coff; it is the duty of the coff version specific include file |
to override the definitions of various packing routines in |
@file{coffcode.h}. E.g., the size of line number entry in coff is |
sometimes 16 bits, and sometimes 32 bits. @code{#define}ing |
@code{PUT_LNSZ_LNNO} and @code{GET_LNSZ_LNNO} will select the |
correct one. No doubt, some day someone will find a version of |
coff which has a varying field size not catered to at the |
moment. To port BFD, that person will have to add more @code{#defines}. |
Three of the bit twiddling routines are exported to |
@code{gdb}; @code{coff_swap_aux_in}, @code{coff_swap_sym_in} |
and @code{coff_swap_lineno_in}. @code{GDB} reads the symbol |
table on its own, but uses BFD to fix things up. More of the |
bit twiddlers are exported for @code{gas}; |
@code{coff_swap_aux_out}, @code{coff_swap_sym_out}, |
@code{coff_swap_lineno_out}, @code{coff_swap_reloc_out}, |
@code{coff_swap_filehdr_out}, @code{coff_swap_aouthdr_out}, |
@code{coff_swap_scnhdr_out}. @code{Gas} currently keeps track |
of all the symbol table and reloc drudgery itself, thereby |
saving the internal BFD overhead, but uses BFD to swap things |
on the way out, making cross ports much safer. Doing so also |
allows BFD (and thus the linker) to use the same header files |
as @code{gas}, which makes one avenue to disaster disappear. |
SUBSUBSECTION |
Symbol reading |
The simple canonical form for symbols used by BFD is not rich |
enough to keep all the information available in a coff symbol |
table. The back end gets around this problem by keeping the original |
symbol table around, "behind the scenes". |
When a symbol table is requested (through a call to |
@code{bfd_canonicalize_symtab}), a request gets through to |
@code{coff_get_normalized_symtab}. This reads the symbol table from |
the coff file and swaps all the structures inside into the |
internal form. It also fixes up all the pointers in the table |
(represented in the file by offsets from the first symbol in |
the table) into physical pointers to elements in the new |
internal table. This involves some work since the meanings of |
fields change depending upon context: a field that is a |
pointer to another structure in the symbol table at one moment |
may be the size in bytes of a structure at the next. Another |
pass is made over the table. All symbols which mark file names |
(<<C_FILE>> symbols) are modified so that the internal |
string points to the value in the auxent (the real filename) |
rather than the normal text associated with the symbol |
(@code{".file"}). |
At this time the symbol names are moved around. Coff stores |
all symbols less than nine characters long physically |
within the symbol table; longer strings are kept at the end of |
the file in the string table. This pass moves all strings |
into memory and replaces them with pointers to the strings. |
The symbol table is massaged once again, this time to create |
the canonical table used by the BFD application. Each symbol |
is inspected in turn, and a decision made (using the |
@code{sclass} field) about the various flags to set in the |
@code{asymbol}. @xref{Symbols}. The generated canonical table |
shares strings with the hidden internal symbol table. |
Any linenumbers are read from the coff file too, and attached |
to the symbols which own the functions the linenumbers belong to. |
SUBSUBSECTION |
Symbol writing |
Writing a symbol to a coff file which didn't come from a coff |
file will lose any debugging information. The @code{asymbol} |
structure remembers the BFD from which the symbol was taken, and on |
output the back end makes sure that the same destination target as |
source target is present. |
When the symbols have come from a coff file then all the |
debugging information is preserved. |
Symbol tables are provided for writing to the back end in a |
vector of pointers to pointers. This allows applications like |
the linker to accumulate and output large symbol tables |
without having to do too much byte copying. |
This function runs through the provided symbol table and |
patches each symbol marked as a file place holder |
(@code{C_FILE}) to point to the next file place holder in the |
list. It also marks each @code{offset} field in the list with |
the offset from the first symbol of the current symbol. |
Another function of this procedure is to turn the canonical |
value form of BFD into the form used by coff. Internally, BFD |
expects symbol values to be offsets from a section base; so a |
symbol physically at 0x120, but in a section starting at |
0x100, would have the value 0x20. Coff expects symbols to |
contain their final value, so symbols have their values |
changed at this point to reflect their sum with their owning |
section. This transformation uses the |
<<output_section>> field of the @code{asymbol}'s |
@code{asection} @xref{Sections}. |
o <<coff_mangle_symbols>> |
This routine runs though the provided symbol table and uses |
the offsets generated by the previous pass and the pointers |
generated when the symbol table was read in to create the |
structured hierarchy required by coff. It changes each pointer |
to a symbol into the index into the symbol table of the asymbol. |
o <<coff_write_symbols>> |
This routine runs through the symbol table and patches up the |
symbols from their internal form into the coff way, calls the |
bit twiddlers, and writes out the table to the file. |
*/ |
/* |
INTERNAL_DEFINITION |
coff_symbol_type |
DESCRIPTION |
The hidden information for an <<asymbol>> is described in a |
<<combined_entry_type>>: |
CODE_FRAGMENT |
. |
.typedef struct coff_ptr_struct |
.{ |
. {* Remembers the offset from the first symbol in the file for |
. this symbol. Generated by coff_renumber_symbols. *} |
. unsigned int offset; |
. |
. {* Should the value of this symbol be renumbered. Used for |
. XCOFF C_BSTAT symbols. Set by coff_slurp_symbol_table. *} |
. unsigned int fix_value : 1; |
. |
. {* Should the tag field of this symbol be renumbered. |
. Created by coff_pointerize_aux. *} |
. unsigned int fix_tag : 1; |
. |
. {* Should the endidx field of this symbol be renumbered. |
. Created by coff_pointerize_aux. *} |
. unsigned int fix_end : 1; |
. |
. {* Should the x_csect.x_scnlen field be renumbered. |
. Created by coff_pointerize_aux. *} |
. unsigned int fix_scnlen : 1; |
. |
. {* Fix up an XCOFF C_BINCL/C_EINCL symbol. The value is the |
. index into the line number entries. Set by coff_slurp_symbol_table. *} |
. unsigned int fix_line : 1; |
. |
. {* The container for the symbol structure as read and translated |
. from the file. *} |
. union |
. { |
. union internal_auxent auxent; |
. struct internal_syment syment; |
. } u; |
.} combined_entry_type; |
. |
. |
.{* Each canonical asymbol really looks like this: *} |
. |
.typedef struct coff_symbol_struct |
.{ |
. {* The actual symbol which the rest of BFD works with *} |
. asymbol symbol; |
. |
. {* A pointer to the hidden information for this symbol *} |
. combined_entry_type *native; |
. |
. {* A pointer to the linenumber information for this symbol *} |
. struct lineno_cache_entry *lineno; |
. |
. {* Have the line numbers been relocated yet ? *} |
. bfd_boolean done_lineno; |
.} coff_symbol_type; |
*/ |
#include "libiberty.h" |
#ifdef COFF_WITH_PE |
#include "peicode.h" |
#else |
#include "coffswap.h" |
#endif |
#define STRING_SIZE_SIZE 4 |
#define DOT_DEBUG ".debug" |
#define DOT_ZDEBUG ".zdebug" |
#define GNU_LINKONCE_WI ".gnu.linkonce.wi." |
#define GNU_LINKONCE_WT ".gnu.linkonce.wt." |
#define DOT_RELOC ".reloc" |
#if defined (COFF_LONG_SECTION_NAMES) |
/* Needed to expand the inputs to BLANKOR1TOODD. */ |
#define COFFLONGSECTIONCATHELPER(x,y) x ## y |
/* If the input macro Y is blank or '1', return an odd number; if it is |
'0', return an even number. Result undefined in all other cases. */ |
#define BLANKOR1TOODD(y) COFFLONGSECTIONCATHELPER(1,y) |
/* Defined to numerical 0 or 1 according to whether generation of long |
section names is disabled or enabled by default. */ |
#define COFF_ENABLE_LONG_SECTION_NAMES (BLANKOR1TOODD(COFF_LONG_SECTION_NAMES) & 1) |
/* Where long section names are supported, we allow them to be enabled |
and disabled at runtime, so select an appropriate hook function for |
_bfd_coff_set_long_section_names. */ |
#define COFF_LONG_SECTION_NAMES_SETTER bfd_coff_set_long_section_names_allowed |
#else /* !defined (COFF_LONG_SECTION_NAMES) */ |
/* If long section names are not supported, this stub disallows any |
attempt to enable them at run-time. */ |
#define COFF_LONG_SECTION_NAMES_SETTER bfd_coff_set_long_section_names_disallowed |
#endif /* defined (COFF_LONG_SECTION_NAMES) */ |
/* Define a macro that can be used to initialise both the fields relating |
to long section names in the backend data struct simultaneously. */ |
#if COFF_ENABLE_LONG_SECTION_NAMES |
#define COFF_DEFAULT_LONG_SECTION_NAMES (TRUE), COFF_LONG_SECTION_NAMES_SETTER |
#else /* !COFF_ENABLE_LONG_SECTION_NAMES */ |
#define COFF_DEFAULT_LONG_SECTION_NAMES (FALSE), COFF_LONG_SECTION_NAMES_SETTER |
#endif /* COFF_ENABLE_LONG_SECTION_NAMES */ |
#if defined (COFF_LONG_SECTION_NAMES) |
static bfd_boolean bfd_coff_set_long_section_names_allowed |
(bfd *, int); |
#else /* !defined (COFF_LONG_SECTION_NAMES) */ |
static bfd_boolean bfd_coff_set_long_section_names_disallowed |
(bfd *, int); |
#endif /* defined (COFF_LONG_SECTION_NAMES) */ |
static long sec_to_styp_flags |
(const char *, flagword); |
static bfd_boolean styp_to_sec_flags |
(bfd *, void *, const char *, asection *, flagword *); |
static bfd_boolean coff_bad_format_hook |
(bfd *, void *); |
static void coff_set_custom_section_alignment |
(bfd *, asection *, const struct coff_section_alignment_entry *, |
const unsigned int); |
static bfd_boolean coff_new_section_hook |
(bfd *, asection *); |
static bfd_boolean coff_set_arch_mach_hook |
(bfd *, void *); |
static bfd_boolean coff_write_relocs |
(bfd *, int); |
static bfd_boolean coff_set_flags |
(bfd *, unsigned int *, unsigned short *); |
static bfd_boolean coff_set_arch_mach |
(bfd *, enum bfd_architecture, unsigned long) ATTRIBUTE_UNUSED; |
static bfd_boolean coff_compute_section_file_positions |
(bfd *); |
static bfd_boolean coff_write_object_contents |
(bfd *) ATTRIBUTE_UNUSED; |
static bfd_boolean coff_set_section_contents |
(bfd *, asection *, const void *, file_ptr, bfd_size_type); |
static void * buy_and_read |
(bfd *, file_ptr, bfd_size_type); |
static bfd_boolean coff_slurp_line_table |
(bfd *, asection *); |
static bfd_boolean coff_slurp_symbol_table |
(bfd *); |
static enum coff_symbol_classification coff_classify_symbol |
(bfd *, struct internal_syment *); |
static bfd_boolean coff_slurp_reloc_table |
(bfd *, asection *, asymbol **); |
static long coff_canonicalize_reloc |
(bfd *, asection *, arelent **, asymbol **); |
#ifndef coff_mkobject_hook |
static void * coff_mkobject_hook |
(bfd *, void *, void *); |
#endif |
#ifdef COFF_WITH_PE |
static flagword handle_COMDAT |
(bfd *, flagword, void *, const char *, asection *); |
#endif |
#ifdef COFF_IMAGE_WITH_PE |
static bfd_boolean coff_read_word |
(bfd *, unsigned int *); |
static unsigned int coff_compute_checksum |
(bfd *); |
static bfd_boolean coff_apply_checksum |
(bfd *); |
#endif |
#ifdef TICOFF |
static bfd_boolean ticoff0_bad_format_hook |
(bfd *, void * ); |
static bfd_boolean ticoff1_bad_format_hook |
(bfd *, void * ); |
#endif |
/* void warning(); */ |
#if defined (COFF_LONG_SECTION_NAMES) |
static bfd_boolean |
bfd_coff_set_long_section_names_allowed (bfd *abfd, int enable) |
{ |
coff_backend_info (abfd)->_bfd_coff_long_section_names = enable; |
return TRUE; |
} |
#else /* !defined (COFF_LONG_SECTION_NAMES) */ |
static bfd_boolean |
bfd_coff_set_long_section_names_disallowed (bfd *abfd, int enable) |
{ |
(void) abfd; |
(void) enable; |
return FALSE; |
} |
#endif /* defined (COFF_LONG_SECTION_NAMES) */ |
/* Return a word with STYP_* (scnhdr.s_flags) flags set to represent |
the incoming SEC_* flags. The inverse of this function is |
styp_to_sec_flags(). NOTE: If you add to/change this routine, you |
should probably mirror the changes in styp_to_sec_flags(). */ |
#ifndef COFF_WITH_PE |
/* Macros for setting debugging flags. */ |
#ifdef STYP_DEBUG |
#define STYP_XCOFF_DEBUG STYP_DEBUG |
#else |
#define STYP_XCOFF_DEBUG STYP_INFO |
#endif |
#ifdef COFF_ALIGN_IN_S_FLAGS |
#define STYP_DEBUG_INFO STYP_DSECT |
#else |
#define STYP_DEBUG_INFO STYP_INFO |
#endif |
static long |
sec_to_styp_flags (const char *sec_name, flagword sec_flags) |
{ |
long styp_flags = 0; |
if (!strcmp (sec_name, _TEXT)) |
{ |
styp_flags = STYP_TEXT; |
} |
else if (!strcmp (sec_name, _DATA)) |
{ |
styp_flags = STYP_DATA; |
} |
else if (!strcmp (sec_name, _BSS)) |
{ |
styp_flags = STYP_BSS; |
#ifdef _COMMENT |
} |
else if (!strcmp (sec_name, _COMMENT)) |
{ |
styp_flags = STYP_INFO; |
#endif /* _COMMENT */ |
#ifdef _LIB |
} |
else if (!strcmp (sec_name, _LIB)) |
{ |
styp_flags = STYP_LIB; |
#endif /* _LIB */ |
#ifdef _LIT |
} |
else if (!strcmp (sec_name, _LIT)) |
{ |
styp_flags = STYP_LIT; |
#endif /* _LIT */ |
} |
else if (CONST_STRNEQ (sec_name, DOT_DEBUG) |
|| CONST_STRNEQ (sec_name, DOT_ZDEBUG)) |
{ |
/* Handle the XCOFF debug section and DWARF2 debug sections. */ |
if (!sec_name[6]) |
styp_flags = STYP_XCOFF_DEBUG; |
else |
styp_flags = STYP_DEBUG_INFO; |
} |
else if (CONST_STRNEQ (sec_name, ".stab")) |
{ |
styp_flags = STYP_DEBUG_INFO; |
} |
#ifdef COFF_LONG_SECTION_NAMES |
else if (CONST_STRNEQ (sec_name, GNU_LINKONCE_WI) |
|| CONST_STRNEQ (sec_name, GNU_LINKONCE_WT)) |
{ |
styp_flags = STYP_DEBUG_INFO; |
} |
#endif |
#ifdef RS6000COFF_C |
else if (!strcmp (sec_name, _PAD)) |
{ |
styp_flags = STYP_PAD; |
} |
else if (!strcmp (sec_name, _LOADER)) |
{ |
styp_flags = STYP_LOADER; |
} |
else if (!strcmp (sec_name, _EXCEPT)) |
{ |
styp_flags = STYP_EXCEPT; |
} |
else if (!strcmp (sec_name, _TYPCHK)) |
{ |
styp_flags = STYP_TYPCHK; |
} |
else if (sec_flags & SEC_DEBUGGING) |
{ |
int i; |
for (i = 0; i < XCOFF_DWSECT_NBR_NAMES; i++) |
if (!strcmp (sec_name, xcoff_dwsect_names[i].name)) |
{ |
styp_flags = STYP_DWARF | xcoff_dwsect_names[i].flag; |
break; |
} |
} |
#endif |
/* Try and figure out what it should be */ |
else if (sec_flags & SEC_CODE) |
{ |
styp_flags = STYP_TEXT; |
} |
else if (sec_flags & SEC_DATA) |
{ |
styp_flags = STYP_DATA; |
} |
else if (sec_flags & SEC_READONLY) |
{ |
#ifdef STYP_LIT /* 29k readonly text/data section */ |
styp_flags = STYP_LIT; |
#else |
styp_flags = STYP_TEXT; |
#endif /* STYP_LIT */ |
} |
else if (sec_flags & SEC_LOAD) |
{ |
styp_flags = STYP_TEXT; |
} |
else if (sec_flags & SEC_ALLOC) |
{ |
styp_flags = STYP_BSS; |
} |
#ifdef STYP_CLINK |
if (sec_flags & SEC_TIC54X_CLINK) |
styp_flags |= STYP_CLINK; |
#endif |
#ifdef STYP_BLOCK |
if (sec_flags & SEC_TIC54X_BLOCK) |
styp_flags |= STYP_BLOCK; |
#endif |
#ifdef STYP_NOLOAD |
if ((sec_flags & (SEC_NEVER_LOAD | SEC_COFF_SHARED_LIBRARY)) != 0) |
styp_flags |= STYP_NOLOAD; |
#endif |
return styp_flags; |
} |
#else /* COFF_WITH_PE */ |
/* The PE version; see above for the general comments. The non-PE |
case seems to be more guessing, and breaks PE format; specifically, |
.rdata is readonly, but it sure ain't text. Really, all this |
should be set up properly in gas (or whatever assembler is in use), |
and honor whatever objcopy/strip, etc. sent us as input. */ |
static long |
sec_to_styp_flags (const char *sec_name, flagword sec_flags) |
{ |
long styp_flags = 0; |
bfd_boolean is_dbg = FALSE; |
if (CONST_STRNEQ (sec_name, DOT_DEBUG) |
|| CONST_STRNEQ (sec_name, DOT_ZDEBUG) |
#ifdef COFF_LONG_SECTION_NAMES |
|| CONST_STRNEQ (sec_name, GNU_LINKONCE_WI) |
|| CONST_STRNEQ (sec_name, GNU_LINKONCE_WT) |
#endif |
|| CONST_STRNEQ (sec_name, ".stab")) |
is_dbg = TRUE; |
/* caution: there are at least three groups of symbols that have |
very similar bits and meanings: IMAGE_SCN*, SEC_*, and STYP_*. |
SEC_* are the BFD internal flags, used for generic BFD |
information. STYP_* are the COFF section flags which appear in |
COFF files. IMAGE_SCN_* are the PE section flags which appear in |
PE files. The STYP_* flags and the IMAGE_SCN_* flags overlap, |
but there are more IMAGE_SCN_* flags. */ |
/* FIXME: There is no gas syntax to specify the debug section flag. */ |
if (is_dbg) |
{ |
sec_flags &= (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD |
| SEC_LINK_DUPLICATES_SAME_CONTENTS |
| SEC_LINK_DUPLICATES_SAME_SIZE); |
sec_flags |= SEC_DEBUGGING | SEC_READONLY; |
} |
/* skip LOAD */ |
/* READONLY later */ |
/* skip RELOC */ |
if ((sec_flags & SEC_CODE) != 0) |
styp_flags |= IMAGE_SCN_CNT_CODE; |
if ((sec_flags & (SEC_DATA | SEC_DEBUGGING)) != 0) |
styp_flags |= IMAGE_SCN_CNT_INITIALIZED_DATA; |
if ((sec_flags & SEC_ALLOC) != 0 && (sec_flags & SEC_LOAD) == 0) |
styp_flags |= IMAGE_SCN_CNT_UNINITIALIZED_DATA; /* ==STYP_BSS */ |
/* skip ROM */ |
/* skip constRUCTOR */ |
/* skip CONTENTS */ |
if ((sec_flags & SEC_IS_COMMON) != 0) |
styp_flags |= IMAGE_SCN_LNK_COMDAT; |
if ((sec_flags & SEC_DEBUGGING) != 0) |
styp_flags |= IMAGE_SCN_MEM_DISCARDABLE; |
if ((sec_flags & SEC_EXCLUDE) != 0 && !is_dbg) |
styp_flags |= IMAGE_SCN_LNK_REMOVE; |
if ((sec_flags & SEC_NEVER_LOAD) != 0 && !is_dbg) |
styp_flags |= IMAGE_SCN_LNK_REMOVE; |
/* skip IN_MEMORY */ |
/* skip SORT */ |
if (sec_flags & SEC_LINK_ONCE) |
styp_flags |= IMAGE_SCN_LNK_COMDAT; |
if ((sec_flags |
& (SEC_LINK_DUPLICATES_DISCARD | SEC_LINK_DUPLICATES_SAME_CONTENTS |
| SEC_LINK_DUPLICATES_SAME_SIZE)) != 0) |
styp_flags |= IMAGE_SCN_LNK_COMDAT; |
/* skip LINKER_CREATED */ |
if ((sec_flags & SEC_COFF_NOREAD) == 0) |
styp_flags |= IMAGE_SCN_MEM_READ; /* Invert NOREAD for read. */ |
if ((sec_flags & SEC_READONLY) == 0) |
styp_flags |= IMAGE_SCN_MEM_WRITE; /* Invert READONLY for write. */ |
if (sec_flags & SEC_CODE) |
styp_flags |= IMAGE_SCN_MEM_EXECUTE; /* CODE->EXECUTE. */ |
if (sec_flags & SEC_COFF_SHARED) |
styp_flags |= IMAGE_SCN_MEM_SHARED; /* Shared remains meaningful. */ |
return styp_flags; |
} |
#endif /* COFF_WITH_PE */ |
/* Return a word with SEC_* flags set to represent the incoming STYP_* |
flags (from scnhdr.s_flags). The inverse of this function is |
sec_to_styp_flags(). NOTE: If you add to/change this routine, you |
should probably mirror the changes in sec_to_styp_flags(). */ |
#ifndef COFF_WITH_PE |
static bfd_boolean |
styp_to_sec_flags (bfd *abfd ATTRIBUTE_UNUSED, |
void * hdr, |
const char *name, |
asection *section ATTRIBUTE_UNUSED, |
flagword *flags_ptr) |
{ |
struct internal_scnhdr *internal_s = (struct internal_scnhdr *) hdr; |
long styp_flags = internal_s->s_flags; |
flagword sec_flags = 0; |
#ifdef STYP_BLOCK |
if (styp_flags & STYP_BLOCK) |
sec_flags |= SEC_TIC54X_BLOCK; |
#endif |
#ifdef STYP_CLINK |
if (styp_flags & STYP_CLINK) |
sec_flags |= SEC_TIC54X_CLINK; |
#endif |
#ifdef STYP_NOLOAD |
if (styp_flags & STYP_NOLOAD) |
sec_flags |= SEC_NEVER_LOAD; |
#endif /* STYP_NOLOAD */ |
/* For 386 COFF, at least, an unloadable text or data section is |
actually a shared library section. */ |
if (styp_flags & STYP_TEXT) |
{ |
if (sec_flags & SEC_NEVER_LOAD) |
sec_flags |= SEC_CODE | SEC_COFF_SHARED_LIBRARY; |
else |
sec_flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC; |
} |
else if (styp_flags & STYP_DATA) |
{ |
if (sec_flags & SEC_NEVER_LOAD) |
sec_flags |= SEC_DATA | SEC_COFF_SHARED_LIBRARY; |
else |
sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC; |
} |
else if (styp_flags & STYP_BSS) |
{ |
#ifdef BSS_NOLOAD_IS_SHARED_LIBRARY |
if (sec_flags & SEC_NEVER_LOAD) |
sec_flags |= SEC_ALLOC | SEC_COFF_SHARED_LIBRARY; |
else |
#endif |
sec_flags |= SEC_ALLOC; |
} |
else if (styp_flags & STYP_INFO) |
{ |
/* We mark these as SEC_DEBUGGING, but only if COFF_PAGE_SIZE is |
defined. coff_compute_section_file_positions uses |
COFF_PAGE_SIZE to ensure that the low order bits of the |
section VMA and the file offset match. If we don't know |
COFF_PAGE_SIZE, we can't ensure the correct correspondence, |
and demand page loading of the file will fail. */ |
#if defined (COFF_PAGE_SIZE) && !defined (COFF_ALIGN_IN_S_FLAGS) |
sec_flags |= SEC_DEBUGGING; |
#endif |
} |
else if (styp_flags & STYP_PAD) |
sec_flags = 0; |
#ifdef RS6000COFF_C |
else if (styp_flags & STYP_EXCEPT) |
sec_flags |= SEC_LOAD; |
else if (styp_flags & STYP_LOADER) |
sec_flags |= SEC_LOAD; |
else if (styp_flags & STYP_TYPCHK) |
sec_flags |= SEC_LOAD; |
else if (styp_flags & STYP_DWARF) |
sec_flags |= SEC_DEBUGGING; |
#endif |
else if (strcmp (name, _TEXT) == 0) |
{ |
if (sec_flags & SEC_NEVER_LOAD) |
sec_flags |= SEC_CODE | SEC_COFF_SHARED_LIBRARY; |
else |
sec_flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC; |
} |
else if (strcmp (name, _DATA) == 0) |
{ |
if (sec_flags & SEC_NEVER_LOAD) |
sec_flags |= SEC_DATA | SEC_COFF_SHARED_LIBRARY; |
else |
sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC; |
} |
else if (strcmp (name, _BSS) == 0) |
{ |
#ifdef BSS_NOLOAD_IS_SHARED_LIBRARY |
if (sec_flags & SEC_NEVER_LOAD) |
sec_flags |= SEC_ALLOC | SEC_COFF_SHARED_LIBRARY; |
else |
#endif |
sec_flags |= SEC_ALLOC; |
} |
else if (CONST_STRNEQ (name, DOT_DEBUG) |
|| CONST_STRNEQ (name, DOT_ZDEBUG) |
#ifdef _COMMENT |
|| strcmp (name, _COMMENT) == 0 |
#endif |
#ifdef COFF_LONG_SECTION_NAMES |
|| CONST_STRNEQ (name, GNU_LINKONCE_WI) |
|| CONST_STRNEQ (name, GNU_LINKONCE_WT) |
#endif |
|| CONST_STRNEQ (name, ".stab")) |
{ |
#ifdef COFF_PAGE_SIZE |
sec_flags |= SEC_DEBUGGING; |
#endif |
} |
#ifdef _LIB |
else if (strcmp (name, _LIB) == 0) |
; |
#endif |
#ifdef _LIT |
else if (strcmp (name, _LIT) == 0) |
sec_flags = SEC_LOAD | SEC_ALLOC | SEC_READONLY; |
#endif |
else |
sec_flags |= SEC_ALLOC | SEC_LOAD; |
#ifdef STYP_LIT /* A29k readonly text/data section type. */ |
if ((styp_flags & STYP_LIT) == STYP_LIT) |
sec_flags = (SEC_LOAD | SEC_ALLOC | SEC_READONLY); |
#endif /* STYP_LIT */ |
#ifdef STYP_OTHER_LOAD /* Other loaded sections. */ |
if (styp_flags & STYP_OTHER_LOAD) |
sec_flags = (SEC_LOAD | SEC_ALLOC); |
#endif /* STYP_SDATA */ |
#if defined (COFF_LONG_SECTION_NAMES) && defined (COFF_SUPPORT_GNU_LINKONCE) |
/* As a GNU extension, if the name begins with .gnu.linkonce, we |
only link a single copy of the section. This is used to support |
g++. g++ will emit each template expansion in its own section. |
The symbols will be defined as weak, so that multiple definitions |
are permitted. The GNU linker extension is to actually discard |
all but one of the sections. */ |
if (CONST_STRNEQ (name, ".gnu.linkonce")) |
sec_flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; |
#endif |
if (flags_ptr == NULL) |
return FALSE; |
* flags_ptr = sec_flags; |
return TRUE; |
} |
#else /* COFF_WITH_PE */ |
static flagword |
handle_COMDAT (bfd * abfd, |
flagword sec_flags, |
void * hdr, |
const char *name, |
asection *section) |
{ |
struct internal_scnhdr *internal_s = (struct internal_scnhdr *) hdr; |
bfd_byte *esymstart, *esym, *esymend; |
int seen_state = 0; |
char *target_name = NULL; |
sec_flags |= SEC_LINK_ONCE; |
/* Unfortunately, the PE format stores essential information in |
the symbol table, of all places. We need to extract that |
information now, so that objdump and the linker will know how |
to handle the section without worrying about the symbols. We |
can't call slurp_symtab, because the linker doesn't want the |
swapped symbols. */ |
/* COMDAT sections are special. The first symbol is the section |
symbol, which tells what kind of COMDAT section it is. The |
second symbol is the "comdat symbol" - the one with the |
unique name. GNU uses the section symbol for the unique |
name; MS uses ".text" for every comdat section. Sigh. - DJ */ |
/* This is not mirrored in sec_to_styp_flags(), but there |
doesn't seem to be a need to, either, and it would at best be |
rather messy. */ |
if (! _bfd_coff_get_external_symbols (abfd)) |
return sec_flags; |
esymstart = esym = (bfd_byte *) obj_coff_external_syms (abfd); |
esymend = esym + obj_raw_syment_count (abfd) * bfd_coff_symesz (abfd); |
while (esym < esymend) |
{ |
struct internal_syment isym; |
char buf[SYMNMLEN + 1]; |
const char *symname; |
bfd_coff_swap_sym_in (abfd, esym, & isym); |
if (sizeof (internal_s->s_name) > SYMNMLEN) |
{ |
/* This case implies that the matching |
symbol name will be in the string table. */ |
abort (); |
} |
if (isym.n_scnum == section->target_index) |
{ |
/* According to the MSVC documentation, the first |
TWO entries with the section # are both of |
interest to us. The first one is the "section |
symbol" (section name). The second is the comdat |
symbol name. Here, we've found the first |
qualifying entry; we distinguish it from the |
second with a state flag. |
In the case of gas-generated (at least until that |
is fixed) .o files, it isn't necessarily the |
second one. It may be some other later symbol. |
Since gas also doesn't follow MS conventions and |
emits the section similar to .text$<name>, where |
<something> is the name we're looking for, we |
distinguish the two as follows: |
If the section name is simply a section name (no |
$) we presume it's MS-generated, and look at |
precisely the second symbol for the comdat name. |
If the section name has a $, we assume it's |
gas-generated, and look for <something> (whatever |
follows the $) as the comdat symbol. */ |
/* All 3 branches use this. */ |
symname = _bfd_coff_internal_syment_name (abfd, &isym, buf); |
if (symname == NULL) |
abort (); |
switch (seen_state) |
{ |
case 0: |
{ |
/* The first time we've seen the symbol. */ |
union internal_auxent aux; |
/* If it isn't the stuff we're expecting, die; |
The MS documentation is vague, but it |
appears that the second entry serves BOTH |
as the comdat symbol and the defining |
symbol record (either C_STAT or C_EXT, |
possibly with an aux entry with debug |
information if it's a function.) It |
appears the only way to find the second one |
is to count. (On Intel, they appear to be |
adjacent, but on Alpha, they have been |
found separated.) |
Here, we think we've found the first one, |
but there's some checking we can do to be |
sure. */ |
if (! ((isym.n_sclass == C_STAT |
|| isym.n_sclass == C_EXT) |
&& BTYPE (isym.n_type) == T_NULL |
&& isym.n_value == 0)) |
abort (); |
/* FIXME LATER: MSVC generates section names |
like .text for comdats. Gas generates |
names like .text$foo__Fv (in the case of a |
function). See comment above for more. */ |
if (isym.n_sclass == C_STAT && strcmp (name, symname) != 0) |
_bfd_error_handler (_("%B: warning: COMDAT symbol '%s' does not match section name '%s'"), |
abfd, symname, name); |
seen_state = 1; |
/* This is the section symbol. */ |
bfd_coff_swap_aux_in (abfd, (esym + bfd_coff_symesz (abfd)), |
isym.n_type, isym.n_sclass, |
0, isym.n_numaux, & aux); |
target_name = strchr (name, '$'); |
if (target_name != NULL) |
{ |
/* Gas mode. */ |
seen_state = 2; |
/* Skip the `$'. */ |
target_name += 1; |
} |
/* FIXME: Microsoft uses NODUPLICATES and |
ASSOCIATIVE, but gnu uses ANY and |
SAME_SIZE. Unfortunately, gnu doesn't do |
the comdat symbols right. So, until we can |
fix it to do the right thing, we are |
temporarily disabling comdats for the MS |
types (they're used in DLLs and C++, but we |
don't support *their* C++ libraries anyway |
- DJ. */ |
/* Cygwin does not follow the MS style, and |
uses ANY and SAME_SIZE where NODUPLICATES |
and ASSOCIATIVE should be used. For |
Interix, we just do the right thing up |
front. */ |
switch (aux.x_scn.x_comdat) |
{ |
case IMAGE_COMDAT_SELECT_NODUPLICATES: |
#ifdef STRICT_PE_FORMAT |
sec_flags |= SEC_LINK_DUPLICATES_ONE_ONLY; |
#else |
sec_flags &= ~SEC_LINK_ONCE; |
#endif |
break; |
case IMAGE_COMDAT_SELECT_ANY: |
sec_flags |= SEC_LINK_DUPLICATES_DISCARD; |
break; |
case IMAGE_COMDAT_SELECT_SAME_SIZE: |
sec_flags |= SEC_LINK_DUPLICATES_SAME_SIZE; |
break; |
case IMAGE_COMDAT_SELECT_EXACT_MATCH: |
/* Not yet fully implemented ??? */ |
sec_flags |= SEC_LINK_DUPLICATES_SAME_CONTENTS; |
break; |
/* debug$S gets this case; other |
implications ??? */ |
/* There may be no symbol... we'll search |
the whole table... Is this the right |
place to play this game? Or should we do |
it when reading it in. */ |
case IMAGE_COMDAT_SELECT_ASSOCIATIVE: |
#ifdef STRICT_PE_FORMAT |
/* FIXME: This is not currently implemented. */ |
sec_flags |= SEC_LINK_DUPLICATES_DISCARD; |
#else |
sec_flags &= ~SEC_LINK_ONCE; |
#endif |
break; |
default: /* 0 means "no symbol" */ |
/* debug$F gets this case; other |
implications ??? */ |
sec_flags |= SEC_LINK_DUPLICATES_DISCARD; |
break; |
} |
} |
break; |
case 2: |
/* Gas mode: the first matching on partial name. */ |
#ifndef TARGET_UNDERSCORE |
#define TARGET_UNDERSCORE 0 |
#endif |
/* Is this the name we're looking for ? */ |
if (strcmp (target_name, |
symname + (TARGET_UNDERSCORE ? 1 : 0)) != 0) |
{ |
/* Not the name we're looking for */ |
esym += (isym.n_numaux + 1) * bfd_coff_symesz (abfd); |
continue; |
} |
/* Fall through. */ |
case 1: |
/* MSVC mode: the lexically second symbol (or |
drop through from the above). */ |
{ |
char *newname; |
bfd_size_type amt; |
/* This must the second symbol with the |
section #. It is the actual symbol name. |
Intel puts the two adjacent, but Alpha (at |
least) spreads them out. */ |
amt = sizeof (struct coff_comdat_info); |
coff_section_data (abfd, section)->comdat |
= (struct coff_comdat_info *) bfd_alloc (abfd, amt); |
if (coff_section_data (abfd, section)->comdat == NULL) |
abort (); |
coff_section_data (abfd, section)->comdat->symbol = |
(esym - esymstart) / bfd_coff_symesz (abfd); |
amt = strlen (symname) + 1; |
newname = (char *) bfd_alloc (abfd, amt); |
if (newname == NULL) |
abort (); |
strcpy (newname, symname); |
coff_section_data (abfd, section)->comdat->name |
= newname; |
} |
goto breakloop; |
} |
} |
esym += (isym.n_numaux + 1) * bfd_coff_symesz (abfd); |
} |
breakloop: |
return sec_flags; |
} |
/* The PE version; see above for the general comments. |
Since to set the SEC_LINK_ONCE and associated flags, we have to |
look at the symbol table anyway, we return the symbol table index |
of the symbol being used as the COMDAT symbol. This is admittedly |
ugly, but there's really nowhere else that we have access to the |
required information. FIXME: Is the COMDAT symbol index used for |
any purpose other than objdump? */ |
static bfd_boolean |
styp_to_sec_flags (bfd *abfd, |
void * hdr, |
const char *name, |
asection *section, |
flagword *flags_ptr) |
{ |
struct internal_scnhdr *internal_s = (struct internal_scnhdr *) hdr; |
long styp_flags = internal_s->s_flags; |
flagword sec_flags; |
bfd_boolean result = TRUE; |
bfd_boolean is_dbg = FALSE; |
if (CONST_STRNEQ (name, DOT_DEBUG) |
|| CONST_STRNEQ (name, DOT_ZDEBUG) |
#ifdef COFF_LONG_SECTION_NAMES |
|| CONST_STRNEQ (name, GNU_LINKONCE_WI) |
|| CONST_STRNEQ (name, GNU_LINKONCE_WT) |
#endif |
|| CONST_STRNEQ (name, ".stab")) |
is_dbg = TRUE; |
/* Assume read only unless IMAGE_SCN_MEM_WRITE is specified. */ |
sec_flags = SEC_READONLY; |
/* If section disallows read, then set the NOREAD flag. */ |
if ((styp_flags & IMAGE_SCN_MEM_READ) == 0) |
sec_flags |= SEC_COFF_NOREAD; |
/* Process each flag bit in styp_flags in turn. */ |
while (styp_flags) |
{ |
long flag = styp_flags & - styp_flags; |
char * unhandled = NULL; |
styp_flags &= ~ flag; |
/* We infer from the distinct read/write/execute bits the settings |
of some of the bfd flags; the actual values, should we need them, |
are also in pei_section_data (abfd, section)->pe_flags. */ |
switch (flag) |
{ |
case STYP_DSECT: |
unhandled = "STYP_DSECT"; |
break; |
case STYP_GROUP: |
unhandled = "STYP_GROUP"; |
break; |
case STYP_COPY: |
unhandled = "STYP_COPY"; |
break; |
case STYP_OVER: |
unhandled = "STYP_OVER"; |
break; |
#ifdef SEC_NEVER_LOAD |
case STYP_NOLOAD: |
sec_flags |= SEC_NEVER_LOAD; |
break; |
#endif |
case IMAGE_SCN_MEM_READ: |
sec_flags &= ~SEC_COFF_NOREAD; |
break; |
case IMAGE_SCN_TYPE_NO_PAD: |
/* Skip. */ |
break; |
case IMAGE_SCN_LNK_OTHER: |
unhandled = "IMAGE_SCN_LNK_OTHER"; |
break; |
case IMAGE_SCN_MEM_NOT_CACHED: |
unhandled = "IMAGE_SCN_MEM_NOT_CACHED"; |
break; |
case IMAGE_SCN_MEM_NOT_PAGED: |
/* Generate a warning message rather using the 'unhandled' |
variable as this will allow some .sys files generate by |
other toolchains to be processed. See bugzilla issue 196. */ |
_bfd_error_handler (_("%B: Warning: Ignoring section flag IMAGE_SCN_MEM_NOT_PAGED in section %s"), |
abfd, name); |
break; |
case IMAGE_SCN_MEM_EXECUTE: |
sec_flags |= SEC_CODE; |
break; |
case IMAGE_SCN_MEM_WRITE: |
sec_flags &= ~ SEC_READONLY; |
break; |
case IMAGE_SCN_MEM_DISCARDABLE: |
/* The MS PE spec says that debug sections are DISCARDABLE, |
but the presence of a DISCARDABLE flag does not necessarily |
mean that a given section contains debug information. Thus |
we only set the SEC_DEBUGGING flag on sections that we |
recognise as containing debug information. */ |
if (is_dbg |
#ifdef _COMMENT |
|| strcmp (name, _COMMENT) == 0 |
#endif |
) |
{ |
sec_flags |= SEC_DEBUGGING | SEC_READONLY; |
} |
break; |
case IMAGE_SCN_MEM_SHARED: |
sec_flags |= SEC_COFF_SHARED; |
break; |
case IMAGE_SCN_LNK_REMOVE: |
if (!is_dbg) |
sec_flags |= SEC_EXCLUDE; |
break; |
case IMAGE_SCN_CNT_CODE: |
sec_flags |= SEC_CODE | SEC_ALLOC | SEC_LOAD; |
break; |
case IMAGE_SCN_CNT_INITIALIZED_DATA: |
if (is_dbg) |
sec_flags |= SEC_DEBUGGING; |
else |
sec_flags |= SEC_DATA | SEC_ALLOC | SEC_LOAD; |
break; |
case IMAGE_SCN_CNT_UNINITIALIZED_DATA: |
sec_flags |= SEC_ALLOC; |
break; |
case IMAGE_SCN_LNK_INFO: |
/* We mark these as SEC_DEBUGGING, but only if COFF_PAGE_SIZE is |
defined. coff_compute_section_file_positions uses |
COFF_PAGE_SIZE to ensure that the low order bits of the |
section VMA and the file offset match. If we don't know |
COFF_PAGE_SIZE, we can't ensure the correct correspondence, |
and demand page loading of the file will fail. */ |
#ifdef COFF_PAGE_SIZE |
sec_flags |= SEC_DEBUGGING; |
#endif |
break; |
case IMAGE_SCN_LNK_COMDAT: |
/* COMDAT gets very special treatment. */ |
sec_flags = handle_COMDAT (abfd, sec_flags, hdr, name, section); |
break; |
default: |
/* Silently ignore for now. */ |
break; |
} |
/* If the section flag was not handled, report it here. */ |
if (unhandled != NULL) |
{ |
(*_bfd_error_handler) |
(_("%B (%s): Section flag %s (0x%x) ignored"), |
abfd, name, unhandled, flag); |
result = FALSE; |
} |
} |
#if defined (COFF_LONG_SECTION_NAMES) && defined (COFF_SUPPORT_GNU_LINKONCE) |
/* As a GNU extension, if the name begins with .gnu.linkonce, we |
only link a single copy of the section. This is used to support |
g++. g++ will emit each template expansion in its own section. |
The symbols will be defined as weak, so that multiple definitions |
are permitted. The GNU linker extension is to actually discard |
all but one of the sections. */ |
if (CONST_STRNEQ (name, ".gnu.linkonce")) |
sec_flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; |
#endif |
if (flags_ptr) |
* flags_ptr = sec_flags; |
return result; |
} |
#endif /* COFF_WITH_PE */ |
#define get_index(symbol) ((symbol)->udata.i) |
/* |
INTERNAL_DEFINITION |
bfd_coff_backend_data |
CODE_FRAGMENT |
.{* COFF symbol classifications. *} |
. |
.enum coff_symbol_classification |
.{ |
. {* Global symbol. *} |
. COFF_SYMBOL_GLOBAL, |
. {* Common symbol. *} |
. COFF_SYMBOL_COMMON, |
. {* Undefined symbol. *} |
. COFF_SYMBOL_UNDEFINED, |
. {* Local symbol. *} |
. COFF_SYMBOL_LOCAL, |
. {* PE section symbol. *} |
. COFF_SYMBOL_PE_SECTION |
.}; |
. |
Special entry points for gdb to swap in coff symbol table parts: |
.typedef struct |
.{ |
. void (*_bfd_coff_swap_aux_in) |
. (bfd *, void *, int, int, int, int, void *); |
. |
. void (*_bfd_coff_swap_sym_in) |
. (bfd *, void *, void *); |
. |
. void (*_bfd_coff_swap_lineno_in) |
. (bfd *, void *, void *); |
. |
. unsigned int (*_bfd_coff_swap_aux_out) |
. (bfd *, void *, int, int, int, int, void *); |
. |
. unsigned int (*_bfd_coff_swap_sym_out) |
. (bfd *, void *, void *); |
. |
. unsigned int (*_bfd_coff_swap_lineno_out) |
. (bfd *, void *, void *); |
. |
. unsigned int (*_bfd_coff_swap_reloc_out) |
. (bfd *, void *, void *); |
. |
. unsigned int (*_bfd_coff_swap_filehdr_out) |
. (bfd *, void *, void *); |
. |
. unsigned int (*_bfd_coff_swap_aouthdr_out) |
. (bfd *, void *, void *); |
. |
. unsigned int (*_bfd_coff_swap_scnhdr_out) |
. (bfd *, void *, void *); |
. |
. unsigned int _bfd_filhsz; |
. unsigned int _bfd_aoutsz; |
. unsigned int _bfd_scnhsz; |
. unsigned int _bfd_symesz; |
. unsigned int _bfd_auxesz; |
. unsigned int _bfd_relsz; |
. unsigned int _bfd_linesz; |
. unsigned int _bfd_filnmlen; |
. bfd_boolean _bfd_coff_long_filenames; |
. |
. bfd_boolean _bfd_coff_long_section_names; |
. bfd_boolean (*_bfd_coff_set_long_section_names) |
. (bfd *, int); |
. |
. unsigned int _bfd_coff_default_section_alignment_power; |
. bfd_boolean _bfd_coff_force_symnames_in_strings; |
. unsigned int _bfd_coff_debug_string_prefix_length; |
. |
. void (*_bfd_coff_swap_filehdr_in) |
. (bfd *, void *, void *); |
. |
. void (*_bfd_coff_swap_aouthdr_in) |
. (bfd *, void *, void *); |
. |
. void (*_bfd_coff_swap_scnhdr_in) |
. (bfd *, void *, void *); |
. |
. void (*_bfd_coff_swap_reloc_in) |
. (bfd *abfd, void *, void *); |
. |
. bfd_boolean (*_bfd_coff_bad_format_hook) |
. (bfd *, void *); |
. |
. bfd_boolean (*_bfd_coff_set_arch_mach_hook) |
. (bfd *, void *); |
. |
. void * (*_bfd_coff_mkobject_hook) |
. (bfd *, void *, void *); |
. |
. bfd_boolean (*_bfd_styp_to_sec_flags_hook) |
. (bfd *, void *, const char *, asection *, flagword *); |
. |
. void (*_bfd_set_alignment_hook) |
. (bfd *, asection *, void *); |
. |
. bfd_boolean (*_bfd_coff_slurp_symbol_table) |
. (bfd *); |
. |
. bfd_boolean (*_bfd_coff_symname_in_debug) |
. (bfd *, struct internal_syment *); |
. |
. bfd_boolean (*_bfd_coff_pointerize_aux_hook) |
. (bfd *, combined_entry_type *, combined_entry_type *, |
. unsigned int, combined_entry_type *); |
. |
. bfd_boolean (*_bfd_coff_print_aux) |
. (bfd *, FILE *, combined_entry_type *, combined_entry_type *, |
. combined_entry_type *, unsigned int); |
. |
. void (*_bfd_coff_reloc16_extra_cases) |
. (bfd *, struct bfd_link_info *, struct bfd_link_order *, arelent *, |
. bfd_byte *, unsigned int *, unsigned int *); |
. |
. int (*_bfd_coff_reloc16_estimate) |
. (bfd *, asection *, arelent *, unsigned int, |
. struct bfd_link_info *); |
. |
. enum coff_symbol_classification (*_bfd_coff_classify_symbol) |
. (bfd *, struct internal_syment *); |
. |
. bfd_boolean (*_bfd_coff_compute_section_file_positions) |
. (bfd *); |
. |
. bfd_boolean (*_bfd_coff_start_final_link) |
. (bfd *, struct bfd_link_info *); |
. |
. bfd_boolean (*_bfd_coff_relocate_section) |
. (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, |
. struct internal_reloc *, struct internal_syment *, asection **); |
. |
. reloc_howto_type *(*_bfd_coff_rtype_to_howto) |
. (bfd *, asection *, struct internal_reloc *, |
. struct coff_link_hash_entry *, struct internal_syment *, |
. bfd_vma *); |
. |
. bfd_boolean (*_bfd_coff_adjust_symndx) |
. (bfd *, struct bfd_link_info *, bfd *, asection *, |
. struct internal_reloc *, bfd_boolean *); |
. |
. bfd_boolean (*_bfd_coff_link_add_one_symbol) |
. (struct bfd_link_info *, bfd *, const char *, flagword, |
. asection *, bfd_vma, const char *, bfd_boolean, bfd_boolean, |
. struct bfd_link_hash_entry **); |
. |
. bfd_boolean (*_bfd_coff_link_output_has_begun) |
. (bfd *, struct coff_final_link_info *); |
. |
. bfd_boolean (*_bfd_coff_final_link_postscript) |
. (bfd *, struct coff_final_link_info *); |
. |
. bfd_boolean (*_bfd_coff_print_pdata) |
. (bfd *, void *); |
. |
.} bfd_coff_backend_data; |
. |
.#define coff_backend_info(abfd) \ |
. ((bfd_coff_backend_data *) (abfd)->xvec->backend_data) |
. |
.#define bfd_coff_swap_aux_in(a,e,t,c,ind,num,i) \ |
. ((coff_backend_info (a)->_bfd_coff_swap_aux_in) (a,e,t,c,ind,num,i)) |
. |
.#define bfd_coff_swap_sym_in(a,e,i) \ |
. ((coff_backend_info (a)->_bfd_coff_swap_sym_in) (a,e,i)) |
. |
.#define bfd_coff_swap_lineno_in(a,e,i) \ |
. ((coff_backend_info ( a)->_bfd_coff_swap_lineno_in) (a,e,i)) |
. |
.#define bfd_coff_swap_reloc_out(abfd, i, o) \ |
. ((coff_backend_info (abfd)->_bfd_coff_swap_reloc_out) (abfd, i, o)) |
. |
.#define bfd_coff_swap_lineno_out(abfd, i, o) \ |
. ((coff_backend_info (abfd)->_bfd_coff_swap_lineno_out) (abfd, i, o)) |
. |
.#define bfd_coff_swap_aux_out(a,i,t,c,ind,num,o) \ |
. ((coff_backend_info (a)->_bfd_coff_swap_aux_out) (a,i,t,c,ind,num,o)) |
. |
.#define bfd_coff_swap_sym_out(abfd, i,o) \ |
. ((coff_backend_info (abfd)->_bfd_coff_swap_sym_out) (abfd, i, o)) |
. |
.#define bfd_coff_swap_scnhdr_out(abfd, i,o) \ |
. ((coff_backend_info (abfd)->_bfd_coff_swap_scnhdr_out) (abfd, i, o)) |
. |
.#define bfd_coff_swap_filehdr_out(abfd, i,o) \ |
. ((coff_backend_info (abfd)->_bfd_coff_swap_filehdr_out) (abfd, i, o)) |
. |
.#define bfd_coff_swap_aouthdr_out(abfd, i,o) \ |
. ((coff_backend_info (abfd)->_bfd_coff_swap_aouthdr_out) (abfd, i, o)) |
. |
.#define bfd_coff_filhsz(abfd) (coff_backend_info (abfd)->_bfd_filhsz) |
.#define bfd_coff_aoutsz(abfd) (coff_backend_info (abfd)->_bfd_aoutsz) |
.#define bfd_coff_scnhsz(abfd) (coff_backend_info (abfd)->_bfd_scnhsz) |
.#define bfd_coff_symesz(abfd) (coff_backend_info (abfd)->_bfd_symesz) |
.#define bfd_coff_auxesz(abfd) (coff_backend_info (abfd)->_bfd_auxesz) |
.#define bfd_coff_relsz(abfd) (coff_backend_info (abfd)->_bfd_relsz) |
.#define bfd_coff_linesz(abfd) (coff_backend_info (abfd)->_bfd_linesz) |
.#define bfd_coff_filnmlen(abfd) (coff_backend_info (abfd)->_bfd_filnmlen) |
.#define bfd_coff_long_filenames(abfd) \ |
. (coff_backend_info (abfd)->_bfd_coff_long_filenames) |
.#define bfd_coff_long_section_names(abfd) \ |
. (coff_backend_info (abfd)->_bfd_coff_long_section_names) |
.#define bfd_coff_set_long_section_names(abfd, enable) \ |
. ((coff_backend_info (abfd)->_bfd_coff_set_long_section_names) (abfd, enable)) |
.#define bfd_coff_default_section_alignment_power(abfd) \ |
. (coff_backend_info (abfd)->_bfd_coff_default_section_alignment_power) |
.#define bfd_coff_swap_filehdr_in(abfd, i,o) \ |
. ((coff_backend_info (abfd)->_bfd_coff_swap_filehdr_in) (abfd, i, o)) |
. |
.#define bfd_coff_swap_aouthdr_in(abfd, i,o) \ |
. ((coff_backend_info (abfd)->_bfd_coff_swap_aouthdr_in) (abfd, i, o)) |
. |
.#define bfd_coff_swap_scnhdr_in(abfd, i,o) \ |
. ((coff_backend_info (abfd)->_bfd_coff_swap_scnhdr_in) (abfd, i, o)) |
. |
.#define bfd_coff_swap_reloc_in(abfd, i, o) \ |
. ((coff_backend_info (abfd)->_bfd_coff_swap_reloc_in) (abfd, i, o)) |
. |
.#define bfd_coff_bad_format_hook(abfd, filehdr) \ |
. ((coff_backend_info (abfd)->_bfd_coff_bad_format_hook) (abfd, filehdr)) |
. |
.#define bfd_coff_set_arch_mach_hook(abfd, filehdr)\ |
. ((coff_backend_info (abfd)->_bfd_coff_set_arch_mach_hook) (abfd, filehdr)) |
.#define bfd_coff_mkobject_hook(abfd, filehdr, aouthdr)\ |
. ((coff_backend_info (abfd)->_bfd_coff_mkobject_hook)\ |
. (abfd, filehdr, aouthdr)) |
. |
.#define bfd_coff_styp_to_sec_flags_hook(abfd, scnhdr, name, section, flags_ptr)\ |
. ((coff_backend_info (abfd)->_bfd_styp_to_sec_flags_hook)\ |
. (abfd, scnhdr, name, section, flags_ptr)) |
. |
.#define bfd_coff_set_alignment_hook(abfd, sec, scnhdr)\ |
. ((coff_backend_info (abfd)->_bfd_set_alignment_hook) (abfd, sec, scnhdr)) |
. |
.#define bfd_coff_slurp_symbol_table(abfd)\ |
. ((coff_backend_info (abfd)->_bfd_coff_slurp_symbol_table) (abfd)) |
. |
.#define bfd_coff_symname_in_debug(abfd, sym)\ |
. ((coff_backend_info (abfd)->_bfd_coff_symname_in_debug) (abfd, sym)) |
. |
.#define bfd_coff_force_symnames_in_strings(abfd)\ |
. (coff_backend_info (abfd)->_bfd_coff_force_symnames_in_strings) |
. |
.#define bfd_coff_debug_string_prefix_length(abfd)\ |
. (coff_backend_info (abfd)->_bfd_coff_debug_string_prefix_length) |
. |
.#define bfd_coff_print_aux(abfd, file, base, symbol, aux, indaux)\ |
. ((coff_backend_info (abfd)->_bfd_coff_print_aux)\ |
. (abfd, file, base, symbol, aux, indaux)) |
. |
.#define bfd_coff_reloc16_extra_cases(abfd, link_info, link_order,\ |
. reloc, data, src_ptr, dst_ptr)\ |
. ((coff_backend_info (abfd)->_bfd_coff_reloc16_extra_cases)\ |
. (abfd, link_info, link_order, reloc, data, src_ptr, dst_ptr)) |
. |
.#define bfd_coff_reloc16_estimate(abfd, section, reloc, shrink, link_info)\ |
. ((coff_backend_info (abfd)->_bfd_coff_reloc16_estimate)\ |
. (abfd, section, reloc, shrink, link_info)) |
. |
.#define bfd_coff_classify_symbol(abfd, sym)\ |
. ((coff_backend_info (abfd)->_bfd_coff_classify_symbol)\ |
. (abfd, sym)) |
. |
.#define bfd_coff_compute_section_file_positions(abfd)\ |
. ((coff_backend_info (abfd)->_bfd_coff_compute_section_file_positions)\ |
. (abfd)) |
. |
.#define bfd_coff_start_final_link(obfd, info)\ |
. ((coff_backend_info (obfd)->_bfd_coff_start_final_link)\ |
. (obfd, info)) |
.#define bfd_coff_relocate_section(obfd,info,ibfd,o,con,rel,isyms,secs)\ |
. ((coff_backend_info (ibfd)->_bfd_coff_relocate_section)\ |
. (obfd, info, ibfd, o, con, rel, isyms, secs)) |
.#define bfd_coff_rtype_to_howto(abfd, sec, rel, h, sym, addendp)\ |
. ((coff_backend_info (abfd)->_bfd_coff_rtype_to_howto)\ |
. (abfd, sec, rel, h, sym, addendp)) |
.#define bfd_coff_adjust_symndx(obfd, info, ibfd, sec, rel, adjustedp)\ |
. ((coff_backend_info (abfd)->_bfd_coff_adjust_symndx)\ |
. (obfd, info, ibfd, sec, rel, adjustedp)) |
.#define bfd_coff_link_add_one_symbol(info, abfd, name, flags, section,\ |
. value, string, cp, coll, hashp)\ |
. ((coff_backend_info (abfd)->_bfd_coff_link_add_one_symbol)\ |
. (info, abfd, name, flags, section, value, string, cp, coll, hashp)) |
. |
.#define bfd_coff_link_output_has_begun(a,p) \ |
. ((coff_backend_info (a)->_bfd_coff_link_output_has_begun) (a, p)) |
.#define bfd_coff_final_link_postscript(a,p) \ |
. ((coff_backend_info (a)->_bfd_coff_final_link_postscript) (a, p)) |
. |
.#define bfd_coff_have_print_pdata(a) \ |
. (coff_backend_info (a)->_bfd_coff_print_pdata) |
.#define bfd_coff_print_pdata(a,p) \ |
. ((coff_backend_info (a)->_bfd_coff_print_pdata) (a, p)) |
. |
.{* Macro: Returns true if the bfd is a PE executable as opposed to a |
. PE object file. *} |
.#define bfd_pei_p(abfd) \ |
. (CONST_STRNEQ ((abfd)->xvec->name, "pei-")) |
*/ |
/* See whether the magic number matches. */ |
static bfd_boolean |
coff_bad_format_hook (bfd * abfd ATTRIBUTE_UNUSED, void * filehdr) |
{ |
struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; |
if (BADMAG (*internal_f)) |
return FALSE; |
/* If the optional header is NULL or not the correct size then |
quit; the only difference I can see between m88k dgux headers (MC88DMAGIC) |
and Intel 960 readwrite headers (I960WRMAGIC) is that the |
optional header is of a different size. |
But the mips keeps extra stuff in it's opthdr, so dont check |
when doing that. */ |
#if defined(M88) || defined(I960) |
if (internal_f->f_opthdr != 0 && bfd_coff_aoutsz (abfd) != internal_f->f_opthdr) |
return FALSE; |
#endif |
return TRUE; |
} |
#ifdef TICOFF |
static bfd_boolean |
ticoff0_bad_format_hook (bfd *abfd ATTRIBUTE_UNUSED, void * filehdr) |
{ |
struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; |
if (COFF0_BADMAG (*internal_f)) |
return FALSE; |
return TRUE; |
} |
#endif |
#ifdef TICOFF |
static bfd_boolean |
ticoff1_bad_format_hook (bfd *abfd ATTRIBUTE_UNUSED, void * filehdr) |
{ |
struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; |
if (COFF1_BADMAG (*internal_f)) |
return FALSE; |
return TRUE; |
} |
#endif |
/* Check whether this section uses an alignment other than the |
default. */ |
static void |
coff_set_custom_section_alignment (bfd *abfd ATTRIBUTE_UNUSED, |
asection *section, |
const struct coff_section_alignment_entry *alignment_table, |
const unsigned int table_size) |
{ |
const unsigned int default_alignment = COFF_DEFAULT_SECTION_ALIGNMENT_POWER; |
unsigned int i; |
for (i = 0; i < table_size; ++i) |
{ |
const char *secname = bfd_get_section_name (abfd, section); |
if (alignment_table[i].comparison_length == (unsigned int) -1 |
? strcmp (alignment_table[i].name, secname) == 0 |
: strncmp (alignment_table[i].name, secname, |
alignment_table[i].comparison_length) == 0) |
break; |
} |
if (i >= table_size) |
return; |
if (alignment_table[i].default_alignment_min != COFF_ALIGNMENT_FIELD_EMPTY |
&& default_alignment < alignment_table[i].default_alignment_min) |
return; |
if (alignment_table[i].default_alignment_max != COFF_ALIGNMENT_FIELD_EMPTY |
#if COFF_DEFAULT_SECTION_ALIGNMENT_POWER != 0 |
&& default_alignment > alignment_table[i].default_alignment_max |
#endif |
) |
return; |
section->alignment_power = alignment_table[i].alignment_power; |
} |
/* Custom section alignment records. */ |
static const struct coff_section_alignment_entry |
coff_section_alignment_table[] = |
{ |
#ifdef COFF_SECTION_ALIGNMENT_ENTRIES |
COFF_SECTION_ALIGNMENT_ENTRIES, |
#endif |
/* There must not be any gaps between .stabstr sections. */ |
{ COFF_SECTION_NAME_PARTIAL_MATCH (".stabstr"), |
1, COFF_ALIGNMENT_FIELD_EMPTY, 0 }, |
/* The .stab section must be aligned to 2**2 at most, to avoid gaps. */ |
{ COFF_SECTION_NAME_PARTIAL_MATCH (".stab"), |
3, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, |
/* Similarly for the .ctors and .dtors sections. */ |
{ COFF_SECTION_NAME_EXACT_MATCH (".ctors"), |
3, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, |
{ COFF_SECTION_NAME_EXACT_MATCH (".dtors"), |
3, COFF_ALIGNMENT_FIELD_EMPTY, 2 } |
}; |
static const unsigned int coff_section_alignment_table_size = |
sizeof coff_section_alignment_table / sizeof coff_section_alignment_table[0]; |
/* Initialize a section structure with information peculiar to this |
particular implementation of COFF. */ |
static bfd_boolean |
coff_new_section_hook (bfd * abfd, asection * section) |
{ |
combined_entry_type *native; |
bfd_size_type amt; |
unsigned char sclass = C_STAT; |
section->alignment_power = COFF_DEFAULT_SECTION_ALIGNMENT_POWER; |
#ifdef RS6000COFF_C |
if (bfd_xcoff_text_align_power (abfd) != 0 |
&& strcmp (bfd_get_section_name (abfd, section), ".text") == 0) |
section->alignment_power = bfd_xcoff_text_align_power (abfd); |
else if (bfd_xcoff_data_align_power (abfd) != 0 |
&& strcmp (bfd_get_section_name (abfd, section), ".data") == 0) |
section->alignment_power = bfd_xcoff_data_align_power (abfd); |
else |
{ |
int i; |
for (i = 0; i < XCOFF_DWSECT_NBR_NAMES; i++) |
if (strcmp (bfd_get_section_name (abfd, section), |
xcoff_dwsect_names[i].name) == 0) |
{ |
section->alignment_power = 0; |
sclass = C_DWARF; |
break; |
} |
} |
#endif |
/* Set up the section symbol. */ |
if (!_bfd_generic_new_section_hook (abfd, section)) |
return FALSE; |
/* Allocate aux records for section symbols, to store size and |
related info. |
@@ The 10 is a guess at a plausible maximum number of aux entries |
(but shouldn't be a constant). */ |
amt = sizeof (combined_entry_type) * 10; |
native = (combined_entry_type *) bfd_zalloc (abfd, amt); |
if (native == NULL) |
return FALSE; |
/* We don't need to set up n_name, n_value, or n_scnum in the native |
symbol information, since they'll be overridden by the BFD symbol |
anyhow. However, we do need to set the type and storage class, |
in case this symbol winds up getting written out. The value 0 |
for n_numaux is already correct. */ |
native->u.syment.n_type = T_NULL; |
native->u.syment.n_sclass = sclass; |
coffsymbol (section->symbol)->native = native; |
coff_set_custom_section_alignment (abfd, section, |
coff_section_alignment_table, |
coff_section_alignment_table_size); |
return TRUE; |
} |
#ifdef COFF_ALIGN_IN_SECTION_HEADER |
/* Set the alignment of a BFD section. */ |
static void |
coff_set_alignment_hook (bfd * abfd ATTRIBUTE_UNUSED, |
asection * section, |
void * scnhdr) |
{ |
struct internal_scnhdr *hdr = (struct internal_scnhdr *) scnhdr; |
unsigned int i; |
#ifdef I960 |
/* Extract ALIGN from 2**ALIGN stored in section header. */ |
for (i = 0; i < 32; i++) |
if ((1 << i) >= hdr->s_align) |
break; |
#endif |
#ifdef TIC80COFF |
/* TI tools puts the alignment power in bits 8-11. */ |
i = (hdr->s_flags >> 8) & 0xF ; |
#endif |
#ifdef COFF_DECODE_ALIGNMENT |
i = COFF_DECODE_ALIGNMENT(hdr->s_flags); |
#endif |
section->alignment_power = i; |
#ifdef coff_set_section_load_page |
coff_set_section_load_page (section, hdr->s_page); |
#endif |
} |
#else /* ! COFF_ALIGN_IN_SECTION_HEADER */ |
#ifdef COFF_WITH_PE |
static void |
coff_set_alignment_hook (bfd * abfd ATTRIBUTE_UNUSED, |
asection * section, |
void * scnhdr) |
{ |
struct internal_scnhdr *hdr = (struct internal_scnhdr *) scnhdr; |
bfd_size_type amt; |
unsigned int alignment_power_const |
= hdr->s_flags & IMAGE_SCN_ALIGN_POWER_BIT_MASK; |
switch (alignment_power_const) |
{ |
case IMAGE_SCN_ALIGN_8192BYTES: |
case IMAGE_SCN_ALIGN_4096BYTES: |
case IMAGE_SCN_ALIGN_2048BYTES: |
case IMAGE_SCN_ALIGN_1024BYTES: |
case IMAGE_SCN_ALIGN_512BYTES: |
case IMAGE_SCN_ALIGN_256BYTES: |
case IMAGE_SCN_ALIGN_128BYTES: |
case IMAGE_SCN_ALIGN_64BYTES: |
case IMAGE_SCN_ALIGN_32BYTES: |
case IMAGE_SCN_ALIGN_16BYTES: |
case IMAGE_SCN_ALIGN_8BYTES: |
case IMAGE_SCN_ALIGN_4BYTES: |
case IMAGE_SCN_ALIGN_2BYTES: |
case IMAGE_SCN_ALIGN_1BYTES: |
section->alignment_power |
= IMAGE_SCN_ALIGN_POWER_NUM (alignment_power_const); |
break; |
default: |
break; |
} |
/* In a PE image file, the s_paddr field holds the virtual size of a |
section, while the s_size field holds the raw size. We also keep |
the original section flag value, since not every bit can be |
mapped onto a generic BFD section bit. */ |
if (coff_section_data (abfd, section) == NULL) |
{ |
amt = sizeof (struct coff_section_tdata); |
section->used_by_bfd = bfd_zalloc (abfd, amt); |
if (section->used_by_bfd == NULL) |
/* FIXME: Return error. */ |
abort (); |
} |
if (pei_section_data (abfd, section) == NULL) |
{ |
amt = sizeof (struct pei_section_tdata); |
coff_section_data (abfd, section)->tdata = bfd_zalloc (abfd, amt); |
if (coff_section_data (abfd, section)->tdata == NULL) |
/* FIXME: Return error. */ |
abort (); |
} |
pei_section_data (abfd, section)->virt_size = hdr->s_paddr; |
pei_section_data (abfd, section)->pe_flags = hdr->s_flags; |
section->lma = hdr->s_vaddr; |
/* Check for extended relocs. */ |
if (hdr->s_flags & IMAGE_SCN_LNK_NRELOC_OVFL) |
{ |
struct external_reloc dst; |
struct internal_reloc n; |
file_ptr oldpos = bfd_tell (abfd); |
bfd_size_type relsz = bfd_coff_relsz (abfd); |
if (bfd_seek (abfd, (file_ptr) hdr->s_relptr, 0) != 0) |
return; |
if (bfd_bread (& dst, relsz, abfd) != relsz) |
return; |
coff_swap_reloc_in (abfd, &dst, &n); |
if (bfd_seek (abfd, oldpos, 0) != 0) |
return; |
section->reloc_count = hdr->s_nreloc = n.r_vaddr - 1; |
section->rel_filepos += relsz; |
} |
else if (hdr->s_nreloc == 0xffff) |
(*_bfd_error_handler) |
("%s: warning: claims to have 0xffff relocs, without overflow", |
bfd_get_filename (abfd)); |
} |
#undef ALIGN_SET |
#undef ELIFALIGN_SET |
#else /* ! COFF_WITH_PE */ |
#ifdef RS6000COFF_C |
/* We grossly abuse this function to handle XCOFF overflow headers. |
When we see one, we correct the reloc and line number counts in the |
real header, and remove the section we just created. */ |
static void |
coff_set_alignment_hook (bfd *abfd, asection *section, void * scnhdr) |
{ |
struct internal_scnhdr *hdr = (struct internal_scnhdr *) scnhdr; |
asection *real_sec; |
if ((hdr->s_flags & STYP_OVRFLO) == 0) |
return; |
real_sec = coff_section_from_bfd_index (abfd, (int) hdr->s_nreloc); |
if (real_sec == NULL) |
return; |
real_sec->reloc_count = hdr->s_paddr; |
real_sec->lineno_count = hdr->s_vaddr; |
if (!bfd_section_removed_from_list (abfd, section)) |
{ |
bfd_section_list_remove (abfd, section); |
--abfd->section_count; |
} |
} |
#else /* ! RS6000COFF_C */ |
#define coff_set_alignment_hook \ |
((void (*) (bfd *, asection *, void *)) bfd_void) |
#endif /* ! RS6000COFF_C */ |
#endif /* ! COFF_WITH_PE */ |
#endif /* ! COFF_ALIGN_IN_SECTION_HEADER */ |
#ifndef coff_mkobject |
static bfd_boolean |
coff_mkobject (bfd * abfd) |
{ |
coff_data_type *coff; |
bfd_size_type amt = sizeof (coff_data_type); |
abfd->tdata.coff_obj_data = bfd_zalloc (abfd, amt); |
if (abfd->tdata.coff_obj_data == NULL) |
return FALSE; |
coff = coff_data (abfd); |
coff->symbols = NULL; |
coff->conversion_table = NULL; |
coff->raw_syments = NULL; |
coff->relocbase = 0; |
coff->local_toc_sym_map = 0; |
/* make_abs_section(abfd);*/ |
return TRUE; |
} |
#endif |
/* Create the COFF backend specific information. */ |
#ifndef coff_mkobject_hook |
static void * |
coff_mkobject_hook (bfd * abfd, |
void * filehdr, |
void * aouthdr ATTRIBUTE_UNUSED) |
{ |
struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; |
coff_data_type *coff; |
if (! coff_mkobject (abfd)) |
return NULL; |
coff = coff_data (abfd); |
coff->sym_filepos = internal_f->f_symptr; |
/* These members communicate important constants about the symbol |
table to GDB's symbol-reading code. These `constants' |
unfortunately vary among coff implementations... */ |
coff->local_n_btmask = N_BTMASK; |
coff->local_n_btshft = N_BTSHFT; |
coff->local_n_tmask = N_TMASK; |
coff->local_n_tshift = N_TSHIFT; |
coff->local_symesz = bfd_coff_symesz (abfd); |
coff->local_auxesz = bfd_coff_auxesz (abfd); |
coff->local_linesz = bfd_coff_linesz (abfd); |
coff->timestamp = internal_f->f_timdat; |
obj_raw_syment_count (abfd) = |
obj_conv_table_size (abfd) = |
internal_f->f_nsyms; |
#ifdef RS6000COFF_C |
if ((internal_f->f_flags & F_SHROBJ) != 0) |
abfd->flags |= DYNAMIC; |
if (aouthdr != NULL && internal_f->f_opthdr >= bfd_coff_aoutsz (abfd)) |
{ |
struct internal_aouthdr *internal_a = |
(struct internal_aouthdr *) aouthdr; |
struct xcoff_tdata *xcoff; |
xcoff = xcoff_data (abfd); |
# ifdef U803XTOCMAGIC |
xcoff->xcoff64 = internal_f->f_magic == U803XTOCMAGIC; |
# else |
xcoff->xcoff64 = 0; |
# endif |
xcoff->full_aouthdr = TRUE; |
xcoff->toc = internal_a->o_toc; |
xcoff->sntoc = internal_a->o_sntoc; |
xcoff->snentry = internal_a->o_snentry; |
bfd_xcoff_text_align_power (abfd) = internal_a->o_algntext; |
bfd_xcoff_data_align_power (abfd) = internal_a->o_algndata; |
xcoff->modtype = internal_a->o_modtype; |
xcoff->cputype = internal_a->o_cputype; |
xcoff->maxdata = internal_a->o_maxdata; |
xcoff->maxstack = internal_a->o_maxstack; |
} |
#endif |
#ifdef ARM |
/* Set the flags field from the COFF header read in. */ |
if (! _bfd_coff_arm_set_private_flags (abfd, internal_f->f_flags)) |
coff->flags = 0; |
#endif |
#ifdef COFF_WITH_PE |
/* FIXME: I'm not sure this is ever executed, since peicode.h |
defines coff_mkobject_hook. */ |
if ((internal_f->f_flags & IMAGE_FILE_DEBUG_STRIPPED) == 0) |
abfd->flags |= HAS_DEBUG; |
#endif |
if ((internal_f->f_flags & F_GO32STUB) != 0) |
coff->go32stub = (char *) bfd_alloc (abfd, (bfd_size_type) GO32_STUBSIZE); |
if (coff->go32stub != NULL) |
memcpy (coff->go32stub, internal_f->go32stub, GO32_STUBSIZE); |
return coff; |
} |
#endif |
/* Determine the machine architecture and type. FIXME: This is target |
dependent because the magic numbers are defined in the target |
dependent header files. But there is no particular need for this. |
If the magic numbers were moved to a separate file, this function |
would be target independent and would also be much more successful |
at linking together COFF files for different architectures. */ |
static bfd_boolean |
coff_set_arch_mach_hook (bfd *abfd, void * filehdr) |
{ |
unsigned long machine; |
enum bfd_architecture arch; |
struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; |
/* Zero selects the default machine for an arch. */ |
machine = 0; |
switch (internal_f->f_magic) |
{ |
#ifdef OR32_MAGIC_BIG |
case OR32_MAGIC_BIG: |
case OR32_MAGIC_LITTLE: |
arch = bfd_arch_or32; |
break; |
#endif |
#ifdef PPCMAGIC |
case PPCMAGIC: |
arch = bfd_arch_powerpc; |
break; |
#endif |
#ifdef I386MAGIC |
case I386MAGIC: |
case I386PTXMAGIC: |
case I386AIXMAGIC: /* Danbury PS/2 AIX C Compiler. */ |
case LYNXCOFFMAGIC: /* Shadows the m68k Lynx number below, sigh. */ |
arch = bfd_arch_i386; |
break; |
#endif |
#ifdef AMD64MAGIC |
case AMD64MAGIC: |
arch = bfd_arch_i386; |
machine = bfd_mach_x86_64; |
break; |
#endif |
#ifdef IA64MAGIC |
case IA64MAGIC: |
arch = bfd_arch_ia64; |
break; |
#endif |
#ifdef ARMMAGIC |
case ARMMAGIC: |
case ARMPEMAGIC: |
case THUMBPEMAGIC: |
arch = bfd_arch_arm; |
machine = bfd_arm_get_mach_from_notes (abfd, ARM_NOTE_SECTION); |
if (machine == bfd_mach_arm_unknown) |
{ |
switch (internal_f->f_flags & F_ARM_ARCHITECTURE_MASK) |
{ |
case F_ARM_2: machine = bfd_mach_arm_2; break; |
case F_ARM_2a: machine = bfd_mach_arm_2a; break; |
case F_ARM_3: machine = bfd_mach_arm_3; break; |
default: |
case F_ARM_3M: machine = bfd_mach_arm_3M; break; |
case F_ARM_4: machine = bfd_mach_arm_4; break; |
case F_ARM_4T: machine = bfd_mach_arm_4T; break; |
/* The COFF header does not have enough bits available |
to cover all the different ARM architectures. So |
we interpret F_ARM_5, the highest flag value to mean |
"the highest ARM architecture known to BFD" which is |
currently the XScale. */ |
case F_ARM_5: machine = bfd_mach_arm_XScale; break; |
} |
} |
break; |
#endif |
#ifdef MC68MAGIC |
case MC68MAGIC: |
case M68MAGIC: |
#ifdef MC68KBCSMAGIC |
case MC68KBCSMAGIC: |
#endif |
#ifdef APOLLOM68KMAGIC |
case APOLLOM68KMAGIC: |
#endif |
#ifdef LYNXCOFFMAGIC |
case LYNXCOFFMAGIC: |
#endif |
arch = bfd_arch_m68k; |
machine = bfd_mach_m68020; |
break; |
#endif |
#ifdef MC88MAGIC |
case MC88MAGIC: |
case MC88DMAGIC: |
case MC88OMAGIC: |
arch = bfd_arch_m88k; |
machine = 88100; |
break; |
#endif |
#ifdef Z80MAGIC |
case Z80MAGIC: |
arch = bfd_arch_z80; |
switch (internal_f->f_flags & F_MACHMASK) |
{ |
case 0: |
case bfd_mach_z80strict << 12: |
case bfd_mach_z80 << 12: |
case bfd_mach_z80full << 12: |
case bfd_mach_r800 << 12: |
machine = ((unsigned)internal_f->f_flags & F_MACHMASK) >> 12; |
break; |
default: |
return FALSE; |
} |
break; |
#endif |
#ifdef Z8KMAGIC |
case Z8KMAGIC: |
arch = bfd_arch_z8k; |
switch (internal_f->f_flags & F_MACHMASK) |
{ |
case F_Z8001: |
machine = bfd_mach_z8001; |
break; |
case F_Z8002: |
machine = bfd_mach_z8002; |
break; |
default: |
return FALSE; |
} |
break; |
#endif |
#ifdef I860 |
case I860MAGIC: |
arch = bfd_arch_i860; |
break; |
#endif |
#ifdef I960 |
#ifdef I960ROMAGIC |
case I960ROMAGIC: |
case I960RWMAGIC: |
arch = bfd_arch_i960; |
switch (F_I960TYPE & internal_f->f_flags) |
{ |
default: |
case F_I960CORE: |
machine = bfd_mach_i960_core; |
break; |
case F_I960KB: |
machine = bfd_mach_i960_kb_sb; |
break; |
case F_I960MC: |
machine = bfd_mach_i960_mc; |
break; |
case F_I960XA: |
machine = bfd_mach_i960_xa; |
break; |
case F_I960CA: |
machine = bfd_mach_i960_ca; |
break; |
case F_I960KA: |
machine = bfd_mach_i960_ka_sa; |
break; |
case F_I960JX: |
machine = bfd_mach_i960_jx; |
break; |
case F_I960HX: |
machine = bfd_mach_i960_hx; |
break; |
} |
break; |
#endif |
#endif |
#ifdef RS6000COFF_C |
#ifdef XCOFF64 |
case U64_TOCMAGIC: |
case U803XTOCMAGIC: |
#else |
case U802ROMAGIC: |
case U802WRMAGIC: |
case U802TOCMAGIC: |
#endif |
{ |
int cputype; |
if (xcoff_data (abfd)->cputype != -1) |
cputype = xcoff_data (abfd)->cputype & 0xff; |
else |
{ |
/* We did not get a value from the a.out header. If the |
file has not been stripped, we may be able to get the |
architecture information from the first symbol, if it |
is a .file symbol. */ |
if (obj_raw_syment_count (abfd) == 0) |
cputype = 0; |
else |
{ |
bfd_byte *buf; |
struct internal_syment sym; |
bfd_size_type amt = bfd_coff_symesz (abfd); |
buf = bfd_malloc (amt); |
if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0 |
|| bfd_bread (buf, amt, abfd) != amt) |
{ |
free (buf); |
return FALSE; |
} |
bfd_coff_swap_sym_in (abfd, buf, & sym); |
if (sym.n_sclass == C_FILE) |
cputype = sym.n_type & 0xff; |
else |
cputype = 0; |
free (buf); |
} |
} |
/* FIXME: We don't handle all cases here. */ |
switch (cputype) |
{ |
default: |
case 0: |
arch = bfd_xcoff_architecture (abfd); |
machine = bfd_xcoff_machine (abfd); |
break; |
case 1: |
arch = bfd_arch_powerpc; |
machine = bfd_mach_ppc_601; |
break; |
case 2: /* 64 bit PowerPC */ |
arch = bfd_arch_powerpc; |
machine = bfd_mach_ppc_620; |
break; |
case 3: |
arch = bfd_arch_powerpc; |
machine = bfd_mach_ppc; |
break; |
case 4: |
arch = bfd_arch_rs6000; |
machine = bfd_mach_rs6k; |
break; |
} |
} |
break; |
#endif |
#ifdef WE32KMAGIC |
case WE32KMAGIC: |
arch = bfd_arch_we32k; |
break; |
#endif |
#ifdef H8300MAGIC |
case H8300MAGIC: |
arch = bfd_arch_h8300; |
machine = bfd_mach_h8300; |
/* !! FIXME this probably isn't the right place for this. */ |
abfd->flags |= BFD_IS_RELAXABLE; |
break; |
#endif |
#ifdef H8300HMAGIC |
case H8300HMAGIC: |
arch = bfd_arch_h8300; |
machine = bfd_mach_h8300h; |
/* !! FIXME this probably isn't the right place for this. */ |
abfd->flags |= BFD_IS_RELAXABLE; |
break; |
#endif |
#ifdef H8300SMAGIC |
case H8300SMAGIC: |
arch = bfd_arch_h8300; |
machine = bfd_mach_h8300s; |
/* !! FIXME this probably isn't the right place for this. */ |
abfd->flags |= BFD_IS_RELAXABLE; |
break; |
#endif |
#ifdef H8300HNMAGIC |
case H8300HNMAGIC: |
arch = bfd_arch_h8300; |
machine = bfd_mach_h8300hn; |
/* !! FIXME this probably isn't the right place for this. */ |
abfd->flags |= BFD_IS_RELAXABLE; |
break; |
#endif |
#ifdef H8300SNMAGIC |
case H8300SNMAGIC: |
arch = bfd_arch_h8300; |
machine = bfd_mach_h8300sn; |
/* !! FIXME this probably isn't the right place for this. */ |
abfd->flags |= BFD_IS_RELAXABLE; |
break; |
#endif |
#ifdef SH_ARCH_MAGIC_BIG |
case SH_ARCH_MAGIC_BIG: |
case SH_ARCH_MAGIC_LITTLE: |
#ifdef COFF_WITH_PE |
case SH_ARCH_MAGIC_WINCE: |
#endif |
arch = bfd_arch_sh; |
break; |
#endif |
#ifdef MIPS_ARCH_MAGIC_WINCE |
case MIPS_ARCH_MAGIC_WINCE: |
arch = bfd_arch_mips; |
break; |
#endif |
#ifdef H8500MAGIC |
case H8500MAGIC: |
arch = bfd_arch_h8500; |
break; |
#endif |
#ifdef SPARCMAGIC |
case SPARCMAGIC: |
#ifdef LYNXCOFFMAGIC |
case LYNXCOFFMAGIC: |
#endif |
arch = bfd_arch_sparc; |
break; |
#endif |
#ifdef TIC30MAGIC |
case TIC30MAGIC: |
arch = bfd_arch_tic30; |
break; |
#endif |
#ifdef TICOFF0MAGIC |
#ifdef TICOFF_TARGET_ARCH |
/* This TI COFF section should be used by all new TI COFF v0 targets. */ |
case TICOFF0MAGIC: |
arch = TICOFF_TARGET_ARCH; |
machine = TICOFF_TARGET_MACHINE_GET (internal_f->f_flags); |
break; |
#endif |
#endif |
#ifdef TICOFF1MAGIC |
/* This TI COFF section should be used by all new TI COFF v1/2 targets. */ |
/* TI COFF1 and COFF2 use the target_id field to specify which arch. */ |
case TICOFF1MAGIC: |
case TICOFF2MAGIC: |
switch (internal_f->f_target_id) |
{ |
#ifdef TI_TARGET_ID |
case TI_TARGET_ID: |
arch = TICOFF_TARGET_ARCH; |
machine = TICOFF_TARGET_MACHINE_GET (internal_f->f_flags); |
break; |
#endif |
default: |
arch = bfd_arch_obscure; |
(*_bfd_error_handler) |
(_("Unrecognized TI COFF target id '0x%x'"), |
internal_f->f_target_id); |
break; |
} |
break; |
#endif |
#ifdef TIC80_ARCH_MAGIC |
case TIC80_ARCH_MAGIC: |
arch = bfd_arch_tic80; |
break; |
#endif |
#ifdef MCOREMAGIC |
case MCOREMAGIC: |
arch = bfd_arch_mcore; |
break; |
#endif |
#ifdef W65MAGIC |
case W65MAGIC: |
arch = bfd_arch_w65; |
break; |
#endif |
default: /* Unreadable input file type. */ |
arch = bfd_arch_obscure; |
break; |
} |
bfd_default_set_arch_mach (abfd, arch, machine); |
return TRUE; |
} |
#ifdef SYMNAME_IN_DEBUG |
static bfd_boolean |
symname_in_debug_hook (bfd * abfd ATTRIBUTE_UNUSED, struct internal_syment *sym) |
{ |
return SYMNAME_IN_DEBUG (sym) != 0; |
} |
#else |
#define symname_in_debug_hook \ |
(bfd_boolean (*) (bfd *, struct internal_syment *)) bfd_false |
#endif |
#ifdef RS6000COFF_C |
#ifdef XCOFF64 |
#define FORCE_SYMNAMES_IN_STRINGS |
#endif |
/* Handle the csect auxent of a C_EXT, C_AIX_WEAKEXT or C_HIDEXT symbol. */ |
static bfd_boolean |
coff_pointerize_aux_hook (bfd *abfd ATTRIBUTE_UNUSED, |
combined_entry_type *table_base, |
combined_entry_type *symbol, |
unsigned int indaux, |
combined_entry_type *aux) |
{ |
int n_sclass = symbol->u.syment.n_sclass; |
if (CSECT_SYM_P (n_sclass) |
&& indaux + 1 == symbol->u.syment.n_numaux) |
{ |
if (SMTYP_SMTYP (aux->u.auxent.x_csect.x_smtyp) == XTY_LD) |
{ |
aux->u.auxent.x_csect.x_scnlen.p = |
table_base + aux->u.auxent.x_csect.x_scnlen.l; |
aux->fix_scnlen = 1; |
} |
/* Return TRUE to indicate that the caller should not do any |
further work on this auxent. */ |
return TRUE; |
} |
/* Return FALSE to indicate that this auxent should be handled by |
the caller. */ |
return FALSE; |
} |
#else |
#ifdef I960 |
/* We don't want to pointerize bal entries. */ |
static bfd_boolean |
coff_pointerize_aux_hook (bfd *abfd ATTRIBUTE_UNUSED, |
combined_entry_type *table_base ATTRIBUTE_UNUSED, |
combined_entry_type *symbol, |
unsigned int indaux, |
combined_entry_type *aux ATTRIBUTE_UNUSED) |
{ |
/* Return TRUE if we don't want to pointerize this aux entry, which |
is the case for the lastfirst aux entry for a C_LEAFPROC symbol. */ |
return (indaux == 1 |
&& (symbol->u.syment.n_sclass == C_LEAFPROC |
|| symbol->u.syment.n_sclass == C_LEAFSTAT |
|| symbol->u.syment.n_sclass == C_LEAFEXT)); |
} |
#else /* ! I960 */ |
#define coff_pointerize_aux_hook 0 |
#endif /* ! I960 */ |
#endif /* ! RS6000COFF_C */ |
/* Print an aux entry. This returns TRUE if it has printed it. */ |
static bfd_boolean |
coff_print_aux (bfd *abfd ATTRIBUTE_UNUSED, |
FILE *file ATTRIBUTE_UNUSED, |
combined_entry_type *table_base ATTRIBUTE_UNUSED, |
combined_entry_type *symbol ATTRIBUTE_UNUSED, |
combined_entry_type *aux ATTRIBUTE_UNUSED, |
unsigned int indaux ATTRIBUTE_UNUSED) |
{ |
#ifdef RS6000COFF_C |
if (CSECT_SYM_P (symbol->u.syment.n_sclass) |
&& indaux + 1 == symbol->u.syment.n_numaux) |
{ |
/* This is a csect entry. */ |
fprintf (file, "AUX "); |
if (SMTYP_SMTYP (aux->u.auxent.x_csect.x_smtyp) != XTY_LD) |
{ |
BFD_ASSERT (! aux->fix_scnlen); |
#ifdef XCOFF64 |
fprintf (file, "val %5lld", |
(long long) aux->u.auxent.x_csect.x_scnlen.l); |
#else |
fprintf (file, "val %5ld", (long) aux->u.auxent.x_csect.x_scnlen.l); |
#endif |
} |
else |
{ |
fprintf (file, "indx "); |
if (! aux->fix_scnlen) |
#ifdef XCOFF64 |
fprintf (file, "%4lld", |
(long long) aux->u.auxent.x_csect.x_scnlen.l); |
#else |
fprintf (file, "%4ld", (long) aux->u.auxent.x_csect.x_scnlen.l); |
#endif |
else |
fprintf (file, "%4ld", |
(long) (aux->u.auxent.x_csect.x_scnlen.p - table_base)); |
} |
fprintf (file, |
" prmhsh %ld snhsh %u typ %d algn %d clss %u stb %ld snstb %u", |
aux->u.auxent.x_csect.x_parmhash, |
(unsigned int) aux->u.auxent.x_csect.x_snhash, |
SMTYP_SMTYP (aux->u.auxent.x_csect.x_smtyp), |
SMTYP_ALIGN (aux->u.auxent.x_csect.x_smtyp), |
(unsigned int) aux->u.auxent.x_csect.x_smclas, |
aux->u.auxent.x_csect.x_stab, |
(unsigned int) aux->u.auxent.x_csect.x_snstab); |
return TRUE; |
} |
#endif |
/* Return FALSE to indicate that no special action was taken. */ |
return FALSE; |
} |
/* |
SUBSUBSECTION |
Writing relocations |
To write relocations, the back end steps though the |
canonical relocation table and create an |
@code{internal_reloc}. The symbol index to use is removed from |
the @code{offset} field in the symbol table supplied. The |
address comes directly from the sum of the section base |
address and the relocation offset; the type is dug directly |
from the howto field. Then the @code{internal_reloc} is |
swapped into the shape of an @code{external_reloc} and written |
out to disk. |
*/ |
#ifdef TARG_AUX |
/* AUX's ld wants relocations to be sorted. */ |
static int |
compare_arelent_ptr (const void * x, const void * y) |
{ |
const arelent **a = (const arelent **) x; |
const arelent **b = (const arelent **) y; |
bfd_size_type aadr = (*a)->address; |
bfd_size_type badr = (*b)->address; |
return (aadr < badr ? -1 : badr < aadr ? 1 : 0); |
} |
#endif /* TARG_AUX */ |
static bfd_boolean |
coff_write_relocs (bfd * abfd, int first_undef) |
{ |
asection *s; |
for (s = abfd->sections; s != NULL; s = s->next) |
{ |
unsigned int i; |
struct external_reloc dst; |
arelent **p; |
#ifndef TARG_AUX |
p = s->orelocation; |
#else |
{ |
/* Sort relocations before we write them out. */ |
bfd_size_type amt; |
amt = s->reloc_count; |
amt *= sizeof (arelent *); |
p = bfd_malloc (amt); |
if (p == NULL && s->reloc_count > 0) |
return FALSE; |
memcpy (p, s->orelocation, (size_t) amt); |
qsort (p, s->reloc_count, sizeof (arelent *), compare_arelent_ptr); |
} |
#endif |
if (bfd_seek (abfd, s->rel_filepos, SEEK_SET) != 0) |
return FALSE; |
#ifdef COFF_WITH_PE |
if (obj_pe (abfd) && s->reloc_count >= 0xffff) |
{ |
/* Encode real count here as first reloc. */ |
struct internal_reloc n; |
memset (& n, 0, sizeof (n)); |
/* Add one to count *this* reloc (grr). */ |
n.r_vaddr = s->reloc_count + 1; |
coff_swap_reloc_out (abfd, &n, &dst); |
if (bfd_bwrite (& dst, (bfd_size_type) bfd_coff_relsz (abfd), |
abfd) != bfd_coff_relsz (abfd)) |
return FALSE; |
} |
#endif |
for (i = 0; i < s->reloc_count; i++) |
{ |
struct internal_reloc n; |
arelent *q = p[i]; |
memset (& n, 0, sizeof (n)); |
/* Now we've renumbered the symbols we know where the |
undefined symbols live in the table. Check the reloc |
entries for symbols who's output bfd isn't the right one. |
This is because the symbol was undefined (which means |
that all the pointers are never made to point to the same |
place). This is a bad thing,'cause the symbols attached |
to the output bfd are indexed, so that the relocation |
entries know which symbol index they point to. So we |
have to look up the output symbol here. */ |
if (q->sym_ptr_ptr[0] != NULL && q->sym_ptr_ptr[0]->the_bfd != abfd) |
{ |
int j; |
const char *sname = q->sym_ptr_ptr[0]->name; |
asymbol **outsyms = abfd->outsymbols; |
for (j = first_undef; outsyms[j]; j++) |
{ |
const char *intable = outsyms[j]->name; |
if (strcmp (intable, sname) == 0) |
{ |
/* Got a hit, so repoint the reloc. */ |
q->sym_ptr_ptr = outsyms + j; |
break; |
} |
} |
} |
n.r_vaddr = q->address + s->vma; |
#ifdef R_IHCONST |
/* The 29k const/consth reloc pair is a real kludge. The consth |
part doesn't have a symbol; it has an offset. So rebuilt |
that here. */ |
if (q->howto->type == R_IHCONST) |
n.r_symndx = q->addend; |
else |
#endif |
if (q->sym_ptr_ptr && q->sym_ptr_ptr[0] != NULL) |
{ |
#ifdef SECTION_RELATIVE_ABSOLUTE_SYMBOL_P |
if (SECTION_RELATIVE_ABSOLUTE_SYMBOL_P (q, s)) |
#else |
if ((*q->sym_ptr_ptr)->section == bfd_abs_section_ptr |
&& ((*q->sym_ptr_ptr)->flags & BSF_SECTION_SYM) != 0) |
#endif |
/* This is a relocation relative to the absolute symbol. */ |
n.r_symndx = -1; |
else |
{ |
n.r_symndx = get_index ((*(q->sym_ptr_ptr))); |
/* Check to see if the symbol reloc points to a symbol |
we don't have in our symbol table. */ |
if (n.r_symndx > obj_conv_table_size (abfd)) |
{ |
bfd_set_error (bfd_error_bad_value); |
_bfd_error_handler (_("%B: reloc against a non-existant symbol index: %ld"), |
abfd, n.r_symndx); |
return FALSE; |
} |
} |
} |
#ifdef SWAP_OUT_RELOC_OFFSET |
n.r_offset = q->addend; |
#endif |
#ifdef SELECT_RELOC |
/* Work out reloc type from what is required. */ |
SELECT_RELOC (n, q->howto); |
#else |
n.r_type = q->howto->type; |
#endif |
coff_swap_reloc_out (abfd, &n, &dst); |
if (bfd_bwrite (& dst, (bfd_size_type) bfd_coff_relsz (abfd), |
abfd) != bfd_coff_relsz (abfd)) |
return FALSE; |
} |
#ifdef TARG_AUX |
if (p != NULL) |
free (p); |
#endif |
} |
return TRUE; |
} |
/* Set flags and magic number of a coff file from architecture and machine |
type. Result is TRUE if we can represent the arch&type, FALSE if not. */ |
static bfd_boolean |
coff_set_flags (bfd * abfd, |
unsigned int *magicp ATTRIBUTE_UNUSED, |
unsigned short *flagsp ATTRIBUTE_UNUSED) |
{ |
switch (bfd_get_arch (abfd)) |
{ |
#ifdef Z80MAGIC |
case bfd_arch_z80: |
*magicp = Z80MAGIC; |
switch (bfd_get_mach (abfd)) |
{ |
case 0: |
case bfd_mach_z80strict: |
case bfd_mach_z80: |
case bfd_mach_z80full: |
case bfd_mach_r800: |
*flagsp = bfd_get_mach (abfd) << 12; |
break; |
default: |
return FALSE; |
} |
return TRUE; |
#endif |
#ifdef Z8KMAGIC |
case bfd_arch_z8k: |
*magicp = Z8KMAGIC; |
switch (bfd_get_mach (abfd)) |
{ |
case bfd_mach_z8001: *flagsp = F_Z8001; break; |
case bfd_mach_z8002: *flagsp = F_Z8002; break; |
default: return FALSE; |
} |
return TRUE; |
#endif |
#ifdef I960ROMAGIC |
case bfd_arch_i960: |
{ |
unsigned flags; |
*magicp = I960ROMAGIC; |
switch (bfd_get_mach (abfd)) |
{ |
case bfd_mach_i960_core: flags = F_I960CORE; break; |
case bfd_mach_i960_kb_sb: flags = F_I960KB; break; |
case bfd_mach_i960_mc: flags = F_I960MC; break; |
case bfd_mach_i960_xa: flags = F_I960XA; break; |
case bfd_mach_i960_ca: flags = F_I960CA; break; |
case bfd_mach_i960_ka_sa: flags = F_I960KA; break; |
case bfd_mach_i960_jx: flags = F_I960JX; break; |
case bfd_mach_i960_hx: flags = F_I960HX; break; |
default: return FALSE; |
} |
*flagsp = flags; |
return TRUE; |
} |
break; |
#endif |
#ifdef TIC30MAGIC |
case bfd_arch_tic30: |
*magicp = TIC30MAGIC; |
return TRUE; |
#endif |
#ifdef TICOFF_DEFAULT_MAGIC |
case TICOFF_TARGET_ARCH: |
/* If there's no indication of which version we want, use the default. */ |
if (!abfd->xvec ) |
*magicp = TICOFF_DEFAULT_MAGIC; |
else |
{ |
/* We may want to output in a different COFF version. */ |
switch (abfd->xvec->name[4]) |
{ |
case '0': |
*magicp = TICOFF0MAGIC; |
break; |
case '1': |
*magicp = TICOFF1MAGIC; |
break; |
case '2': |
*magicp = TICOFF2MAGIC; |
break; |
default: |
return FALSE; |
} |
} |
TICOFF_TARGET_MACHINE_SET (flagsp, bfd_get_mach (abfd)); |
return TRUE; |
#endif |
#ifdef TIC80_ARCH_MAGIC |
case bfd_arch_tic80: |
*magicp = TIC80_ARCH_MAGIC; |
return TRUE; |
#endif |
#ifdef ARMMAGIC |
case bfd_arch_arm: |
#ifdef ARM_WINCE |
* magicp = ARMPEMAGIC; |
#else |
* magicp = ARMMAGIC; |
#endif |
* flagsp = 0; |
if (APCS_SET (abfd)) |
{ |
if (APCS_26_FLAG (abfd)) |
* flagsp |= F_APCS26; |
if (APCS_FLOAT_FLAG (abfd)) |
* flagsp |= F_APCS_FLOAT; |
if (PIC_FLAG (abfd)) |
* flagsp |= F_PIC; |
} |
if (INTERWORK_SET (abfd) && INTERWORK_FLAG (abfd)) |
* flagsp |= F_INTERWORK; |
switch (bfd_get_mach (abfd)) |
{ |
case bfd_mach_arm_2: * flagsp |= F_ARM_2; break; |
case bfd_mach_arm_2a: * flagsp |= F_ARM_2a; break; |
case bfd_mach_arm_3: * flagsp |= F_ARM_3; break; |
case bfd_mach_arm_3M: * flagsp |= F_ARM_3M; break; |
case bfd_mach_arm_4: * flagsp |= F_ARM_4; break; |
case bfd_mach_arm_4T: * flagsp |= F_ARM_4T; break; |
case bfd_mach_arm_5: * flagsp |= F_ARM_5; break; |
/* FIXME: we do not have F_ARM vaues greater than F_ARM_5. |
See also the comment in coff_set_arch_mach_hook(). */ |
case bfd_mach_arm_5T: * flagsp |= F_ARM_5; break; |
case bfd_mach_arm_5TE: * flagsp |= F_ARM_5; break; |
case bfd_mach_arm_XScale: * flagsp |= F_ARM_5; break; |
} |
return TRUE; |
#endif |
#ifdef PPCMAGIC |
case bfd_arch_powerpc: |
*magicp = PPCMAGIC; |
return TRUE; |
#endif |
#if defined(I386MAGIC) || defined(AMD64MAGIC) |
case bfd_arch_i386: |
#if defined(I386MAGIC) |
*magicp = I386MAGIC; |
#endif |
#if defined LYNXOS |
/* Just overwrite the usual value if we're doing Lynx. */ |
*magicp = LYNXCOFFMAGIC; |
#endif |
#if defined AMD64MAGIC |
*magicp = AMD64MAGIC; |
#endif |
return TRUE; |
#endif |
#ifdef I860MAGIC |
case bfd_arch_i860: |
*magicp = I860MAGIC; |
return TRUE; |
#endif |
#ifdef IA64MAGIC |
case bfd_arch_ia64: |
*magicp = IA64MAGIC; |
return TRUE; |
#endif |
#ifdef MC68MAGIC |
case bfd_arch_m68k: |
#ifdef APOLLOM68KMAGIC |
*magicp = APOLLO_COFF_VERSION_NUMBER; |
#else |
/* NAMES_HAVE_UNDERSCORE may be defined by coff-u68k.c. */ |
#ifdef NAMES_HAVE_UNDERSCORE |
*magicp = MC68KBCSMAGIC; |
#else |
*magicp = MC68MAGIC; |
#endif |
#endif |
#ifdef LYNXOS |
/* Just overwrite the usual value if we're doing Lynx. */ |
*magicp = LYNXCOFFMAGIC; |
#endif |
return TRUE; |
#endif |
#ifdef MC88MAGIC |
case bfd_arch_m88k: |
*magicp = MC88OMAGIC; |
return TRUE; |
#endif |
#ifdef H8300MAGIC |
case bfd_arch_h8300: |
switch (bfd_get_mach (abfd)) |
{ |
case bfd_mach_h8300: *magicp = H8300MAGIC; return TRUE; |
case bfd_mach_h8300h: *magicp = H8300HMAGIC; return TRUE; |
case bfd_mach_h8300s: *magicp = H8300SMAGIC; return TRUE; |
case bfd_mach_h8300hn: *magicp = H8300HNMAGIC; return TRUE; |
case bfd_mach_h8300sn: *magicp = H8300SNMAGIC; return TRUE; |
default: break; |
} |
break; |
#endif |
#ifdef SH_ARCH_MAGIC_BIG |
case bfd_arch_sh: |
#ifdef COFF_IMAGE_WITH_PE |
*magicp = SH_ARCH_MAGIC_WINCE; |
#else |
if (bfd_big_endian (abfd)) |
*magicp = SH_ARCH_MAGIC_BIG; |
else |
*magicp = SH_ARCH_MAGIC_LITTLE; |
#endif |
return TRUE; |
#endif |
#ifdef MIPS_ARCH_MAGIC_WINCE |
case bfd_arch_mips: |
*magicp = MIPS_ARCH_MAGIC_WINCE; |
return TRUE; |
#endif |
#ifdef SPARCMAGIC |
case bfd_arch_sparc: |
*magicp = SPARCMAGIC; |
#ifdef LYNXOS |
/* Just overwrite the usual value if we're doing Lynx. */ |
*magicp = LYNXCOFFMAGIC; |
#endif |
return TRUE; |
#endif |
#ifdef H8500MAGIC |
case bfd_arch_h8500: |
*magicp = H8500MAGIC; |
return TRUE; |
break; |
#endif |
#ifdef WE32KMAGIC |
case bfd_arch_we32k: |
*magicp = WE32KMAGIC; |
return TRUE; |
#endif |
#ifdef RS6000COFF_C |
case bfd_arch_rs6000: |
#ifndef PPCMAGIC |
case bfd_arch_powerpc: |
#endif |
BFD_ASSERT (bfd_get_flavour (abfd) == bfd_target_xcoff_flavour); |
*magicp = bfd_xcoff_magic_number (abfd); |
return TRUE; |
#endif |
#ifdef MCOREMAGIC |
case bfd_arch_mcore: |
* magicp = MCOREMAGIC; |
return TRUE; |
#endif |
#ifdef W65MAGIC |
case bfd_arch_w65: |
*magicp = W65MAGIC; |
return TRUE; |
#endif |
#ifdef OR32_MAGIC_BIG |
case bfd_arch_or32: |
if (bfd_big_endian (abfd)) |
* magicp = OR32_MAGIC_BIG; |
else |
* magicp = OR32_MAGIC_LITTLE; |
return TRUE; |
#endif |
default: /* Unknown architecture. */ |
/* Fall through to "return FALSE" below, to avoid |
"statement never reached" errors on the one below. */ |
break; |
} |
return FALSE; |
} |
static bfd_boolean |
coff_set_arch_mach (bfd * abfd, |
enum bfd_architecture arch, |
unsigned long machine) |
{ |
unsigned dummy1; |
unsigned short dummy2; |
if (! bfd_default_set_arch_mach (abfd, arch, machine)) |
return FALSE; |
if (arch != bfd_arch_unknown |
&& ! coff_set_flags (abfd, &dummy1, &dummy2)) |
return FALSE; /* We can't represent this type. */ |
return TRUE; /* We're easy... */ |
} |
#ifdef COFF_IMAGE_WITH_PE |
/* This is used to sort sections by VMA, as required by PE image |
files. */ |
static int |
sort_by_secaddr (const void * arg1, const void * arg2) |
{ |
const asection *a = *(const asection **) arg1; |
const asection *b = *(const asection **) arg2; |
if (a->vma < b->vma) |
return -1; |
else if (a->vma > b->vma) |
return 1; |
return 0; |
} |
#endif /* COFF_IMAGE_WITH_PE */ |
/* Calculate the file position for each section. */ |
#ifndef I960 |
#define ALIGN_SECTIONS_IN_FILE |
#endif |
#if defined(TIC80COFF) || defined(TICOFF) |
#undef ALIGN_SECTIONS_IN_FILE |
#endif |
static bfd_boolean |
coff_compute_section_file_positions (bfd * abfd) |
{ |
asection *current; |
file_ptr sofar = bfd_coff_filhsz (abfd); |
bfd_boolean align_adjust; |
int target_index; |
#ifdef ALIGN_SECTIONS_IN_FILE |
asection *previous = NULL; |
file_ptr old_sofar; |
#endif |
#ifdef COFF_IMAGE_WITH_PE |
int page_size; |
if (coff_data (abfd)->link_info) |
{ |
page_size = pe_data (abfd)->pe_opthdr.FileAlignment; |
/* If no file alignment has been set, default to one. |
This repairs 'ld -r' for arm-wince-pe target. */ |
if (page_size == 0) |
page_size = 1; |
} |
else |
page_size = PE_DEF_FILE_ALIGNMENT; |
#else |
#ifdef COFF_PAGE_SIZE |
int page_size = COFF_PAGE_SIZE; |
#endif |
#endif |
#ifdef RS6000COFF_C |
/* On XCOFF, if we have symbols, set up the .debug section. */ |
if (bfd_get_symcount (abfd) > 0) |
{ |
bfd_size_type sz; |
bfd_size_type i, symcount; |
asymbol **symp; |
sz = 0; |
symcount = bfd_get_symcount (abfd); |
for (symp = abfd->outsymbols, i = 0; i < symcount; symp++, i++) |
{ |
coff_symbol_type *cf; |
cf = coff_symbol_from (abfd, *symp); |
if (cf != NULL |
&& cf->native != NULL |
&& SYMNAME_IN_DEBUG (&cf->native->u.syment)) |
{ |
size_t len; |
len = strlen (bfd_asymbol_name (*symp)); |
if (len > SYMNMLEN || bfd_coff_force_symnames_in_strings (abfd)) |
sz += len + 1 + bfd_coff_debug_string_prefix_length (abfd); |
} |
} |
if (sz > 0) |
{ |
asection *dsec; |
dsec = bfd_make_section_old_way (abfd, DOT_DEBUG); |
if (dsec == NULL) |
abort (); |
dsec->size = sz; |
dsec->flags |= SEC_HAS_CONTENTS; |
} |
} |
#endif |
if (bfd_get_start_address (abfd)) |
/* A start address may have been added to the original file. In this |
case it will need an optional header to record it. */ |
abfd->flags |= EXEC_P; |
if (abfd->flags & EXEC_P) |
sofar += bfd_coff_aoutsz (abfd); |
#ifdef RS6000COFF_C |
else if (xcoff_data (abfd)->full_aouthdr) |
sofar += bfd_coff_aoutsz (abfd); |
else |
sofar += SMALL_AOUTSZ; |
#endif |
sofar += abfd->section_count * bfd_coff_scnhsz (abfd); |
#ifdef RS6000COFF_C |
/* XCOFF handles overflows in the reloc and line number count fields |
by allocating a new section header to hold the correct counts. */ |
for (current = abfd->sections; current != NULL; current = current->next) |
if (current->reloc_count >= 0xffff || current->lineno_count >= 0xffff) |
sofar += bfd_coff_scnhsz (abfd); |
#endif |
#ifdef COFF_IMAGE_WITH_PE |
{ |
/* PE requires the sections to be in memory order when listed in |
the section headers. It also does not like empty loadable |
sections. The sections apparently do not have to be in the |
right order in the image file itself, but we do need to get the |
target_index values right. */ |
unsigned int count; |
asection **section_list; |
unsigned int i; |
bfd_size_type amt; |
#ifdef COFF_PAGE_SIZE |
/* Clear D_PAGED if section alignment is smaller than |
COFF_PAGE_SIZE. */ |
if (pe_data (abfd)->pe_opthdr.SectionAlignment < COFF_PAGE_SIZE) |
abfd->flags &= ~D_PAGED; |
#endif |
count = 0; |
for (current = abfd->sections; current != NULL; current = current->next) |
++count; |
/* We allocate an extra cell to simplify the final loop. */ |
amt = sizeof (struct asection *) * (count + 1); |
section_list = (asection **) bfd_malloc (amt); |
if (section_list == NULL) |
return FALSE; |
i = 0; |
for (current = abfd->sections; current != NULL; current = current->next) |
{ |
section_list[i] = current; |
++i; |
} |
section_list[i] = NULL; |
qsort (section_list, count, sizeof (asection *), sort_by_secaddr); |
/* Rethread the linked list into sorted order; at the same time, |
assign target_index values. */ |
target_index = 1; |
abfd->sections = NULL; |
abfd->section_last = NULL; |
for (i = 0; i < count; i++) |
{ |
current = section_list[i]; |
bfd_section_list_append (abfd, current); |
/* Later, if the section has zero size, we'll be throwing it |
away, so we don't want to number it now. Note that having |
a zero size and having real contents are different |
concepts: .bss has no contents, but (usually) non-zero |
size. */ |
if (current->size == 0) |
{ |
/* Discard. However, it still might have (valid) symbols |
in it, so arbitrarily set it to section 1 (indexing is |
1-based here; usually .text). __end__ and other |
contents of .endsection really have this happen. |
FIXME: This seems somewhat dubious. */ |
current->target_index = 1; |
} |
else |
current->target_index = target_index++; |
} |
free (section_list); |
} |
#else /* ! COFF_IMAGE_WITH_PE */ |
{ |
/* Set the target_index field. */ |
target_index = 1; |
for (current = abfd->sections; current != NULL; current = current->next) |
current->target_index = target_index++; |
} |
#endif /* ! COFF_IMAGE_WITH_PE */ |
if (target_index >= 32768) |
{ |
bfd_set_error (bfd_error_file_too_big); |
(*_bfd_error_handler) |
(_("%B: too many sections (%d)"), abfd, target_index); |
return FALSE; |
} |
align_adjust = FALSE; |
for (current = abfd->sections; |
current != NULL; |
current = current->next) |
{ |
#ifdef COFF_IMAGE_WITH_PE |
/* With PE we have to pad each section to be a multiple of its |
page size too, and remember both sizes. */ |
if (coff_section_data (abfd, current) == NULL) |
{ |
bfd_size_type amt = sizeof (struct coff_section_tdata); |
current->used_by_bfd = bfd_zalloc (abfd, amt); |
if (current->used_by_bfd == NULL) |
return FALSE; |
} |
if (pei_section_data (abfd, current) == NULL) |
{ |
bfd_size_type amt = sizeof (struct pei_section_tdata); |
coff_section_data (abfd, current)->tdata = bfd_zalloc (abfd, amt); |
if (coff_section_data (abfd, current)->tdata == NULL) |
return FALSE; |
} |
if (pei_section_data (abfd, current)->virt_size == 0) |
pei_section_data (abfd, current)->virt_size = current->size; |
#endif |
/* Only deal with sections which have contents. */ |
if (!(current->flags & SEC_HAS_CONTENTS)) |
continue; |
current->rawsize = current->size; |
#ifdef COFF_IMAGE_WITH_PE |
/* Make sure we skip empty sections in a PE image. */ |
if (current->size == 0) |
continue; |
#endif |
/* Align the sections in the file to the same boundary on |
which they are aligned in virtual memory. I960 doesn't |
do this (FIXME) so we can stay in sync with Intel. 960 |
doesn't yet page from files... */ |
#ifdef ALIGN_SECTIONS_IN_FILE |
if ((abfd->flags & EXEC_P) != 0) |
{ |
/* Make sure this section is aligned on the right boundary - by |
padding the previous section up if necessary. */ |
old_sofar = sofar; |
sofar = BFD_ALIGN (sofar, 1 << current->alignment_power); |
#ifdef RS6000COFF_C |
/* Make sure the file offset and the vma of .text/.data are at the |
same page offset, so that the file can be mmap'ed without being |
relocated. Failing that, AIX is able to load and execute the |
program, but it will be silently relocated (possible as |
executables are PIE). But the relocation is slightly costly and |
complexify the use of addr2line or gdb. So better to avoid it, |
like does the native linker. Usually gnu ld makes sure that |
the vma of .text is the file offset so this issue shouldn't |
appear unless you are stripping such an executable. |
AIX loader checks the text section alignment of (vma - filepos), |
and the native linker doesn't try to align the text sections. |
For example: |
0 .text 000054cc 10000128 10000128 00000128 2**5 |
CONTENTS, ALLOC, LOAD, CODE |
*/ |
if (!strcmp (current->name, _TEXT) |
|| !strcmp (current->name, _DATA)) |
{ |
bfd_vma align = 4096; |
bfd_vma sofar_off = sofar % align; |
bfd_vma vma_off = current->vma % align; |
if (vma_off > sofar_off) |
sofar += vma_off - sofar_off; |
else if (vma_off < sofar_off) |
sofar += align + vma_off - sofar_off; |
} |
#endif |
if (previous != NULL) |
previous->size += sofar - old_sofar; |
} |
#endif |
/* In demand paged files the low order bits of the file offset |
must match the low order bits of the virtual address. */ |
#ifdef COFF_PAGE_SIZE |
if ((abfd->flags & D_PAGED) != 0 |
&& (current->flags & SEC_ALLOC) != 0) |
sofar += (current->vma - (bfd_vma) sofar) % page_size; |
#endif |
current->filepos = sofar; |
#ifdef COFF_IMAGE_WITH_PE |
/* Set the padded size. */ |
current->size = (current->size + page_size - 1) & -page_size; |
#endif |
sofar += current->size; |
#ifdef ALIGN_SECTIONS_IN_FILE |
/* Make sure that this section is of the right size too. */ |
if ((abfd->flags & EXEC_P) == 0) |
{ |
bfd_size_type old_size; |
old_size = current->size; |
current->size = BFD_ALIGN (current->size, |
1 << current->alignment_power); |
align_adjust = current->size != old_size; |
sofar += current->size - old_size; |
} |
else |
{ |
old_sofar = sofar; |
sofar = BFD_ALIGN (sofar, 1 << current->alignment_power); |
align_adjust = sofar != old_sofar; |
current->size += sofar - old_sofar; |
} |
#endif |
#ifdef COFF_IMAGE_WITH_PE |
/* For PE we need to make sure we pad out to the aligned |
size, in case the caller only writes out data to the |
unaligned size. */ |
if (pei_section_data (abfd, current)->virt_size < current->size) |
align_adjust = TRUE; |
#endif |
#ifdef _LIB |
/* Force .lib sections to start at zero. The vma is then |
incremented in coff_set_section_contents. This is right for |
SVR3.2. */ |
if (strcmp (current->name, _LIB) == 0) |
(void) bfd_set_section_vma (abfd, current, 0); |
#endif |
#ifdef ALIGN_SECTIONS_IN_FILE |
previous = current; |
#endif |
} |
/* It is now safe to write to the output file. If we needed an |
alignment adjustment for the last section, then make sure that |
there is a byte at offset sofar. If there are no symbols and no |
relocs, then nothing follows the last section. If we don't force |
the last byte out, then the file may appear to be truncated. */ |
if (align_adjust) |
{ |
bfd_byte b; |
b = 0; |
if (bfd_seek (abfd, sofar - 1, SEEK_SET) != 0 |
|| bfd_bwrite (&b, (bfd_size_type) 1, abfd) != 1) |
return FALSE; |
} |
/* Make sure the relocations are aligned. We don't need to make |
sure that this byte exists, because it will only matter if there |
really are relocs. */ |
sofar = BFD_ALIGN (sofar, 1 << COFF_DEFAULT_SECTION_ALIGNMENT_POWER); |
obj_relocbase (abfd) = sofar; |
abfd->output_has_begun = TRUE; |
return TRUE; |
} |
#ifdef COFF_IMAGE_WITH_PE |
static unsigned int pelength; |
static unsigned int peheader; |
static bfd_boolean |
coff_read_word (bfd *abfd, unsigned int *value) |
{ |
unsigned char b[2]; |
int status; |
status = bfd_bread (b, (bfd_size_type) 2, abfd); |
if (status < 1) |
{ |
*value = 0; |
return FALSE; |
} |
if (status == 1) |
*value = (unsigned int) b[0]; |
else |
*value = (unsigned int) (b[0] + (b[1] << 8)); |
pelength += (unsigned int) status; |
return TRUE; |
} |
static unsigned int |
coff_compute_checksum (bfd *abfd) |
{ |
bfd_boolean more_data; |
file_ptr filepos; |
unsigned int value; |
unsigned int total; |
total = 0; |
pelength = 0; |
filepos = (file_ptr) 0; |
do |
{ |
if (bfd_seek (abfd, filepos, SEEK_SET) != 0) |
return 0; |
more_data = coff_read_word (abfd, &value); |
total += value; |
total = 0xffff & (total + (total >> 0x10)); |
filepos += 2; |
} |
while (more_data); |
return (0xffff & (total + (total >> 0x10))); |
} |
static bfd_boolean |
coff_apply_checksum (bfd *abfd) |
{ |
unsigned int computed; |
unsigned int checksum = 0; |
if (bfd_seek (abfd, 0x3c, SEEK_SET) != 0) |
return FALSE; |
if (!coff_read_word (abfd, &peheader)) |
return FALSE; |
if (bfd_seek (abfd, peheader + 0x58, SEEK_SET) != 0) |
return FALSE; |
checksum = 0; |
bfd_bwrite (&checksum, (bfd_size_type) 4, abfd); |
if (bfd_seek (abfd, peheader, SEEK_SET) != 0) |
return FALSE; |
computed = coff_compute_checksum (abfd); |
checksum = computed + pelength; |
if (bfd_seek (abfd, peheader + 0x58, SEEK_SET) != 0) |
return FALSE; |
bfd_bwrite (&checksum, (bfd_size_type) 4, abfd); |
return TRUE; |
} |
#endif /* COFF_IMAGE_WITH_PE */ |
static bfd_boolean |
coff_write_object_contents (bfd * abfd) |
{ |
asection *current; |
bfd_boolean hasrelocs = FALSE; |
bfd_boolean haslinno = FALSE; |
#ifdef COFF_IMAGE_WITH_PE |
bfd_boolean hasdebug = FALSE; |
#endif |
file_ptr scn_base; |
file_ptr reloc_base; |
file_ptr lineno_base; |
file_ptr sym_base; |
unsigned long reloc_size = 0, reloc_count = 0; |
unsigned long lnno_size = 0; |
bfd_boolean long_section_names; |
asection *text_sec = NULL; |
asection *data_sec = NULL; |
asection *bss_sec = NULL; |
struct internal_filehdr internal_f; |
struct internal_aouthdr internal_a; |
#ifdef COFF_LONG_SECTION_NAMES |
size_t string_size = STRING_SIZE_SIZE; |
#endif |
bfd_set_error (bfd_error_system_call); |
/* Make a pass through the symbol table to count line number entries and |
put them into the correct asections. */ |
lnno_size = coff_count_linenumbers (abfd) * bfd_coff_linesz (abfd); |
if (! abfd->output_has_begun) |
{ |
if (! coff_compute_section_file_positions (abfd)) |
return FALSE; |
} |
reloc_base = obj_relocbase (abfd); |
/* Work out the size of the reloc and linno areas. */ |
for (current = abfd->sections; current != NULL; current = |
current->next) |
{ |
#ifdef COFF_WITH_PE |
/* We store the actual reloc count in the first reloc's addr. */ |
if (obj_pe (abfd) && current->reloc_count >= 0xffff) |
reloc_count ++; |
#endif |
reloc_count += current->reloc_count; |
} |
reloc_size = reloc_count * bfd_coff_relsz (abfd); |
lineno_base = reloc_base + reloc_size; |
sym_base = lineno_base + lnno_size; |
/* Indicate in each section->line_filepos its actual file address. */ |
for (current = abfd->sections; current != NULL; current = |
current->next) |
{ |
if (current->lineno_count) |
{ |
current->line_filepos = lineno_base; |
current->moving_line_filepos = lineno_base; |
lineno_base += current->lineno_count * bfd_coff_linesz (abfd); |
} |
else |
current->line_filepos = 0; |
if (current->reloc_count) |
{ |
current->rel_filepos = reloc_base; |
reloc_base += current->reloc_count * bfd_coff_relsz (abfd); |
#ifdef COFF_WITH_PE |
/* Extra reloc to hold real count. */ |
if (obj_pe (abfd) && current->reloc_count >= 0xffff) |
reloc_base += bfd_coff_relsz (abfd); |
#endif |
} |
else |
current->rel_filepos = 0; |
} |
/* Write section headers to the file. */ |
internal_f.f_nscns = 0; |
if ((abfd->flags & EXEC_P) != 0) |
scn_base = bfd_coff_filhsz (abfd) + bfd_coff_aoutsz (abfd); |
else |
{ |
scn_base = bfd_coff_filhsz (abfd); |
#ifdef RS6000COFF_C |
#ifndef XCOFF64 |
if (xcoff_data (abfd)->full_aouthdr) |
scn_base += bfd_coff_aoutsz (abfd); |
else |
scn_base += SMALL_AOUTSZ; |
#endif |
#endif |
} |
if (bfd_seek (abfd, scn_base, SEEK_SET) != 0) |
return FALSE; |
long_section_names = FALSE; |
for (current = abfd->sections; |
current != NULL; |
current = current->next) |
{ |
struct internal_scnhdr section; |
#ifdef COFF_IMAGE_WITH_PE |
bfd_boolean is_reloc_section = FALSE; |
if (strcmp (current->name, DOT_RELOC) == 0) |
{ |
is_reloc_section = TRUE; |
hasrelocs = TRUE; |
pe_data (abfd)->has_reloc_section = 1; |
} |
#endif |
internal_f.f_nscns++; |
strncpy (section.s_name, current->name, SCNNMLEN); |
#ifdef COFF_LONG_SECTION_NAMES |
/* Handle long section names as in PE. This must be compatible |
with the code in coff_write_symbols and _bfd_coff_final_link. */ |
if (bfd_coff_long_section_names (abfd)) |
{ |
size_t len; |
len = strlen (current->name); |
if (len > SCNNMLEN) |
{ |
/* The s_name field is defined to be NUL-padded but need not be |
NUL-terminated. We use a temporary buffer so that we can still |
sprintf all eight chars without splatting a terminating NUL |
over the first byte of the following member (s_paddr). */ |
char s_name_buf[SCNNMLEN + 1]; |
/* An inherent limitation of the /nnnnnnn notation used to indicate |
the offset of the long name in the string table is that we |
cannot address entries beyone the ten million byte boundary. */ |
if (string_size >= 10000000) |
{ |
bfd_set_error (bfd_error_file_too_big); |
(*_bfd_error_handler) |
(_("%B: section %s: string table overflow at offset %ld"), |
abfd, current->name, string_size); |
return FALSE; |
} |
/* snprintf not strictly necessary now we've verified the value |
has less than eight ASCII digits, but never mind. */ |
snprintf (s_name_buf, SCNNMLEN + 1, "/%lu", (unsigned long) string_size); |
/* Then strncpy takes care of any padding for us. */ |
strncpy (section.s_name, s_name_buf, SCNNMLEN); |
string_size += len + 1; |
long_section_names = TRUE; |
} |
} |
#endif |
#ifdef _LIB |
/* Always set s_vaddr of .lib to 0. This is right for SVR3.2 |
Ian Taylor <ian@cygnus.com>. */ |
if (strcmp (current->name, _LIB) == 0) |
section.s_vaddr = 0; |
else |
#endif |
section.s_vaddr = current->vma; |
section.s_paddr = current->lma; |
section.s_size = current->size; |
#ifdef coff_get_section_load_page |
section.s_page = coff_get_section_load_page (current); |
#else |
section.s_page = 0; |
#endif |
#ifdef COFF_WITH_PE |
section.s_paddr = 0; |
#endif |
#ifdef COFF_IMAGE_WITH_PE |
/* Reminder: s_paddr holds the virtual size of the section. */ |
if (coff_section_data (abfd, current) != NULL |
&& pei_section_data (abfd, current) != NULL) |
section.s_paddr = pei_section_data (abfd, current)->virt_size; |
else |
section.s_paddr = 0; |
#endif |
/* If this section has no size or is unloadable then the scnptr |
will be 0 too. */ |
if (current->size == 0 |
|| (current->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0) |
section.s_scnptr = 0; |
else |
section.s_scnptr = current->filepos; |
section.s_relptr = current->rel_filepos; |
section.s_lnnoptr = current->line_filepos; |
section.s_nreloc = current->reloc_count; |
section.s_nlnno = current->lineno_count; |
#ifndef COFF_IMAGE_WITH_PE |
/* In PEI, relocs come in the .reloc section. */ |
if (current->reloc_count != 0) |
hasrelocs = TRUE; |
#endif |
if (current->lineno_count != 0) |
haslinno = TRUE; |
#ifdef COFF_IMAGE_WITH_PE |
if ((current->flags & SEC_DEBUGGING) != 0 |
&& ! is_reloc_section) |
hasdebug = TRUE; |
#endif |
#ifdef RS6000COFF_C |
#ifndef XCOFF64 |
/* Indicate the use of an XCOFF overflow section header. */ |
if (current->reloc_count >= 0xffff || current->lineno_count >= 0xffff) |
{ |
section.s_nreloc = 0xffff; |
section.s_nlnno = 0xffff; |
} |
#endif |
#endif |
section.s_flags = sec_to_styp_flags (current->name, current->flags); |
if (!strcmp (current->name, _TEXT)) |
text_sec = current; |
else if (!strcmp (current->name, _DATA)) |
data_sec = current; |
else if (!strcmp (current->name, _BSS)) |
bss_sec = current; |
#ifdef I960 |
section.s_align = (current->alignment_power |
? 1 << current->alignment_power |
: 0); |
#endif |
#ifdef TIC80COFF |
/* TI COFF puts the alignment power in bits 8-11 of the flags. */ |
section.s_flags |= (current->alignment_power & 0xF) << 8; |
#endif |
#ifdef COFF_ENCODE_ALIGNMENT |
COFF_ENCODE_ALIGNMENT(section, current->alignment_power); |
#endif |
#ifdef COFF_IMAGE_WITH_PE |
/* Suppress output of the sections if they are null. ld |
includes the bss and data sections even if there is no size |
assigned to them. NT loader doesn't like it if these section |
headers are included if the sections themselves are not |
needed. See also coff_compute_section_file_positions. */ |
if (section.s_size == 0) |
internal_f.f_nscns--; |
else |
#endif |
{ |
SCNHDR buff; |
bfd_size_type amt = bfd_coff_scnhsz (abfd); |
if (coff_swap_scnhdr_out (abfd, §ion, &buff) == 0 |
|| bfd_bwrite (& buff, amt, abfd) != amt) |
return FALSE; |
} |
#ifdef COFF_WITH_PE |
/* PE stores COMDAT section information in the symbol table. If |
this section is supposed to have some COMDAT info, track down |
the symbol in the symbol table and modify it. */ |
if ((current->flags & SEC_LINK_ONCE) != 0) |
{ |
unsigned int i, count; |
asymbol **psym; |
coff_symbol_type *csym = NULL; |
asymbol **psymsec; |
psymsec = NULL; |
count = bfd_get_symcount (abfd); |
for (i = 0, psym = abfd->outsymbols; i < count; i++, psym++) |
{ |
if ((*psym)->section != current) |
continue; |
/* Remember the location of the first symbol in this |
section. */ |
if (psymsec == NULL) |
psymsec = psym; |
/* See if this is the section symbol. */ |
if (strcmp ((*psym)->name, current->name) == 0) |
{ |
csym = coff_symbol_from (abfd, *psym); |
if (csym == NULL |
|| csym->native == NULL |
|| csym->native->u.syment.n_numaux < 1 |
|| csym->native->u.syment.n_sclass != C_STAT |
|| csym->native->u.syment.n_type != T_NULL) |
continue; |
/* Here *PSYM is the section symbol for CURRENT. */ |
break; |
} |
} |
/* Did we find it? |
Note that we might not if we're converting the file from |
some other object file format. */ |
if (i < count) |
{ |
combined_entry_type *aux; |
/* We don't touch the x_checksum field. The |
x_associated field is not currently supported. */ |
aux = csym->native + 1; |
switch (current->flags & SEC_LINK_DUPLICATES) |
{ |
case SEC_LINK_DUPLICATES_DISCARD: |
aux->u.auxent.x_scn.x_comdat = IMAGE_COMDAT_SELECT_ANY; |
break; |
case SEC_LINK_DUPLICATES_ONE_ONLY: |
aux->u.auxent.x_scn.x_comdat = |
IMAGE_COMDAT_SELECT_NODUPLICATES; |
break; |
case SEC_LINK_DUPLICATES_SAME_SIZE: |
aux->u.auxent.x_scn.x_comdat = |
IMAGE_COMDAT_SELECT_SAME_SIZE; |
break; |
case SEC_LINK_DUPLICATES_SAME_CONTENTS: |
aux->u.auxent.x_scn.x_comdat = |
IMAGE_COMDAT_SELECT_EXACT_MATCH; |
break; |
} |
/* The COMDAT symbol must be the first symbol from this |
section in the symbol table. In order to make this |
work, we move the COMDAT symbol before the first |
symbol we found in the search above. It's OK to |
rearrange the symbol table at this point, because |
coff_renumber_symbols is going to rearrange it |
further and fix up all the aux entries. */ |
if (psym != psymsec) |
{ |
asymbol *hold; |
asymbol **pcopy; |
hold = *psym; |
for (pcopy = psym; pcopy > psymsec; pcopy--) |
pcopy[0] = pcopy[-1]; |
*psymsec = hold; |
} |
} |
} |
#endif /* COFF_WITH_PE */ |
} |
#ifdef RS6000COFF_C |
#ifndef XCOFF64 |
/* XCOFF handles overflows in the reloc and line number count fields |
by creating a new section header to hold the correct values. */ |
for (current = abfd->sections; current != NULL; current = current->next) |
{ |
if (current->reloc_count >= 0xffff || current->lineno_count >= 0xffff) |
{ |
struct internal_scnhdr scnhdr; |
SCNHDR buff; |
bfd_size_type amt; |
internal_f.f_nscns++; |
memcpy (scnhdr.s_name, ".ovrflo", 8); |
scnhdr.s_paddr = current->reloc_count; |
scnhdr.s_vaddr = current->lineno_count; |
scnhdr.s_size = 0; |
scnhdr.s_scnptr = 0; |
scnhdr.s_relptr = current->rel_filepos; |
scnhdr.s_lnnoptr = current->line_filepos; |
scnhdr.s_nreloc = current->target_index; |
scnhdr.s_nlnno = current->target_index; |
scnhdr.s_flags = STYP_OVRFLO; |
amt = bfd_coff_scnhsz (abfd); |
if (coff_swap_scnhdr_out (abfd, &scnhdr, &buff) == 0 |
|| bfd_bwrite (& buff, amt, abfd) != amt) |
return FALSE; |
} |
} |
#endif |
#endif |
/* OK, now set up the filehdr... */ |
/* Don't include the internal abs section in the section count */ |
/* We will NOT put a fucking timestamp in the header here. Every time you |
put it back, I will come in and take it out again. I'm sorry. This |
field does not belong here. We fill it with a 0 so it compares the |
same but is not a reasonable time. -- gnu@cygnus.com */ |
internal_f.f_timdat = 0; |
internal_f.f_flags = 0; |
if (abfd->flags & EXEC_P) |
internal_f.f_opthdr = bfd_coff_aoutsz (abfd); |
else |
{ |
internal_f.f_opthdr = 0; |
#ifdef RS6000COFF_C |
#ifndef XCOFF64 |
if (xcoff_data (abfd)->full_aouthdr) |
internal_f.f_opthdr = bfd_coff_aoutsz (abfd); |
else |
internal_f.f_opthdr = SMALL_AOUTSZ; |
#endif |
#endif |
} |
if (!hasrelocs) |
internal_f.f_flags |= F_RELFLG; |
if (!haslinno) |
internal_f.f_flags |= F_LNNO; |
if (abfd->flags & EXEC_P) |
internal_f.f_flags |= F_EXEC; |
#ifdef COFF_IMAGE_WITH_PE |
if (! hasdebug) |
internal_f.f_flags |= IMAGE_FILE_DEBUG_STRIPPED; |
if (pe_data (abfd)->real_flags & IMAGE_FILE_LARGE_ADDRESS_AWARE) |
internal_f.f_flags |= IMAGE_FILE_LARGE_ADDRESS_AWARE; |
#endif |
#ifndef COFF_WITH_pex64 |
#ifdef COFF_WITH_PE |
internal_f.f_flags |= IMAGE_FILE_32BIT_MACHINE; |
#else |
if (bfd_little_endian (abfd)) |
internal_f.f_flags |= F_AR32WR; |
else |
internal_f.f_flags |= F_AR32W; |
#endif |
#endif |
#ifdef TI_TARGET_ID |
/* Target id is used in TI COFF v1 and later; COFF0 won't use this field, |
but it doesn't hurt to set it internally. */ |
internal_f.f_target_id = TI_TARGET_ID; |
#endif |
#ifdef TIC80_TARGET_ID |
internal_f.f_target_id = TIC80_TARGET_ID; |
#endif |
/* FIXME, should do something about the other byte orders and |
architectures. */ |
#ifdef RS6000COFF_C |
if ((abfd->flags & DYNAMIC) != 0) |
internal_f.f_flags |= F_SHROBJ; |
if (bfd_get_section_by_name (abfd, _LOADER) != NULL) |
internal_f.f_flags |= F_DYNLOAD; |
#endif |
memset (&internal_a, 0, sizeof internal_a); |
/* Set up architecture-dependent stuff. */ |
{ |
unsigned int magic = 0; |
unsigned short flags = 0; |
coff_set_flags (abfd, &magic, &flags); |
internal_f.f_magic = magic; |
internal_f.f_flags |= flags; |
/* ...and the "opt"hdr... */ |
#ifdef TICOFF_AOUT_MAGIC |
internal_a.magic = TICOFF_AOUT_MAGIC; |
#define __A_MAGIC_SET__ |
#endif |
#ifdef TIC80COFF |
internal_a.magic = TIC80_ARCH_MAGIC; |
#define __A_MAGIC_SET__ |
#endif /* TIC80 */ |
#ifdef I860 |
/* FIXME: What are the a.out magic numbers for the i860? */ |
internal_a.magic = 0; |
#define __A_MAGIC_SET__ |
#endif /* I860 */ |
#ifdef I960 |
internal_a.magic = (magic == I960ROMAGIC ? NMAGIC : OMAGIC); |
#define __A_MAGIC_SET__ |
#endif /* I960 */ |
#if M88 |
#define __A_MAGIC_SET__ |
internal_a.magic = PAGEMAGICBCS; |
#endif /* M88 */ |
#if APOLLO_M68 |
#define __A_MAGIC_SET__ |
internal_a.magic = APOLLO_COFF_VERSION_NUMBER; |
#endif |
#if defined(M68) || defined(WE32K) || defined(M68K) |
#define __A_MAGIC_SET__ |
#if defined(LYNXOS) |
internal_a.magic = LYNXCOFFMAGIC; |
#else |
#if defined(TARG_AUX) |
internal_a.magic = (abfd->flags & D_PAGED ? PAGEMAGICPEXECPAGED : |
abfd->flags & WP_TEXT ? PAGEMAGICPEXECSWAPPED : |
PAGEMAGICEXECSWAPPED); |
#else |
#if defined (PAGEMAGICPEXECPAGED) |
internal_a.magic = PAGEMAGICPEXECPAGED; |
#endif |
#endif /* TARG_AUX */ |
#endif /* LYNXOS */ |
#endif /* M68 || WE32K || M68K */ |
#if defined(ARM) |
#define __A_MAGIC_SET__ |
internal_a.magic = ZMAGIC; |
#endif |
#if defined(PPC_PE) |
#define __A_MAGIC_SET__ |
internal_a.magic = IMAGE_NT_OPTIONAL_HDR_MAGIC; |
#endif |
#if defined MCORE_PE |
#define __A_MAGIC_SET__ |
internal_a.magic = IMAGE_NT_OPTIONAL_HDR_MAGIC; |
#endif |
#if defined(I386) |
#define __A_MAGIC_SET__ |
#if defined LYNXOS |
internal_a.magic = LYNXCOFFMAGIC; |
#elif defined AMD64 |
internal_a.magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC; |
#else |
internal_a.magic = ZMAGIC; |
#endif |
#endif /* I386 */ |
#if defined(IA64) |
#define __A_MAGIC_SET__ |
internal_a.magic = PE32PMAGIC; |
#endif /* IA64 */ |
#if defined(SPARC) |
#define __A_MAGIC_SET__ |
#if defined(LYNXOS) |
internal_a.magic = LYNXCOFFMAGIC; |
#endif /* LYNXOS */ |
#endif /* SPARC */ |
#ifdef RS6000COFF_C |
#define __A_MAGIC_SET__ |
internal_a.magic = (abfd->flags & D_PAGED) ? RS6K_AOUTHDR_ZMAGIC : |
(abfd->flags & WP_TEXT) ? RS6K_AOUTHDR_NMAGIC : |
RS6K_AOUTHDR_OMAGIC; |
#endif |
#if defined(SH) && defined(COFF_WITH_PE) |
#define __A_MAGIC_SET__ |
internal_a.magic = SH_PE_MAGIC; |
#endif |
#if defined(MIPS) && defined(COFF_WITH_PE) |
#define __A_MAGIC_SET__ |
internal_a.magic = MIPS_PE_MAGIC; |
#endif |
#ifdef OR32 |
#define __A_MAGIC_SET__ |
internal_a.magic = NMAGIC; /* Assume separate i/d. */ |
#endif |
#ifndef __A_MAGIC_SET__ |
#include "Your aouthdr magic number is not being set!" |
#else |
#undef __A_MAGIC_SET__ |
#endif |
} |
/* FIXME: Does anybody ever set this to another value? */ |
internal_a.vstamp = 0; |
/* Now should write relocs, strings, syms. */ |
obj_sym_filepos (abfd) = sym_base; |
if (bfd_get_symcount (abfd) != 0) |
{ |
int firstundef; |
if (!coff_renumber_symbols (abfd, &firstundef)) |
return FALSE; |
coff_mangle_symbols (abfd); |
if (! coff_write_symbols (abfd)) |
return FALSE; |
if (! coff_write_linenumbers (abfd)) |
return FALSE; |
if (! coff_write_relocs (abfd, firstundef)) |
return FALSE; |
} |
#ifdef COFF_LONG_SECTION_NAMES |
else if (long_section_names && ! obj_coff_strings_written (abfd)) |
{ |
/* If we have long section names we have to write out the string |
table even if there are no symbols. */ |
if (! coff_write_symbols (abfd)) |
return FALSE; |
} |
#endif |
#ifdef COFF_IMAGE_WITH_PE |
#ifdef PPC_PE |
else if ((abfd->flags & EXEC_P) != 0) |
{ |
bfd_byte b; |
/* PowerPC PE appears to require that all executable files be |
rounded up to the page size. */ |
b = 0; |
if (bfd_seek (abfd, |
(file_ptr) BFD_ALIGN (sym_base, COFF_PAGE_SIZE) - 1, |
SEEK_SET) != 0 |
|| bfd_bwrite (&b, (bfd_size_type) 1, abfd) != 1) |
return FALSE; |
} |
#endif |
#endif |
/* If bfd_get_symcount (abfd) != 0, then we are not using the COFF |
backend linker, and obj_raw_syment_count is not valid until after |
coff_write_symbols is called. */ |
if (obj_raw_syment_count (abfd) != 0) |
{ |
internal_f.f_symptr = sym_base; |
#ifdef RS6000COFF_C |
/* AIX appears to require that F_RELFLG not be set if there are |
local symbols but no relocations. */ |
internal_f.f_flags &=~ F_RELFLG; |
#endif |
} |
else |
{ |
if (long_section_names) |
internal_f.f_symptr = sym_base; |
else |
internal_f.f_symptr = 0; |
internal_f.f_flags |= F_LSYMS; |
} |
if (text_sec) |
{ |
internal_a.tsize = text_sec->size; |
internal_a.text_start = internal_a.tsize ? text_sec->vma : 0; |
} |
if (data_sec) |
{ |
internal_a.dsize = data_sec->size; |
internal_a.data_start = internal_a.dsize ? data_sec->vma : 0; |
} |
if (bss_sec) |
{ |
internal_a.bsize = bss_sec->size; |
if (internal_a.bsize && bss_sec->vma < internal_a.data_start) |
internal_a.data_start = bss_sec->vma; |
} |
internal_a.entry = bfd_get_start_address (abfd); |
internal_f.f_nsyms = obj_raw_syment_count (abfd); |
#ifdef RS6000COFF_C |
if (xcoff_data (abfd)->full_aouthdr) |
{ |
bfd_vma toc; |
asection *loader_sec; |
internal_a.vstamp = 1; |
internal_a.o_snentry = xcoff_data (abfd)->snentry; |
if (internal_a.o_snentry == 0) |
internal_a.entry = (bfd_vma) -1; |
if (text_sec != NULL) |
{ |
internal_a.o_sntext = text_sec->target_index; |
internal_a.o_algntext = bfd_get_section_alignment (abfd, text_sec); |
} |
else |
{ |
internal_a.o_sntext = 0; |
internal_a.o_algntext = 0; |
} |
if (data_sec != NULL) |
{ |
internal_a.o_sndata = data_sec->target_index; |
internal_a.o_algndata = bfd_get_section_alignment (abfd, data_sec); |
} |
else |
{ |
internal_a.o_sndata = 0; |
internal_a.o_algndata = 0; |
} |
loader_sec = bfd_get_section_by_name (abfd, ".loader"); |
if (loader_sec != NULL) |
internal_a.o_snloader = loader_sec->target_index; |
else |
internal_a.o_snloader = 0; |
if (bss_sec != NULL) |
internal_a.o_snbss = bss_sec->target_index; |
else |
internal_a.o_snbss = 0; |
toc = xcoff_data (abfd)->toc; |
internal_a.o_toc = toc; |
internal_a.o_sntoc = xcoff_data (abfd)->sntoc; |
internal_a.o_modtype = xcoff_data (abfd)->modtype; |
if (xcoff_data (abfd)->cputype != -1) |
internal_a.o_cputype = xcoff_data (abfd)->cputype; |
else |
{ |
switch (bfd_get_arch (abfd)) |
{ |
case bfd_arch_rs6000: |
internal_a.o_cputype = 4; |
break; |
case bfd_arch_powerpc: |
if (bfd_get_mach (abfd) == bfd_mach_ppc) |
internal_a.o_cputype = 3; |
else |
internal_a.o_cputype = 1; |
break; |
default: |
abort (); |
} |
} |
internal_a.o_maxstack = xcoff_data (abfd)->maxstack; |
internal_a.o_maxdata = xcoff_data (abfd)->maxdata; |
} |
#endif |
/* Now write them. */ |
if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) |
return FALSE; |
{ |
char * buff; |
bfd_size_type amount = bfd_coff_filhsz (abfd); |
buff = (char *) bfd_malloc (amount); |
if (buff == NULL) |
return FALSE; |
bfd_coff_swap_filehdr_out (abfd, & internal_f, buff); |
amount = bfd_bwrite (buff, amount, abfd); |
free (buff); |
if (amount != bfd_coff_filhsz (abfd)) |
return FALSE; |
} |
if (abfd->flags & EXEC_P) |
{ |
/* Note that peicode.h fills in a PEAOUTHDR, not an AOUTHDR. |
include/coff/pe.h sets AOUTSZ == sizeof (PEAOUTHDR)). */ |
char * buff; |
bfd_size_type amount = bfd_coff_aoutsz (abfd); |
buff = (char *) bfd_malloc (amount); |
if (buff == NULL) |
return FALSE; |
coff_swap_aouthdr_out (abfd, & internal_a, buff); |
amount = bfd_bwrite (buff, amount, abfd); |
free (buff); |
if (amount != bfd_coff_aoutsz (abfd)) |
return FALSE; |
#ifdef COFF_IMAGE_WITH_PE |
if (! coff_apply_checksum (abfd)) |
return FALSE; |
#endif |
} |
#ifdef RS6000COFF_C |
else |
{ |
AOUTHDR buff; |
size_t size; |
/* XCOFF seems to always write at least a small a.out header. */ |
coff_swap_aouthdr_out (abfd, & internal_a, & buff); |
if (xcoff_data (abfd)->full_aouthdr) |
size = bfd_coff_aoutsz (abfd); |
else |
size = SMALL_AOUTSZ; |
if (bfd_bwrite (& buff, (bfd_size_type) size, abfd) != size) |
return FALSE; |
} |
#endif |
return TRUE; |
} |
static bfd_boolean |
coff_set_section_contents (bfd * abfd, |
sec_ptr section, |
const void * location, |
file_ptr offset, |
bfd_size_type count) |
{ |
if (! abfd->output_has_begun) /* Set by bfd.c handler. */ |
{ |
if (! coff_compute_section_file_positions (abfd)) |
return FALSE; |
} |
#if defined(_LIB) && !defined(TARG_AUX) |
/* The physical address field of a .lib section is used to hold the |
number of shared libraries in the section. This code counts the |
number of sections being written, and increments the lma field |
with the number. |
I have found no documentation on the contents of this section. |
Experimentation indicates that the section contains zero or more |
records, each of which has the following structure: |
- a (four byte) word holding the length of this record, in words, |
- a word that always seems to be set to "2", |
- the path to a shared library, null-terminated and then padded |
to a whole word boundary. |
bfd_assert calls have been added to alert if an attempt is made |
to write a section which doesn't follow these assumptions. The |
code has been tested on ISC 4.1 by me, and on SCO by Robert Lipe |
<robertl@arnet.com> (Thanks!). |
Gvran Uddeborg <gvran@uddeborg.pp.se>. */ |
if (strcmp (section->name, _LIB) == 0) |
{ |
bfd_byte *rec, *recend; |
rec = (bfd_byte *) location; |
recend = rec + count; |
while (rec < recend) |
{ |
++section->lma; |
rec += bfd_get_32 (abfd, rec) * 4; |
} |
BFD_ASSERT (rec == recend); |
} |
#endif |
/* Don't write out bss sections - one way to do this is to |
see if the filepos has not been set. */ |
if (section->filepos == 0) |
return TRUE; |
if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0) |
return FALSE; |
if (count == 0) |
return TRUE; |
return bfd_bwrite (location, count, abfd) == count; |
} |
static void * |
buy_and_read (bfd *abfd, file_ptr where, bfd_size_type size) |
{ |
void * area = bfd_alloc (abfd, size); |
if (!area) |
return (NULL); |
if (bfd_seek (abfd, where, SEEK_SET) != 0 |
|| bfd_bread (area, size, abfd) != size) |
return (NULL); |
return (area); |
} |
/* |
SUBSUBSECTION |
Reading linenumbers |
Creating the linenumber table is done by reading in the entire |
coff linenumber table, and creating another table for internal use. |
A coff linenumber table is structured so that each function |
is marked as having a line number of 0. Each line within the |
function is an offset from the first line in the function. The |
base of the line number information for the table is stored in |
the symbol associated with the function. |
Note: The PE format uses line number 0 for a flag indicating a |
new source file. |
The information is copied from the external to the internal |
table, and each symbol which marks a function is marked by |
pointing its... |
How does this work ? |
*/ |
static int |
coff_sort_func_alent (const void * arg1, const void * arg2) |
{ |
const alent *al1 = *(const alent **) arg1; |
const alent *al2 = *(const alent **) arg2; |
const coff_symbol_type *s1 = (const coff_symbol_type *) (al1->u.sym); |
const coff_symbol_type *s2 = (const coff_symbol_type *) (al2->u.sym); |
if (s1->symbol.value < s2->symbol.value) |
return -1; |
else if (s1->symbol.value > s2->symbol.value) |
return 1; |
return 0; |
} |
static bfd_boolean |
coff_slurp_line_table (bfd *abfd, asection *asect) |
{ |
LINENO *native_lineno; |
alent *lineno_cache; |
bfd_size_type amt; |
unsigned int counter; |
alent *cache_ptr; |
bfd_vma prev_offset = 0; |
int ordered = 1; |
unsigned int nbr_func; |
LINENO *src; |
BFD_ASSERT (asect->lineno == NULL); |
amt = ((bfd_size_type) asect->lineno_count + 1) * sizeof (alent); |
lineno_cache = (alent *) bfd_alloc (abfd, amt); |
if (lineno_cache == NULL) |
return FALSE; |
amt = (bfd_size_type) bfd_coff_linesz (abfd) * asect->lineno_count; |
native_lineno = (LINENO *) buy_and_read (abfd, asect->line_filepos, amt); |
if (native_lineno == NULL) |
{ |
(*_bfd_error_handler) |
(_("%B: warning: line number table read failed"), abfd); |
bfd_release (abfd, lineno_cache); |
return FALSE; |
} |
cache_ptr = lineno_cache; |
asect->lineno = lineno_cache; |
src = native_lineno; |
nbr_func = 0; |
for (counter = 0; counter < asect->lineno_count; counter++) |
{ |
struct internal_lineno dst; |
bfd_coff_swap_lineno_in (abfd, src, &dst); |
cache_ptr->line_number = dst.l_lnno; |
if (cache_ptr->line_number == 0) |
{ |
bfd_boolean warned; |
bfd_signed_vma symndx; |
coff_symbol_type *sym; |
nbr_func++; |
warned = FALSE; |
symndx = dst.l_addr.l_symndx; |
if (symndx < 0 |
|| (bfd_vma) symndx >= obj_raw_syment_count (abfd)) |
{ |
(*_bfd_error_handler) |
(_("%B: warning: illegal symbol index %ld in line numbers"), |
abfd, (long) symndx); |
symndx = 0; |
warned = TRUE; |
} |
/* FIXME: We should not be casting between ints and |
pointers like this. */ |
sym = ((coff_symbol_type *) |
((symndx + obj_raw_syments (abfd)) |
->u.syment._n._n_n._n_zeroes)); |
cache_ptr->u.sym = (asymbol *) sym; |
if (sym->lineno != NULL && ! warned) |
(*_bfd_error_handler) |
(_("%B: warning: duplicate line number information for `%s'"), |
abfd, bfd_asymbol_name (&sym->symbol)); |
sym->lineno = cache_ptr; |
if (sym->symbol.value < prev_offset) |
ordered = 0; |
prev_offset = sym->symbol.value; |
} |
else |
cache_ptr->u.offset = dst.l_addr.l_paddr |
- bfd_section_vma (abfd, asect); |
cache_ptr++; |
src++; |
} |
cache_ptr->line_number = 0; |
bfd_release (abfd, native_lineno); |
/* On some systems (eg AIX5.3) the lineno table may not be sorted. */ |
if (!ordered) |
{ |
/* Sort the table. */ |
alent **func_table; |
alent *n_lineno_cache; |
/* Create a table of functions. */ |
func_table = (alent **) bfd_alloc (abfd, nbr_func * sizeof (alent *)); |
if (func_table != NULL) |
{ |
alent **p = func_table; |
unsigned int i; |
for (i = 0; i < counter; i++) |
if (lineno_cache[i].line_number == 0) |
*p++ = &lineno_cache[i]; |
/* Sort by functions. */ |
qsort (func_table, nbr_func, sizeof (alent *), coff_sort_func_alent); |
/* Create the new sorted table. */ |
amt = ((bfd_size_type) asect->lineno_count + 1) * sizeof (alent); |
n_lineno_cache = (alent *) bfd_alloc (abfd, amt); |
if (n_lineno_cache != NULL) |
{ |
alent *n_cache_ptr = n_lineno_cache; |
for (i = 0; i < nbr_func; i++) |
{ |
coff_symbol_type *sym; |
alent *old_ptr = func_table[i]; |
/* Copy the function entry and update it. */ |
*n_cache_ptr = *old_ptr; |
sym = (coff_symbol_type *)n_cache_ptr->u.sym; |
sym->lineno = n_cache_ptr; |
n_cache_ptr++; |
old_ptr++; |
/* Copy the line number entries. */ |
while (old_ptr->line_number != 0) |
*n_cache_ptr++ = *old_ptr++; |
} |
n_cache_ptr->line_number = 0; |
memcpy (lineno_cache, n_lineno_cache, amt); |
} |
bfd_release (abfd, func_table); |
} |
} |
return TRUE; |
} |
/* Slurp in the symbol table, converting it to generic form. Note |
that if coff_relocate_section is defined, the linker will read |
symbols via coff_link_add_symbols, rather than via this routine. */ |
static bfd_boolean |
coff_slurp_symbol_table (bfd * abfd) |
{ |
combined_entry_type *native_symbols; |
coff_symbol_type *cached_area; |
unsigned int *table_ptr; |
bfd_size_type amt; |
unsigned int number_of_symbols = 0; |
if (obj_symbols (abfd)) |
return TRUE; |
/* Read in the symbol table. */ |
if ((native_symbols = coff_get_normalized_symtab (abfd)) == NULL) |
return FALSE; |
/* Allocate enough room for all the symbols in cached form. */ |
amt = obj_raw_syment_count (abfd); |
amt *= sizeof (coff_symbol_type); |
cached_area = (coff_symbol_type *) bfd_alloc (abfd, amt); |
if (cached_area == NULL) |
return FALSE; |
amt = obj_raw_syment_count (abfd); |
amt *= sizeof (unsigned int); |
table_ptr = (unsigned int *) bfd_alloc (abfd, amt); |
if (table_ptr == NULL) |
return FALSE; |
else |
{ |
coff_symbol_type *dst = cached_area; |
unsigned int last_native_index = obj_raw_syment_count (abfd); |
unsigned int this_index = 0; |
while (this_index < last_native_index) |
{ |
combined_entry_type *src = native_symbols + this_index; |
table_ptr[this_index] = number_of_symbols; |
dst->symbol.the_bfd = abfd; |
dst->symbol.name = (char *) (src->u.syment._n._n_n._n_offset); |
/* We use the native name field to point to the cached field. */ |
src->u.syment._n._n_n._n_zeroes = (bfd_hostptr_t) dst; |
dst->symbol.section = coff_section_from_bfd_index (abfd, |
src->u.syment.n_scnum); |
dst->symbol.flags = 0; |
dst->done_lineno = FALSE; |
switch (src->u.syment.n_sclass) |
{ |
#ifdef I960 |
case C_LEAFEXT: |
/* Fall through to next case. */ |
#endif |
case C_EXT: |
case C_WEAKEXT: |
#if defined ARM |
case C_THUMBEXT: |
case C_THUMBEXTFUNC: |
#endif |
#ifdef RS6000COFF_C |
case C_HIDEXT: |
#endif |
#ifdef C_SYSTEM |
case C_SYSTEM: /* System Wide variable. */ |
#endif |
#ifdef COFF_WITH_PE |
/* In PE, 0x68 (104) denotes a section symbol. */ |
case C_SECTION: |
/* In PE, 0x69 (105) denotes a weak external symbol. */ |
case C_NT_WEAK: |
#endif |
switch (coff_classify_symbol (abfd, &src->u.syment)) |
{ |
case COFF_SYMBOL_GLOBAL: |
dst->symbol.flags = BSF_EXPORT | BSF_GLOBAL; |
#if defined COFF_WITH_PE |
/* PE sets the symbol to a value relative to the |
start of the section. */ |
dst->symbol.value = src->u.syment.n_value; |
#else |
dst->symbol.value = (src->u.syment.n_value |
- dst->symbol.section->vma); |
#endif |
if (ISFCN ((src->u.syment.n_type))) |
/* A function ext does not go at the end of a |
file. */ |
dst->symbol.flags |= BSF_NOT_AT_END | BSF_FUNCTION; |
break; |
case COFF_SYMBOL_COMMON: |
dst->symbol.section = bfd_com_section_ptr; |
dst->symbol.value = src->u.syment.n_value; |
break; |
case COFF_SYMBOL_UNDEFINED: |
dst->symbol.section = bfd_und_section_ptr; |
dst->symbol.value = 0; |
break; |
case COFF_SYMBOL_PE_SECTION: |
dst->symbol.flags |= BSF_EXPORT | BSF_SECTION_SYM; |
dst->symbol.value = 0; |
break; |
case COFF_SYMBOL_LOCAL: |
dst->symbol.flags = BSF_LOCAL; |
#if defined COFF_WITH_PE |
/* PE sets the symbol to a value relative to the |
start of the section. */ |
dst->symbol.value = src->u.syment.n_value; |
#else |
dst->symbol.value = (src->u.syment.n_value |
- dst->symbol.section->vma); |
#endif |
if (ISFCN ((src->u.syment.n_type))) |
dst->symbol.flags |= BSF_NOT_AT_END | BSF_FUNCTION; |
break; |
} |
#ifdef RS6000COFF_C |
/* A symbol with a csect entry should not go at the end. */ |
if (src->u.syment.n_numaux > 0) |
dst->symbol.flags |= BSF_NOT_AT_END; |
#endif |
#ifdef COFF_WITH_PE |
if (src->u.syment.n_sclass == C_NT_WEAK) |
dst->symbol.flags |= BSF_WEAK; |
if (src->u.syment.n_sclass == C_SECTION |
&& src->u.syment.n_scnum > 0) |
dst->symbol.flags = BSF_LOCAL; |
#endif |
if (src->u.syment.n_sclass == C_WEAKEXT) |
dst->symbol.flags |= BSF_WEAK; |
break; |
case C_STAT: /* Static. */ |
#ifdef I960 |
case C_LEAFSTAT: /* Static leaf procedure. */ |
#endif |
#if defined ARM |
case C_THUMBSTAT: /* Thumb static. */ |
case C_THUMBLABEL: /* Thumb label. */ |
case C_THUMBSTATFUNC:/* Thumb static function. */ |
#endif |
#ifdef RS6000COFF_C |
case C_DWARF: /* A label in a dwarf section. */ |
case C_INFO: /* A label in a comment section. */ |
#endif |
case C_LABEL: /* Label. */ |
if (src->u.syment.n_scnum == N_DEBUG) |
dst->symbol.flags = BSF_DEBUGGING; |
else |
dst->symbol.flags = BSF_LOCAL; |
/* Base the value as an index from the base of the |
section, if there is one. */ |
if (dst->symbol.section) |
{ |
#if defined COFF_WITH_PE |
/* PE sets the symbol to a value relative to the |
start of the section. */ |
dst->symbol.value = src->u.syment.n_value; |
#else |
dst->symbol.value = (src->u.syment.n_value |
- dst->symbol.section->vma); |
#endif |
} |
else |
dst->symbol.value = src->u.syment.n_value; |
break; |
case C_MOS: /* Member of structure. */ |
case C_EOS: /* End of structure. */ |
case C_REGPARM: /* Register parameter. */ |
case C_REG: /* register variable. */ |
/* C_AUTOARG conflicts with TI COFF C_UEXT. */ |
#if !defined (TIC80COFF) && !defined (TICOFF) |
#ifdef C_AUTOARG |
case C_AUTOARG: /* 960-specific storage class. */ |
#endif |
#endif |
case C_TPDEF: /* Type definition. */ |
case C_ARG: |
case C_AUTO: /* Automatic variable. */ |
case C_FIELD: /* Bit field. */ |
case C_ENTAG: /* Enumeration tag. */ |
case C_MOE: /* Member of enumeration. */ |
case C_MOU: /* Member of union. */ |
case C_UNTAG: /* Union tag. */ |
dst->symbol.flags = BSF_DEBUGGING; |
dst->symbol.value = (src->u.syment.n_value); |
break; |
case C_FILE: /* File name. */ |
case C_STRTAG: /* Structure tag. */ |
#ifdef RS6000COFF_C |
case C_GSYM: |
case C_LSYM: |
case C_PSYM: |
case C_RSYM: |
case C_RPSYM: |
case C_STSYM: |
case C_TCSYM: |
case C_BCOMM: |
case C_ECOML: |
case C_ECOMM: |
case C_DECL: |
case C_ENTRY: |
case C_FUN: |
case C_ESTAT: |
#endif |
dst->symbol.flags = BSF_DEBUGGING; |
dst->symbol.value = (src->u.syment.n_value); |
break; |
#ifdef RS6000COFF_C |
case C_BINCL: /* Beginning of include file. */ |
case C_EINCL: /* Ending of include file. */ |
/* The value is actually a pointer into the line numbers |
of the file. We locate the line number entry, and |
set the section to the section which contains it, and |
the value to the index in that section. */ |
{ |
asection *sec; |
dst->symbol.flags = BSF_DEBUGGING; |
for (sec = abfd->sections; sec != NULL; sec = sec->next) |
if (sec->line_filepos <= (file_ptr) src->u.syment.n_value |
&& ((file_ptr) (sec->line_filepos |
+ sec->lineno_count * bfd_coff_linesz (abfd)) |
> (file_ptr) src->u.syment.n_value)) |
break; |
if (sec == NULL) |
dst->symbol.value = 0; |
else |
{ |
dst->symbol.section = sec; |
dst->symbol.value = ((src->u.syment.n_value |
- sec->line_filepos) |
/ bfd_coff_linesz (abfd)); |
src->fix_line = 1; |
} |
} |
break; |
case C_BSTAT: |
dst->symbol.flags = BSF_DEBUGGING; |
/* The value is actually a symbol index. Save a pointer |
to the symbol instead of the index. FIXME: This |
should use a union. */ |
src->u.syment.n_value = |
(long) (intptr_t) (native_symbols + src->u.syment.n_value); |
dst->symbol.value = src->u.syment.n_value; |
src->fix_value = 1; |
break; |
#endif |
case C_BLOCK: /* ".bb" or ".eb". */ |
case C_FCN: /* ".bf" or ".ef" (or PE ".lf"). */ |
case C_EFCN: /* Physical end of function. */ |
#if defined COFF_WITH_PE |
/* PE sets the symbol to a value relative to the start |
of the section. */ |
dst->symbol.value = src->u.syment.n_value; |
if (strcmp (dst->symbol.name, ".bf") != 0) |
{ |
/* PE uses funny values for .ef and .lf; don't |
relocate them. */ |
dst->symbol.flags = BSF_DEBUGGING; |
} |
else |
dst->symbol.flags = BSF_DEBUGGING | BSF_DEBUGGING_RELOC; |
#else |
/* Base the value as an index from the base of the |
section. */ |
dst->symbol.flags = BSF_LOCAL; |
dst->symbol.value = (src->u.syment.n_value |
- dst->symbol.section->vma); |
#endif |
break; |
case C_STATLAB: /* Static load time label. */ |
dst->symbol.value = src->u.syment.n_value; |
dst->symbol.flags = BSF_GLOBAL; |
break; |
case C_NULL: |
/* PE DLLs sometimes have zeroed out symbols for some |
reason. Just ignore them without a warning. */ |
if (src->u.syment.n_type == 0 |
&& src->u.syment.n_value == 0 |
&& src->u.syment.n_scnum == 0) |
break; |
#ifdef RS6000COFF_C |
/* XCOFF specific: deleted entry. */ |
if (src->u.syment.n_value == C_NULL_VALUE) |
break; |
#endif |
/* Fall through. */ |
case C_EXTDEF: /* External definition. */ |
case C_ULABEL: /* Undefined label. */ |
case C_USTATIC: /* Undefined static. */ |
#ifndef COFF_WITH_PE |
/* C_LINE in regular coff is 0x68. NT has taken over this storage |
class to represent a section symbol. */ |
case C_LINE: /* line # reformatted as symbol table entry. */ |
/* NT uses 0x67 for a weak symbol, not C_ALIAS. */ |
case C_ALIAS: /* Duplicate tag. */ |
#endif |
/* New storage classes for TI COFF. */ |
#if defined(TIC80COFF) || defined(TICOFF) |
case C_UEXT: /* Tentative external definition. */ |
#endif |
case C_EXTLAB: /* External load time label. */ |
case C_HIDDEN: /* Ext symbol in dmert public lib. */ |
default: |
(*_bfd_error_handler) |
(_("%B: Unrecognized storage class %d for %s symbol `%s'"), |
abfd, src->u.syment.n_sclass, |
dst->symbol.section->name, dst->symbol.name); |
dst->symbol.flags = BSF_DEBUGGING; |
dst->symbol.value = (src->u.syment.n_value); |
break; |
} |
dst->native = src; |
dst->symbol.udata.i = 0; |
dst->lineno = NULL; |
this_index += (src->u.syment.n_numaux) + 1; |
dst++; |
number_of_symbols++; |
} |
} |
obj_symbols (abfd) = cached_area; |
obj_raw_syments (abfd) = native_symbols; |
bfd_get_symcount (abfd) = number_of_symbols; |
obj_convert (abfd) = table_ptr; |
/* Slurp the line tables for each section too. */ |
{ |
asection *p; |
p = abfd->sections; |
while (p) |
{ |
coff_slurp_line_table (abfd, p); |
p = p->next; |
} |
} |
return TRUE; |
} |
/* Classify a COFF symbol. A couple of targets have globally visible |
symbols which are not class C_EXT, and this handles those. It also |
recognizes some special PE cases. */ |
static enum coff_symbol_classification |
coff_classify_symbol (bfd *abfd, |
struct internal_syment *syment) |
{ |
/* FIXME: This partially duplicates the switch in |
coff_slurp_symbol_table. */ |
switch (syment->n_sclass) |
{ |
case C_EXT: |
case C_WEAKEXT: |
#ifdef I960 |
case C_LEAFEXT: |
#endif |
#ifdef ARM |
case C_THUMBEXT: |
case C_THUMBEXTFUNC: |
#endif |
#ifdef C_SYSTEM |
case C_SYSTEM: |
#endif |
#ifdef COFF_WITH_PE |
case C_NT_WEAK: |
#endif |
if (syment->n_scnum == 0) |
{ |
if (syment->n_value == 0) |
return COFF_SYMBOL_UNDEFINED; |
else |
return COFF_SYMBOL_COMMON; |
} |
return COFF_SYMBOL_GLOBAL; |
default: |
break; |
} |
#ifdef COFF_WITH_PE |
if (syment->n_sclass == C_STAT) |
{ |
if (syment->n_scnum == 0) |
/* The Microsoft compiler sometimes generates these if a |
small static function is inlined every time it is used. |
The function is discarded, but the symbol table entry |
remains. */ |
return COFF_SYMBOL_LOCAL; |
#ifdef STRICT_PE_FORMAT |
/* This is correct for Microsoft generated objects, but it |
breaks gas generated objects. */ |
if (syment->n_value == 0) |
{ |
asection *sec; |
char buf[SYMNMLEN + 1]; |
sec = coff_section_from_bfd_index (abfd, syment->n_scnum); |
if (sec != NULL |
&& (strcmp (bfd_get_section_name (abfd, sec), |
_bfd_coff_internal_syment_name (abfd, syment, buf)) |
== 0)) |
return COFF_SYMBOL_PE_SECTION; |
} |
#endif |
return COFF_SYMBOL_LOCAL; |
} |
if (syment->n_sclass == C_SECTION) |
{ |
/* In some cases in a DLL generated by the Microsoft linker, the |
n_value field will contain garbage. FIXME: This should |
probably be handled by the swapping function instead. */ |
syment->n_value = 0; |
if (syment->n_scnum == 0) |
return COFF_SYMBOL_UNDEFINED; |
return COFF_SYMBOL_PE_SECTION; |
} |
#endif /* COFF_WITH_PE */ |
/* If it is not a global symbol, we presume it is a local symbol. */ |
if (syment->n_scnum == 0) |
{ |
char buf[SYMNMLEN + 1]; |
(*_bfd_error_handler) |
(_("warning: %B: local symbol `%s' has no section"), |
abfd, _bfd_coff_internal_syment_name (abfd, syment, buf)); |
} |
return COFF_SYMBOL_LOCAL; |
} |
/* |
SUBSUBSECTION |
Reading relocations |
Coff relocations are easily transformed into the internal BFD form |
(@code{arelent}). |
Reading a coff relocation table is done in the following stages: |
o Read the entire coff relocation table into memory. |
o Process each relocation in turn; first swap it from the |
external to the internal form. |
o Turn the symbol referenced in the relocation's symbol index |
into a pointer into the canonical symbol table. |
This table is the same as the one returned by a call to |
@code{bfd_canonicalize_symtab}. The back end will call that |
routine and save the result if a canonicalization hasn't been done. |
o The reloc index is turned into a pointer to a howto |
structure, in a back end specific way. For instance, the 386 |
and 960 use the @code{r_type} to directly produce an index |
into a howto table vector; the 88k subtracts a number from the |
@code{r_type} field and creates an addend field. |
*/ |
#ifndef CALC_ADDEND |
#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr) \ |
{ \ |
coff_symbol_type *coffsym = NULL; \ |
\ |
if (ptr && bfd_asymbol_bfd (ptr) != abfd) \ |
coffsym = (obj_symbols (abfd) \ |
+ (cache_ptr->sym_ptr_ptr - symbols)); \ |
else if (ptr) \ |
coffsym = coff_symbol_from (abfd, ptr); \ |
if (coffsym != NULL \ |
&& coffsym->native->u.syment.n_scnum == 0) \ |
cache_ptr->addend = 0; \ |
else if (ptr && bfd_asymbol_bfd (ptr) == abfd \ |
&& ptr->section != NULL) \ |
cache_ptr->addend = - (ptr->section->vma + ptr->value); \ |
else \ |
cache_ptr->addend = 0; \ |
} |
#endif |
static bfd_boolean |
coff_slurp_reloc_table (bfd * abfd, sec_ptr asect, asymbol ** symbols) |
{ |
RELOC *native_relocs; |
arelent *reloc_cache; |
arelent *cache_ptr; |
unsigned int idx; |
bfd_size_type amt; |
if (asect->relocation) |
return TRUE; |
if (asect->reloc_count == 0) |
return TRUE; |
if (asect->flags & SEC_CONSTRUCTOR) |
return TRUE; |
if (!coff_slurp_symbol_table (abfd)) |
return FALSE; |
amt = (bfd_size_type) bfd_coff_relsz (abfd) * asect->reloc_count; |
native_relocs = (RELOC *) buy_and_read (abfd, asect->rel_filepos, amt); |
amt = (bfd_size_type) asect->reloc_count * sizeof (arelent); |
reloc_cache = (arelent *) bfd_alloc (abfd, amt); |
if (reloc_cache == NULL || native_relocs == NULL) |
return FALSE; |
for (idx = 0; idx < asect->reloc_count; idx++) |
{ |
struct internal_reloc dst; |
struct external_reloc *src; |
#ifndef RELOC_PROCESSING |
asymbol *ptr; |
#endif |
cache_ptr = reloc_cache + idx; |
src = native_relocs + idx; |
dst.r_offset = 0; |
coff_swap_reloc_in (abfd, src, &dst); |
#ifdef RELOC_PROCESSING |
RELOC_PROCESSING (cache_ptr, &dst, symbols, abfd, asect); |
#else |
cache_ptr->address = dst.r_vaddr; |
if (dst.r_symndx != -1) |
{ |
if (dst.r_symndx < 0 || dst.r_symndx >= obj_conv_table_size (abfd)) |
{ |
(*_bfd_error_handler) |
(_("%B: warning: illegal symbol index %ld in relocs"), |
abfd, (long) dst.r_symndx); |
cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; |
ptr = NULL; |
} |
else |
{ |
cache_ptr->sym_ptr_ptr = (symbols |
+ obj_convert (abfd)[dst.r_symndx]); |
ptr = *(cache_ptr->sym_ptr_ptr); |
} |
} |
else |
{ |
cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; |
ptr = NULL; |
} |
/* The symbols definitions that we have read in have been |
relocated as if their sections started at 0. But the offsets |
refering to the symbols in the raw data have not been |
modified, so we have to have a negative addend to compensate. |
Note that symbols which used to be common must be left alone. */ |
/* Calculate any reloc addend by looking at the symbol. */ |
CALC_ADDEND (abfd, ptr, dst, cache_ptr); |
(void) ptr; |
cache_ptr->address -= asect->vma; |
/* !! cache_ptr->section = NULL;*/ |
/* Fill in the cache_ptr->howto field from dst.r_type. */ |
RTYPE2HOWTO (cache_ptr, &dst); |
#endif /* RELOC_PROCESSING */ |
if (cache_ptr->howto == NULL) |
{ |
(*_bfd_error_handler) |
(_("%B: illegal relocation type %d at address 0x%lx"), |
abfd, dst.r_type, (long) dst.r_vaddr); |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
} |
asect->relocation = reloc_cache; |
return TRUE; |
} |
#ifndef coff_rtype_to_howto |
#ifdef RTYPE2HOWTO |
/* Get the howto structure for a reloc. This is only used if the file |
including this one defines coff_relocate_section to be |
_bfd_coff_generic_relocate_section, so it is OK if it does not |
always work. It is the responsibility of the including file to |
make sure it is reasonable if it is needed. */ |
static reloc_howto_type * |
coff_rtype_to_howto (bfd *abfd ATTRIBUTE_UNUSED, |
asection *sec ATTRIBUTE_UNUSED, |
struct internal_reloc *rel, |
struct coff_link_hash_entry *h ATTRIBUTE_UNUSED, |
struct internal_syment *sym ATTRIBUTE_UNUSED, |
bfd_vma *addendp ATTRIBUTE_UNUSED) |
{ |
arelent genrel; |
genrel.howto = NULL; |
RTYPE2HOWTO (&genrel, rel); |
return genrel.howto; |
} |
#else /* ! defined (RTYPE2HOWTO) */ |
#define coff_rtype_to_howto NULL |
#endif /* ! defined (RTYPE2HOWTO) */ |
#endif /* ! defined (coff_rtype_to_howto) */ |
/* This is stupid. This function should be a boolean predicate. */ |
static long |
coff_canonicalize_reloc (bfd * abfd, |
sec_ptr section, |
arelent ** relptr, |
asymbol ** symbols) |
{ |
arelent *tblptr = section->relocation; |
unsigned int count = 0; |
if (section->flags & SEC_CONSTRUCTOR) |
{ |
/* This section has relocs made up by us, they are not in the |
file, so take them out of their chain and place them into |
the data area provided. */ |
arelent_chain *chain = section->constructor_chain; |
for (count = 0; count < section->reloc_count; count++) |
{ |
*relptr++ = &chain->relent; |
chain = chain->next; |
} |
} |
else |
{ |
if (! coff_slurp_reloc_table (abfd, section, symbols)) |
return -1; |
tblptr = section->relocation; |
for (; count++ < section->reloc_count;) |
*relptr++ = tblptr++; |
} |
*relptr = 0; |
return section->reloc_count; |
} |
#ifndef coff_reloc16_estimate |
#define coff_reloc16_estimate dummy_reloc16_estimate |
static int |
dummy_reloc16_estimate (bfd *abfd ATTRIBUTE_UNUSED, |
asection *input_section ATTRIBUTE_UNUSED, |
arelent *reloc ATTRIBUTE_UNUSED, |
unsigned int shrink ATTRIBUTE_UNUSED, |
struct bfd_link_info *link_info ATTRIBUTE_UNUSED) |
{ |
abort (); |
return 0; |
} |
#endif |
#ifndef coff_reloc16_extra_cases |
#define coff_reloc16_extra_cases dummy_reloc16_extra_cases |
/* This works even if abort is not declared in any header file. */ |
static void |
dummy_reloc16_extra_cases (bfd *abfd ATTRIBUTE_UNUSED, |
struct bfd_link_info *link_info ATTRIBUTE_UNUSED, |
struct bfd_link_order *link_order ATTRIBUTE_UNUSED, |
arelent *reloc ATTRIBUTE_UNUSED, |
bfd_byte *data ATTRIBUTE_UNUSED, |
unsigned int *src_ptr ATTRIBUTE_UNUSED, |
unsigned int *dst_ptr ATTRIBUTE_UNUSED) |
{ |
abort (); |
} |
#endif |
#ifndef coff_bfd_link_hash_table_free |
#define coff_bfd_link_hash_table_free _bfd_generic_link_hash_table_free |
#endif |
/* If coff_relocate_section is defined, we can use the optimized COFF |
backend linker. Otherwise we must continue to use the old linker. */ |
#ifdef coff_relocate_section |
#ifndef coff_bfd_link_hash_table_create |
#define coff_bfd_link_hash_table_create _bfd_coff_link_hash_table_create |
#endif |
#ifndef coff_bfd_link_add_symbols |
#define coff_bfd_link_add_symbols _bfd_coff_link_add_symbols |
#endif |
#ifndef coff_bfd_final_link |
#define coff_bfd_final_link _bfd_coff_final_link |
#endif |
#else /* ! defined (coff_relocate_section) */ |
#define coff_relocate_section NULL |
#ifndef coff_bfd_link_hash_table_create |
#define coff_bfd_link_hash_table_create _bfd_generic_link_hash_table_create |
#endif |
#ifndef coff_bfd_link_add_symbols |
#define coff_bfd_link_add_symbols _bfd_generic_link_add_symbols |
#endif |
#define coff_bfd_final_link _bfd_generic_final_link |
#endif /* ! defined (coff_relocate_section) */ |
#define coff_bfd_link_just_syms _bfd_generic_link_just_syms |
#define coff_bfd_copy_link_hash_symbol_type \ |
_bfd_generic_copy_link_hash_symbol_type |
#define coff_bfd_link_split_section _bfd_generic_link_split_section |
#ifndef coff_start_final_link |
#define coff_start_final_link NULL |
#endif |
#ifndef coff_adjust_symndx |
#define coff_adjust_symndx NULL |
#endif |
#ifndef coff_link_add_one_symbol |
#define coff_link_add_one_symbol _bfd_generic_link_add_one_symbol |
#endif |
#ifndef coff_link_output_has_begun |
static bfd_boolean |
coff_link_output_has_begun (bfd * abfd, |
struct coff_final_link_info * info ATTRIBUTE_UNUSED) |
{ |
return abfd->output_has_begun; |
} |
#endif |
#ifndef coff_final_link_postscript |
static bfd_boolean |
coff_final_link_postscript (bfd * abfd ATTRIBUTE_UNUSED, |
struct coff_final_link_info * pfinfo ATTRIBUTE_UNUSED) |
{ |
return TRUE; |
} |
#endif |
#ifndef coff_SWAP_aux_in |
#define coff_SWAP_aux_in coff_swap_aux_in |
#endif |
#ifndef coff_SWAP_sym_in |
#define coff_SWAP_sym_in coff_swap_sym_in |
#endif |
#ifndef coff_SWAP_lineno_in |
#define coff_SWAP_lineno_in coff_swap_lineno_in |
#endif |
#ifndef coff_SWAP_aux_out |
#define coff_SWAP_aux_out coff_swap_aux_out |
#endif |
#ifndef coff_SWAP_sym_out |
#define coff_SWAP_sym_out coff_swap_sym_out |
#endif |
#ifndef coff_SWAP_lineno_out |
#define coff_SWAP_lineno_out coff_swap_lineno_out |
#endif |
#ifndef coff_SWAP_reloc_out |
#define coff_SWAP_reloc_out coff_swap_reloc_out |
#endif |
#ifndef coff_SWAP_filehdr_out |
#define coff_SWAP_filehdr_out coff_swap_filehdr_out |
#endif |
#ifndef coff_SWAP_aouthdr_out |
#define coff_SWAP_aouthdr_out coff_swap_aouthdr_out |
#endif |
#ifndef coff_SWAP_scnhdr_out |
#define coff_SWAP_scnhdr_out coff_swap_scnhdr_out |
#endif |
#ifndef coff_SWAP_reloc_in |
#define coff_SWAP_reloc_in coff_swap_reloc_in |
#endif |
#ifndef coff_SWAP_filehdr_in |
#define coff_SWAP_filehdr_in coff_swap_filehdr_in |
#endif |
#ifndef coff_SWAP_aouthdr_in |
#define coff_SWAP_aouthdr_in coff_swap_aouthdr_in |
#endif |
#ifndef coff_SWAP_scnhdr_in |
#define coff_SWAP_scnhdr_in coff_swap_scnhdr_in |
#endif |
static bfd_coff_backend_data bfd_coff_std_swap_table ATTRIBUTE_UNUSED = |
{ |
coff_SWAP_aux_in, coff_SWAP_sym_in, coff_SWAP_lineno_in, |
coff_SWAP_aux_out, coff_SWAP_sym_out, |
coff_SWAP_lineno_out, coff_SWAP_reloc_out, |
coff_SWAP_filehdr_out, coff_SWAP_aouthdr_out, |
coff_SWAP_scnhdr_out, |
FILHSZ, AOUTSZ, SCNHSZ, SYMESZ, AUXESZ, RELSZ, LINESZ, FILNMLEN, |
#ifdef COFF_LONG_FILENAMES |
TRUE, |
#else |
FALSE, |
#endif |
COFF_DEFAULT_LONG_SECTION_NAMES, |
COFF_DEFAULT_SECTION_ALIGNMENT_POWER, |
#ifdef COFF_FORCE_SYMBOLS_IN_STRINGS |
TRUE, |
#else |
FALSE, |
#endif |
#ifdef COFF_DEBUG_STRING_WIDE_PREFIX |
4, |
#else |
2, |
#endif |
coff_SWAP_filehdr_in, coff_SWAP_aouthdr_in, coff_SWAP_scnhdr_in, |
coff_SWAP_reloc_in, coff_bad_format_hook, coff_set_arch_mach_hook, |
coff_mkobject_hook, styp_to_sec_flags, coff_set_alignment_hook, |
coff_slurp_symbol_table, symname_in_debug_hook, coff_pointerize_aux_hook, |
coff_print_aux, coff_reloc16_extra_cases, coff_reloc16_estimate, |
coff_classify_symbol, coff_compute_section_file_positions, |
coff_start_final_link, coff_relocate_section, coff_rtype_to_howto, |
coff_adjust_symndx, coff_link_add_one_symbol, |
coff_link_output_has_begun, coff_final_link_postscript, |
bfd_pe_print_pdata |
}; |
#ifdef TICOFF |
/* COFF0 differs in file/section header size and relocation entry size. */ |
static bfd_coff_backend_data ticoff0_swap_table = |
{ |
coff_SWAP_aux_in, coff_SWAP_sym_in, coff_SWAP_lineno_in, |
coff_SWAP_aux_out, coff_SWAP_sym_out, |
coff_SWAP_lineno_out, coff_SWAP_reloc_out, |
coff_SWAP_filehdr_out, coff_SWAP_aouthdr_out, |
coff_SWAP_scnhdr_out, |
FILHSZ_V0, AOUTSZ, SCNHSZ_V01, SYMESZ, AUXESZ, RELSZ_V0, LINESZ, FILNMLEN, |
#ifdef COFF_LONG_FILENAMES |
TRUE, |
#else |
FALSE, |
#endif |
COFF_DEFAULT_LONG_SECTION_NAMES, |
COFF_DEFAULT_SECTION_ALIGNMENT_POWER, |
#ifdef COFF_FORCE_SYMBOLS_IN_STRINGS |
TRUE, |
#else |
FALSE, |
#endif |
#ifdef COFF_DEBUG_STRING_WIDE_PREFIX |
4, |
#else |
2, |
#endif |
coff_SWAP_filehdr_in, coff_SWAP_aouthdr_in, coff_SWAP_scnhdr_in, |
coff_SWAP_reloc_in, ticoff0_bad_format_hook, coff_set_arch_mach_hook, |
coff_mkobject_hook, styp_to_sec_flags, coff_set_alignment_hook, |
coff_slurp_symbol_table, symname_in_debug_hook, coff_pointerize_aux_hook, |
coff_print_aux, coff_reloc16_extra_cases, coff_reloc16_estimate, |
coff_classify_symbol, coff_compute_section_file_positions, |
coff_start_final_link, coff_relocate_section, coff_rtype_to_howto, |
coff_adjust_symndx, coff_link_add_one_symbol, |
coff_link_output_has_begun, coff_final_link_postscript, |
bfd_pe_print_pdata |
}; |
#endif |
#ifdef TICOFF |
/* COFF1 differs in section header size. */ |
static bfd_coff_backend_data ticoff1_swap_table = |
{ |
coff_SWAP_aux_in, coff_SWAP_sym_in, coff_SWAP_lineno_in, |
coff_SWAP_aux_out, coff_SWAP_sym_out, |
coff_SWAP_lineno_out, coff_SWAP_reloc_out, |
coff_SWAP_filehdr_out, coff_SWAP_aouthdr_out, |
coff_SWAP_scnhdr_out, |
FILHSZ, AOUTSZ, SCNHSZ_V01, SYMESZ, AUXESZ, RELSZ, LINESZ, FILNMLEN, |
#ifdef COFF_LONG_FILENAMES |
TRUE, |
#else |
FALSE, |
#endif |
COFF_DEFAULT_LONG_SECTION_NAMES, |
COFF_DEFAULT_SECTION_ALIGNMENT_POWER, |
#ifdef COFF_FORCE_SYMBOLS_IN_STRINGS |
TRUE, |
#else |
FALSE, |
#endif |
#ifdef COFF_DEBUG_STRING_WIDE_PREFIX |
4, |
#else |
2, |
#endif |
coff_SWAP_filehdr_in, coff_SWAP_aouthdr_in, coff_SWAP_scnhdr_in, |
coff_SWAP_reloc_in, ticoff1_bad_format_hook, coff_set_arch_mach_hook, |
coff_mkobject_hook, styp_to_sec_flags, coff_set_alignment_hook, |
coff_slurp_symbol_table, symname_in_debug_hook, coff_pointerize_aux_hook, |
coff_print_aux, coff_reloc16_extra_cases, coff_reloc16_estimate, |
coff_classify_symbol, coff_compute_section_file_positions, |
coff_start_final_link, coff_relocate_section, coff_rtype_to_howto, |
coff_adjust_symndx, coff_link_add_one_symbol, |
coff_link_output_has_begun, coff_final_link_postscript, |
bfd_pe_print_pdata /* huh */ |
}; |
#endif |
#ifndef coff_close_and_cleanup |
#define coff_close_and_cleanup _bfd_generic_close_and_cleanup |
#endif |
#ifndef coff_bfd_free_cached_info |
#define coff_bfd_free_cached_info _bfd_generic_bfd_free_cached_info |
#endif |
#ifndef coff_get_section_contents |
#define coff_get_section_contents _bfd_generic_get_section_contents |
#endif |
#ifndef coff_bfd_copy_private_symbol_data |
#define coff_bfd_copy_private_symbol_data _bfd_generic_bfd_copy_private_symbol_data |
#endif |
#ifndef coff_bfd_copy_private_header_data |
#define coff_bfd_copy_private_header_data _bfd_generic_bfd_copy_private_header_data |
#endif |
#ifndef coff_bfd_copy_private_section_data |
#define coff_bfd_copy_private_section_data _bfd_generic_bfd_copy_private_section_data |
#endif |
#ifndef coff_bfd_copy_private_bfd_data |
#define coff_bfd_copy_private_bfd_data _bfd_generic_bfd_copy_private_bfd_data |
#endif |
#ifndef coff_bfd_merge_private_bfd_data |
#define coff_bfd_merge_private_bfd_data _bfd_generic_bfd_merge_private_bfd_data |
#endif |
#ifndef coff_bfd_set_private_flags |
#define coff_bfd_set_private_flags _bfd_generic_bfd_set_private_flags |
#endif |
#ifndef coff_bfd_print_private_bfd_data |
#define coff_bfd_print_private_bfd_data _bfd_generic_bfd_print_private_bfd_data |
#endif |
#ifndef coff_bfd_is_local_label_name |
#define coff_bfd_is_local_label_name _bfd_coff_is_local_label_name |
#endif |
#ifndef coff_bfd_is_target_special_symbol |
#define coff_bfd_is_target_special_symbol ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) |
#endif |
#ifndef coff_read_minisymbols |
#define coff_read_minisymbols _bfd_generic_read_minisymbols |
#endif |
#ifndef coff_minisymbol_to_symbol |
#define coff_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol |
#endif |
/* The reloc lookup routine must be supplied by each individual COFF |
backend. */ |
#ifndef coff_bfd_reloc_type_lookup |
#define coff_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup |
#endif |
#ifndef coff_bfd_reloc_name_lookup |
#define coff_bfd_reloc_name_lookup _bfd_norelocs_bfd_reloc_name_lookup |
#endif |
#ifndef coff_bfd_get_relocated_section_contents |
#define coff_bfd_get_relocated_section_contents \ |
bfd_generic_get_relocated_section_contents |
#endif |
#ifndef coff_bfd_relax_section |
#define coff_bfd_relax_section bfd_generic_relax_section |
#endif |
#ifndef coff_bfd_gc_sections |
#define coff_bfd_gc_sections bfd_generic_gc_sections |
#endif |
#ifndef coff_bfd_lookup_section_flags |
#define coff_bfd_lookup_section_flags bfd_generic_lookup_section_flags |
#endif |
#ifndef coff_bfd_merge_sections |
#define coff_bfd_merge_sections bfd_generic_merge_sections |
#endif |
#ifndef coff_bfd_is_group_section |
#define coff_bfd_is_group_section bfd_generic_is_group_section |
#endif |
#ifndef coff_bfd_discard_group |
#define coff_bfd_discard_group bfd_generic_discard_group |
#endif |
#ifndef coff_section_already_linked |
#define coff_section_already_linked \ |
_bfd_coff_section_already_linked |
#endif |
#ifndef coff_bfd_define_common_symbol |
#define coff_bfd_define_common_symbol bfd_generic_define_common_symbol |
#endif |
#define CREATE_BIG_COFF_TARGET_VEC(VAR, NAME, EXTRA_O_FLAGS, EXTRA_S_FLAGS, UNDER, ALTERNATIVE, SWAP_TABLE) \ |
const bfd_target VAR = \ |
{ \ |
NAME , \ |
bfd_target_coff_flavour, \ |
BFD_ENDIAN_BIG, /* Data byte order is big. */ \ |
BFD_ENDIAN_BIG, /* Header byte order is big. */ \ |
/* object flags */ \ |
(HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | \ |
HAS_SYMS | HAS_LOCALS | WP_TEXT | EXTRA_O_FLAGS), \ |
/* section flags */ \ |
(SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | EXTRA_S_FLAGS),\ |
UNDER, /* Leading symbol underscore. */ \ |
'/', /* AR_pad_char. */ \ |
15, /* AR_max_namelen. */ \ |
0, /* match priority. */ \ |
\ |
/* Data conversion functions. */ \ |
bfd_getb64, bfd_getb_signed_64, bfd_putb64, \ |
bfd_getb32, bfd_getb_signed_32, bfd_putb32, \ |
bfd_getb16, bfd_getb_signed_16, bfd_putb16, \ |
\ |
/* Header conversion functions. */ \ |
bfd_getb64, bfd_getb_signed_64, bfd_putb64, \ |
bfd_getb32, bfd_getb_signed_32, bfd_putb32, \ |
bfd_getb16, bfd_getb_signed_16, bfd_putb16, \ |
\ |
/* bfd_check_format. */ \ |
{ _bfd_dummy_target, coff_object_p, bfd_generic_archive_p, \ |
_bfd_dummy_target }, \ |
/* bfd_set_format. */ \ |
{ bfd_false, coff_mkobject, _bfd_generic_mkarchive, bfd_false }, \ |
/* bfd_write_contents. */ \ |
{ bfd_false, coff_write_object_contents, _bfd_write_archive_contents, \ |
bfd_false }, \ |
\ |
BFD_JUMP_TABLE_GENERIC (coff), \ |
BFD_JUMP_TABLE_COPY (coff), \ |
BFD_JUMP_TABLE_CORE (_bfd_nocore), \ |
BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), \ |
BFD_JUMP_TABLE_SYMBOLS (coff), \ |
BFD_JUMP_TABLE_RELOCS (coff), \ |
BFD_JUMP_TABLE_WRITE (coff), \ |
BFD_JUMP_TABLE_LINK (coff), \ |
BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), \ |
\ |
ALTERNATIVE, \ |
\ |
SWAP_TABLE \ |
}; |
#define CREATE_BIGHDR_COFF_TARGET_VEC(VAR, NAME, EXTRA_O_FLAGS, EXTRA_S_FLAGS, UNDER, ALTERNATIVE, SWAP_TABLE) \ |
const bfd_target VAR = \ |
{ \ |
NAME , \ |
bfd_target_coff_flavour, \ |
BFD_ENDIAN_LITTLE, /* Data byte order is little. */ \ |
BFD_ENDIAN_BIG, /* Header byte order is big. */ \ |
/* object flags */ \ |
(HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | \ |
HAS_SYMS | HAS_LOCALS | WP_TEXT | EXTRA_O_FLAGS), \ |
/* section flags */ \ |
(SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | EXTRA_S_FLAGS),\ |
UNDER, /* Leading symbol underscore. */ \ |
'/', /* AR_pad_char. */ \ |
15, /* AR_max_namelen. */ \ |
0, /* match priority. */ \ |
\ |
/* Data conversion functions. */ \ |
bfd_getb64, bfd_getb_signed_64, bfd_putb64, \ |
bfd_getb32, bfd_getb_signed_32, bfd_putb32, \ |
bfd_getb16, bfd_getb_signed_16, bfd_putb16, \ |
\ |
/* Header conversion functions. */ \ |
bfd_getb64, bfd_getb_signed_64, bfd_putb64, \ |
bfd_getb32, bfd_getb_signed_32, bfd_putb32, \ |
bfd_getb16, bfd_getb_signed_16, bfd_putb16, \ |
\ |
/* bfd_check_format. */ \ |
{ _bfd_dummy_target, coff_object_p, bfd_generic_archive_p, \ |
_bfd_dummy_target }, \ |
/* bfd_set_format. */ \ |
{ bfd_false, coff_mkobject, _bfd_generic_mkarchive, bfd_false }, \ |
/* bfd_write_contents. */ \ |
{ bfd_false, coff_write_object_contents, _bfd_write_archive_contents, \ |
bfd_false }, \ |
\ |
BFD_JUMP_TABLE_GENERIC (coff), \ |
BFD_JUMP_TABLE_COPY (coff), \ |
BFD_JUMP_TABLE_CORE (_bfd_nocore), \ |
BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), \ |
BFD_JUMP_TABLE_SYMBOLS (coff), \ |
BFD_JUMP_TABLE_RELOCS (coff), \ |
BFD_JUMP_TABLE_WRITE (coff), \ |
BFD_JUMP_TABLE_LINK (coff), \ |
BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), \ |
\ |
ALTERNATIVE, \ |
\ |
SWAP_TABLE \ |
}; |
#define CREATE_LITTLE_COFF_TARGET_VEC(VAR, NAME, EXTRA_O_FLAGS, EXTRA_S_FLAGS, UNDER, ALTERNATIVE, SWAP_TABLE) \ |
const bfd_target VAR = \ |
{ \ |
NAME , \ |
bfd_target_coff_flavour, \ |
BFD_ENDIAN_LITTLE, /* Data byte order is little. */ \ |
BFD_ENDIAN_LITTLE, /* Header byte order is little. */ \ |
/* object flags */ \ |
(HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | \ |
HAS_SYMS | HAS_LOCALS | WP_TEXT | EXTRA_O_FLAGS), \ |
/* section flags */ \ |
(SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | EXTRA_S_FLAGS),\ |
UNDER, /* Leading symbol underscore. */ \ |
'/', /* AR_pad_char. */ \ |
15, /* AR_max_namelen. */ \ |
0, /* match priority. */ \ |
\ |
/* Data conversion functions. */ \ |
bfd_getl64, bfd_getl_signed_64, bfd_putl64, \ |
bfd_getl32, bfd_getl_signed_32, bfd_putl32, \ |
bfd_getl16, bfd_getl_signed_16, bfd_putl16, \ |
/* Header conversion functions. */ \ |
bfd_getl64, bfd_getl_signed_64, bfd_putl64, \ |
bfd_getl32, bfd_getl_signed_32, bfd_putl32, \ |
bfd_getl16, bfd_getl_signed_16, bfd_putl16, \ |
/* bfd_check_format. */ \ |
{ _bfd_dummy_target, coff_object_p, bfd_generic_archive_p, \ |
_bfd_dummy_target }, \ |
/* bfd_set_format. */ \ |
{ bfd_false, coff_mkobject, _bfd_generic_mkarchive, bfd_false }, \ |
/* bfd_write_contents. */ \ |
{ bfd_false, coff_write_object_contents, _bfd_write_archive_contents, \ |
bfd_false }, \ |
\ |
BFD_JUMP_TABLE_GENERIC (coff), \ |
BFD_JUMP_TABLE_COPY (coff), \ |
BFD_JUMP_TABLE_CORE (_bfd_nocore), \ |
BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), \ |
BFD_JUMP_TABLE_SYMBOLS (coff), \ |
BFD_JUMP_TABLE_RELOCS (coff), \ |
BFD_JUMP_TABLE_WRITE (coff), \ |
BFD_JUMP_TABLE_LINK (coff), \ |
BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), \ |
\ |
ALTERNATIVE, \ |
\ |
SWAP_TABLE \ |
}; |
/contrib/toolchain/binutils/bfd/coffgen.c |
---|
0,0 → 1,2610 |
/* Support for the generic parts of COFF, for BFD. |
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, |
2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 |
Free Software Foundation, Inc. |
Written by Cygnus Support. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* Most of this hacked by Steve Chamberlain, sac@cygnus.com. |
Split out of coffcode.h by Ian Taylor, ian@cygnus.com. */ |
/* This file contains COFF code that is not dependent on any |
particular COFF target. There is only one version of this file in |
libbfd.a, so no target specific code may be put in here. Or, to |
put it another way, |
********** DO NOT PUT TARGET SPECIFIC CODE IN THIS FILE ********** |
If you need to add some target specific behaviour, add a new hook |
function to bfd_coff_backend_data. |
Some of these functions are also called by the ECOFF routines. |
Those functions may not use any COFF specific information, such as |
coff_data (abfd). */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
#include "coff/internal.h" |
#include "libcoff.h" |
/* Take a section header read from a coff file (in HOST byte order), |
and make a BFD "section" out of it. This is used by ECOFF. */ |
static bfd_boolean |
make_a_section_from_file (bfd *abfd, |
struct internal_scnhdr *hdr, |
unsigned int target_index) |
{ |
asection *return_section; |
char *name; |
bfd_boolean result = TRUE; |
flagword flags; |
name = NULL; |
/* Handle long section names as in PE. On reading, we want to |
accept long names if the format permits them at all, regardless |
of the current state of the flag that dictates if we would generate |
them in outputs; this construct checks if that is the case by |
attempting to set the flag, without changing its state; the call |
will fail for formats that do not support long names at all. */ |
if (bfd_coff_set_long_section_names (abfd, bfd_coff_long_section_names (abfd)) |
&& hdr->s_name[0] == '/') |
{ |
char buf[SCNNMLEN]; |
long strindex; |
char *p; |
const char *strings; |
/* Flag that this BFD uses long names, even though the format might |
expect them to be off by default. This won't directly affect the |
format of any output BFD created from this one, but the information |
can be used to decide what to do. */ |
bfd_coff_set_long_section_names (abfd, TRUE); |
memcpy (buf, hdr->s_name + 1, SCNNMLEN - 1); |
buf[SCNNMLEN - 1] = '\0'; |
strindex = strtol (buf, &p, 10); |
if (*p == '\0' && strindex >= 0) |
{ |
strings = _bfd_coff_read_string_table (abfd); |
if (strings == NULL) |
return FALSE; |
/* FIXME: For extra safety, we should make sure that |
strindex does not run us past the end, but right now we |
don't know the length of the string table. */ |
strings += strindex; |
name = (char *) bfd_alloc (abfd, |
(bfd_size_type) strlen (strings) + 1 + 1); |
if (name == NULL) |
return FALSE; |
strcpy (name, strings); |
} |
} |
if (name == NULL) |
{ |
/* Assorted wastage to null-terminate the name, thanks AT&T! */ |
name = (char *) bfd_alloc (abfd, |
(bfd_size_type) sizeof (hdr->s_name) + 1 + 1); |
if (name == NULL) |
return FALSE; |
strncpy (name, (char *) &hdr->s_name[0], sizeof (hdr->s_name)); |
name[sizeof (hdr->s_name)] = 0; |
} |
return_section = bfd_make_section_anyway (abfd, name); |
if (return_section == NULL) |
return FALSE; |
return_section->vma = hdr->s_vaddr; |
return_section->lma = hdr->s_paddr; |
return_section->size = hdr->s_size; |
return_section->filepos = hdr->s_scnptr; |
return_section->rel_filepos = hdr->s_relptr; |
return_section->reloc_count = hdr->s_nreloc; |
bfd_coff_set_alignment_hook (abfd, return_section, hdr); |
return_section->line_filepos = hdr->s_lnnoptr; |
return_section->lineno_count = hdr->s_nlnno; |
return_section->userdata = NULL; |
return_section->next = NULL; |
return_section->target_index = target_index; |
if (! bfd_coff_styp_to_sec_flags_hook (abfd, hdr, name, return_section, |
& flags)) |
result = FALSE; |
return_section->flags = flags; |
/* At least on i386-coff, the line number count for a shared library |
section must be ignored. */ |
if ((return_section->flags & SEC_COFF_SHARED_LIBRARY) != 0) |
return_section->lineno_count = 0; |
if (hdr->s_nreloc != 0) |
return_section->flags |= SEC_RELOC; |
/* FIXME: should this check 'hdr->s_size > 0'. */ |
if (hdr->s_scnptr != 0) |
return_section->flags |= SEC_HAS_CONTENTS; |
/* Compress/decompress DWARF debug sections with names: .debug_* and |
.zdebug_*, after the section flags is set. */ |
if ((flags & SEC_DEBUGGING) |
&& ((name[1] == 'd' && name[6] == '_') |
|| (name[1] == 'z' && name[7] == '_'))) |
{ |
enum { nothing, compress, decompress } action = nothing; |
char *new_name = NULL; |
if (bfd_is_section_compressed (abfd, return_section)) |
{ |
/* Compressed section. Check if we should decompress. */ |
if ((abfd->flags & BFD_DECOMPRESS)) |
action = decompress; |
} |
else if (!bfd_is_section_compressed (abfd, return_section)) |
{ |
/* Normal section. Check if we should compress. */ |
if ((abfd->flags & BFD_COMPRESS) && return_section->size != 0) |
action = compress; |
} |
switch (action) |
{ |
case nothing: |
break; |
case compress: |
if (!bfd_init_section_compress_status (abfd, return_section)) |
{ |
(*_bfd_error_handler) |
(_("%B: unable to initialize compress status for section %s"), |
abfd, name); |
return FALSE; |
} |
if (name[1] != 'z') |
{ |
unsigned int len = strlen (name); |
new_name = bfd_alloc (abfd, len + 2); |
if (new_name == NULL) |
return FALSE; |
new_name[0] = '.'; |
new_name[1] = 'z'; |
memcpy (new_name + 2, name + 1, len); |
} |
break; |
case decompress: |
if (!bfd_init_section_decompress_status (abfd, return_section)) |
{ |
(*_bfd_error_handler) |
(_("%B: unable to initialize decompress status for section %s"), |
abfd, name); |
return FALSE; |
} |
if (name[1] == 'z') |
{ |
unsigned int len = strlen (name); |
new_name = bfd_alloc (abfd, len); |
if (new_name == NULL) |
return FALSE; |
new_name[0] = '.'; |
memcpy (new_name + 1, name + 2, len - 1); |
} |
break; |
} |
if (new_name != NULL) |
bfd_rename_section (abfd, return_section, new_name); |
} |
return result; |
} |
/* Read in a COFF object and make it into a BFD. This is used by |
ECOFF as well. */ |
const bfd_target * |
coff_real_object_p (bfd *, |
unsigned, |
struct internal_filehdr *, |
struct internal_aouthdr *); |
const bfd_target * |
coff_real_object_p (bfd *abfd, |
unsigned nscns, |
struct internal_filehdr *internal_f, |
struct internal_aouthdr *internal_a) |
{ |
flagword oflags = abfd->flags; |
bfd_vma ostart = bfd_get_start_address (abfd); |
void * tdata; |
void * tdata_save; |
bfd_size_type readsize; /* Length of file_info. */ |
unsigned int scnhsz; |
char *external_sections; |
if (!(internal_f->f_flags & F_RELFLG)) |
abfd->flags |= HAS_RELOC; |
if ((internal_f->f_flags & F_EXEC)) |
abfd->flags |= EXEC_P; |
if (!(internal_f->f_flags & F_LNNO)) |
abfd->flags |= HAS_LINENO; |
if (!(internal_f->f_flags & F_LSYMS)) |
abfd->flags |= HAS_LOCALS; |
/* FIXME: How can we set D_PAGED correctly? */ |
if ((internal_f->f_flags & F_EXEC) != 0) |
abfd->flags |= D_PAGED; |
bfd_get_symcount (abfd) = internal_f->f_nsyms; |
if (internal_f->f_nsyms) |
abfd->flags |= HAS_SYMS; |
if (internal_a != (struct internal_aouthdr *) NULL) |
bfd_get_start_address (abfd) = internal_a->entry; |
else |
bfd_get_start_address (abfd) = 0; |
/* Set up the tdata area. ECOFF uses its own routine, and overrides |
abfd->flags. */ |
tdata_save = abfd->tdata.any; |
tdata = bfd_coff_mkobject_hook (abfd, (void *) internal_f, (void *) internal_a); |
if (tdata == NULL) |
goto fail2; |
scnhsz = bfd_coff_scnhsz (abfd); |
readsize = (bfd_size_type) nscns * scnhsz; |
external_sections = (char *) bfd_alloc (abfd, readsize); |
if (!external_sections) |
goto fail; |
if (bfd_bread ((void *) external_sections, readsize, abfd) != readsize) |
goto fail; |
/* Set the arch/mach *before* swapping in sections; section header swapping |
may depend on arch/mach info. */ |
if (! bfd_coff_set_arch_mach_hook (abfd, (void *) internal_f)) |
goto fail; |
/* Now copy data as required; construct all asections etc. */ |
if (nscns != 0) |
{ |
unsigned int i; |
for (i = 0; i < nscns; i++) |
{ |
struct internal_scnhdr tmp; |
bfd_coff_swap_scnhdr_in (abfd, |
(void *) (external_sections + i * scnhsz), |
(void *) & tmp); |
if (! make_a_section_from_file (abfd, &tmp, i + 1)) |
goto fail; |
} |
} |
return abfd->xvec; |
fail: |
bfd_release (abfd, tdata); |
fail2: |
abfd->tdata.any = tdata_save; |
abfd->flags = oflags; |
bfd_get_start_address (abfd) = ostart; |
return (const bfd_target *) NULL; |
} |
/* Turn a COFF file into a BFD, but fail with bfd_error_wrong_format if it is |
not a COFF file. This is also used by ECOFF. */ |
const bfd_target * |
coff_object_p (bfd *abfd) |
{ |
bfd_size_type filhsz; |
bfd_size_type aoutsz; |
unsigned int nscns; |
void * filehdr; |
struct internal_filehdr internal_f; |
struct internal_aouthdr internal_a; |
/* Figure out how much to read. */ |
filhsz = bfd_coff_filhsz (abfd); |
aoutsz = bfd_coff_aoutsz (abfd); |
filehdr = bfd_alloc (abfd, filhsz); |
if (filehdr == NULL) |
return NULL; |
if (bfd_bread (filehdr, filhsz, abfd) != filhsz) |
{ |
if (bfd_get_error () != bfd_error_system_call) |
bfd_set_error (bfd_error_wrong_format); |
bfd_release (abfd, filehdr); |
return NULL; |
} |
bfd_coff_swap_filehdr_in (abfd, filehdr, &internal_f); |
bfd_release (abfd, filehdr); |
/* The XCOFF format has two sizes for the f_opthdr. SMALL_AOUTSZ |
(less than aoutsz) used in object files and AOUTSZ (equal to |
aoutsz) in executables. The bfd_coff_swap_aouthdr_in function |
expects this header to be aoutsz bytes in length, so we use that |
value in the call to bfd_alloc below. But we must be careful to |
only read in f_opthdr bytes in the call to bfd_bread. We should |
also attempt to catch corrupt or non-COFF binaries with a strange |
value for f_opthdr. */ |
if (! bfd_coff_bad_format_hook (abfd, &internal_f) |
|| internal_f.f_opthdr > aoutsz) |
{ |
bfd_set_error (bfd_error_wrong_format); |
return NULL; |
} |
nscns = internal_f.f_nscns; |
if (internal_f.f_opthdr) |
{ |
void * opthdr; |
opthdr = bfd_alloc (abfd, aoutsz); |
if (opthdr == NULL) |
return NULL; |
if (bfd_bread (opthdr, (bfd_size_type) internal_f.f_opthdr, abfd) |
!= internal_f.f_opthdr) |
{ |
bfd_release (abfd, opthdr); |
return NULL; |
} |
bfd_coff_swap_aouthdr_in (abfd, opthdr, (void *) &internal_a); |
bfd_release (abfd, opthdr); |
} |
return coff_real_object_p (abfd, nscns, &internal_f, |
(internal_f.f_opthdr != 0 |
? &internal_a |
: (struct internal_aouthdr *) NULL)); |
} |
/* Get the BFD section from a COFF symbol section number. */ |
asection * |
coff_section_from_bfd_index (bfd *abfd, int section_index) |
{ |
struct bfd_section *answer = abfd->sections; |
if (section_index == N_ABS) |
return bfd_abs_section_ptr; |
if (section_index == N_UNDEF) |
return bfd_und_section_ptr; |
if (section_index == N_DEBUG) |
return bfd_abs_section_ptr; |
while (answer) |
{ |
if (answer->target_index == section_index) |
return answer; |
answer = answer->next; |
} |
/* We should not reach this point, but the SCO 3.2v4 /lib/libc_s.a |
has a bad symbol table in biglitpow.o. */ |
return bfd_und_section_ptr; |
} |
/* Get the upper bound of a COFF symbol table. */ |
long |
coff_get_symtab_upper_bound (bfd *abfd) |
{ |
if (!bfd_coff_slurp_symbol_table (abfd)) |
return -1; |
return (bfd_get_symcount (abfd) + 1) * (sizeof (coff_symbol_type *)); |
} |
/* Canonicalize a COFF symbol table. */ |
long |
coff_canonicalize_symtab (bfd *abfd, asymbol **alocation) |
{ |
unsigned int counter; |
coff_symbol_type *symbase; |
coff_symbol_type **location = (coff_symbol_type **) alocation; |
if (!bfd_coff_slurp_symbol_table (abfd)) |
return -1; |
symbase = obj_symbols (abfd); |
counter = bfd_get_symcount (abfd); |
while (counter-- > 0) |
*location++ = symbase++; |
*location = NULL; |
return bfd_get_symcount (abfd); |
} |
/* Get the name of a symbol. The caller must pass in a buffer of size |
>= SYMNMLEN + 1. */ |
const char * |
_bfd_coff_internal_syment_name (bfd *abfd, |
const struct internal_syment *sym, |
char *buf) |
{ |
/* FIXME: It's not clear this will work correctly if sizeof |
(_n_zeroes) != 4. */ |
if (sym->_n._n_n._n_zeroes != 0 |
|| sym->_n._n_n._n_offset == 0) |
{ |
memcpy (buf, sym->_n._n_name, SYMNMLEN); |
buf[SYMNMLEN] = '\0'; |
return buf; |
} |
else |
{ |
const char *strings; |
BFD_ASSERT (sym->_n._n_n._n_offset >= STRING_SIZE_SIZE); |
strings = obj_coff_strings (abfd); |
if (strings == NULL) |
{ |
strings = _bfd_coff_read_string_table (abfd); |
if (strings == NULL) |
return NULL; |
} |
return strings + sym->_n._n_n._n_offset; |
} |
} |
/* Read in and swap the relocs. This returns a buffer holding the |
relocs for section SEC in file ABFD. If CACHE is TRUE and |
INTERNAL_RELOCS is NULL, the relocs read in will be saved in case |
the function is called again. If EXTERNAL_RELOCS is not NULL, it |
is a buffer large enough to hold the unswapped relocs. If |
INTERNAL_RELOCS is not NULL, it is a buffer large enough to hold |
the swapped relocs. If REQUIRE_INTERNAL is TRUE, then the return |
value must be INTERNAL_RELOCS. The function returns NULL on error. */ |
struct internal_reloc * |
_bfd_coff_read_internal_relocs (bfd *abfd, |
asection *sec, |
bfd_boolean cache, |
bfd_byte *external_relocs, |
bfd_boolean require_internal, |
struct internal_reloc *internal_relocs) |
{ |
bfd_size_type relsz; |
bfd_byte *free_external = NULL; |
struct internal_reloc *free_internal = NULL; |
bfd_byte *erel; |
bfd_byte *erel_end; |
struct internal_reloc *irel; |
bfd_size_type amt; |
if (sec->reloc_count == 0) |
return internal_relocs; /* Nothing to do. */ |
if (coff_section_data (abfd, sec) != NULL |
&& coff_section_data (abfd, sec)->relocs != NULL) |
{ |
if (! require_internal) |
return coff_section_data (abfd, sec)->relocs; |
memcpy (internal_relocs, coff_section_data (abfd, sec)->relocs, |
sec->reloc_count * sizeof (struct internal_reloc)); |
return internal_relocs; |
} |
relsz = bfd_coff_relsz (abfd); |
amt = sec->reloc_count * relsz; |
if (external_relocs == NULL) |
{ |
free_external = (bfd_byte *) bfd_malloc (amt); |
if (free_external == NULL) |
goto error_return; |
external_relocs = free_external; |
} |
if (bfd_seek (abfd, sec->rel_filepos, SEEK_SET) != 0 |
|| bfd_bread (external_relocs, amt, abfd) != amt) |
goto error_return; |
if (internal_relocs == NULL) |
{ |
amt = sec->reloc_count; |
amt *= sizeof (struct internal_reloc); |
free_internal = (struct internal_reloc *) bfd_malloc (amt); |
if (free_internal == NULL) |
goto error_return; |
internal_relocs = free_internal; |
} |
/* Swap in the relocs. */ |
erel = external_relocs; |
erel_end = erel + relsz * sec->reloc_count; |
irel = internal_relocs; |
for (; erel < erel_end; erel += relsz, irel++) |
bfd_coff_swap_reloc_in (abfd, (void *) erel, (void *) irel); |
if (free_external != NULL) |
{ |
free (free_external); |
free_external = NULL; |
} |
if (cache && free_internal != NULL) |
{ |
if (coff_section_data (abfd, sec) == NULL) |
{ |
amt = sizeof (struct coff_section_tdata); |
sec->used_by_bfd = bfd_zalloc (abfd, amt); |
if (sec->used_by_bfd == NULL) |
goto error_return; |
coff_section_data (abfd, sec)->contents = NULL; |
} |
coff_section_data (abfd, sec)->relocs = free_internal; |
} |
return internal_relocs; |
error_return: |
if (free_external != NULL) |
free (free_external); |
if (free_internal != NULL) |
free (free_internal); |
return NULL; |
} |
/* Set lineno_count for the output sections of a COFF file. */ |
int |
coff_count_linenumbers (bfd *abfd) |
{ |
unsigned int limit = bfd_get_symcount (abfd); |
unsigned int i; |
int total = 0; |
asymbol **p; |
asection *s; |
if (limit == 0) |
{ |
/* This may be from the backend linker, in which case the |
lineno_count in the sections is correct. */ |
for (s = abfd->sections; s != NULL; s = s->next) |
total += s->lineno_count; |
return total; |
} |
for (s = abfd->sections; s != NULL; s = s->next) |
BFD_ASSERT (s->lineno_count == 0); |
for (p = abfd->outsymbols, i = 0; i < limit; i++, p++) |
{ |
asymbol *q_maybe = *p; |
if (bfd_family_coff (bfd_asymbol_bfd (q_maybe))) |
{ |
coff_symbol_type *q = coffsymbol (q_maybe); |
/* The AIX 4.1 compiler can sometimes generate line numbers |
attached to debugging symbols. We try to simply ignore |
those here. */ |
if (q->lineno != NULL |
&& q->symbol.section->owner != NULL) |
{ |
/* This symbol has line numbers. Increment the owning |
section's linenumber count. */ |
alent *l = q->lineno; |
do |
{ |
asection * sec = q->symbol.section->output_section; |
/* Do not try to update fields in read-only sections. */ |
if (! bfd_is_const_section (sec)) |
sec->lineno_count ++; |
++total; |
++l; |
} |
while (l->line_number != 0); |
} |
} |
} |
return total; |
} |
/* Takes a bfd and a symbol, returns a pointer to the coff specific |
area of the symbol if there is one. */ |
coff_symbol_type * |
coff_symbol_from (bfd *ignore_abfd ATTRIBUTE_UNUSED, |
asymbol *symbol) |
{ |
if (!bfd_family_coff (bfd_asymbol_bfd (symbol))) |
return (coff_symbol_type *) NULL; |
if (bfd_asymbol_bfd (symbol)->tdata.coff_obj_data == (coff_data_type *) NULL) |
return (coff_symbol_type *) NULL; |
return (coff_symbol_type *) symbol; |
} |
static void |
fixup_symbol_value (bfd *abfd, |
coff_symbol_type *coff_symbol_ptr, |
struct internal_syment *syment) |
{ |
/* Normalize the symbol flags. */ |
if (coff_symbol_ptr->symbol.section |
&& bfd_is_com_section (coff_symbol_ptr->symbol.section)) |
{ |
/* A common symbol is undefined with a value. */ |
syment->n_scnum = N_UNDEF; |
syment->n_value = coff_symbol_ptr->symbol.value; |
} |
else if ((coff_symbol_ptr->symbol.flags & BSF_DEBUGGING) != 0 |
&& (coff_symbol_ptr->symbol.flags & BSF_DEBUGGING_RELOC) == 0) |
{ |
syment->n_value = coff_symbol_ptr->symbol.value; |
} |
else if (bfd_is_und_section (coff_symbol_ptr->symbol.section)) |
{ |
syment->n_scnum = N_UNDEF; |
syment->n_value = 0; |
} |
/* FIXME: Do we need to handle the absolute section here? */ |
else |
{ |
if (coff_symbol_ptr->symbol.section) |
{ |
syment->n_scnum = |
coff_symbol_ptr->symbol.section->output_section->target_index; |
syment->n_value = (coff_symbol_ptr->symbol.value |
+ coff_symbol_ptr->symbol.section->output_offset); |
if (! obj_pe (abfd)) |
{ |
syment->n_value += (syment->n_sclass == C_STATLAB) |
? coff_symbol_ptr->symbol.section->output_section->lma |
: coff_symbol_ptr->symbol.section->output_section->vma; |
} |
} |
else |
{ |
BFD_ASSERT (0); |
/* This can happen, but I don't know why yet (steve@cygnus.com) */ |
syment->n_scnum = N_ABS; |
syment->n_value = coff_symbol_ptr->symbol.value; |
} |
} |
} |
/* Run through all the symbols in the symbol table and work out what |
their indexes into the symbol table will be when output. |
Coff requires that each C_FILE symbol points to the next one in the |
chain, and that the last one points to the first external symbol. We |
do that here too. */ |
bfd_boolean |
coff_renumber_symbols (bfd *bfd_ptr, int *first_undef) |
{ |
unsigned int symbol_count = bfd_get_symcount (bfd_ptr); |
asymbol **symbol_ptr_ptr = bfd_ptr->outsymbols; |
unsigned int native_index = 0; |
struct internal_syment *last_file = NULL; |
unsigned int symbol_index; |
/* COFF demands that undefined symbols come after all other symbols. |
Since we don't need to impose this extra knowledge on all our |
client programs, deal with that here. Sort the symbol table; |
just move the undefined symbols to the end, leaving the rest |
alone. The O'Reilly book says that defined global symbols come |
at the end before the undefined symbols, so we do that here as |
well. */ |
/* @@ Do we have some condition we could test for, so we don't always |
have to do this? I don't think relocatability is quite right, but |
I'm not certain. [raeburn:19920508.1711EST] */ |
{ |
asymbol **newsyms; |
unsigned int i; |
bfd_size_type amt; |
amt = sizeof (asymbol *) * ((bfd_size_type) symbol_count + 1); |
newsyms = (asymbol **) bfd_alloc (bfd_ptr, amt); |
if (!newsyms) |
return FALSE; |
bfd_ptr->outsymbols = newsyms; |
for (i = 0; i < symbol_count; i++) |
if ((symbol_ptr_ptr[i]->flags & BSF_NOT_AT_END) != 0 |
|| (!bfd_is_und_section (symbol_ptr_ptr[i]->section) |
&& !bfd_is_com_section (symbol_ptr_ptr[i]->section) |
&& ((symbol_ptr_ptr[i]->flags & BSF_FUNCTION) != 0 |
|| ((symbol_ptr_ptr[i]->flags & (BSF_GLOBAL | BSF_WEAK)) |
== 0)))) |
*newsyms++ = symbol_ptr_ptr[i]; |
for (i = 0; i < symbol_count; i++) |
if ((symbol_ptr_ptr[i]->flags & BSF_NOT_AT_END) == 0 |
&& !bfd_is_und_section (symbol_ptr_ptr[i]->section) |
&& (bfd_is_com_section (symbol_ptr_ptr[i]->section) |
|| ((symbol_ptr_ptr[i]->flags & BSF_FUNCTION) == 0 |
&& ((symbol_ptr_ptr[i]->flags & (BSF_GLOBAL | BSF_WEAK)) |
!= 0)))) |
*newsyms++ = symbol_ptr_ptr[i]; |
*first_undef = newsyms - bfd_ptr->outsymbols; |
for (i = 0; i < symbol_count; i++) |
if ((symbol_ptr_ptr[i]->flags & BSF_NOT_AT_END) == 0 |
&& bfd_is_und_section (symbol_ptr_ptr[i]->section)) |
*newsyms++ = symbol_ptr_ptr[i]; |
*newsyms = (asymbol *) NULL; |
symbol_ptr_ptr = bfd_ptr->outsymbols; |
} |
for (symbol_index = 0; symbol_index < symbol_count; symbol_index++) |
{ |
coff_symbol_type *coff_symbol_ptr = coff_symbol_from (bfd_ptr, symbol_ptr_ptr[symbol_index]); |
symbol_ptr_ptr[symbol_index]->udata.i = symbol_index; |
if (coff_symbol_ptr && coff_symbol_ptr->native) |
{ |
combined_entry_type *s = coff_symbol_ptr->native; |
int i; |
if (s->u.syment.n_sclass == C_FILE) |
{ |
if (last_file != NULL) |
last_file->n_value = native_index; |
last_file = &(s->u.syment); |
} |
else |
/* Modify the symbol values according to their section and |
type. */ |
fixup_symbol_value (bfd_ptr, coff_symbol_ptr, &(s->u.syment)); |
for (i = 0; i < s->u.syment.n_numaux + 1; i++) |
s[i].offset = native_index++; |
} |
else |
native_index++; |
} |
obj_conv_table_size (bfd_ptr) = native_index; |
return TRUE; |
} |
/* Run thorough the symbol table again, and fix it so that all |
pointers to entries are changed to the entries' index in the output |
symbol table. */ |
void |
coff_mangle_symbols (bfd *bfd_ptr) |
{ |
unsigned int symbol_count = bfd_get_symcount (bfd_ptr); |
asymbol **symbol_ptr_ptr = bfd_ptr->outsymbols; |
unsigned int symbol_index; |
for (symbol_index = 0; symbol_index < symbol_count; symbol_index++) |
{ |
coff_symbol_type *coff_symbol_ptr = |
coff_symbol_from (bfd_ptr, symbol_ptr_ptr[symbol_index]); |
if (coff_symbol_ptr && coff_symbol_ptr->native) |
{ |
int i; |
combined_entry_type *s = coff_symbol_ptr->native; |
if (s->fix_value) |
{ |
/* FIXME: We should use a union here. */ |
s->u.syment.n_value = |
(bfd_hostptr_t) ((combined_entry_type *) |
((bfd_hostptr_t) s->u.syment.n_value))->offset; |
s->fix_value = 0; |
} |
if (s->fix_line) |
{ |
/* The value is the offset into the line number entries |
for the symbol's section. On output, the symbol's |
section should be N_DEBUG. */ |
s->u.syment.n_value = |
(coff_symbol_ptr->symbol.section->output_section->line_filepos |
+ s->u.syment.n_value * bfd_coff_linesz (bfd_ptr)); |
coff_symbol_ptr->symbol.section = |
coff_section_from_bfd_index (bfd_ptr, N_DEBUG); |
BFD_ASSERT (coff_symbol_ptr->symbol.flags & BSF_DEBUGGING); |
} |
for (i = 0; i < s->u.syment.n_numaux; i++) |
{ |
combined_entry_type *a = s + i + 1; |
if (a->fix_tag) |
{ |
a->u.auxent.x_sym.x_tagndx.l = |
a->u.auxent.x_sym.x_tagndx.p->offset; |
a->fix_tag = 0; |
} |
if (a->fix_end) |
{ |
a->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l = |
a->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p->offset; |
a->fix_end = 0; |
} |
if (a->fix_scnlen) |
{ |
a->u.auxent.x_csect.x_scnlen.l = |
a->u.auxent.x_csect.x_scnlen.p->offset; |
a->fix_scnlen = 0; |
} |
} |
} |
} |
} |
static void |
coff_fix_symbol_name (bfd *abfd, |
asymbol *symbol, |
combined_entry_type *native, |
bfd_size_type *string_size_p, |
asection **debug_string_section_p, |
bfd_size_type *debug_string_size_p) |
{ |
unsigned int name_length; |
union internal_auxent *auxent; |
char *name = (char *) (symbol->name); |
if (name == NULL) |
{ |
/* COFF symbols always have names, so we'll make one up. */ |
symbol->name = "strange"; |
name = (char *) symbol->name; |
} |
name_length = strlen (name); |
if (native->u.syment.n_sclass == C_FILE |
&& native->u.syment.n_numaux > 0) |
{ |
unsigned int filnmlen; |
if (bfd_coff_force_symnames_in_strings (abfd)) |
{ |
native->u.syment._n._n_n._n_offset = |
(*string_size_p + STRING_SIZE_SIZE); |
native->u.syment._n._n_n._n_zeroes = 0; |
*string_size_p += 6; /* strlen(".file") + 1 */ |
} |
else |
strncpy (native->u.syment._n._n_name, ".file", SYMNMLEN); |
auxent = &(native + 1)->u.auxent; |
filnmlen = bfd_coff_filnmlen (abfd); |
if (bfd_coff_long_filenames (abfd)) |
{ |
if (name_length <= filnmlen) |
strncpy (auxent->x_file.x_fname, name, filnmlen); |
else |
{ |
auxent->x_file.x_n.x_offset = *string_size_p + STRING_SIZE_SIZE; |
auxent->x_file.x_n.x_zeroes = 0; |
*string_size_p += name_length + 1; |
} |
} |
else |
{ |
strncpy (auxent->x_file.x_fname, name, filnmlen); |
if (name_length > filnmlen) |
name[filnmlen] = '\0'; |
} |
} |
else |
{ |
if (name_length <= SYMNMLEN && !bfd_coff_force_symnames_in_strings (abfd)) |
/* This name will fit into the symbol neatly. */ |
strncpy (native->u.syment._n._n_name, symbol->name, SYMNMLEN); |
else if (!bfd_coff_symname_in_debug (abfd, &native->u.syment)) |
{ |
native->u.syment._n._n_n._n_offset = (*string_size_p |
+ STRING_SIZE_SIZE); |
native->u.syment._n._n_n._n_zeroes = 0; |
*string_size_p += name_length + 1; |
} |
else |
{ |
file_ptr filepos; |
bfd_byte buf[4]; |
int prefix_len = bfd_coff_debug_string_prefix_length (abfd); |
/* This name should be written into the .debug section. For |
some reason each name is preceded by a two byte length |
and also followed by a null byte. FIXME: We assume that |
the .debug section has already been created, and that it |
is large enough. */ |
if (*debug_string_section_p == (asection *) NULL) |
*debug_string_section_p = bfd_get_section_by_name (abfd, ".debug"); |
filepos = bfd_tell (abfd); |
if (prefix_len == 4) |
bfd_put_32 (abfd, (bfd_vma) (name_length + 1), buf); |
else |
bfd_put_16 (abfd, (bfd_vma) (name_length + 1), buf); |
if (!bfd_set_section_contents (abfd, |
*debug_string_section_p, |
(void *) buf, |
(file_ptr) *debug_string_size_p, |
(bfd_size_type) prefix_len) |
|| !bfd_set_section_contents (abfd, |
*debug_string_section_p, |
(void *) symbol->name, |
(file_ptr) (*debug_string_size_p |
+ prefix_len), |
(bfd_size_type) name_length + 1)) |
abort (); |
if (bfd_seek (abfd, filepos, SEEK_SET) != 0) |
abort (); |
native->u.syment._n._n_n._n_offset = |
*debug_string_size_p + prefix_len; |
native->u.syment._n._n_n._n_zeroes = 0; |
*debug_string_size_p += name_length + 1 + prefix_len; |
} |
} |
} |
/* We need to keep track of the symbol index so that when we write out |
the relocs we can get the index for a symbol. This method is a |
hack. FIXME. */ |
#define set_index(symbol, idx) ((symbol)->udata.i = (idx)) |
/* Write a symbol out to a COFF file. */ |
static bfd_boolean |
coff_write_symbol (bfd *abfd, |
asymbol *symbol, |
combined_entry_type *native, |
bfd_vma *written, |
bfd_size_type *string_size_p, |
asection **debug_string_section_p, |
bfd_size_type *debug_string_size_p) |
{ |
unsigned int numaux = native->u.syment.n_numaux; |
int type = native->u.syment.n_type; |
int n_sclass = (int) native->u.syment.n_sclass; |
asection *output_section = symbol->section->output_section |
? symbol->section->output_section |
: symbol->section; |
void * buf; |
bfd_size_type symesz; |
if (native->u.syment.n_sclass == C_FILE) |
symbol->flags |= BSF_DEBUGGING; |
if (symbol->flags & BSF_DEBUGGING |
&& bfd_is_abs_section (symbol->section)) |
native->u.syment.n_scnum = N_DEBUG; |
else if (bfd_is_abs_section (symbol->section)) |
native->u.syment.n_scnum = N_ABS; |
else if (bfd_is_und_section (symbol->section)) |
native->u.syment.n_scnum = N_UNDEF; |
else |
native->u.syment.n_scnum = |
output_section->target_index; |
coff_fix_symbol_name (abfd, symbol, native, string_size_p, |
debug_string_section_p, debug_string_size_p); |
symesz = bfd_coff_symesz (abfd); |
buf = bfd_alloc (abfd, symesz); |
if (!buf) |
return FALSE; |
bfd_coff_swap_sym_out (abfd, &native->u.syment, buf); |
if (bfd_bwrite (buf, symesz, abfd) != symesz) |
return FALSE; |
bfd_release (abfd, buf); |
if (native->u.syment.n_numaux > 0) |
{ |
bfd_size_type auxesz; |
unsigned int j; |
auxesz = bfd_coff_auxesz (abfd); |
buf = bfd_alloc (abfd, auxesz); |
if (!buf) |
return FALSE; |
for (j = 0; j < native->u.syment.n_numaux; j++) |
{ |
bfd_coff_swap_aux_out (abfd, |
&((native + j + 1)->u.auxent), |
type, n_sclass, (int) j, |
native->u.syment.n_numaux, |
buf); |
if (bfd_bwrite (buf, auxesz, abfd) != auxesz) |
return FALSE; |
} |
bfd_release (abfd, buf); |
} |
/* Store the index for use when we write out the relocs. */ |
set_index (symbol, *written); |
*written += numaux + 1; |
return TRUE; |
} |
/* Write out a symbol to a COFF file that does not come from a COFF |
file originally. This symbol may have been created by the linker, |
or we may be linking a non COFF file to a COFF file. */ |
bfd_boolean |
coff_write_alien_symbol (bfd *abfd, |
asymbol *symbol, |
struct internal_syment *isym, |
bfd_vma *written, |
bfd_size_type *string_size_p, |
asection **debug_string_section_p, |
bfd_size_type *debug_string_size_p) |
{ |
combined_entry_type *native; |
combined_entry_type dummy[2]; |
asection *output_section = symbol->section->output_section |
? symbol->section->output_section |
: symbol->section; |
struct bfd_link_info *link_info = coff_data (abfd)->link_info; |
bfd_boolean ret; |
if ((!link_info || link_info->strip_discarded) |
&& !bfd_is_abs_section (symbol->section) |
&& symbol->section->output_section == bfd_abs_section_ptr) |
{ |
symbol->name = ""; |
if (isym != NULL) |
memset (isym, 0, sizeof(*isym)); |
return TRUE; |
} |
native = dummy; |
native->u.syment.n_type = T_NULL; |
native->u.syment.n_flags = 0; |
native->u.syment.n_numaux = 0; |
if (bfd_is_und_section (symbol->section)) |
{ |
native->u.syment.n_scnum = N_UNDEF; |
native->u.syment.n_value = symbol->value; |
} |
else if (bfd_is_com_section (symbol->section)) |
{ |
native->u.syment.n_scnum = N_UNDEF; |
native->u.syment.n_value = symbol->value; |
} |
else if (symbol->flags & BSF_FILE) |
{ |
native->u.syment.n_scnum = N_DEBUG; |
native->u.syment.n_numaux = 1; |
} |
else if (symbol->flags & BSF_DEBUGGING) |
{ |
/* There isn't much point to writing out a debugging symbol |
unless we are prepared to convert it into COFF debugging |
format. So, we just ignore them. We must clobber the symbol |
name to keep it from being put in the string table. */ |
symbol->name = ""; |
if (isym != NULL) |
memset (isym, 0, sizeof(*isym)); |
return TRUE; |
} |
else |
{ |
native->u.syment.n_scnum = output_section->target_index; |
native->u.syment.n_value = (symbol->value |
+ symbol->section->output_offset); |
if (! obj_pe (abfd)) |
native->u.syment.n_value += output_section->vma; |
/* Copy the any flags from the file header into the symbol. |
FIXME: Why? */ |
{ |
coff_symbol_type *c = coff_symbol_from (abfd, symbol); |
if (c != (coff_symbol_type *) NULL) |
native->u.syment.n_flags = bfd_asymbol_bfd (&c->symbol)->flags; |
} |
} |
native->u.syment.n_type = 0; |
if (symbol->flags & BSF_FILE) |
native->u.syment.n_sclass = C_FILE; |
else if (symbol->flags & BSF_LOCAL) |
native->u.syment.n_sclass = C_STAT; |
else if (symbol->flags & BSF_WEAK) |
native->u.syment.n_sclass = obj_pe (abfd) ? C_NT_WEAK : C_WEAKEXT; |
else |
native->u.syment.n_sclass = C_EXT; |
ret = coff_write_symbol (abfd, symbol, native, written, string_size_p, |
debug_string_section_p, debug_string_size_p); |
if (isym != NULL) |
*isym = native->u.syment; |
return ret; |
} |
/* Write a native symbol to a COFF file. */ |
static bfd_boolean |
coff_write_native_symbol (bfd *abfd, |
coff_symbol_type *symbol, |
bfd_vma *written, |
bfd_size_type *string_size_p, |
asection **debug_string_section_p, |
bfd_size_type *debug_string_size_p) |
{ |
combined_entry_type *native = symbol->native; |
alent *lineno = symbol->lineno; |
struct bfd_link_info *link_info = coff_data (abfd)->link_info; |
if ((!link_info || link_info->strip_discarded) |
&& !bfd_is_abs_section (symbol->symbol.section) |
&& symbol->symbol.section->output_section == bfd_abs_section_ptr) |
{ |
symbol->symbol.name = ""; |
return TRUE; |
} |
/* If this symbol has an associated line number, we must store the |
symbol index in the line number field. We also tag the auxent to |
point to the right place in the lineno table. */ |
if (lineno && !symbol->done_lineno && symbol->symbol.section->owner != NULL) |
{ |
unsigned int count = 0; |
lineno[count].u.offset = *written; |
if (native->u.syment.n_numaux) |
{ |
union internal_auxent *a = &((native + 1)->u.auxent); |
a->x_sym.x_fcnary.x_fcn.x_lnnoptr = |
symbol->symbol.section->output_section->moving_line_filepos; |
} |
/* Count and relocate all other linenumbers. */ |
count++; |
while (lineno[count].line_number != 0) |
{ |
lineno[count].u.offset += |
(symbol->symbol.section->output_section->vma |
+ symbol->symbol.section->output_offset); |
count++; |
} |
symbol->done_lineno = TRUE; |
if (! bfd_is_const_section (symbol->symbol.section->output_section)) |
symbol->symbol.section->output_section->moving_line_filepos += |
count * bfd_coff_linesz (abfd); |
} |
return coff_write_symbol (abfd, &(symbol->symbol), native, written, |
string_size_p, debug_string_section_p, |
debug_string_size_p); |
} |
static void |
null_error_handler (const char * fmt ATTRIBUTE_UNUSED, ...) |
{ |
} |
/* Write out the COFF symbols. */ |
bfd_boolean |
coff_write_symbols (bfd *abfd) |
{ |
bfd_size_type string_size; |
asection *debug_string_section; |
bfd_size_type debug_string_size; |
unsigned int i; |
unsigned int limit = bfd_get_symcount (abfd); |
bfd_vma written = 0; |
asymbol **p; |
string_size = 0; |
debug_string_section = NULL; |
debug_string_size = 0; |
/* If this target supports long section names, they must be put into |
the string table. This is supported by PE. This code must |
handle section names just as they are handled in |
coff_write_object_contents. */ |
if (bfd_coff_long_section_names (abfd)) |
{ |
asection *o; |
for (o = abfd->sections; o != NULL; o = o->next) |
{ |
size_t len; |
len = strlen (o->name); |
if (len > SCNNMLEN) |
string_size += len + 1; |
} |
} |
/* Seek to the right place. */ |
if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0) |
return FALSE; |
/* Output all the symbols we have. */ |
written = 0; |
for (p = abfd->outsymbols, i = 0; i < limit; i++, p++) |
{ |
asymbol *symbol = *p; |
coff_symbol_type *c_symbol = coff_symbol_from (abfd, symbol); |
if (c_symbol == (coff_symbol_type *) NULL |
|| c_symbol->native == (combined_entry_type *) NULL) |
{ |
if (!coff_write_alien_symbol (abfd, symbol, NULL, &written, |
&string_size, &debug_string_section, |
&debug_string_size)) |
return FALSE; |
} |
else |
{ |
if (coff_backend_info (abfd)->_bfd_coff_classify_symbol != NULL) |
{ |
bfd_error_handler_type current_error_handler; |
enum coff_symbol_classification sym_class; |
unsigned char *n_sclass; |
/* Suppress error reporting by bfd_coff_classify_symbol. |
Error messages can be generated when we are processing a local |
symbol which has no associated section and we do not have to |
worry about this, all we need to know is that it is local. */ |
current_error_handler = bfd_set_error_handler (null_error_handler); |
sym_class = bfd_coff_classify_symbol (abfd, |
&c_symbol->native->u.syment); |
(void) bfd_set_error_handler (current_error_handler); |
n_sclass = &c_symbol->native->u.syment.n_sclass; |
/* If the symbol class has been changed (eg objcopy/ld script/etc) |
we cannot retain the existing sclass from the original symbol. |
Weak symbols only have one valid sclass, so just set it always. |
If it is not local class and should be, set it C_STAT. |
If it is global and not classified as global, or if it is |
weak (which is also classified as global), set it C_EXT. */ |
if (symbol->flags & BSF_WEAK) |
*n_sclass = obj_pe (abfd) ? C_NT_WEAK : C_WEAKEXT; |
else if (symbol->flags & BSF_LOCAL && sym_class != COFF_SYMBOL_LOCAL) |
*n_sclass = C_STAT; |
else if (symbol->flags & BSF_GLOBAL |
&& (sym_class != COFF_SYMBOL_GLOBAL |
#ifdef COFF_WITH_PE |
|| *n_sclass == C_NT_WEAK |
#endif |
|| *n_sclass == C_WEAKEXT)) |
c_symbol->native->u.syment.n_sclass = C_EXT; |
} |
if (!coff_write_native_symbol (abfd, c_symbol, &written, |
&string_size, &debug_string_section, |
&debug_string_size)) |
return FALSE; |
} |
} |
obj_raw_syment_count (abfd) = written; |
/* Now write out strings. */ |
if (string_size != 0) |
{ |
unsigned int size = string_size + STRING_SIZE_SIZE; |
bfd_byte buffer[STRING_SIZE_SIZE]; |
#if STRING_SIZE_SIZE == 4 |
H_PUT_32 (abfd, size, buffer); |
#else |
#error Change H_PUT_32 |
#endif |
if (bfd_bwrite ((void *) buffer, (bfd_size_type) sizeof (buffer), abfd) |
!= sizeof (buffer)) |
return FALSE; |
/* Handle long section names. This code must handle section |
names just as they are handled in coff_write_object_contents. */ |
if (bfd_coff_long_section_names (abfd)) |
{ |
asection *o; |
for (o = abfd->sections; o != NULL; o = o->next) |
{ |
size_t len; |
len = strlen (o->name); |
if (len > SCNNMLEN) |
{ |
if (bfd_bwrite (o->name, (bfd_size_type) (len + 1), abfd) |
!= len + 1) |
return FALSE; |
} |
} |
} |
for (p = abfd->outsymbols, i = 0; |
i < limit; |
i++, p++) |
{ |
asymbol *q = *p; |
size_t name_length = strlen (q->name); |
coff_symbol_type *c_symbol = coff_symbol_from (abfd, q); |
size_t maxlen; |
/* Figure out whether the symbol name should go in the string |
table. Symbol names that are short enough are stored |
directly in the syment structure. File names permit a |
different, longer, length in the syment structure. On |
XCOFF, some symbol names are stored in the .debug section |
rather than in the string table. */ |
if (c_symbol == NULL |
|| c_symbol->native == NULL) |
/* This is not a COFF symbol, so it certainly is not a |
file name, nor does it go in the .debug section. */ |
maxlen = bfd_coff_force_symnames_in_strings (abfd) ? 0 : SYMNMLEN; |
else if (bfd_coff_symname_in_debug (abfd, |
&c_symbol->native->u.syment)) |
/* This symbol name is in the XCOFF .debug section. |
Don't write it into the string table. */ |
maxlen = name_length; |
else if (c_symbol->native->u.syment.n_sclass == C_FILE |
&& c_symbol->native->u.syment.n_numaux > 0) |
{ |
if (bfd_coff_force_symnames_in_strings (abfd)) |
{ |
if (bfd_bwrite (".file", (bfd_size_type) 6, abfd) != 6) |
return FALSE; |
} |
maxlen = bfd_coff_filnmlen (abfd); |
} |
else |
maxlen = bfd_coff_force_symnames_in_strings (abfd) ? 0 : SYMNMLEN; |
if (name_length > maxlen) |
{ |
if (bfd_bwrite ((void *) (q->name), (bfd_size_type) name_length + 1, |
abfd) != name_length + 1) |
return FALSE; |
} |
} |
} |
else |
{ |
/* We would normally not write anything here, but we'll write |
out 4 so that any stupid coff reader which tries to read the |
string table even when there isn't one won't croak. */ |
unsigned int size = STRING_SIZE_SIZE; |
bfd_byte buffer[STRING_SIZE_SIZE]; |
#if STRING_SIZE_SIZE == 4 |
H_PUT_32 (abfd, size, buffer); |
#else |
#error Change H_PUT_32 |
#endif |
if (bfd_bwrite ((void *) buffer, (bfd_size_type) STRING_SIZE_SIZE, abfd) |
!= STRING_SIZE_SIZE) |
return FALSE; |
} |
/* Make sure the .debug section was created to be the correct size. |
We should create it ourselves on the fly, but we don't because |
BFD won't let us write to any section until we know how large all |
the sections are. We could still do it by making another pass |
over the symbols. FIXME. */ |
BFD_ASSERT (debug_string_size == 0 |
|| (debug_string_section != (asection *) NULL |
&& (BFD_ALIGN (debug_string_size, |
1 << debug_string_section->alignment_power) |
== debug_string_section->size))); |
return TRUE; |
} |
bfd_boolean |
coff_write_linenumbers (bfd *abfd) |
{ |
asection *s; |
bfd_size_type linesz; |
void * buff; |
linesz = bfd_coff_linesz (abfd); |
buff = bfd_alloc (abfd, linesz); |
if (!buff) |
return FALSE; |
for (s = abfd->sections; s != (asection *) NULL; s = s->next) |
{ |
if (s->lineno_count) |
{ |
asymbol **q = abfd->outsymbols; |
if (bfd_seek (abfd, s->line_filepos, SEEK_SET) != 0) |
return FALSE; |
/* Find all the linenumbers in this section. */ |
while (*q) |
{ |
asymbol *p = *q; |
if (p->section->output_section == s) |
{ |
alent *l = |
BFD_SEND (bfd_asymbol_bfd (p), _get_lineno, |
(bfd_asymbol_bfd (p), p)); |
if (l) |
{ |
/* Found a linenumber entry, output. */ |
struct internal_lineno out; |
memset ((void *) & out, 0, sizeof (out)); |
out.l_lnno = 0; |
out.l_addr.l_symndx = l->u.offset; |
bfd_coff_swap_lineno_out (abfd, &out, buff); |
if (bfd_bwrite (buff, (bfd_size_type) linesz, abfd) |
!= linesz) |
return FALSE; |
l++; |
while (l->line_number) |
{ |
out.l_lnno = l->line_number; |
out.l_addr.l_symndx = l->u.offset; |
bfd_coff_swap_lineno_out (abfd, &out, buff); |
if (bfd_bwrite (buff, (bfd_size_type) linesz, abfd) |
!= linesz) |
return FALSE; |
l++; |
} |
} |
} |
q++; |
} |
} |
} |
bfd_release (abfd, buff); |
return TRUE; |
} |
alent * |
coff_get_lineno (bfd *ignore_abfd ATTRIBUTE_UNUSED, asymbol *symbol) |
{ |
return coffsymbol (symbol)->lineno; |
} |
/* This function transforms the offsets into the symbol table into |
pointers to syments. */ |
static void |
coff_pointerize_aux (bfd *abfd, |
combined_entry_type *table_base, |
combined_entry_type *symbol, |
unsigned int indaux, |
combined_entry_type *auxent) |
{ |
unsigned int type = symbol->u.syment.n_type; |
unsigned int n_sclass = symbol->u.syment.n_sclass; |
if (coff_backend_info (abfd)->_bfd_coff_pointerize_aux_hook) |
{ |
if ((*coff_backend_info (abfd)->_bfd_coff_pointerize_aux_hook) |
(abfd, table_base, symbol, indaux, auxent)) |
return; |
} |
/* Don't bother if this is a file or a section. */ |
if (n_sclass == C_STAT && type == T_NULL) |
return; |
if (n_sclass == C_FILE) |
return; |
/* Otherwise patch up. */ |
#define N_TMASK coff_data (abfd)->local_n_tmask |
#define N_BTSHFT coff_data (abfd)->local_n_btshft |
if ((ISFCN (type) || ISTAG (n_sclass) || n_sclass == C_BLOCK |
|| n_sclass == C_FCN) |
&& auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l > 0) |
{ |
auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p = |
table_base + auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l; |
auxent->fix_end = 1; |
} |
/* A negative tagndx is meaningless, but the SCO 3.2v4 cc can |
generate one, so we must be careful to ignore it. */ |
if (auxent->u.auxent.x_sym.x_tagndx.l > 0) |
{ |
auxent->u.auxent.x_sym.x_tagndx.p = |
table_base + auxent->u.auxent.x_sym.x_tagndx.l; |
auxent->fix_tag = 1; |
} |
} |
/* Allocate space for the ".debug" section, and read it. |
We did not read the debug section until now, because |
we didn't want to go to the trouble until someone needed it. */ |
static char * |
build_debug_section (bfd *abfd) |
{ |
char *debug_section; |
file_ptr position; |
bfd_size_type sec_size; |
asection *sect = bfd_get_section_by_name (abfd, ".debug"); |
if (!sect) |
{ |
bfd_set_error (bfd_error_no_debug_section); |
return NULL; |
} |
sec_size = sect->size; |
debug_section = (char *) bfd_alloc (abfd, sec_size); |
if (debug_section == NULL) |
return NULL; |
/* Seek to the beginning of the `.debug' section and read it. |
Save the current position first; it is needed by our caller. |
Then read debug section and reset the file pointer. */ |
position = bfd_tell (abfd); |
if (bfd_seek (abfd, sect->filepos, SEEK_SET) != 0 |
|| bfd_bread (debug_section, sec_size, abfd) != sec_size |
|| bfd_seek (abfd, position, SEEK_SET) != 0) |
return NULL; |
return debug_section; |
} |
/* Return a pointer to a malloc'd copy of 'name'. 'name' may not be |
\0-terminated, but will not exceed 'maxlen' characters. The copy *will* |
be \0-terminated. */ |
static char * |
copy_name (bfd *abfd, char *name, size_t maxlen) |
{ |
size_t len; |
char *newname; |
for (len = 0; len < maxlen; ++len) |
if (name[len] == '\0') |
break; |
if ((newname = (char *) bfd_alloc (abfd, (bfd_size_type) len + 1)) == NULL) |
return NULL; |
strncpy (newname, name, len); |
newname[len] = '\0'; |
return newname; |
} |
/* Read in the external symbols. */ |
bfd_boolean |
_bfd_coff_get_external_symbols (bfd *abfd) |
{ |
bfd_size_type symesz; |
bfd_size_type size; |
void * syms; |
if (obj_coff_external_syms (abfd) != NULL) |
return TRUE; |
symesz = bfd_coff_symesz (abfd); |
size = obj_raw_syment_count (abfd) * symesz; |
if (size == 0) |
return TRUE; |
syms = bfd_malloc (size); |
if (syms == NULL) |
return FALSE; |
if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0 |
|| bfd_bread (syms, size, abfd) != size) |
{ |
if (syms != NULL) |
free (syms); |
return FALSE; |
} |
obj_coff_external_syms (abfd) = syms; |
return TRUE; |
} |
/* Read in the external strings. The strings are not loaded until |
they are needed. This is because we have no simple way of |
detecting a missing string table in an archive. */ |
const char * |
_bfd_coff_read_string_table (bfd *abfd) |
{ |
char extstrsize[STRING_SIZE_SIZE]; |
bfd_size_type strsize; |
char *strings; |
file_ptr pos; |
if (obj_coff_strings (abfd) != NULL) |
return obj_coff_strings (abfd); |
if (obj_sym_filepos (abfd) == 0) |
{ |
bfd_set_error (bfd_error_no_symbols); |
return NULL; |
} |
pos = obj_sym_filepos (abfd); |
pos += obj_raw_syment_count (abfd) * bfd_coff_symesz (abfd); |
if (bfd_seek (abfd, pos, SEEK_SET) != 0) |
return NULL; |
if (bfd_bread (extstrsize, (bfd_size_type) sizeof extstrsize, abfd) |
!= sizeof extstrsize) |
{ |
if (bfd_get_error () != bfd_error_file_truncated) |
return NULL; |
/* There is no string table. */ |
strsize = STRING_SIZE_SIZE; |
} |
else |
{ |
#if STRING_SIZE_SIZE == 4 |
strsize = H_GET_32 (abfd, extstrsize); |
#else |
#error Change H_GET_32 |
#endif |
} |
if (strsize < STRING_SIZE_SIZE) |
{ |
(*_bfd_error_handler) |
(_("%B: bad string table size %lu"), abfd, (unsigned long) strsize); |
bfd_set_error (bfd_error_bad_value); |
return NULL; |
} |
strings = (char *) bfd_malloc (strsize); |
if (strings == NULL) |
return NULL; |
if (bfd_bread (strings + STRING_SIZE_SIZE, strsize - STRING_SIZE_SIZE, abfd) |
!= strsize - STRING_SIZE_SIZE) |
{ |
free (strings); |
return NULL; |
} |
obj_coff_strings (abfd) = strings; |
return strings; |
} |
/* Free up the external symbols and strings read from a COFF file. */ |
bfd_boolean |
_bfd_coff_free_symbols (bfd *abfd) |
{ |
if (obj_coff_external_syms (abfd) != NULL |
&& ! obj_coff_keep_syms (abfd)) |
{ |
free (obj_coff_external_syms (abfd)); |
obj_coff_external_syms (abfd) = NULL; |
} |
if (obj_coff_strings (abfd) != NULL |
&& ! obj_coff_keep_strings (abfd)) |
{ |
free (obj_coff_strings (abfd)); |
obj_coff_strings (abfd) = NULL; |
} |
return TRUE; |
} |
/* Read a symbol table into freshly bfd_allocated memory, swap it, and |
knit the symbol names into a normalized form. By normalized here I |
mean that all symbols have an n_offset pointer that points to a null- |
terminated string. */ |
combined_entry_type * |
coff_get_normalized_symtab (bfd *abfd) |
{ |
combined_entry_type *internal; |
combined_entry_type *internal_ptr; |
combined_entry_type *symbol_ptr; |
combined_entry_type *internal_end; |
size_t symesz; |
char *raw_src; |
char *raw_end; |
const char *string_table = NULL; |
char *debug_section = NULL; |
bfd_size_type size; |
if (obj_raw_syments (abfd) != NULL) |
return obj_raw_syments (abfd); |
size = obj_raw_syment_count (abfd) * sizeof (combined_entry_type); |
internal = (combined_entry_type *) bfd_zalloc (abfd, size); |
if (internal == NULL && size != 0) |
return NULL; |
internal_end = internal + obj_raw_syment_count (abfd); |
if (! _bfd_coff_get_external_symbols (abfd)) |
return NULL; |
raw_src = (char *) obj_coff_external_syms (abfd); |
/* Mark the end of the symbols. */ |
symesz = bfd_coff_symesz (abfd); |
raw_end = (char *) raw_src + obj_raw_syment_count (abfd) * symesz; |
/* FIXME SOMEDAY. A string table size of zero is very weird, but |
probably possible. If one shows up, it will probably kill us. */ |
/* Swap all the raw entries. */ |
for (internal_ptr = internal; |
raw_src < raw_end; |
raw_src += symesz, internal_ptr++) |
{ |
unsigned int i; |
bfd_coff_swap_sym_in (abfd, (void *) raw_src, |
(void *) & internal_ptr->u.syment); |
symbol_ptr = internal_ptr; |
for (i = 0; |
i < symbol_ptr->u.syment.n_numaux; |
i++) |
{ |
internal_ptr++; |
raw_src += symesz; |
bfd_coff_swap_aux_in (abfd, (void *) raw_src, |
symbol_ptr->u.syment.n_type, |
symbol_ptr->u.syment.n_sclass, |
(int) i, symbol_ptr->u.syment.n_numaux, |
&(internal_ptr->u.auxent)); |
coff_pointerize_aux (abfd, internal, symbol_ptr, i, |
internal_ptr); |
} |
} |
/* Free the raw symbols, but not the strings (if we have them). */ |
obj_coff_keep_strings (abfd) = TRUE; |
if (! _bfd_coff_free_symbols (abfd)) |
return NULL; |
for (internal_ptr = internal; internal_ptr < internal_end; |
internal_ptr++) |
{ |
if (internal_ptr->u.syment.n_sclass == C_FILE |
&& internal_ptr->u.syment.n_numaux > 0) |
{ |
/* Make a file symbol point to the name in the auxent, since |
the text ".file" is redundant. */ |
if ((internal_ptr + 1)->u.auxent.x_file.x_n.x_zeroes == 0) |
{ |
/* The filename is a long one, point into the string table. */ |
if (string_table == NULL) |
{ |
string_table = _bfd_coff_read_string_table (abfd); |
if (string_table == NULL) |
return NULL; |
} |
internal_ptr->u.syment._n._n_n._n_offset = |
((bfd_hostptr_t) |
(string_table |
+ (internal_ptr + 1)->u.auxent.x_file.x_n.x_offset)); |
} |
else |
{ |
/* Ordinary short filename, put into memory anyway. The |
Microsoft PE tools sometimes store a filename in |
multiple AUX entries. */ |
if (internal_ptr->u.syment.n_numaux > 1 |
&& coff_data (abfd)->pe) |
internal_ptr->u.syment._n._n_n._n_offset = |
((bfd_hostptr_t) |
copy_name (abfd, |
(internal_ptr + 1)->u.auxent.x_file.x_fname, |
internal_ptr->u.syment.n_numaux * symesz)); |
else |
internal_ptr->u.syment._n._n_n._n_offset = |
((bfd_hostptr_t) |
copy_name (abfd, |
(internal_ptr + 1)->u.auxent.x_file.x_fname, |
(size_t) bfd_coff_filnmlen (abfd))); |
} |
} |
else |
{ |
if (internal_ptr->u.syment._n._n_n._n_zeroes != 0) |
{ |
/* This is a "short" name. Make it long. */ |
size_t i; |
char *newstring; |
/* Find the length of this string without walking into memory |
that isn't ours. */ |
for (i = 0; i < 8; ++i) |
if (internal_ptr->u.syment._n._n_name[i] == '\0') |
break; |
newstring = (char *) bfd_zalloc (abfd, (bfd_size_type) (i + 1)); |
if (newstring == NULL) |
return NULL; |
strncpy (newstring, internal_ptr->u.syment._n._n_name, i); |
internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) newstring; |
internal_ptr->u.syment._n._n_n._n_zeroes = 0; |
} |
else if (internal_ptr->u.syment._n._n_n._n_offset == 0) |
internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) ""; |
else if (!bfd_coff_symname_in_debug (abfd, &internal_ptr->u.syment)) |
{ |
/* Long name already. Point symbol at the string in the |
table. */ |
if (string_table == NULL) |
{ |
string_table = _bfd_coff_read_string_table (abfd); |
if (string_table == NULL) |
return NULL; |
} |
internal_ptr->u.syment._n._n_n._n_offset = |
((bfd_hostptr_t) |
(string_table |
+ internal_ptr->u.syment._n._n_n._n_offset)); |
} |
else |
{ |
/* Long name in debug section. Very similar. */ |
if (debug_section == NULL) |
debug_section = build_debug_section (abfd); |
internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) |
(debug_section + internal_ptr->u.syment._n._n_n._n_offset); |
} |
} |
internal_ptr += internal_ptr->u.syment.n_numaux; |
} |
obj_raw_syments (abfd) = internal; |
BFD_ASSERT (obj_raw_syment_count (abfd) |
== (unsigned int) (internal_ptr - internal)); |
return internal; |
} |
long |
coff_get_reloc_upper_bound (bfd *abfd, sec_ptr asect) |
{ |
if (bfd_get_format (abfd) != bfd_object) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return -1; |
} |
return (asect->reloc_count + 1) * sizeof (arelent *); |
} |
asymbol * |
coff_make_empty_symbol (bfd *abfd) |
{ |
bfd_size_type amt = sizeof (coff_symbol_type); |
coff_symbol_type *new_symbol = (coff_symbol_type *) bfd_zalloc (abfd, amt); |
if (new_symbol == NULL) |
return NULL; |
new_symbol->symbol.section = 0; |
new_symbol->native = 0; |
new_symbol->lineno = NULL; |
new_symbol->done_lineno = FALSE; |
new_symbol->symbol.the_bfd = abfd; |
return & new_symbol->symbol; |
} |
/* Make a debugging symbol. */ |
asymbol * |
coff_bfd_make_debug_symbol (bfd *abfd, |
void * ptr ATTRIBUTE_UNUSED, |
unsigned long sz ATTRIBUTE_UNUSED) |
{ |
bfd_size_type amt = sizeof (coff_symbol_type); |
coff_symbol_type *new_symbol = (coff_symbol_type *) bfd_alloc (abfd, amt); |
if (new_symbol == NULL) |
return NULL; |
/* @@ The 10 is a guess at a plausible maximum number of aux entries |
(but shouldn't be a constant). */ |
amt = sizeof (combined_entry_type) * 10; |
new_symbol->native = (combined_entry_type *) bfd_zalloc (abfd, amt); |
if (!new_symbol->native) |
return NULL; |
new_symbol->symbol.section = bfd_abs_section_ptr; |
new_symbol->symbol.flags = BSF_DEBUGGING; |
new_symbol->lineno = NULL; |
new_symbol->done_lineno = FALSE; |
new_symbol->symbol.the_bfd = abfd; |
return & new_symbol->symbol; |
} |
void |
coff_get_symbol_info (bfd *abfd, asymbol *symbol, symbol_info *ret) |
{ |
bfd_symbol_info (symbol, ret); |
if (coffsymbol (symbol)->native != NULL |
&& coffsymbol (symbol)->native->fix_value) |
ret->value = coffsymbol (symbol)->native->u.syment.n_value - |
(bfd_hostptr_t) obj_raw_syments (abfd); |
} |
/* Return the COFF syment for a symbol. */ |
bfd_boolean |
bfd_coff_get_syment (bfd *abfd, |
asymbol *symbol, |
struct internal_syment *psyment) |
{ |
coff_symbol_type *csym; |
csym = coff_symbol_from (abfd, symbol); |
if (csym == NULL || csym->native == NULL) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
*psyment = csym->native->u.syment; |
if (csym->native->fix_value) |
psyment->n_value = psyment->n_value - |
(bfd_hostptr_t) obj_raw_syments (abfd); |
/* FIXME: We should handle fix_line here. */ |
return TRUE; |
} |
/* Return the COFF auxent for a symbol. */ |
bfd_boolean |
bfd_coff_get_auxent (bfd *abfd, |
asymbol *symbol, |
int indx, |
union internal_auxent *pauxent) |
{ |
coff_symbol_type *csym; |
combined_entry_type *ent; |
csym = coff_symbol_from (abfd, symbol); |
if (csym == NULL |
|| csym->native == NULL |
|| indx >= csym->native->u.syment.n_numaux) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
ent = csym->native + indx + 1; |
*pauxent = ent->u.auxent; |
if (ent->fix_tag) |
pauxent->x_sym.x_tagndx.l = |
((combined_entry_type *) pauxent->x_sym.x_tagndx.p |
- obj_raw_syments (abfd)); |
if (ent->fix_end) |
pauxent->x_sym.x_fcnary.x_fcn.x_endndx.l = |
((combined_entry_type *) pauxent->x_sym.x_fcnary.x_fcn.x_endndx.p |
- obj_raw_syments (abfd)); |
if (ent->fix_scnlen) |
pauxent->x_csect.x_scnlen.l = |
((combined_entry_type *) pauxent->x_csect.x_scnlen.p |
- obj_raw_syments (abfd)); |
return TRUE; |
} |
/* Print out information about COFF symbol. */ |
void |
coff_print_symbol (bfd *abfd, |
void * filep, |
asymbol *symbol, |
bfd_print_symbol_type how) |
{ |
FILE * file = (FILE *) filep; |
switch (how) |
{ |
case bfd_print_symbol_name: |
fprintf (file, "%s", symbol->name); |
break; |
case bfd_print_symbol_more: |
fprintf (file, "coff %s %s", |
coffsymbol (symbol)->native ? "n" : "g", |
coffsymbol (symbol)->lineno ? "l" : " "); |
break; |
case bfd_print_symbol_all: |
if (coffsymbol (symbol)->native) |
{ |
bfd_vma val; |
unsigned int aux; |
combined_entry_type *combined = coffsymbol (symbol)->native; |
combined_entry_type *root = obj_raw_syments (abfd); |
struct lineno_cache_entry *l = coffsymbol (symbol)->lineno; |
fprintf (file, "[%3ld]", (long) (combined - root)); |
if (! combined->fix_value) |
val = (bfd_vma) combined->u.syment.n_value; |
else |
val = combined->u.syment.n_value - (bfd_hostptr_t) root; |
fprintf (file, "(sec %2d)(fl 0x%02x)(ty %3x)(scl %3d) (nx %d) 0x", |
combined->u.syment.n_scnum, |
combined->u.syment.n_flags, |
combined->u.syment.n_type, |
combined->u.syment.n_sclass, |
combined->u.syment.n_numaux); |
bfd_fprintf_vma (abfd, file, val); |
fprintf (file, " %s", symbol->name); |
for (aux = 0; aux < combined->u.syment.n_numaux; aux++) |
{ |
combined_entry_type *auxp = combined + aux + 1; |
long tagndx; |
if (auxp->fix_tag) |
tagndx = auxp->u.auxent.x_sym.x_tagndx.p - root; |
else |
tagndx = auxp->u.auxent.x_sym.x_tagndx.l; |
fprintf (file, "\n"); |
if (bfd_coff_print_aux (abfd, file, root, combined, auxp, aux)) |
continue; |
switch (combined->u.syment.n_sclass) |
{ |
case C_FILE: |
fprintf (file, "File "); |
break; |
case C_STAT: |
if (combined->u.syment.n_type == T_NULL) |
/* Probably a section symbol ? */ |
{ |
fprintf (file, "AUX scnlen 0x%lx nreloc %d nlnno %d", |
(unsigned long) auxp->u.auxent.x_scn.x_scnlen, |
auxp->u.auxent.x_scn.x_nreloc, |
auxp->u.auxent.x_scn.x_nlinno); |
if (auxp->u.auxent.x_scn.x_checksum != 0 |
|| auxp->u.auxent.x_scn.x_associated != 0 |
|| auxp->u.auxent.x_scn.x_comdat != 0) |
fprintf (file, " checksum 0x%lx assoc %d comdat %d", |
auxp->u.auxent.x_scn.x_checksum, |
auxp->u.auxent.x_scn.x_associated, |
auxp->u.auxent.x_scn.x_comdat); |
break; |
} |
/* Otherwise fall through. */ |
case C_EXT: |
case C_AIX_WEAKEXT: |
if (ISFCN (combined->u.syment.n_type)) |
{ |
long next, llnos; |
if (auxp->fix_end) |
next = (auxp->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p |
- root); |
else |
next = auxp->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l; |
llnos = auxp->u.auxent.x_sym.x_fcnary.x_fcn.x_lnnoptr; |
fprintf (file, |
"AUX tagndx %ld ttlsiz 0x%lx lnnos %ld next %ld", |
tagndx, |
(unsigned long) auxp->u.auxent.x_sym.x_misc.x_fsize, |
llnos, next); |
break; |
} |
/* Otherwise fall through. */ |
default: |
fprintf (file, "AUX lnno %d size 0x%x tagndx %ld", |
auxp->u.auxent.x_sym.x_misc.x_lnsz.x_lnno, |
auxp->u.auxent.x_sym.x_misc.x_lnsz.x_size, |
tagndx); |
if (auxp->fix_end) |
fprintf (file, " endndx %ld", |
((long) |
(auxp->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p |
- root))); |
break; |
} |
} |
if (l) |
{ |
fprintf (file, "\n%s :", l->u.sym->name); |
l++; |
while (l->line_number) |
{ |
fprintf (file, "\n%4d : ", l->line_number); |
bfd_fprintf_vma (abfd, file, l->u.offset + symbol->section->vma); |
l++; |
} |
} |
} |
else |
{ |
bfd_print_symbol_vandf (abfd, (void *) file, symbol); |
fprintf (file, " %-5s %s %s %s", |
symbol->section->name, |
coffsymbol (symbol)->native ? "n" : "g", |
coffsymbol (symbol)->lineno ? "l" : " ", |
symbol->name); |
} |
} |
} |
/* Return whether a symbol name implies a local symbol. In COFF, |
local symbols generally start with ``.L''. Most targets use this |
function for the is_local_label_name entry point, but some may |
override it. */ |
bfd_boolean |
_bfd_coff_is_local_label_name (bfd *abfd ATTRIBUTE_UNUSED, |
const char *name) |
{ |
return name[0] == '.' && name[1] == 'L'; |
} |
/* Provided a BFD, a section and an offset (in bytes, not octets) into the |
section, calculate and return the name of the source file and the line |
nearest to the wanted location. */ |
bfd_boolean |
coff_find_nearest_line_with_names (bfd *abfd, |
const struct dwarf_debug_section *debug_sections, |
asection *section, |
asymbol **symbols, |
bfd_vma offset, |
const char **filename_ptr, |
const char **functionname_ptr, |
unsigned int *line_ptr) |
{ |
bfd_boolean found; |
unsigned int i; |
unsigned int line_base; |
coff_data_type *cof = coff_data (abfd); |
/* Run through the raw syments if available. */ |
combined_entry_type *p; |
combined_entry_type *pend; |
alent *l; |
struct coff_section_tdata *sec_data; |
bfd_size_type amt; |
/* Before looking through the symbol table, try to use a .stab |
section to find the information. */ |
if (! _bfd_stab_section_find_nearest_line (abfd, symbols, section, offset, |
&found, filename_ptr, |
functionname_ptr, line_ptr, |
&coff_data(abfd)->line_info)) |
return FALSE; |
if (found) |
return TRUE; |
/* Also try examining DWARF2 debugging information. */ |
if (_bfd_dwarf2_find_nearest_line (abfd, debug_sections, |
section, symbols, offset, |
filename_ptr, functionname_ptr, |
line_ptr, NULL, 0, |
&coff_data(abfd)->dwarf2_find_line_info)) |
return TRUE; |
*filename_ptr = 0; |
*functionname_ptr = 0; |
*line_ptr = 0; |
/* Don't try and find line numbers in a non coff file. */ |
if (!bfd_family_coff (abfd)) |
return FALSE; |
if (cof == NULL) |
return FALSE; |
/* Find the first C_FILE symbol. */ |
p = cof->raw_syments; |
if (!p) |
return FALSE; |
pend = p + cof->raw_syment_count; |
while (p < pend) |
{ |
if (p->u.syment.n_sclass == C_FILE) |
break; |
p += 1 + p->u.syment.n_numaux; |
} |
if (p < pend) |
{ |
bfd_vma sec_vma; |
bfd_vma maxdiff; |
/* Look through the C_FILE symbols to find the best one. */ |
sec_vma = bfd_get_section_vma (abfd, section); |
*filename_ptr = (char *) p->u.syment._n._n_n._n_offset; |
maxdiff = (bfd_vma) 0 - (bfd_vma) 1; |
while (1) |
{ |
bfd_vma file_addr; |
combined_entry_type *p2; |
for (p2 = p + 1 + p->u.syment.n_numaux; |
p2 < pend; |
p2 += 1 + p2->u.syment.n_numaux) |
{ |
if (p2->u.syment.n_scnum > 0 |
&& (section |
== coff_section_from_bfd_index (abfd, |
p2->u.syment.n_scnum))) |
break; |
if (p2->u.syment.n_sclass == C_FILE) |
{ |
p2 = pend; |
break; |
} |
} |
file_addr = (bfd_vma) p2->u.syment.n_value; |
/* PR 11512: Include the section address of the function name symbol. */ |
if (p2->u.syment.n_scnum > 0) |
file_addr += coff_section_from_bfd_index (abfd, |
p2->u.syment.n_scnum)->vma; |
/* We use <= MAXDIFF here so that if we get a zero length |
file, we actually use the next file entry. */ |
if (p2 < pend |
&& offset + sec_vma >= file_addr |
&& offset + sec_vma - file_addr <= maxdiff) |
{ |
*filename_ptr = (char *) p->u.syment._n._n_n._n_offset; |
maxdiff = offset + sec_vma - p2->u.syment.n_value; |
} |
/* Avoid endless loops on erroneous files by ensuring that |
we always move forward in the file. */ |
if (p >= cof->raw_syments + p->u.syment.n_value) |
break; |
p = cof->raw_syments + p->u.syment.n_value; |
if (p > pend || p->u.syment.n_sclass != C_FILE) |
break; |
} |
} |
/* Now wander though the raw linenumbers of the section. */ |
/* If we have been called on this section before, and the offset we |
want is further down then we can prime the lookup loop. */ |
sec_data = coff_section_data (abfd, section); |
if (sec_data != NULL |
&& sec_data->i > 0 |
&& offset >= sec_data->offset) |
{ |
i = sec_data->i; |
*functionname_ptr = sec_data->function; |
line_base = sec_data->line_base; |
} |
else |
{ |
i = 0; |
line_base = 0; |
} |
if (section->lineno != NULL) |
{ |
bfd_vma last_value = 0; |
l = §ion->lineno[i]; |
for (; i < section->lineno_count; i++) |
{ |
if (l->line_number == 0) |
{ |
/* Get the symbol this line number points at. */ |
coff_symbol_type *coff = (coff_symbol_type *) (l->u.sym); |
if (coff->symbol.value > offset) |
break; |
*functionname_ptr = coff->symbol.name; |
last_value = coff->symbol.value; |
if (coff->native) |
{ |
combined_entry_type *s = coff->native; |
s = s + 1 + s->u.syment.n_numaux; |
/* In XCOFF a debugging symbol can follow the |
function symbol. */ |
if (s->u.syment.n_scnum == N_DEBUG) |
s = s + 1 + s->u.syment.n_numaux; |
/* S should now point to the .bf of the function. */ |
if (s->u.syment.n_numaux) |
{ |
/* The linenumber is stored in the auxent. */ |
union internal_auxent *a = &((s + 1)->u.auxent); |
line_base = a->x_sym.x_misc.x_lnsz.x_lnno; |
*line_ptr = line_base; |
} |
} |
} |
else |
{ |
if (l->u.offset > offset) |
break; |
*line_ptr = l->line_number + line_base - 1; |
} |
l++; |
} |
/* If we fell off the end of the loop, then assume that this |
symbol has no line number info. Otherwise, symbols with no |
line number info get reported with the line number of the |
last line of the last symbol which does have line number |
info. We use 0x100 as a slop to account for cases where the |
last line has executable code. */ |
if (i >= section->lineno_count |
&& last_value != 0 |
&& offset - last_value > 0x100) |
{ |
*functionname_ptr = NULL; |
*line_ptr = 0; |
} |
} |
/* Cache the results for the next call. */ |
if (sec_data == NULL && section->owner == abfd) |
{ |
amt = sizeof (struct coff_section_tdata); |
section->used_by_bfd = bfd_zalloc (abfd, amt); |
sec_data = (struct coff_section_tdata *) section->used_by_bfd; |
} |
if (sec_data != NULL) |
{ |
sec_data->offset = offset; |
sec_data->i = i - 1; |
sec_data->function = *functionname_ptr; |
sec_data->line_base = line_base; |
} |
return TRUE; |
} |
bfd_boolean |
coff_find_nearest_line (bfd *abfd, |
asection *section, |
asymbol **symbols, |
bfd_vma offset, |
const char **filename_ptr, |
const char **functionname_ptr, |
unsigned int *line_ptr) |
{ |
return coff_find_nearest_line_with_names (abfd, dwarf_debug_sections, |
section, symbols, offset, |
filename_ptr, functionname_ptr, |
line_ptr); |
} |
bfd_boolean |
coff_find_nearest_line_discriminator (bfd *abfd, |
asection *section, |
asymbol **symbols, |
bfd_vma offset, |
const char **filename_ptr, |
const char **functionname_ptr, |
unsigned int *line_ptr, |
unsigned int *discriminator) |
{ |
*discriminator = 0; |
return coff_find_nearest_line_with_names (abfd, dwarf_debug_sections, |
section, symbols, offset, |
filename_ptr, functionname_ptr, |
line_ptr); |
} |
bfd_boolean |
coff_find_inliner_info (bfd *abfd, |
const char **filename_ptr, |
const char **functionname_ptr, |
unsigned int *line_ptr) |
{ |
bfd_boolean found; |
found = _bfd_dwarf2_find_inliner_info (abfd, filename_ptr, |
functionname_ptr, line_ptr, |
&coff_data(abfd)->dwarf2_find_line_info); |
return (found); |
} |
int |
coff_sizeof_headers (bfd *abfd, struct bfd_link_info *info) |
{ |
size_t size; |
if (!info->relocatable) |
size = bfd_coff_filhsz (abfd) + bfd_coff_aoutsz (abfd); |
else |
size = bfd_coff_filhsz (abfd); |
size += abfd->section_count * bfd_coff_scnhsz (abfd); |
return size; |
} |
/* Change the class of a coff symbol held by BFD. */ |
bfd_boolean |
bfd_coff_set_symbol_class (bfd * abfd, |
asymbol * symbol, |
unsigned int symbol_class) |
{ |
coff_symbol_type * csym; |
csym = coff_symbol_from (abfd, symbol); |
if (csym == NULL) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
else if (csym->native == NULL) |
{ |
/* This is an alien symbol which no native coff backend data. |
We cheat here by creating a fake native entry for it and |
then filling in the class. This code is based on that in |
coff_write_alien_symbol(). */ |
combined_entry_type * native; |
bfd_size_type amt = sizeof (* native); |
native = (combined_entry_type *) bfd_zalloc (abfd, amt); |
if (native == NULL) |
return FALSE; |
native->u.syment.n_type = T_NULL; |
native->u.syment.n_sclass = symbol_class; |
if (bfd_is_und_section (symbol->section)) |
{ |
native->u.syment.n_scnum = N_UNDEF; |
native->u.syment.n_value = symbol->value; |
} |
else if (bfd_is_com_section (symbol->section)) |
{ |
native->u.syment.n_scnum = N_UNDEF; |
native->u.syment.n_value = symbol->value; |
} |
else |
{ |
native->u.syment.n_scnum = |
symbol->section->output_section->target_index; |
native->u.syment.n_value = (symbol->value |
+ symbol->section->output_offset); |
if (! obj_pe (abfd)) |
native->u.syment.n_value += symbol->section->output_section->vma; |
/* Copy the any flags from the file header into the symbol. |
FIXME: Why? */ |
native->u.syment.n_flags = bfd_asymbol_bfd (& csym->symbol)->flags; |
} |
csym->native = native; |
} |
else |
csym->native->u.syment.n_sclass = symbol_class; |
return TRUE; |
} |
struct coff_comdat_info * |
bfd_coff_get_comdat_section (bfd *abfd, struct bfd_section *sec) |
{ |
if (bfd_get_flavour (abfd) == bfd_target_coff_flavour |
&& coff_section_data (abfd, sec) != NULL) |
return coff_section_data (abfd, sec)->comdat; |
else |
return NULL; |
} |
bfd_boolean |
_bfd_coff_section_already_linked (bfd *abfd, |
asection *sec, |
struct bfd_link_info *info) |
{ |
flagword flags; |
const char *name, *key; |
struct bfd_section_already_linked *l; |
struct bfd_section_already_linked_hash_entry *already_linked_list; |
struct coff_comdat_info *s_comdat; |
flags = sec->flags; |
if ((flags & SEC_LINK_ONCE) == 0) |
return FALSE; |
/* The COFF backend linker doesn't support group sections. */ |
if ((flags & SEC_GROUP) != 0) |
return FALSE; |
name = bfd_get_section_name (abfd, sec); |
s_comdat = bfd_coff_get_comdat_section (abfd, sec); |
if (s_comdat != NULL) |
key = s_comdat->name; |
else |
{ |
if (CONST_STRNEQ (name, ".gnu.linkonce.") |
&& (key = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL) |
key++; |
else |
/* FIXME: gcc as of 2011-09 emits sections like .text$<key>, |
.xdata$<key> and .pdata$<key> only the first of which has a |
comdat key. Should these all match the LTO IR key? */ |
key = name; |
} |
already_linked_list = bfd_section_already_linked_table_lookup (key); |
for (l = already_linked_list->entry; l != NULL; l = l->next) |
{ |
struct coff_comdat_info *l_comdat; |
l_comdat = bfd_coff_get_comdat_section (l->sec->owner, l->sec); |
/* The section names must match, and both sections must be |
comdat and have the same comdat name, or both sections must |
be non-comdat. LTO IR plugin sections are an exception. They |
are always named .gnu.linkonce.t.<key> (<key> is some string) |
and match any comdat section with comdat name of <key>, and |
any linkonce section with the same suffix, ie. |
.gnu.linkonce.*.<key>. */ |
if (((s_comdat != NULL) == (l_comdat != NULL) |
&& strcmp (name, l->sec->name) == 0) |
|| (l->sec->owner->flags & BFD_PLUGIN) != 0) |
{ |
/* The section has already been linked. See if we should |
issue a warning. */ |
return _bfd_handle_already_linked (sec, l, info); |
} |
} |
/* This is the first section with this name. Record it. */ |
if (!bfd_section_already_linked_table_insert (already_linked_list, sec)) |
info->callbacks->einfo (_("%F%P: already_linked_table: %E\n")); |
return FALSE; |
} |
/contrib/toolchain/binutils/bfd/cofflink.c |
---|
0,0 → 1,3196 |
/* COFF specific linker code. |
Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, |
2004, 2005, 2006, 2007, 2008, 2009, 2011 Free Software Foundation, Inc. |
Written by Ian Lance Taylor, Cygnus Support. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* This file contains the COFF backend linker code. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "bfdlink.h" |
#include "libbfd.h" |
#include "coff/internal.h" |
#include "libcoff.h" |
#include "safe-ctype.h" |
static bfd_boolean coff_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info); |
static bfd_boolean coff_link_check_archive_element (bfd *abfd, struct bfd_link_info *info, bfd_boolean *pneeded); |
static bfd_boolean coff_link_add_symbols (bfd *abfd, struct bfd_link_info *info); |
/* Return TRUE if SYM is a weak, external symbol. */ |
#define IS_WEAK_EXTERNAL(abfd, sym) \ |
((sym).n_sclass == C_WEAKEXT \ |
|| (obj_pe (abfd) && (sym).n_sclass == C_NT_WEAK)) |
/* Return TRUE if SYM is an external symbol. */ |
#define IS_EXTERNAL(abfd, sym) \ |
((sym).n_sclass == C_EXT || IS_WEAK_EXTERNAL (abfd, sym)) |
/* Define macros so that the ISFCN, et. al., macros work correctly. |
These macros are defined in include/coff/internal.h in terms of |
N_TMASK, etc. These definitions require a user to define local |
variables with the appropriate names, and with values from the |
coff_data (abfd) structure. */ |
#define N_TMASK n_tmask |
#define N_BTSHFT n_btshft |
#define N_BTMASK n_btmask |
/* Create an entry in a COFF linker hash table. */ |
struct bfd_hash_entry * |
_bfd_coff_link_hash_newfunc (struct bfd_hash_entry *entry, |
struct bfd_hash_table *table, |
const char *string) |
{ |
struct coff_link_hash_entry *ret = (struct coff_link_hash_entry *) entry; |
/* Allocate the structure if it has not already been allocated by a |
subclass. */ |
if (ret == (struct coff_link_hash_entry *) NULL) |
ret = ((struct coff_link_hash_entry *) |
bfd_hash_allocate (table, sizeof (struct coff_link_hash_entry))); |
if (ret == (struct coff_link_hash_entry *) NULL) |
return (struct bfd_hash_entry *) ret; |
/* Call the allocation method of the superclass. */ |
ret = ((struct coff_link_hash_entry *) |
_bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret, |
table, string)); |
if (ret != (struct coff_link_hash_entry *) NULL) |
{ |
/* Set local fields. */ |
ret->indx = -1; |
ret->type = T_NULL; |
ret->symbol_class = C_NULL; |
ret->numaux = 0; |
ret->auxbfd = NULL; |
ret->aux = NULL; |
} |
return (struct bfd_hash_entry *) ret; |
} |
/* Initialize a COFF linker hash table. */ |
bfd_boolean |
_bfd_coff_link_hash_table_init (struct coff_link_hash_table *table, |
bfd *abfd, |
struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *, |
struct bfd_hash_table *, |
const char *), |
unsigned int entsize) |
{ |
memset (&table->stab_info, 0, sizeof (table->stab_info)); |
return _bfd_link_hash_table_init (&table->root, abfd, newfunc, entsize); |
} |
/* Create a COFF linker hash table. */ |
struct bfd_link_hash_table * |
_bfd_coff_link_hash_table_create (bfd *abfd) |
{ |
struct coff_link_hash_table *ret; |
bfd_size_type amt = sizeof (struct coff_link_hash_table); |
ret = (struct coff_link_hash_table *) bfd_malloc (amt); |
if (ret == NULL) |
return NULL; |
if (! _bfd_coff_link_hash_table_init (ret, abfd, |
_bfd_coff_link_hash_newfunc, |
sizeof (struct coff_link_hash_entry))) |
{ |
free (ret); |
return (struct bfd_link_hash_table *) NULL; |
} |
return &ret->root; |
} |
/* Create an entry in a COFF debug merge hash table. */ |
struct bfd_hash_entry * |
_bfd_coff_debug_merge_hash_newfunc (struct bfd_hash_entry *entry, |
struct bfd_hash_table *table, |
const char *string) |
{ |
struct coff_debug_merge_hash_entry *ret = |
(struct coff_debug_merge_hash_entry *) entry; |
/* Allocate the structure if it has not already been allocated by a |
subclass. */ |
if (ret == (struct coff_debug_merge_hash_entry *) NULL) |
ret = ((struct coff_debug_merge_hash_entry *) |
bfd_hash_allocate (table, |
sizeof (struct coff_debug_merge_hash_entry))); |
if (ret == (struct coff_debug_merge_hash_entry *) NULL) |
return (struct bfd_hash_entry *) ret; |
/* Call the allocation method of the superclass. */ |
ret = ((struct coff_debug_merge_hash_entry *) |
bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); |
if (ret != (struct coff_debug_merge_hash_entry *) NULL) |
{ |
/* Set local fields. */ |
ret->types = NULL; |
} |
return (struct bfd_hash_entry *) ret; |
} |
/* Given a COFF BFD, add symbols to the global hash table as |
appropriate. */ |
bfd_boolean |
_bfd_coff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) |
{ |
switch (bfd_get_format (abfd)) |
{ |
case bfd_object: |
return coff_link_add_object_symbols (abfd, info); |
case bfd_archive: |
return _bfd_generic_link_add_archive_symbols |
(abfd, info, coff_link_check_archive_element); |
default: |
bfd_set_error (bfd_error_wrong_format); |
return FALSE; |
} |
} |
/* Add symbols from a COFF object file. */ |
static bfd_boolean |
coff_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) |
{ |
if (! _bfd_coff_get_external_symbols (abfd)) |
return FALSE; |
if (! coff_link_add_symbols (abfd, info)) |
return FALSE; |
if (! info->keep_memory |
&& ! _bfd_coff_free_symbols (abfd)) |
return FALSE; |
return TRUE; |
} |
/* Look through the symbols to see if this object file should be |
included in the link. */ |
static bfd_boolean |
coff_link_check_ar_symbols (bfd *abfd, |
struct bfd_link_info *info, |
bfd_boolean *pneeded, |
bfd **subsbfd) |
{ |
bfd_size_type symesz; |
bfd_byte *esym; |
bfd_byte *esym_end; |
*pneeded = FALSE; |
symesz = bfd_coff_symesz (abfd); |
esym = (bfd_byte *) obj_coff_external_syms (abfd); |
esym_end = esym + obj_raw_syment_count (abfd) * symesz; |
while (esym < esym_end) |
{ |
struct internal_syment sym; |
enum coff_symbol_classification classification; |
bfd_coff_swap_sym_in (abfd, esym, &sym); |
classification = bfd_coff_classify_symbol (abfd, &sym); |
if (classification == COFF_SYMBOL_GLOBAL |
|| classification == COFF_SYMBOL_COMMON) |
{ |
const char *name; |
char buf[SYMNMLEN + 1]; |
struct bfd_link_hash_entry *h; |
/* This symbol is externally visible, and is defined by this |
object file. */ |
name = _bfd_coff_internal_syment_name (abfd, &sym, buf); |
if (name == NULL) |
return FALSE; |
h = bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, TRUE); |
/* Auto import. */ |
if (!h |
&& info->pei386_auto_import |
&& CONST_STRNEQ (name, "__imp_")) |
h = bfd_link_hash_lookup (info->hash, name + 6, FALSE, FALSE, TRUE); |
/* We are only interested in symbols that are currently |
undefined. If a symbol is currently known to be common, |
COFF linkers do not bring in an object file which defines |
it. */ |
if (h != (struct bfd_link_hash_entry *) NULL |
&& h->type == bfd_link_hash_undefined) |
{ |
if (!(*info->callbacks |
->add_archive_element) (info, abfd, name, subsbfd)) |
return FALSE; |
*pneeded = TRUE; |
return TRUE; |
} |
} |
esym += (sym.n_numaux + 1) * symesz; |
} |
/* We do not need this object file. */ |
return TRUE; |
} |
/* Check a single archive element to see if we need to include it in |
the link. *PNEEDED is set according to whether this element is |
needed in the link or not. This is called via |
_bfd_generic_link_add_archive_symbols. */ |
static bfd_boolean |
coff_link_check_archive_element (bfd *abfd, |
struct bfd_link_info *info, |
bfd_boolean *pneeded) |
{ |
bfd *oldbfd; |
bfd_boolean needed; |
if (!_bfd_coff_get_external_symbols (abfd)) |
return FALSE; |
oldbfd = abfd; |
if (!coff_link_check_ar_symbols (abfd, info, pneeded, &abfd)) |
return FALSE; |
needed = *pneeded; |
if (needed) |
{ |
/* Potentially, the add_archive_element hook may have set a |
substitute BFD for us. */ |
if (abfd != oldbfd) |
{ |
if (!info->keep_memory |
&& !_bfd_coff_free_symbols (oldbfd)) |
return FALSE; |
if (!_bfd_coff_get_external_symbols (abfd)) |
return FALSE; |
} |
if (!coff_link_add_symbols (abfd, info)) |
return FALSE; |
} |
if (!info->keep_memory || !needed) |
{ |
if (!_bfd_coff_free_symbols (abfd)) |
return FALSE; |
} |
return TRUE; |
} |
/* Add all the symbols from an object file to the hash table. */ |
static bfd_boolean |
coff_link_add_symbols (bfd *abfd, |
struct bfd_link_info *info) |
{ |
unsigned int n_tmask = coff_data (abfd)->local_n_tmask; |
unsigned int n_btshft = coff_data (abfd)->local_n_btshft; |
unsigned int n_btmask = coff_data (abfd)->local_n_btmask; |
bfd_boolean keep_syms; |
bfd_boolean default_copy; |
bfd_size_type symcount; |
struct coff_link_hash_entry **sym_hash; |
bfd_size_type symesz; |
bfd_byte *esym; |
bfd_byte *esym_end; |
bfd_size_type amt; |
symcount = obj_raw_syment_count (abfd); |
if (symcount == 0) |
return TRUE; /* Nothing to do. */ |
/* Keep the symbols during this function, in case the linker needs |
to read the generic symbols in order to report an error message. */ |
keep_syms = obj_coff_keep_syms (abfd); |
obj_coff_keep_syms (abfd) = TRUE; |
if (info->keep_memory) |
default_copy = FALSE; |
else |
default_copy = TRUE; |
/* We keep a list of the linker hash table entries that correspond |
to particular symbols. */ |
amt = symcount * sizeof (struct coff_link_hash_entry *); |
sym_hash = (struct coff_link_hash_entry **) bfd_zalloc (abfd, amt); |
if (sym_hash == NULL) |
goto error_return; |
obj_coff_sym_hashes (abfd) = sym_hash; |
symesz = bfd_coff_symesz (abfd); |
BFD_ASSERT (symesz == bfd_coff_auxesz (abfd)); |
esym = (bfd_byte *) obj_coff_external_syms (abfd); |
esym_end = esym + symcount * symesz; |
while (esym < esym_end) |
{ |
struct internal_syment sym; |
enum coff_symbol_classification classification; |
bfd_boolean copy; |
bfd_coff_swap_sym_in (abfd, esym, &sym); |
classification = bfd_coff_classify_symbol (abfd, &sym); |
if (classification != COFF_SYMBOL_LOCAL) |
{ |
const char *name; |
char buf[SYMNMLEN + 1]; |
flagword flags; |
asection *section; |
bfd_vma value; |
bfd_boolean addit; |
/* This symbol is externally visible. */ |
name = _bfd_coff_internal_syment_name (abfd, &sym, buf); |
if (name == NULL) |
goto error_return; |
/* We must copy the name into memory if we got it from the |
syment itself, rather than the string table. */ |
copy = default_copy; |
if (sym._n._n_n._n_zeroes != 0 |
|| sym._n._n_n._n_offset == 0) |
copy = TRUE; |
value = sym.n_value; |
switch (classification) |
{ |
default: |
abort (); |
case COFF_SYMBOL_GLOBAL: |
flags = BSF_EXPORT | BSF_GLOBAL; |
section = coff_section_from_bfd_index (abfd, sym.n_scnum); |
if (! obj_pe (abfd)) |
value -= section->vma; |
break; |
case COFF_SYMBOL_UNDEFINED: |
flags = 0; |
section = bfd_und_section_ptr; |
break; |
case COFF_SYMBOL_COMMON: |
flags = BSF_GLOBAL; |
section = bfd_com_section_ptr; |
break; |
case COFF_SYMBOL_PE_SECTION: |
flags = BSF_SECTION_SYM | BSF_GLOBAL; |
section = coff_section_from_bfd_index (abfd, sym.n_scnum); |
break; |
} |
if (IS_WEAK_EXTERNAL (abfd, sym)) |
flags = BSF_WEAK; |
addit = TRUE; |
/* In the PE format, section symbols actually refer to the |
start of the output section. We handle them specially |
here. */ |
if (obj_pe (abfd) && (flags & BSF_SECTION_SYM) != 0) |
{ |
*sym_hash = coff_link_hash_lookup (coff_hash_table (info), |
name, FALSE, copy, FALSE); |
if (*sym_hash != NULL) |
{ |
if (((*sym_hash)->coff_link_hash_flags |
& COFF_LINK_HASH_PE_SECTION_SYMBOL) == 0 |
&& (*sym_hash)->root.type != bfd_link_hash_undefined |
&& (*sym_hash)->root.type != bfd_link_hash_undefweak) |
(*_bfd_error_handler) |
("Warning: symbol `%s' is both section and non-section", |
name); |
addit = FALSE; |
} |
} |
/* The Microsoft Visual C compiler does string pooling by |
hashing the constants to an internal symbol name, and |
relying on the linker comdat support to discard |
duplicate names. However, if one string is a literal and |
one is a data initializer, one will end up in the .data |
section and one will end up in the .rdata section. The |
Microsoft linker will combine them into the .data |
section, which seems to be wrong since it might cause the |
literal to change. |
As long as there are no external references to the |
symbols, which there shouldn't be, we can treat the .data |
and .rdata instances as separate symbols. The comdat |
code in the linker will do the appropriate merging. Here |
we avoid getting a multiple definition error for one of |
these special symbols. |
FIXME: I don't think this will work in the case where |
there are two object files which use the constants as a |
literal and two object files which use it as a data |
initializer. One or the other of the second object files |
is going to wind up with an inappropriate reference. */ |
if (obj_pe (abfd) |
&& (classification == COFF_SYMBOL_GLOBAL |
|| classification == COFF_SYMBOL_PE_SECTION) |
&& coff_section_data (abfd, section) != NULL |
&& coff_section_data (abfd, section)->comdat != NULL |
&& CONST_STRNEQ (name, "??_") |
&& strcmp (name, coff_section_data (abfd, section)->comdat->name) == 0) |
{ |
if (*sym_hash == NULL) |
*sym_hash = coff_link_hash_lookup (coff_hash_table (info), |
name, FALSE, copy, FALSE); |
if (*sym_hash != NULL |
&& (*sym_hash)->root.type == bfd_link_hash_defined |
&& coff_section_data (abfd, (*sym_hash)->root.u.def.section)->comdat != NULL |
&& strcmp (coff_section_data (abfd, (*sym_hash)->root.u.def.section)->comdat->name, |
coff_section_data (abfd, section)->comdat->name) == 0) |
addit = FALSE; |
} |
if (addit) |
{ |
if (! (bfd_coff_link_add_one_symbol |
(info, abfd, name, flags, section, value, |
(const char *) NULL, copy, FALSE, |
(struct bfd_link_hash_entry **) sym_hash))) |
goto error_return; |
} |
if (obj_pe (abfd) && (flags & BSF_SECTION_SYM) != 0) |
(*sym_hash)->coff_link_hash_flags |= |
COFF_LINK_HASH_PE_SECTION_SYMBOL; |
/* Limit the alignment of a common symbol to the possible |
alignment of a section. There is no point to permitting |
a higher alignment for a common symbol: we can not |
guarantee it, and it may cause us to allocate extra space |
in the common section. */ |
if (section == bfd_com_section_ptr |
&& (*sym_hash)->root.type == bfd_link_hash_common |
&& ((*sym_hash)->root.u.c.p->alignment_power |
> bfd_coff_default_section_alignment_power (abfd))) |
(*sym_hash)->root.u.c.p->alignment_power |
= bfd_coff_default_section_alignment_power (abfd); |
if (bfd_get_flavour (info->output_bfd) == bfd_get_flavour (abfd)) |
{ |
/* If we don't have any symbol information currently in |
the hash table, or if we are looking at a symbol |
definition, then update the symbol class and type in |
the hash table. */ |
if (((*sym_hash)->symbol_class == C_NULL |
&& (*sym_hash)->type == T_NULL) |
|| sym.n_scnum != 0 |
|| (sym.n_value != 0 |
&& (*sym_hash)->root.type != bfd_link_hash_defined |
&& (*sym_hash)->root.type != bfd_link_hash_defweak)) |
{ |
(*sym_hash)->symbol_class = sym.n_sclass; |
if (sym.n_type != T_NULL) |
{ |
/* We want to warn if the type changed, but not |
if it changed from an unspecified type. |
Testing the whole type byte may work, but the |
change from (e.g.) a function of unspecified |
type to function of known type also wants to |
skip the warning. */ |
if ((*sym_hash)->type != T_NULL |
&& (*sym_hash)->type != sym.n_type |
&& !(DTYPE ((*sym_hash)->type) == DTYPE (sym.n_type) |
&& (BTYPE ((*sym_hash)->type) == T_NULL |
|| BTYPE (sym.n_type) == T_NULL))) |
(*_bfd_error_handler) |
(_("Warning: type of symbol `%s' changed from %d to %d in %B"), |
abfd, name, (*sym_hash)->type, sym.n_type); |
/* We don't want to change from a meaningful |
base type to a null one, but if we know |
nothing, take what little we might now know. */ |
if (BTYPE (sym.n_type) != T_NULL |
|| (*sym_hash)->type == T_NULL) |
(*sym_hash)->type = sym.n_type; |
} |
(*sym_hash)->auxbfd = abfd; |
if (sym.n_numaux != 0) |
{ |
union internal_auxent *alloc; |
unsigned int i; |
bfd_byte *eaux; |
union internal_auxent *iaux; |
(*sym_hash)->numaux = sym.n_numaux; |
alloc = ((union internal_auxent *) |
bfd_hash_allocate (&info->hash->table, |
(sym.n_numaux |
* sizeof (*alloc)))); |
if (alloc == NULL) |
goto error_return; |
for (i = 0, eaux = esym + symesz, iaux = alloc; |
i < sym.n_numaux; |
i++, eaux += symesz, iaux++) |
bfd_coff_swap_aux_in (abfd, eaux, sym.n_type, |
sym.n_sclass, (int) i, |
sym.n_numaux, iaux); |
(*sym_hash)->aux = alloc; |
} |
} |
} |
if (classification == COFF_SYMBOL_PE_SECTION |
&& (*sym_hash)->numaux != 0) |
{ |
/* Some PE sections (such as .bss) have a zero size in |
the section header, but a non-zero size in the AUX |
record. Correct that here. |
FIXME: This is not at all the right place to do this. |
For example, it won't help objdump. This needs to be |
done when we swap in the section header. */ |
BFD_ASSERT ((*sym_hash)->numaux == 1); |
if (section->size == 0) |
section->size = (*sym_hash)->aux[0].x_scn.x_scnlen; |
/* FIXME: We could test whether the section sizes |
matches the size in the aux entry, but apparently |
that sometimes fails unexpectedly. */ |
} |
} |
esym += (sym.n_numaux + 1) * symesz; |
sym_hash += sym.n_numaux + 1; |
} |
/* If this is a non-traditional, non-relocatable link, try to |
optimize the handling of any .stab/.stabstr sections. */ |
if (! info->relocatable |
&& ! info->traditional_format |
&& bfd_get_flavour (info->output_bfd) == bfd_get_flavour (abfd) |
&& (info->strip != strip_all && info->strip != strip_debugger)) |
{ |
asection *stabstr; |
stabstr = bfd_get_section_by_name (abfd, ".stabstr"); |
if (stabstr != NULL) |
{ |
bfd_size_type string_offset = 0; |
asection *stab; |
for (stab = abfd->sections; stab; stab = stab->next) |
if (CONST_STRNEQ (stab->name, ".stab") |
&& (!stab->name[5] |
|| (stab->name[5] == '.' && ISDIGIT (stab->name[6])))) |
{ |
struct coff_link_hash_table *table; |
struct coff_section_tdata *secdata |
= coff_section_data (abfd, stab); |
if (secdata == NULL) |
{ |
amt = sizeof (struct coff_section_tdata); |
stab->used_by_bfd = bfd_zalloc (abfd, amt); |
if (stab->used_by_bfd == NULL) |
goto error_return; |
secdata = coff_section_data (abfd, stab); |
} |
table = coff_hash_table (info); |
if (! _bfd_link_section_stabs (abfd, &table->stab_info, |
stab, stabstr, |
&secdata->stab_info, |
&string_offset)) |
goto error_return; |
} |
} |
} |
obj_coff_keep_syms (abfd) = keep_syms; |
return TRUE; |
error_return: |
obj_coff_keep_syms (abfd) = keep_syms; |
return FALSE; |
} |
/* Do the final link step. */ |
bfd_boolean |
_bfd_coff_final_link (bfd *abfd, |
struct bfd_link_info *info) |
{ |
bfd_size_type symesz; |
struct coff_final_link_info flaginfo; |
bfd_boolean debug_merge_allocated; |
bfd_boolean long_section_names; |
asection *o; |
struct bfd_link_order *p; |
bfd_size_type max_sym_count; |
bfd_size_type max_lineno_count; |
bfd_size_type max_reloc_count; |
bfd_size_type max_output_reloc_count; |
bfd_size_type max_contents_size; |
file_ptr rel_filepos; |
unsigned int relsz; |
file_ptr line_filepos; |
unsigned int linesz; |
bfd *sub; |
bfd_byte *external_relocs = NULL; |
char strbuf[STRING_SIZE_SIZE]; |
bfd_size_type amt; |
symesz = bfd_coff_symesz (abfd); |
flaginfo.info = info; |
flaginfo.output_bfd = abfd; |
flaginfo.strtab = NULL; |
flaginfo.section_info = NULL; |
flaginfo.last_file_index = -1; |
flaginfo.last_bf_index = -1; |
flaginfo.internal_syms = NULL; |
flaginfo.sec_ptrs = NULL; |
flaginfo.sym_indices = NULL; |
flaginfo.outsyms = NULL; |
flaginfo.linenos = NULL; |
flaginfo.contents = NULL; |
flaginfo.external_relocs = NULL; |
flaginfo.internal_relocs = NULL; |
flaginfo.global_to_static = FALSE; |
debug_merge_allocated = FALSE; |
coff_data (abfd)->link_info = info; |
flaginfo.strtab = _bfd_stringtab_init (); |
if (flaginfo.strtab == NULL) |
goto error_return; |
if (! coff_debug_merge_hash_table_init (&flaginfo.debug_merge)) |
goto error_return; |
debug_merge_allocated = TRUE; |
/* Compute the file positions for all the sections. */ |
if (! abfd->output_has_begun) |
{ |
if (! bfd_coff_compute_section_file_positions (abfd)) |
goto error_return; |
} |
/* Count the line numbers and relocation entries required for the |
output file. Set the file positions for the relocs. */ |
rel_filepos = obj_relocbase (abfd); |
relsz = bfd_coff_relsz (abfd); |
max_contents_size = 0; |
max_lineno_count = 0; |
max_reloc_count = 0; |
long_section_names = FALSE; |
for (o = abfd->sections; o != NULL; o = o->next) |
{ |
o->reloc_count = 0; |
o->lineno_count = 0; |
for (p = o->map_head.link_order; p != NULL; p = p->next) |
{ |
if (p->type == bfd_indirect_link_order) |
{ |
asection *sec; |
sec = p->u.indirect.section; |
/* Mark all sections which are to be included in the |
link. This will normally be every section. We need |
to do this so that we can identify any sections which |
the linker has decided to not include. */ |
sec->linker_mark = TRUE; |
if (info->strip == strip_none |
|| info->strip == strip_some) |
o->lineno_count += sec->lineno_count; |
if (info->relocatable) |
o->reloc_count += sec->reloc_count; |
if (sec->rawsize > max_contents_size) |
max_contents_size = sec->rawsize; |
if (sec->size > max_contents_size) |
max_contents_size = sec->size; |
if (sec->lineno_count > max_lineno_count) |
max_lineno_count = sec->lineno_count; |
if (sec->reloc_count > max_reloc_count) |
max_reloc_count = sec->reloc_count; |
} |
else if (info->relocatable |
&& (p->type == bfd_section_reloc_link_order |
|| p->type == bfd_symbol_reloc_link_order)) |
++o->reloc_count; |
} |
if (o->reloc_count == 0) |
o->rel_filepos = 0; |
else |
{ |
o->flags |= SEC_RELOC; |
o->rel_filepos = rel_filepos; |
rel_filepos += o->reloc_count * relsz; |
/* In PE COFF, if there are at least 0xffff relocations an |
extra relocation will be written out to encode the count. */ |
if (obj_pe (abfd) && o->reloc_count >= 0xffff) |
rel_filepos += relsz; |
} |
if (bfd_coff_long_section_names (abfd) |
&& strlen (o->name) > SCNNMLEN) |
{ |
/* This section has a long name which must go in the string |
table. This must correspond to the code in |
coff_write_object_contents which puts the string index |
into the s_name field of the section header. That is why |
we pass hash as FALSE. */ |
if (_bfd_stringtab_add (flaginfo.strtab, o->name, FALSE, FALSE) |
== (bfd_size_type) -1) |
goto error_return; |
long_section_names = TRUE; |
} |
} |
/* If doing a relocatable link, allocate space for the pointers we |
need to keep. */ |
if (info->relocatable) |
{ |
unsigned int i; |
/* We use section_count + 1, rather than section_count, because |
the target_index fields are 1 based. */ |
amt = abfd->section_count + 1; |
amt *= sizeof (struct coff_link_section_info); |
flaginfo.section_info = (struct coff_link_section_info *) bfd_malloc (amt); |
if (flaginfo.section_info == NULL) |
goto error_return; |
for (i = 0; i <= abfd->section_count; i++) |
{ |
flaginfo.section_info[i].relocs = NULL; |
flaginfo.section_info[i].rel_hashes = NULL; |
} |
} |
/* We now know the size of the relocs, so we can determine the file |
positions of the line numbers. */ |
line_filepos = rel_filepos; |
linesz = bfd_coff_linesz (abfd); |
max_output_reloc_count = 0; |
for (o = abfd->sections; o != NULL; o = o->next) |
{ |
if (o->lineno_count == 0) |
o->line_filepos = 0; |
else |
{ |
o->line_filepos = line_filepos; |
line_filepos += o->lineno_count * linesz; |
} |
if (o->reloc_count != 0) |
{ |
/* We don't know the indices of global symbols until we have |
written out all the local symbols. For each section in |
the output file, we keep an array of pointers to hash |
table entries. Each entry in the array corresponds to a |
reloc. When we find a reloc against a global symbol, we |
set the corresponding entry in this array so that we can |
fix up the symbol index after we have written out all the |
local symbols. |
Because of this problem, we also keep the relocs in |
memory until the end of the link. This wastes memory, |
but only when doing a relocatable link, which is not the |
common case. */ |
BFD_ASSERT (info->relocatable); |
amt = o->reloc_count; |
amt *= sizeof (struct internal_reloc); |
flaginfo.section_info[o->target_index].relocs = |
(struct internal_reloc *) bfd_malloc (amt); |
amt = o->reloc_count; |
amt *= sizeof (struct coff_link_hash_entry *); |
flaginfo.section_info[o->target_index].rel_hashes = |
(struct coff_link_hash_entry **) bfd_malloc (amt); |
if (flaginfo.section_info[o->target_index].relocs == NULL |
|| flaginfo.section_info[o->target_index].rel_hashes == NULL) |
goto error_return; |
if (o->reloc_count > max_output_reloc_count) |
max_output_reloc_count = o->reloc_count; |
} |
/* Reset the reloc and lineno counts, so that we can use them to |
count the number of entries we have output so far. */ |
o->reloc_count = 0; |
o->lineno_count = 0; |
} |
obj_sym_filepos (abfd) = line_filepos; |
/* Figure out the largest number of symbols in an input BFD. Take |
the opportunity to clear the output_has_begun fields of all the |
input BFD's. */ |
max_sym_count = 0; |
for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) |
{ |
size_t sz; |
sub->output_has_begun = FALSE; |
sz = bfd_family_coff (sub) ? obj_raw_syment_count (sub) : 2; |
if (sz > max_sym_count) |
max_sym_count = sz; |
} |
/* Allocate some buffers used while linking. */ |
amt = max_sym_count * sizeof (struct internal_syment); |
flaginfo.internal_syms = (struct internal_syment *) bfd_malloc (amt); |
amt = max_sym_count * sizeof (asection *); |
flaginfo.sec_ptrs = (asection **) bfd_malloc (amt); |
amt = max_sym_count * sizeof (long); |
flaginfo.sym_indices = (long int *) bfd_malloc (amt); |
flaginfo.outsyms = (bfd_byte *) bfd_malloc ((max_sym_count + 1) * symesz); |
amt = max_lineno_count * bfd_coff_linesz (abfd); |
flaginfo.linenos = (bfd_byte *) bfd_malloc (amt); |
flaginfo.contents = (bfd_byte *) bfd_malloc (max_contents_size); |
amt = max_reloc_count * relsz; |
flaginfo.external_relocs = (bfd_byte *) bfd_malloc (amt); |
if (! info->relocatable) |
{ |
amt = max_reloc_count * sizeof (struct internal_reloc); |
flaginfo.internal_relocs = (struct internal_reloc *) bfd_malloc (amt); |
} |
if ((flaginfo.internal_syms == NULL && max_sym_count > 0) |
|| (flaginfo.sec_ptrs == NULL && max_sym_count > 0) |
|| (flaginfo.sym_indices == NULL && max_sym_count > 0) |
|| flaginfo.outsyms == NULL |
|| (flaginfo.linenos == NULL && max_lineno_count > 0) |
|| (flaginfo.contents == NULL && max_contents_size > 0) |
|| (flaginfo.external_relocs == NULL && max_reloc_count > 0) |
|| (! info->relocatable |
&& flaginfo.internal_relocs == NULL |
&& max_reloc_count > 0)) |
goto error_return; |
/* We now know the position of everything in the file, except that |
we don't know the size of the symbol table and therefore we don't |
know where the string table starts. We just build the string |
table in memory as we go along. We process all the relocations |
for a single input file at once. */ |
obj_raw_syment_count (abfd) = 0; |
if (coff_backend_info (abfd)->_bfd_coff_start_final_link) |
{ |
if (! bfd_coff_start_final_link (abfd, info)) |
goto error_return; |
} |
for (o = abfd->sections; o != NULL; o = o->next) |
{ |
for (p = o->map_head.link_order; p != NULL; p = p->next) |
{ |
if (p->type == bfd_indirect_link_order |
&& bfd_family_coff (p->u.indirect.section->owner)) |
{ |
sub = p->u.indirect.section->owner; |
if (! bfd_coff_link_output_has_begun (sub, & flaginfo)) |
{ |
if (! _bfd_coff_link_input_bfd (&flaginfo, sub)) |
goto error_return; |
sub->output_has_begun = TRUE; |
} |
} |
else if (p->type == bfd_section_reloc_link_order |
|| p->type == bfd_symbol_reloc_link_order) |
{ |
if (! _bfd_coff_reloc_link_order (abfd, &flaginfo, o, p)) |
goto error_return; |
} |
else |
{ |
if (! _bfd_default_link_order (abfd, info, o, p)) |
goto error_return; |
} |
} |
} |
if (flaginfo.info->strip != strip_all && flaginfo.info->discard != discard_all) |
{ |
/* Add local symbols from foreign inputs. */ |
for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) |
{ |
unsigned int i; |
if (bfd_family_coff (sub) || ! bfd_get_outsymbols (sub)) |
continue; |
for (i = 0; i < bfd_get_symcount (sub); ++i) |
{ |
asymbol *sym = bfd_get_outsymbols (sub) [i]; |
file_ptr pos; |
struct internal_syment isym; |
bfd_size_type string_size = 0; |
bfd_vma written = 0; |
bfd_boolean rewrite = FALSE; |
if (! (sym->flags & BSF_LOCAL) |
|| (sym->flags & (BSF_SECTION_SYM | BSF_DEBUGGING_RELOC |
| BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC |
| BSF_SYNTHETIC)) |
|| ((sym->flags & BSF_DEBUGGING) |
&& ! (sym->flags & BSF_FILE))) |
continue; |
/* See if we are discarding symbols with this name. */ |
if ((flaginfo.info->strip == strip_some |
&& (bfd_hash_lookup (flaginfo.info->keep_hash, |
bfd_asymbol_name(sym), FALSE, FALSE) |
== NULL)) |
|| (((flaginfo.info->discard == discard_sec_merge |
&& (bfd_get_section (sym)->flags & SEC_MERGE) |
&& ! flaginfo.info->relocatable) |
|| flaginfo.info->discard == discard_l) |
&& bfd_is_local_label_name (sub, bfd_asymbol_name(sym)))) |
continue; |
pos = obj_sym_filepos (abfd) + obj_raw_syment_count (abfd) |
* symesz; |
if (bfd_seek (abfd, pos, SEEK_SET) != 0) |
goto error_return; |
if (! coff_write_alien_symbol(abfd, sym, &isym, &written, |
&string_size, NULL, NULL)) |
goto error_return; |
if (string_size) |
{ |
bfd_boolean hash = ! (abfd->flags & BFD_TRADITIONAL_FORMAT); |
bfd_size_type indx; |
indx = _bfd_stringtab_add (flaginfo.strtab, |
bfd_asymbol_name (sym), hash, |
FALSE); |
if (indx == (bfd_size_type) -1) |
goto error_return; |
isym._n._n_n._n_offset = STRING_SIZE_SIZE + indx; |
bfd_coff_swap_sym_out (abfd, &isym, flaginfo.outsyms); |
rewrite = TRUE; |
} |
if (isym.n_sclass == C_FILE) |
{ |
if (flaginfo.last_file_index != -1) |
{ |
flaginfo.last_file.n_value = obj_raw_syment_count (abfd); |
bfd_coff_swap_sym_out (abfd, &flaginfo.last_file, |
flaginfo.outsyms); |
pos = obj_sym_filepos (abfd) + flaginfo.last_file_index |
* symesz; |
rewrite = TRUE; |
} |
flaginfo.last_file_index = obj_raw_syment_count (abfd); |
flaginfo.last_file = isym; |
} |
if (rewrite |
&& (bfd_seek (abfd, pos, SEEK_SET) != 0 |
|| bfd_bwrite (flaginfo.outsyms, symesz, abfd) != symesz)) |
goto error_return; |
obj_raw_syment_count (abfd) += written; |
} |
} |
} |
if (! bfd_coff_final_link_postscript (abfd, & flaginfo)) |
goto error_return; |
/* Free up the buffers used by _bfd_coff_link_input_bfd. */ |
coff_debug_merge_hash_table_free (&flaginfo.debug_merge); |
debug_merge_allocated = FALSE; |
if (flaginfo.internal_syms != NULL) |
{ |
free (flaginfo.internal_syms); |
flaginfo.internal_syms = NULL; |
} |
if (flaginfo.sec_ptrs != NULL) |
{ |
free (flaginfo.sec_ptrs); |
flaginfo.sec_ptrs = NULL; |
} |
if (flaginfo.sym_indices != NULL) |
{ |
free (flaginfo.sym_indices); |
flaginfo.sym_indices = NULL; |
} |
if (flaginfo.linenos != NULL) |
{ |
free (flaginfo.linenos); |
flaginfo.linenos = NULL; |
} |
if (flaginfo.contents != NULL) |
{ |
free (flaginfo.contents); |
flaginfo.contents = NULL; |
} |
if (flaginfo.external_relocs != NULL) |
{ |
free (flaginfo.external_relocs); |
flaginfo.external_relocs = NULL; |
} |
if (flaginfo.internal_relocs != NULL) |
{ |
free (flaginfo.internal_relocs); |
flaginfo.internal_relocs = NULL; |
} |
/* The value of the last C_FILE symbol is supposed to be the symbol |
index of the first external symbol. Write it out again if |
necessary. */ |
if (flaginfo.last_file_index != -1 |
&& (unsigned int) flaginfo.last_file.n_value != obj_raw_syment_count (abfd)) |
{ |
file_ptr pos; |
flaginfo.last_file.n_value = obj_raw_syment_count (abfd); |
bfd_coff_swap_sym_out (abfd, &flaginfo.last_file, |
flaginfo.outsyms); |
pos = obj_sym_filepos (abfd) + flaginfo.last_file_index * symesz; |
if (bfd_seek (abfd, pos, SEEK_SET) != 0 |
|| bfd_bwrite (flaginfo.outsyms, symesz, abfd) != symesz) |
return FALSE; |
} |
/* If doing task linking (ld --task-link) then make a pass through the |
global symbols, writing out any that are defined, and making them |
static. */ |
if (info->task_link) |
{ |
flaginfo.failed = FALSE; |
coff_link_hash_traverse (coff_hash_table (info), |
_bfd_coff_write_task_globals, &flaginfo); |
if (flaginfo.failed) |
goto error_return; |
} |
/* Write out the global symbols. */ |
flaginfo.failed = FALSE; |
bfd_hash_traverse (&info->hash->table, _bfd_coff_write_global_sym, &flaginfo); |
if (flaginfo.failed) |
goto error_return; |
/* The outsyms buffer is used by _bfd_coff_write_global_sym. */ |
if (flaginfo.outsyms != NULL) |
{ |
free (flaginfo.outsyms); |
flaginfo.outsyms = NULL; |
} |
if (info->relocatable && max_output_reloc_count > 0) |
{ |
/* Now that we have written out all the global symbols, we know |
the symbol indices to use for relocs against them, and we can |
finally write out the relocs. */ |
amt = max_output_reloc_count * relsz; |
external_relocs = (bfd_byte *) bfd_malloc (amt); |
if (external_relocs == NULL) |
goto error_return; |
for (o = abfd->sections; o != NULL; o = o->next) |
{ |
struct internal_reloc *irel; |
struct internal_reloc *irelend; |
struct coff_link_hash_entry **rel_hash; |
bfd_byte *erel; |
if (o->reloc_count == 0) |
continue; |
irel = flaginfo.section_info[o->target_index].relocs; |
irelend = irel + o->reloc_count; |
rel_hash = flaginfo.section_info[o->target_index].rel_hashes; |
erel = external_relocs; |
for (; irel < irelend; irel++, rel_hash++, erel += relsz) |
{ |
if (*rel_hash != NULL) |
{ |
BFD_ASSERT ((*rel_hash)->indx >= 0); |
irel->r_symndx = (*rel_hash)->indx; |
} |
bfd_coff_swap_reloc_out (abfd, irel, erel); |
} |
if (bfd_seek (abfd, o->rel_filepos, SEEK_SET) != 0) |
goto error_return; |
if (obj_pe (abfd) && o->reloc_count >= 0xffff) |
{ |
/* In PE COFF, write the count of relocs as the first |
reloc. The header overflow bit will be set |
elsewhere. */ |
struct internal_reloc incount; |
bfd_byte *excount = (bfd_byte *)bfd_malloc (relsz); |
memset (&incount, 0, sizeof (incount)); |
incount.r_vaddr = o->reloc_count + 1; |
bfd_coff_swap_reloc_out (abfd, &incount, excount); |
if (bfd_bwrite (excount, relsz, abfd) != relsz) |
/* We'll leak, but it's an error anyway. */ |
goto error_return; |
free (excount); |
} |
if (bfd_bwrite (external_relocs, |
(bfd_size_type) relsz * o->reloc_count, abfd) |
!= (bfd_size_type) relsz * o->reloc_count) |
goto error_return; |
} |
free (external_relocs); |
external_relocs = NULL; |
} |
/* Free up the section information. */ |
if (flaginfo.section_info != NULL) |
{ |
unsigned int i; |
for (i = 0; i < abfd->section_count; i++) |
{ |
if (flaginfo.section_info[i].relocs != NULL) |
free (flaginfo.section_info[i].relocs); |
if (flaginfo.section_info[i].rel_hashes != NULL) |
free (flaginfo.section_info[i].rel_hashes); |
} |
free (flaginfo.section_info); |
flaginfo.section_info = NULL; |
} |
/* If we have optimized stabs strings, output them. */ |
if (coff_hash_table (info)->stab_info.stabstr != NULL) |
{ |
if (! _bfd_write_stab_strings (abfd, &coff_hash_table (info)->stab_info)) |
return FALSE; |
} |
/* Write out the string table. */ |
if (obj_raw_syment_count (abfd) != 0 || long_section_names) |
{ |
file_ptr pos; |
pos = obj_sym_filepos (abfd) + obj_raw_syment_count (abfd) * symesz; |
if (bfd_seek (abfd, pos, SEEK_SET) != 0) |
return FALSE; |
#if STRING_SIZE_SIZE == 4 |
H_PUT_32 (abfd, |
_bfd_stringtab_size (flaginfo.strtab) + STRING_SIZE_SIZE, |
strbuf); |
#else |
#error Change H_PUT_32 above |
#endif |
if (bfd_bwrite (strbuf, (bfd_size_type) STRING_SIZE_SIZE, abfd) |
!= STRING_SIZE_SIZE) |
return FALSE; |
if (! _bfd_stringtab_emit (abfd, flaginfo.strtab)) |
return FALSE; |
obj_coff_strings_written (abfd) = TRUE; |
} |
_bfd_stringtab_free (flaginfo.strtab); |
/* Setting bfd_get_symcount to 0 will cause write_object_contents to |
not try to write out the symbols. */ |
bfd_get_symcount (abfd) = 0; |
return TRUE; |
error_return: |
if (debug_merge_allocated) |
coff_debug_merge_hash_table_free (&flaginfo.debug_merge); |
if (flaginfo.strtab != NULL) |
_bfd_stringtab_free (flaginfo.strtab); |
if (flaginfo.section_info != NULL) |
{ |
unsigned int i; |
for (i = 0; i < abfd->section_count; i++) |
{ |
if (flaginfo.section_info[i].relocs != NULL) |
free (flaginfo.section_info[i].relocs); |
if (flaginfo.section_info[i].rel_hashes != NULL) |
free (flaginfo.section_info[i].rel_hashes); |
} |
free (flaginfo.section_info); |
} |
if (flaginfo.internal_syms != NULL) |
free (flaginfo.internal_syms); |
if (flaginfo.sec_ptrs != NULL) |
free (flaginfo.sec_ptrs); |
if (flaginfo.sym_indices != NULL) |
free (flaginfo.sym_indices); |
if (flaginfo.outsyms != NULL) |
free (flaginfo.outsyms); |
if (flaginfo.linenos != NULL) |
free (flaginfo.linenos); |
if (flaginfo.contents != NULL) |
free (flaginfo.contents); |
if (flaginfo.external_relocs != NULL) |
free (flaginfo.external_relocs); |
if (flaginfo.internal_relocs != NULL) |
free (flaginfo.internal_relocs); |
if (external_relocs != NULL) |
free (external_relocs); |
return FALSE; |
} |
/* Parse out a -heap <reserved>,<commit> line. */ |
static char * |
dores_com (char *ptr, bfd *output_bfd, int heap) |
{ |
if (coff_data(output_bfd)->pe) |
{ |
int val = strtoul (ptr, &ptr, 0); |
if (heap) |
pe_data(output_bfd)->pe_opthdr.SizeOfHeapReserve = val; |
else |
pe_data(output_bfd)->pe_opthdr.SizeOfStackReserve = val; |
if (ptr[0] == ',') |
{ |
val = strtoul (ptr+1, &ptr, 0); |
if (heap) |
pe_data(output_bfd)->pe_opthdr.SizeOfHeapCommit = val; |
else |
pe_data(output_bfd)->pe_opthdr.SizeOfStackCommit = val; |
} |
} |
return ptr; |
} |
static char * |
get_name (char *ptr, char **dst) |
{ |
while (*ptr == ' ') |
ptr++; |
*dst = ptr; |
while (*ptr && *ptr != ' ') |
ptr++; |
*ptr = 0; |
return ptr+1; |
} |
/* Process any magic embedded commands in a section called .drectve. */ |
static int |
process_embedded_commands (bfd *output_bfd, |
struct bfd_link_info *info ATTRIBUTE_UNUSED, |
bfd *abfd) |
{ |
asection *sec = bfd_get_section_by_name (abfd, ".drectve"); |
char *s; |
char *e; |
bfd_byte *copy; |
if (!sec) |
return 1; |
if (!bfd_malloc_and_get_section (abfd, sec, ©)) |
{ |
if (copy != NULL) |
free (copy); |
return 0; |
} |
e = (char *) copy + sec->size; |
for (s = (char *) copy; s < e ; ) |
{ |
if (s[0] != '-') |
{ |
s++; |
continue; |
} |
if (CONST_STRNEQ (s, "-attr")) |
{ |
char *name; |
char *attribs; |
asection *asec; |
int loop = 1; |
int had_write = 0; |
int had_exec= 0; |
s += 5; |
s = get_name (s, &name); |
s = get_name (s, &attribs); |
while (loop) |
{ |
switch (*attribs++) |
{ |
case 'W': |
had_write = 1; |
break; |
case 'R': |
break; |
case 'S': |
break; |
case 'X': |
had_exec = 1; |
break; |
default: |
loop = 0; |
} |
} |
asec = bfd_get_section_by_name (abfd, name); |
if (asec) |
{ |
if (had_exec) |
asec->flags |= SEC_CODE; |
if (!had_write) |
asec->flags |= SEC_READONLY; |
} |
} |
else if (CONST_STRNEQ (s, "-heap")) |
s = dores_com (s + 5, output_bfd, 1); |
else if (CONST_STRNEQ (s, "-stack")) |
s = dores_com (s + 6, output_bfd, 0); |
/* GNU extension for aligned commons. */ |
else if (CONST_STRNEQ (s, "-aligncomm:")) |
{ |
/* Common symbols must be aligned on reading, as it |
is too late to do anything here, after they have |
already been allocated, so just skip the directive. */ |
s += 11; |
} |
else |
s++; |
} |
free (copy); |
return 1; |
} |
/* Place a marker against all symbols which are used by relocations. |
This marker can be picked up by the 'do we skip this symbol ?' |
loop in _bfd_coff_link_input_bfd() and used to prevent skipping |
that symbol. */ |
static void |
mark_relocs (struct coff_final_link_info *flaginfo, bfd *input_bfd) |
{ |
asection * a; |
if ((bfd_get_file_flags (input_bfd) & HAS_SYMS) == 0) |
return; |
for (a = input_bfd->sections; a != (asection *) NULL; a = a->next) |
{ |
struct internal_reloc * internal_relocs; |
struct internal_reloc * irel; |
struct internal_reloc * irelend; |
if ((a->flags & SEC_RELOC) == 0 || a->reloc_count < 1 |
|| a->linker_mark == 0) |
continue; |
/* Don't mark relocs in excluded sections. */ |
if (a->output_section == bfd_abs_section_ptr) |
continue; |
/* Read in the relocs. */ |
internal_relocs = _bfd_coff_read_internal_relocs |
(input_bfd, a, FALSE, |
flaginfo->external_relocs, |
flaginfo->info->relocatable, |
(flaginfo->info->relocatable |
? (flaginfo->section_info[ a->output_section->target_index ].relocs + a->output_section->reloc_count) |
: flaginfo->internal_relocs) |
); |
if (internal_relocs == NULL) |
continue; |
irel = internal_relocs; |
irelend = irel + a->reloc_count; |
/* Place a mark in the sym_indices array (whose entries have |
been initialised to 0) for all of the symbols that are used |
in the relocation table. This will then be picked up in the |
skip/don't-skip pass. */ |
for (; irel < irelend; irel++) |
flaginfo->sym_indices[ irel->r_symndx ] = -1; |
} |
} |
/* Link an input file into the linker output file. This function |
handles all the sections and relocations of the input file at once. */ |
bfd_boolean |
_bfd_coff_link_input_bfd (struct coff_final_link_info *flaginfo, bfd *input_bfd) |
{ |
unsigned int n_tmask = coff_data (input_bfd)->local_n_tmask; |
unsigned int n_btshft = coff_data (input_bfd)->local_n_btshft; |
bfd_boolean (*adjust_symndx) |
(bfd *, struct bfd_link_info *, bfd *, asection *, |
struct internal_reloc *, bfd_boolean *); |
bfd *output_bfd; |
const char *strings; |
bfd_size_type syment_base; |
bfd_boolean copy, hash; |
bfd_size_type isymesz; |
bfd_size_type osymesz; |
bfd_size_type linesz; |
bfd_byte *esym; |
bfd_byte *esym_end; |
struct internal_syment *isymp; |
asection **secpp; |
long *indexp; |
unsigned long output_index; |
bfd_byte *outsym; |
struct coff_link_hash_entry **sym_hash; |
asection *o; |
/* Move all the symbols to the output file. */ |
output_bfd = flaginfo->output_bfd; |
strings = NULL; |
syment_base = obj_raw_syment_count (output_bfd); |
isymesz = bfd_coff_symesz (input_bfd); |
osymesz = bfd_coff_symesz (output_bfd); |
linesz = bfd_coff_linesz (input_bfd); |
BFD_ASSERT (linesz == bfd_coff_linesz (output_bfd)); |
copy = FALSE; |
if (! flaginfo->info->keep_memory) |
copy = TRUE; |
hash = TRUE; |
if ((output_bfd->flags & BFD_TRADITIONAL_FORMAT) != 0) |
hash = FALSE; |
if (! _bfd_coff_get_external_symbols (input_bfd)) |
return FALSE; |
esym = (bfd_byte *) obj_coff_external_syms (input_bfd); |
esym_end = esym + obj_raw_syment_count (input_bfd) * isymesz; |
isymp = flaginfo->internal_syms; |
secpp = flaginfo->sec_ptrs; |
indexp = flaginfo->sym_indices; |
output_index = syment_base; |
outsym = flaginfo->outsyms; |
if (coff_data (output_bfd)->pe |
&& ! process_embedded_commands (output_bfd, flaginfo->info, input_bfd)) |
return FALSE; |
/* If we are going to perform relocations and also strip/discard some |
symbols then we must make sure that we do not strip/discard those |
symbols that are going to be involved in the relocations. */ |
if (( flaginfo->info->strip != strip_none |
|| flaginfo->info->discard != discard_none) |
&& flaginfo->info->relocatable) |
{ |
/* Mark the symbol array as 'not-used'. */ |
memset (indexp, 0, obj_raw_syment_count (input_bfd) * sizeof * indexp); |
mark_relocs (flaginfo, input_bfd); |
} |
while (esym < esym_end) |
{ |
struct internal_syment isym; |
enum coff_symbol_classification classification; |
bfd_boolean skip; |
bfd_boolean global; |
bfd_boolean dont_skip_symbol; |
int add; |
bfd_coff_swap_sym_in (input_bfd, esym, isymp); |
/* Make a copy of *isymp so that the relocate_section function |
always sees the original values. This is more reliable than |
always recomputing the symbol value even if we are stripping |
the symbol. */ |
isym = *isymp; |
classification = bfd_coff_classify_symbol (input_bfd, &isym); |
switch (classification) |
{ |
default: |
abort (); |
case COFF_SYMBOL_GLOBAL: |
case COFF_SYMBOL_PE_SECTION: |
case COFF_SYMBOL_LOCAL: |
*secpp = coff_section_from_bfd_index (input_bfd, isym.n_scnum); |
break; |
case COFF_SYMBOL_COMMON: |
*secpp = bfd_com_section_ptr; |
break; |
case COFF_SYMBOL_UNDEFINED: |
*secpp = bfd_und_section_ptr; |
break; |
} |
/* Extract the flag indicating if this symbol is used by a |
relocation. */ |
if ((flaginfo->info->strip != strip_none |
|| flaginfo->info->discard != discard_none) |
&& flaginfo->info->relocatable) |
dont_skip_symbol = *indexp; |
else |
dont_skip_symbol = FALSE; |
*indexp = -1; |
skip = FALSE; |
global = FALSE; |
add = 1 + isym.n_numaux; |
/* If we are stripping all symbols, we want to skip this one. */ |
if (flaginfo->info->strip == strip_all && ! dont_skip_symbol) |
skip = TRUE; |
if (! skip) |
{ |
switch (classification) |
{ |
default: |
abort (); |
case COFF_SYMBOL_GLOBAL: |
case COFF_SYMBOL_COMMON: |
case COFF_SYMBOL_PE_SECTION: |
/* This is a global symbol. Global symbols come at the |
end of the symbol table, so skip them for now. |
Locally defined function symbols, however, are an |
exception, and are not moved to the end. */ |
global = TRUE; |
if (! ISFCN (isym.n_type)) |
skip = TRUE; |
break; |
case COFF_SYMBOL_UNDEFINED: |
/* Undefined symbols are left for the end. */ |
global = TRUE; |
skip = TRUE; |
break; |
case COFF_SYMBOL_LOCAL: |
/* This is a local symbol. Skip it if we are discarding |
local symbols. */ |
if (flaginfo->info->discard == discard_all && ! dont_skip_symbol) |
skip = TRUE; |
break; |
} |
} |
#ifndef COFF_WITH_PE |
/* Skip section symbols for sections which are not going to be |
emitted. */ |
if (!skip |
&& !dont_skip_symbol |
&& isym.n_sclass == C_STAT |
&& isym.n_type == T_NULL |
&& isym.n_numaux > 0 |
&& ((*secpp)->output_section == bfd_abs_section_ptr |
|| bfd_section_removed_from_list (output_bfd, |
(*secpp)->output_section))) |
skip = TRUE; |
#endif |
/* If we stripping debugging symbols, and this is a debugging |
symbol, then skip it. FIXME: gas sets the section to N_ABS |
for some types of debugging symbols; I don't know if this is |
a bug or not. In any case, we handle it here. */ |
if (! skip |
&& flaginfo->info->strip == strip_debugger |
&& ! dont_skip_symbol |
&& (isym.n_scnum == N_DEBUG |
|| (isym.n_scnum == N_ABS |
&& (isym.n_sclass == C_AUTO |
|| isym.n_sclass == C_REG |
|| isym.n_sclass == C_MOS |
|| isym.n_sclass == C_MOE |
|| isym.n_sclass == C_MOU |
|| isym.n_sclass == C_ARG |
|| isym.n_sclass == C_REGPARM |
|| isym.n_sclass == C_FIELD |
|| isym.n_sclass == C_EOS)))) |
skip = TRUE; |
/* If some symbols are stripped based on the name, work out the |
name and decide whether to skip this symbol. */ |
if (! skip |
&& (flaginfo->info->strip == strip_some |
|| flaginfo->info->discard == discard_l)) |
{ |
const char *name; |
char buf[SYMNMLEN + 1]; |
name = _bfd_coff_internal_syment_name (input_bfd, &isym, buf); |
if (name == NULL) |
return FALSE; |
if (! dont_skip_symbol |
&& ((flaginfo->info->strip == strip_some |
&& (bfd_hash_lookup (flaginfo->info->keep_hash, name, FALSE, |
FALSE) == NULL)) |
|| (! global |
&& flaginfo->info->discard == discard_l |
&& bfd_is_local_label_name (input_bfd, name)))) |
skip = TRUE; |
} |
/* If this is an enum, struct, or union tag, see if we have |
already output an identical type. */ |
if (! skip |
&& (flaginfo->output_bfd->flags & BFD_TRADITIONAL_FORMAT) == 0 |
&& (isym.n_sclass == C_ENTAG |
|| isym.n_sclass == C_STRTAG |
|| isym.n_sclass == C_UNTAG) |
&& isym.n_numaux == 1) |
{ |
const char *name; |
char buf[SYMNMLEN + 1]; |
struct coff_debug_merge_hash_entry *mh; |
struct coff_debug_merge_type *mt; |
union internal_auxent aux; |
struct coff_debug_merge_element **epp; |
bfd_byte *esl, *eslend; |
struct internal_syment *islp; |
bfd_size_type amt; |
name = _bfd_coff_internal_syment_name (input_bfd, &isym, buf); |
if (name == NULL) |
return FALSE; |
/* Ignore fake names invented by compiler; treat them all as |
the same name. */ |
if (*name == '~' || *name == '.' || *name == '$' |
|| (*name == bfd_get_symbol_leading_char (input_bfd) |
&& (name[1] == '~' || name[1] == '.' || name[1] == '$'))) |
name = ""; |
mh = coff_debug_merge_hash_lookup (&flaginfo->debug_merge, name, |
TRUE, TRUE); |
if (mh == NULL) |
return FALSE; |
/* Allocate memory to hold type information. If this turns |
out to be a duplicate, we pass this address to |
bfd_release. */ |
amt = sizeof (struct coff_debug_merge_type); |
mt = (struct coff_debug_merge_type *) bfd_alloc (input_bfd, amt); |
if (mt == NULL) |
return FALSE; |
mt->type_class = isym.n_sclass; |
/* Pick up the aux entry, which points to the end of the tag |
entries. */ |
bfd_coff_swap_aux_in (input_bfd, (esym + isymesz), |
isym.n_type, isym.n_sclass, 0, isym.n_numaux, |
&aux); |
/* Gather the elements. */ |
epp = &mt->elements; |
mt->elements = NULL; |
islp = isymp + 2; |
esl = esym + 2 * isymesz; |
eslend = ((bfd_byte *) obj_coff_external_syms (input_bfd) |
+ aux.x_sym.x_fcnary.x_fcn.x_endndx.l * isymesz); |
while (esl < eslend) |
{ |
const char *elename; |
char elebuf[SYMNMLEN + 1]; |
char *name_copy; |
bfd_coff_swap_sym_in (input_bfd, esl, islp); |
amt = sizeof (struct coff_debug_merge_element); |
*epp = (struct coff_debug_merge_element *) |
bfd_alloc (input_bfd, amt); |
if (*epp == NULL) |
return FALSE; |
elename = _bfd_coff_internal_syment_name (input_bfd, islp, |
elebuf); |
if (elename == NULL) |
return FALSE; |
amt = strlen (elename) + 1; |
name_copy = (char *) bfd_alloc (input_bfd, amt); |
if (name_copy == NULL) |
return FALSE; |
strcpy (name_copy, elename); |
(*epp)->name = name_copy; |
(*epp)->type = islp->n_type; |
(*epp)->tagndx = 0; |
if (islp->n_numaux >= 1 |
&& islp->n_type != T_NULL |
&& islp->n_sclass != C_EOS) |
{ |
union internal_auxent eleaux; |
long indx; |
bfd_coff_swap_aux_in (input_bfd, (esl + isymesz), |
islp->n_type, islp->n_sclass, 0, |
islp->n_numaux, &eleaux); |
indx = eleaux.x_sym.x_tagndx.l; |
/* FIXME: If this tagndx entry refers to a symbol |
defined later in this file, we just ignore it. |
Handling this correctly would be tedious, and may |
not be required. */ |
if (indx > 0 |
&& (indx |
< ((esym - |
(bfd_byte *) obj_coff_external_syms (input_bfd)) |
/ (long) isymesz))) |
{ |
(*epp)->tagndx = flaginfo->sym_indices[indx]; |
if ((*epp)->tagndx < 0) |
(*epp)->tagndx = 0; |
} |
} |
epp = &(*epp)->next; |
*epp = NULL; |
esl += (islp->n_numaux + 1) * isymesz; |
islp += islp->n_numaux + 1; |
} |
/* See if we already have a definition which matches this |
type. We always output the type if it has no elements, |
for simplicity. */ |
if (mt->elements == NULL) |
bfd_release (input_bfd, mt); |
else |
{ |
struct coff_debug_merge_type *mtl; |
for (mtl = mh->types; mtl != NULL; mtl = mtl->next) |
{ |
struct coff_debug_merge_element *me, *mel; |
if (mtl->type_class != mt->type_class) |
continue; |
for (me = mt->elements, mel = mtl->elements; |
me != NULL && mel != NULL; |
me = me->next, mel = mel->next) |
{ |
if (strcmp (me->name, mel->name) != 0 |
|| me->type != mel->type |
|| me->tagndx != mel->tagndx) |
break; |
} |
if (me == NULL && mel == NULL) |
break; |
} |
if (mtl == NULL || (bfd_size_type) mtl->indx >= syment_base) |
{ |
/* This is the first definition of this type. */ |
mt->indx = output_index; |
mt->next = mh->types; |
mh->types = mt; |
} |
else |
{ |
/* This is a redefinition which can be merged. */ |
bfd_release (input_bfd, mt); |
*indexp = mtl->indx; |
add = (eslend - esym) / isymesz; |
skip = TRUE; |
} |
} |
} |
/* We now know whether we are to skip this symbol or not. */ |
if (! skip) |
{ |
/* Adjust the symbol in order to output it. */ |
if (isym._n._n_n._n_zeroes == 0 |
&& isym._n._n_n._n_offset != 0) |
{ |
const char *name; |
bfd_size_type indx; |
/* This symbol has a long name. Enter it in the string |
table we are building. Note that we do not check |
bfd_coff_symname_in_debug. That is only true for |
XCOFF, and XCOFF requires different linking code |
anyhow. */ |
name = _bfd_coff_internal_syment_name (input_bfd, &isym, NULL); |
if (name == NULL) |
return FALSE; |
indx = _bfd_stringtab_add (flaginfo->strtab, name, hash, copy); |
if (indx == (bfd_size_type) -1) |
return FALSE; |
isym._n._n_n._n_offset = STRING_SIZE_SIZE + indx; |
} |
switch (isym.n_sclass) |
{ |
case C_AUTO: |
case C_MOS: |
case C_EOS: |
case C_MOE: |
case C_MOU: |
case C_UNTAG: |
case C_STRTAG: |
case C_ENTAG: |
case C_TPDEF: |
case C_ARG: |
case C_USTATIC: |
case C_REG: |
case C_REGPARM: |
case C_FIELD: |
/* The symbol value should not be modified. */ |
break; |
case C_FCN: |
if (obj_pe (input_bfd) |
&& strcmp (isym.n_name, ".bf") != 0 |
&& isym.n_scnum > 0) |
{ |
/* For PE, .lf and .ef get their value left alone, |
while .bf gets relocated. However, they all have |
"real" section numbers, and need to be moved into |
the new section. */ |
isym.n_scnum = (*secpp)->output_section->target_index; |
break; |
} |
/* Fall through. */ |
default: |
case C_LABEL: /* Not completely sure about these 2 */ |
case C_EXTDEF: |
case C_BLOCK: |
case C_EFCN: |
case C_NULL: |
case C_EXT: |
case C_STAT: |
case C_SECTION: |
case C_NT_WEAK: |
/* Compute new symbol location. */ |
if (isym.n_scnum > 0) |
{ |
isym.n_scnum = (*secpp)->output_section->target_index; |
isym.n_value += (*secpp)->output_offset; |
if (! obj_pe (input_bfd)) |
isym.n_value -= (*secpp)->vma; |
if (! obj_pe (flaginfo->output_bfd)) |
isym.n_value += (*secpp)->output_section->vma; |
} |
break; |
case C_FILE: |
/* The value of a C_FILE symbol is the symbol index of |
the next C_FILE symbol. The value of the last C_FILE |
symbol is the symbol index to the first external |
symbol (actually, coff_renumber_symbols does not get |
this right--it just sets the value of the last C_FILE |
symbol to zero--and nobody has ever complained about |
it). We try to get this right, below, just before we |
write the symbols out, but in the general case we may |
have to write the symbol out twice. */ |
if (flaginfo->last_file_index != -1 |
&& flaginfo->last_file.n_value != (bfd_vma) output_index) |
{ |
/* We must correct the value of the last C_FILE |
entry. */ |
flaginfo->last_file.n_value = output_index; |
if ((bfd_size_type) flaginfo->last_file_index >= syment_base) |
{ |
/* The last C_FILE symbol is in this input file. */ |
bfd_coff_swap_sym_out (output_bfd, |
&flaginfo->last_file, |
(flaginfo->outsyms |
+ ((flaginfo->last_file_index |
- syment_base) |
* osymesz))); |
} |
else |
{ |
file_ptr pos; |
/* We have already written out the last C_FILE |
symbol. We need to write it out again. We |
borrow *outsym temporarily. */ |
bfd_coff_swap_sym_out (output_bfd, |
&flaginfo->last_file, outsym); |
pos = obj_sym_filepos (output_bfd); |
pos += flaginfo->last_file_index * osymesz; |
if (bfd_seek (output_bfd, pos, SEEK_SET) != 0 |
|| bfd_bwrite (outsym, osymesz, output_bfd) != osymesz) |
return FALSE; |
} |
} |
flaginfo->last_file_index = output_index; |
flaginfo->last_file = isym; |
break; |
} |
/* If doing task linking, convert normal global function symbols to |
static functions. */ |
if (flaginfo->info->task_link && IS_EXTERNAL (input_bfd, isym)) |
isym.n_sclass = C_STAT; |
/* Output the symbol. */ |
bfd_coff_swap_sym_out (output_bfd, &isym, outsym); |
*indexp = output_index; |
if (global) |
{ |
long indx; |
struct coff_link_hash_entry *h; |
indx = ((esym - (bfd_byte *) obj_coff_external_syms (input_bfd)) |
/ isymesz); |
h = obj_coff_sym_hashes (input_bfd)[indx]; |
if (h == NULL) |
{ |
/* This can happen if there were errors earlier in |
the link. */ |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
h->indx = output_index; |
} |
output_index += add; |
outsym += add * osymesz; |
} |
esym += add * isymesz; |
isymp += add; |
++secpp; |
++indexp; |
for (--add; add > 0; --add) |
{ |
*secpp++ = NULL; |
*indexp++ = -1; |
} |
} |
/* Fix up the aux entries. This must be done in a separate pass, |
because we don't know the correct symbol indices until we have |
already decided which symbols we are going to keep. */ |
esym = (bfd_byte *) obj_coff_external_syms (input_bfd); |
esym_end = esym + obj_raw_syment_count (input_bfd) * isymesz; |
isymp = flaginfo->internal_syms; |
indexp = flaginfo->sym_indices; |
sym_hash = obj_coff_sym_hashes (input_bfd); |
outsym = flaginfo->outsyms; |
while (esym < esym_end) |
{ |
int add; |
add = 1 + isymp->n_numaux; |
if ((*indexp < 0 |
|| (bfd_size_type) *indexp < syment_base) |
&& (*sym_hash == NULL |
|| (*sym_hash)->auxbfd != input_bfd)) |
esym += add * isymesz; |
else |
{ |
struct coff_link_hash_entry *h; |
int i; |
h = NULL; |
if (*indexp < 0) |
{ |
h = *sym_hash; |
/* The m68k-motorola-sysv assembler will sometimes |
generate two symbols with the same name, but only one |
will have aux entries. */ |
BFD_ASSERT (isymp->n_numaux == 0 |
|| h->numaux == 0 |
|| h->numaux == isymp->n_numaux); |
} |
esym += isymesz; |
if (h == NULL) |
outsym += osymesz; |
/* Handle the aux entries. This handling is based on |
coff_pointerize_aux. I don't know if it always correct. */ |
for (i = 0; i < isymp->n_numaux && esym < esym_end; i++) |
{ |
union internal_auxent aux; |
union internal_auxent *auxp; |
if (h != NULL && h->aux != NULL && (h->numaux > i)) |
auxp = h->aux + i; |
else |
{ |
bfd_coff_swap_aux_in (input_bfd, esym, isymp->n_type, |
isymp->n_sclass, i, isymp->n_numaux, &aux); |
auxp = &aux; |
} |
if (isymp->n_sclass == C_FILE) |
{ |
/* If this is a long filename, we must put it in the |
string table. */ |
if (auxp->x_file.x_n.x_zeroes == 0 |
&& auxp->x_file.x_n.x_offset != 0) |
{ |
const char *filename; |
bfd_size_type indx; |
BFD_ASSERT (auxp->x_file.x_n.x_offset |
>= STRING_SIZE_SIZE); |
if (strings == NULL) |
{ |
strings = _bfd_coff_read_string_table (input_bfd); |
if (strings == NULL) |
return FALSE; |
} |
filename = strings + auxp->x_file.x_n.x_offset; |
indx = _bfd_stringtab_add (flaginfo->strtab, filename, |
hash, copy); |
if (indx == (bfd_size_type) -1) |
return FALSE; |
auxp->x_file.x_n.x_offset = STRING_SIZE_SIZE + indx; |
} |
} |
else if ((isymp->n_sclass != C_STAT || isymp->n_type != T_NULL) |
&& isymp->n_sclass != C_NT_WEAK) |
{ |
unsigned long indx; |
if (ISFCN (isymp->n_type) |
|| ISTAG (isymp->n_sclass) |
|| isymp->n_sclass == C_BLOCK |
|| isymp->n_sclass == C_FCN) |
{ |
indx = auxp->x_sym.x_fcnary.x_fcn.x_endndx.l; |
if (indx > 0 |
&& indx < obj_raw_syment_count (input_bfd)) |
{ |
/* We look forward through the symbol for |
the index of the next symbol we are going |
to include. I don't know if this is |
entirely right. */ |
while ((flaginfo->sym_indices[indx] < 0 |
|| ((bfd_size_type) flaginfo->sym_indices[indx] |
< syment_base)) |
&& indx < obj_raw_syment_count (input_bfd)) |
++indx; |
if (indx >= obj_raw_syment_count (input_bfd)) |
indx = output_index; |
else |
indx = flaginfo->sym_indices[indx]; |
auxp->x_sym.x_fcnary.x_fcn.x_endndx.l = indx; |
} |
} |
indx = auxp->x_sym.x_tagndx.l; |
if (indx > 0 && indx < obj_raw_syment_count (input_bfd)) |
{ |
long symindx; |
symindx = flaginfo->sym_indices[indx]; |
if (symindx < 0) |
auxp->x_sym.x_tagndx.l = 0; |
else |
auxp->x_sym.x_tagndx.l = symindx; |
} |
/* The .bf symbols are supposed to be linked through |
the endndx field. We need to carry this list |
across object files. */ |
if (i == 0 |
&& h == NULL |
&& isymp->n_sclass == C_FCN |
&& (isymp->_n._n_n._n_zeroes != 0 |
|| isymp->_n._n_n._n_offset == 0) |
&& isymp->_n._n_name[0] == '.' |
&& isymp->_n._n_name[1] == 'b' |
&& isymp->_n._n_name[2] == 'f' |
&& isymp->_n._n_name[3] == '\0') |
{ |
if (flaginfo->last_bf_index != -1) |
{ |
flaginfo->last_bf.x_sym.x_fcnary.x_fcn.x_endndx.l = |
*indexp; |
if ((bfd_size_type) flaginfo->last_bf_index |
>= syment_base) |
{ |
void *auxout; |
/* The last .bf symbol is in this input |
file. This will only happen if the |
assembler did not set up the .bf |
endndx symbols correctly. */ |
auxout = (flaginfo->outsyms |
+ ((flaginfo->last_bf_index |
- syment_base) |
* osymesz)); |
bfd_coff_swap_aux_out (output_bfd, |
&flaginfo->last_bf, |
isymp->n_type, |
isymp->n_sclass, |
0, isymp->n_numaux, |
auxout); |
} |
else |
{ |
file_ptr pos; |
/* We have already written out the last |
.bf aux entry. We need to write it |
out again. We borrow *outsym |
temporarily. FIXME: This case should |
be made faster. */ |
bfd_coff_swap_aux_out (output_bfd, |
&flaginfo->last_bf, |
isymp->n_type, |
isymp->n_sclass, |
0, isymp->n_numaux, |
outsym); |
pos = obj_sym_filepos (output_bfd); |
pos += flaginfo->last_bf_index * osymesz; |
if (bfd_seek (output_bfd, pos, SEEK_SET) != 0 |
|| (bfd_bwrite (outsym, osymesz, output_bfd) |
!= osymesz)) |
return FALSE; |
} |
} |
if (auxp->x_sym.x_fcnary.x_fcn.x_endndx.l != 0) |
flaginfo->last_bf_index = -1; |
else |
{ |
/* The endndx field of this aux entry must |
be updated with the symbol number of the |
next .bf symbol. */ |
flaginfo->last_bf = *auxp; |
flaginfo->last_bf_index = (((outsym - flaginfo->outsyms) |
/ osymesz) |
+ syment_base); |
} |
} |
} |
if (h == NULL) |
{ |
bfd_coff_swap_aux_out (output_bfd, auxp, isymp->n_type, |
isymp->n_sclass, i, isymp->n_numaux, |
outsym); |
outsym += osymesz; |
} |
esym += isymesz; |
} |
} |
indexp += add; |
isymp += add; |
sym_hash += add; |
} |
/* Relocate the line numbers, unless we are stripping them. */ |
if (flaginfo->info->strip == strip_none |
|| flaginfo->info->strip == strip_some) |
{ |
for (o = input_bfd->sections; o != NULL; o = o->next) |
{ |
bfd_vma offset; |
bfd_byte *eline; |
bfd_byte *elineend; |
bfd_byte *oeline; |
bfd_boolean skipping; |
file_ptr pos; |
bfd_size_type amt; |
/* FIXME: If SEC_HAS_CONTENTS is not for the section, then |
build_link_order in ldwrite.c will not have created a |
link order, which means that we will not have seen this |
input section in _bfd_coff_final_link, which means that |
we will not have allocated space for the line numbers of |
this section. I don't think line numbers can be |
meaningful for a section which does not have |
SEC_HAS_CONTENTS set, but, if they do, this must be |
changed. */ |
if (o->lineno_count == 0 |
|| (o->output_section->flags & SEC_HAS_CONTENTS) == 0) |
continue; |
if (bfd_seek (input_bfd, o->line_filepos, SEEK_SET) != 0 |
|| bfd_bread (flaginfo->linenos, linesz * o->lineno_count, |
input_bfd) != linesz * o->lineno_count) |
return FALSE; |
offset = o->output_section->vma + o->output_offset - o->vma; |
eline = flaginfo->linenos; |
oeline = flaginfo->linenos; |
elineend = eline + linesz * o->lineno_count; |
skipping = FALSE; |
for (; eline < elineend; eline += linesz) |
{ |
struct internal_lineno iline; |
bfd_coff_swap_lineno_in (input_bfd, eline, &iline); |
if (iline.l_lnno != 0) |
iline.l_addr.l_paddr += offset; |
else if (iline.l_addr.l_symndx >= 0 |
&& ((unsigned long) iline.l_addr.l_symndx |
< obj_raw_syment_count (input_bfd))) |
{ |
long indx; |
indx = flaginfo->sym_indices[iline.l_addr.l_symndx]; |
if (indx < 0) |
{ |
/* These line numbers are attached to a symbol |
which we are stripping. We must discard the |
line numbers because reading them back with |
no associated symbol (or associating them all |
with symbol #0) will fail. We can't regain |
the space in the output file, but at least |
they're dense. */ |
skipping = TRUE; |
} |
else |
{ |
struct internal_syment is; |
union internal_auxent ia; |
/* Fix up the lnnoptr field in the aux entry of |
the symbol. It turns out that we can't do |
this when we modify the symbol aux entries, |
because gas sometimes screws up the lnnoptr |
field and makes it an offset from the start |
of the line numbers rather than an absolute |
file index. */ |
bfd_coff_swap_sym_in (output_bfd, |
(flaginfo->outsyms |
+ ((indx - syment_base) |
* osymesz)), &is); |
if ((ISFCN (is.n_type) |
|| is.n_sclass == C_BLOCK) |
&& is.n_numaux >= 1) |
{ |
void *auxptr; |
auxptr = (flaginfo->outsyms |
+ ((indx - syment_base + 1) |
* osymesz)); |
bfd_coff_swap_aux_in (output_bfd, auxptr, |
is.n_type, is.n_sclass, |
0, is.n_numaux, &ia); |
ia.x_sym.x_fcnary.x_fcn.x_lnnoptr = |
(o->output_section->line_filepos |
+ o->output_section->lineno_count * linesz |
+ eline - flaginfo->linenos); |
bfd_coff_swap_aux_out (output_bfd, &ia, |
is.n_type, is.n_sclass, 0, |
is.n_numaux, auxptr); |
} |
skipping = FALSE; |
} |
iline.l_addr.l_symndx = indx; |
} |
if (!skipping) |
{ |
bfd_coff_swap_lineno_out (output_bfd, &iline, oeline); |
oeline += linesz; |
} |
} |
pos = o->output_section->line_filepos; |
pos += o->output_section->lineno_count * linesz; |
amt = oeline - flaginfo->linenos; |
if (bfd_seek (output_bfd, pos, SEEK_SET) != 0 |
|| bfd_bwrite (flaginfo->linenos, amt, output_bfd) != amt) |
return FALSE; |
o->output_section->lineno_count += amt / linesz; |
} |
} |
/* If we swapped out a C_FILE symbol, guess that the next C_FILE |
symbol will be the first symbol in the next input file. In the |
normal case, this will save us from writing out the C_FILE symbol |
again. */ |
if (flaginfo->last_file_index != -1 |
&& (bfd_size_type) flaginfo->last_file_index >= syment_base) |
{ |
flaginfo->last_file.n_value = output_index; |
bfd_coff_swap_sym_out (output_bfd, &flaginfo->last_file, |
(flaginfo->outsyms |
+ ((flaginfo->last_file_index - syment_base) |
* osymesz))); |
} |
/* Write the modified symbols to the output file. */ |
if (outsym > flaginfo->outsyms) |
{ |
file_ptr pos; |
bfd_size_type amt; |
pos = obj_sym_filepos (output_bfd) + syment_base * osymesz; |
amt = outsym - flaginfo->outsyms; |
if (bfd_seek (output_bfd, pos, SEEK_SET) != 0 |
|| bfd_bwrite (flaginfo->outsyms, amt, output_bfd) != amt) |
return FALSE; |
BFD_ASSERT ((obj_raw_syment_count (output_bfd) |
+ (outsym - flaginfo->outsyms) / osymesz) |
== output_index); |
obj_raw_syment_count (output_bfd) = output_index; |
} |
/* Relocate the contents of each section. */ |
adjust_symndx = coff_backend_info (input_bfd)->_bfd_coff_adjust_symndx; |
for (o = input_bfd->sections; o != NULL; o = o->next) |
{ |
bfd_byte *contents; |
struct coff_section_tdata *secdata; |
if (! o->linker_mark) |
/* This section was omitted from the link. */ |
continue; |
if ((o->flags & SEC_LINKER_CREATED) != 0) |
continue; |
if ((o->flags & SEC_HAS_CONTENTS) == 0 |
|| (o->size == 0 && (o->flags & SEC_RELOC) == 0)) |
{ |
if ((o->flags & SEC_RELOC) != 0 |
&& o->reloc_count != 0) |
{ |
(*_bfd_error_handler) |
(_("%B: relocs in section `%A', but it has no contents"), |
input_bfd, o); |
bfd_set_error (bfd_error_no_contents); |
return FALSE; |
} |
continue; |
} |
secdata = coff_section_data (input_bfd, o); |
if (secdata != NULL && secdata->contents != NULL) |
contents = secdata->contents; |
else |
{ |
contents = flaginfo->contents; |
if (! bfd_get_full_section_contents (input_bfd, o, &contents)) |
return FALSE; |
} |
if ((o->flags & SEC_RELOC) != 0) |
{ |
int target_index; |
struct internal_reloc *internal_relocs; |
struct internal_reloc *irel; |
/* Read in the relocs. */ |
target_index = o->output_section->target_index; |
internal_relocs = (_bfd_coff_read_internal_relocs |
(input_bfd, o, FALSE, flaginfo->external_relocs, |
flaginfo->info->relocatable, |
(flaginfo->info->relocatable |
? (flaginfo->section_info[target_index].relocs |
+ o->output_section->reloc_count) |
: flaginfo->internal_relocs))); |
if (internal_relocs == NULL |
&& o->reloc_count > 0) |
return FALSE; |
/* Run through the relocs looking for relocs against symbols |
coming from discarded sections and complain about them. */ |
irel = internal_relocs; |
for (; irel < &internal_relocs[o->reloc_count]; irel++) |
{ |
struct coff_link_hash_entry *h; |
asection *ps = NULL; |
long symndx = irel->r_symndx; |
if (symndx < 0) |
continue; |
h = obj_coff_sym_hashes (input_bfd)[symndx]; |
if (h == NULL) |
continue; |
while (h->root.type == bfd_link_hash_indirect |
|| h->root.type == bfd_link_hash_warning) |
h = (struct coff_link_hash_entry *) h->root.u.i.link; |
if (h->root.type == bfd_link_hash_defined |
|| h->root.type == bfd_link_hash_defweak) |
ps = h->root.u.def.section; |
if (ps == NULL) |
continue; |
/* Complain if definition comes from an excluded section. */ |
if (ps->flags & SEC_EXCLUDE) |
(*flaginfo->info->callbacks->einfo) |
(_("%X`%s' referenced in section `%A' of %B: " |
"defined in discarded section `%A' of %B\n"), |
h->root.root.string, o, input_bfd, ps, ps->owner); |
} |
/* Call processor specific code to relocate the section |
contents. */ |
if (! bfd_coff_relocate_section (output_bfd, flaginfo->info, |
input_bfd, o, |
contents, |
internal_relocs, |
flaginfo->internal_syms, |
flaginfo->sec_ptrs)) |
return FALSE; |
if (flaginfo->info->relocatable) |
{ |
bfd_vma offset; |
struct internal_reloc *irelend; |
struct coff_link_hash_entry **rel_hash; |
offset = o->output_section->vma + o->output_offset - o->vma; |
irel = internal_relocs; |
irelend = irel + o->reloc_count; |
rel_hash = (flaginfo->section_info[target_index].rel_hashes |
+ o->output_section->reloc_count); |
for (; irel < irelend; irel++, rel_hash++) |
{ |
struct coff_link_hash_entry *h; |
bfd_boolean adjusted; |
*rel_hash = NULL; |
/* Adjust the reloc address and symbol index. */ |
irel->r_vaddr += offset; |
if (irel->r_symndx == -1) |
continue; |
if (adjust_symndx) |
{ |
if (! (*adjust_symndx) (output_bfd, flaginfo->info, |
input_bfd, o, irel, |
&adjusted)) |
return FALSE; |
if (adjusted) |
continue; |
} |
h = obj_coff_sym_hashes (input_bfd)[irel->r_symndx]; |
if (h != NULL) |
{ |
/* This is a global symbol. */ |
if (h->indx >= 0) |
irel->r_symndx = h->indx; |
else |
{ |
/* This symbol is being written at the end |
of the file, and we do not yet know the |
symbol index. We save the pointer to the |
hash table entry in the rel_hash list. |
We set the indx field to -2 to indicate |
that this symbol must not be stripped. */ |
*rel_hash = h; |
h->indx = -2; |
} |
} |
else |
{ |
long indx; |
indx = flaginfo->sym_indices[irel->r_symndx]; |
if (indx != -1) |
irel->r_symndx = indx; |
else |
{ |
struct internal_syment *is; |
const char *name; |
char buf[SYMNMLEN + 1]; |
/* This reloc is against a symbol we are |
stripping. This should have been handled |
by the 'dont_skip_symbol' code in the while |
loop at the top of this function. */ |
is = flaginfo->internal_syms + irel->r_symndx; |
name = (_bfd_coff_internal_syment_name |
(input_bfd, is, buf)); |
if (name == NULL) |
return FALSE; |
if (! ((*flaginfo->info->callbacks->unattached_reloc) |
(flaginfo->info, name, input_bfd, o, |
irel->r_vaddr))) |
return FALSE; |
} |
} |
} |
o->output_section->reloc_count += o->reloc_count; |
} |
} |
/* Write out the modified section contents. */ |
if (secdata == NULL || secdata->stab_info == NULL) |
{ |
file_ptr loc = o->output_offset * bfd_octets_per_byte (output_bfd); |
if (! bfd_set_section_contents (output_bfd, o->output_section, |
contents, loc, o->size)) |
return FALSE; |
} |
else |
{ |
if (! (_bfd_write_section_stabs |
(output_bfd, &coff_hash_table (flaginfo->info)->stab_info, |
o, &secdata->stab_info, contents))) |
return FALSE; |
} |
} |
if (! flaginfo->info->keep_memory |
&& ! _bfd_coff_free_symbols (input_bfd)) |
return FALSE; |
return TRUE; |
} |
/* Write out a global symbol. Called via bfd_hash_traverse. */ |
bfd_boolean |
_bfd_coff_write_global_sym (struct bfd_hash_entry *bh, void *data) |
{ |
struct coff_link_hash_entry *h = (struct coff_link_hash_entry *) bh; |
struct coff_final_link_info *flaginfo = (struct coff_final_link_info *) data; |
bfd *output_bfd; |
struct internal_syment isym; |
bfd_size_type symesz; |
unsigned int i; |
file_ptr pos; |
output_bfd = flaginfo->output_bfd; |
if (h->root.type == bfd_link_hash_warning) |
{ |
h = (struct coff_link_hash_entry *) h->root.u.i.link; |
if (h->root.type == bfd_link_hash_new) |
return TRUE; |
} |
if (h->indx >= 0) |
return TRUE; |
if (h->indx != -2 |
&& (flaginfo->info->strip == strip_all |
|| (flaginfo->info->strip == strip_some |
&& (bfd_hash_lookup (flaginfo->info->keep_hash, |
h->root.root.string, FALSE, FALSE) |
== NULL)))) |
return TRUE; |
switch (h->root.type) |
{ |
default: |
case bfd_link_hash_new: |
case bfd_link_hash_warning: |
abort (); |
return FALSE; |
case bfd_link_hash_undefined: |
case bfd_link_hash_undefweak: |
isym.n_scnum = N_UNDEF; |
isym.n_value = 0; |
break; |
case bfd_link_hash_defined: |
case bfd_link_hash_defweak: |
{ |
asection *sec; |
sec = h->root.u.def.section->output_section; |
if (bfd_is_abs_section (sec)) |
isym.n_scnum = N_ABS; |
else |
isym.n_scnum = sec->target_index; |
isym.n_value = (h->root.u.def.value |
+ h->root.u.def.section->output_offset); |
if (! obj_pe (flaginfo->output_bfd)) |
isym.n_value += sec->vma; |
} |
break; |
case bfd_link_hash_common: |
isym.n_scnum = N_UNDEF; |
isym.n_value = h->root.u.c.size; |
break; |
case bfd_link_hash_indirect: |
/* Just ignore these. They can't be handled anyhow. */ |
return TRUE; |
} |
if (strlen (h->root.root.string) <= SYMNMLEN) |
strncpy (isym._n._n_name, h->root.root.string, SYMNMLEN); |
else |
{ |
bfd_boolean hash; |
bfd_size_type indx; |
hash = TRUE; |
if ((output_bfd->flags & BFD_TRADITIONAL_FORMAT) != 0) |
hash = FALSE; |
indx = _bfd_stringtab_add (flaginfo->strtab, h->root.root.string, hash, |
FALSE); |
if (indx == (bfd_size_type) -1) |
{ |
flaginfo->failed = TRUE; |
return FALSE; |
} |
isym._n._n_n._n_zeroes = 0; |
isym._n._n_n._n_offset = STRING_SIZE_SIZE + indx; |
} |
isym.n_sclass = h->symbol_class; |
isym.n_type = h->type; |
if (isym.n_sclass == C_NULL) |
isym.n_sclass = C_EXT; |
/* If doing task linking and this is the pass where we convert |
defined globals to statics, then do that conversion now. If the |
symbol is not being converted, just ignore it and it will be |
output during a later pass. */ |
if (flaginfo->global_to_static) |
{ |
if (! IS_EXTERNAL (output_bfd, isym)) |
return TRUE; |
isym.n_sclass = C_STAT; |
} |
/* When a weak symbol is not overridden by a strong one, |
turn it into an external symbol when not building a |
shared or relocatable object. */ |
if (! flaginfo->info->shared |
&& ! flaginfo->info->relocatable |
&& IS_WEAK_EXTERNAL (flaginfo->output_bfd, isym)) |
isym.n_sclass = C_EXT; |
isym.n_numaux = h->numaux; |
bfd_coff_swap_sym_out (output_bfd, &isym, flaginfo->outsyms); |
symesz = bfd_coff_symesz (output_bfd); |
pos = obj_sym_filepos (output_bfd); |
pos += obj_raw_syment_count (output_bfd) * symesz; |
if (bfd_seek (output_bfd, pos, SEEK_SET) != 0 |
|| bfd_bwrite (flaginfo->outsyms, symesz, output_bfd) != symesz) |
{ |
flaginfo->failed = TRUE; |
return FALSE; |
} |
h->indx = obj_raw_syment_count (output_bfd); |
++obj_raw_syment_count (output_bfd); |
/* Write out any associated aux entries. Most of the aux entries |
will have been modified in _bfd_coff_link_input_bfd. We have to |
handle section aux entries here, now that we have the final |
relocation and line number counts. */ |
for (i = 0; i < isym.n_numaux; i++) |
{ |
union internal_auxent *auxp; |
auxp = h->aux + i; |
/* Look for a section aux entry here using the same tests that |
coff_swap_aux_out uses. */ |
if (i == 0 |
&& (isym.n_sclass == C_STAT |
|| isym.n_sclass == C_HIDDEN) |
&& isym.n_type == T_NULL |
&& (h->root.type == bfd_link_hash_defined |
|| h->root.type == bfd_link_hash_defweak)) |
{ |
asection *sec; |
sec = h->root.u.def.section->output_section; |
if (sec != NULL) |
{ |
auxp->x_scn.x_scnlen = sec->size; |
/* For PE, an overflow on the final link reportedly does |
not matter. FIXME: Why not? */ |
if (sec->reloc_count > 0xffff |
&& (! obj_pe (output_bfd) |
|| flaginfo->info->relocatable)) |
(*_bfd_error_handler) |
(_("%s: %s: reloc overflow: 0x%lx > 0xffff"), |
bfd_get_filename (output_bfd), |
bfd_get_section_name (output_bfd, sec), |
sec->reloc_count); |
if (sec->lineno_count > 0xffff |
&& (! obj_pe (output_bfd) |
|| flaginfo->info->relocatable)) |
(*_bfd_error_handler) |
(_("%s: warning: %s: line number overflow: 0x%lx > 0xffff"), |
bfd_get_filename (output_bfd), |
bfd_get_section_name (output_bfd, sec), |
sec->lineno_count); |
auxp->x_scn.x_nreloc = sec->reloc_count; |
auxp->x_scn.x_nlinno = sec->lineno_count; |
auxp->x_scn.x_checksum = 0; |
auxp->x_scn.x_associated = 0; |
auxp->x_scn.x_comdat = 0; |
} |
} |
bfd_coff_swap_aux_out (output_bfd, auxp, isym.n_type, |
isym.n_sclass, (int) i, isym.n_numaux, |
flaginfo->outsyms); |
if (bfd_bwrite (flaginfo->outsyms, symesz, output_bfd) != symesz) |
{ |
flaginfo->failed = TRUE; |
return FALSE; |
} |
++obj_raw_syment_count (output_bfd); |
} |
return TRUE; |
} |
/* Write out task global symbols, converting them to statics. Called |
via coff_link_hash_traverse. Calls bfd_coff_write_global_sym to do |
the dirty work, if the symbol we are processing needs conversion. */ |
bfd_boolean |
_bfd_coff_write_task_globals (struct coff_link_hash_entry *h, void *data) |
{ |
struct coff_final_link_info *flaginfo = (struct coff_final_link_info *) data; |
bfd_boolean rtnval = TRUE; |
bfd_boolean save_global_to_static; |
if (h->root.type == bfd_link_hash_warning) |
h = (struct coff_link_hash_entry *) h->root.u.i.link; |
if (h->indx < 0) |
{ |
switch (h->root.type) |
{ |
case bfd_link_hash_defined: |
case bfd_link_hash_defweak: |
save_global_to_static = flaginfo->global_to_static; |
flaginfo->global_to_static = TRUE; |
rtnval = _bfd_coff_write_global_sym (&h->root.root, data); |
flaginfo->global_to_static = save_global_to_static; |
break; |
default: |
break; |
} |
} |
return (rtnval); |
} |
/* Handle a link order which is supposed to generate a reloc. */ |
bfd_boolean |
_bfd_coff_reloc_link_order (bfd *output_bfd, |
struct coff_final_link_info *flaginfo, |
asection *output_section, |
struct bfd_link_order *link_order) |
{ |
reloc_howto_type *howto; |
struct internal_reloc *irel; |
struct coff_link_hash_entry **rel_hash_ptr; |
howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc); |
if (howto == NULL) |
{ |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
if (link_order->u.reloc.p->addend != 0) |
{ |
bfd_size_type size; |
bfd_byte *buf; |
bfd_reloc_status_type rstat; |
bfd_boolean ok; |
file_ptr loc; |
size = bfd_get_reloc_size (howto); |
buf = (bfd_byte *) bfd_zmalloc (size); |
if (buf == NULL) |
return FALSE; |
rstat = _bfd_relocate_contents (howto, output_bfd, |
(bfd_vma) link_order->u.reloc.p->addend,\ |
buf); |
switch (rstat) |
{ |
case bfd_reloc_ok: |
break; |
default: |
case bfd_reloc_outofrange: |
abort (); |
case bfd_reloc_overflow: |
if (! ((*flaginfo->info->callbacks->reloc_overflow) |
(flaginfo->info, NULL, |
(link_order->type == bfd_section_reloc_link_order |
? bfd_section_name (output_bfd, |
link_order->u.reloc.p->u.section) |
: link_order->u.reloc.p->u.name), |
howto->name, link_order->u.reloc.p->addend, |
(bfd *) NULL, (asection *) NULL, (bfd_vma) 0))) |
{ |
free (buf); |
return FALSE; |
} |
break; |
} |
loc = link_order->offset * bfd_octets_per_byte (output_bfd); |
ok = bfd_set_section_contents (output_bfd, output_section, buf, |
loc, size); |
free (buf); |
if (! ok) |
return FALSE; |
} |
/* Store the reloc information in the right place. It will get |
swapped and written out at the end of the final_link routine. */ |
irel = (flaginfo->section_info[output_section->target_index].relocs |
+ output_section->reloc_count); |
rel_hash_ptr = (flaginfo->section_info[output_section->target_index].rel_hashes |
+ output_section->reloc_count); |
memset (irel, 0, sizeof (struct internal_reloc)); |
*rel_hash_ptr = NULL; |
irel->r_vaddr = output_section->vma + link_order->offset; |
if (link_order->type == bfd_section_reloc_link_order) |
{ |
/* We need to somehow locate a symbol in the right section. The |
symbol must either have a value of zero, or we must adjust |
the addend by the value of the symbol. FIXME: Write this |
when we need it. The old linker couldn't handle this anyhow. */ |
abort (); |
*rel_hash_ptr = NULL; |
irel->r_symndx = 0; |
} |
else |
{ |
struct coff_link_hash_entry *h; |
h = ((struct coff_link_hash_entry *) |
bfd_wrapped_link_hash_lookup (output_bfd, flaginfo->info, |
link_order->u.reloc.p->u.name, |
FALSE, FALSE, TRUE)); |
if (h != NULL) |
{ |
if (h->indx >= 0) |
irel->r_symndx = h->indx; |
else |
{ |
/* Set the index to -2 to force this symbol to get |
written out. */ |
h->indx = -2; |
*rel_hash_ptr = h; |
irel->r_symndx = 0; |
} |
} |
else |
{ |
if (! ((*flaginfo->info->callbacks->unattached_reloc) |
(flaginfo->info, link_order->u.reloc.p->u.name, (bfd *) NULL, |
(asection *) NULL, (bfd_vma) 0))) |
return FALSE; |
irel->r_symndx = 0; |
} |
} |
/* FIXME: Is this always right? */ |
irel->r_type = howto->type; |
/* r_size is only used on the RS/6000, which needs its own linker |
routines anyhow. r_extern is only used for ECOFF. */ |
/* FIXME: What is the right value for r_offset? Is zero OK? */ |
++output_section->reloc_count; |
return TRUE; |
} |
/* A basic reloc handling routine which may be used by processors with |
simple relocs. */ |
bfd_boolean |
_bfd_coff_generic_relocate_section (bfd *output_bfd, |
struct bfd_link_info *info, |
bfd *input_bfd, |
asection *input_section, |
bfd_byte *contents, |
struct internal_reloc *relocs, |
struct internal_syment *syms, |
asection **sections) |
{ |
struct internal_reloc *rel; |
struct internal_reloc *relend; |
rel = relocs; |
relend = rel + input_section->reloc_count; |
for (; rel < relend; rel++) |
{ |
long symndx; |
struct coff_link_hash_entry *h; |
struct internal_syment *sym; |
bfd_vma addend; |
bfd_vma val; |
reloc_howto_type *howto; |
bfd_reloc_status_type rstat; |
symndx = rel->r_symndx; |
if (symndx == -1) |
{ |
h = NULL; |
sym = NULL; |
} |
else if (symndx < 0 |
|| (unsigned long) symndx >= obj_raw_syment_count (input_bfd)) |
{ |
(*_bfd_error_handler) |
("%B: illegal symbol index %ld in relocs", input_bfd, symndx); |
return FALSE; |
} |
else |
{ |
h = obj_coff_sym_hashes (input_bfd)[symndx]; |
sym = syms + symndx; |
} |
/* COFF treats common symbols in one of two ways. Either the |
size of the symbol is included in the section contents, or it |
is not. We assume that the size is not included, and force |
the rtype_to_howto function to adjust the addend as needed. */ |
if (sym != NULL && sym->n_scnum != 0) |
addend = - sym->n_value; |
else |
addend = 0; |
howto = bfd_coff_rtype_to_howto (input_bfd, input_section, rel, h, |
sym, &addend); |
if (howto == NULL) |
return FALSE; |
/* If we are doing a relocatable link, then we can just ignore |
a PC relative reloc that is pcrel_offset. It will already |
have the correct value. If this is not a relocatable link, |
then we should ignore the symbol value. */ |
if (howto->pc_relative && howto->pcrel_offset) |
{ |
if (info->relocatable) |
continue; |
if (sym != NULL && sym->n_scnum != 0) |
addend += sym->n_value; |
} |
val = 0; |
if (h == NULL) |
{ |
asection *sec; |
if (symndx == -1) |
{ |
sec = bfd_abs_section_ptr; |
val = 0; |
} |
else |
{ |
sec = sections[symndx]; |
val = (sec->output_section->vma |
+ sec->output_offset |
+ sym->n_value); |
if (! obj_pe (input_bfd)) |
val -= sec->vma; |
} |
} |
else |
{ |
if (h->root.type == bfd_link_hash_defined |
|| h->root.type == bfd_link_hash_defweak) |
{ |
/* Defined weak symbols are a GNU extension. */ |
asection *sec; |
sec = h->root.u.def.section; |
val = (h->root.u.def.value |
+ sec->output_section->vma |
+ sec->output_offset); |
} |
else if (h->root.type == bfd_link_hash_undefweak) |
{ |
if (h->symbol_class == C_NT_WEAK && h->numaux == 1) |
{ |
/* See _Microsoft Portable Executable and Common Object |
File Format Specification_, section 5.5.3. |
Note that weak symbols without aux records are a GNU |
extension. |
FIXME: All weak externals are treated as having |
characteristic IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY (1). |
These behave as per SVR4 ABI: A library member |
will resolve a weak external only if a normal |
external causes the library member to be linked. |
See also linker.c: generic_link_check_archive_element. */ |
asection *sec; |
struct coff_link_hash_entry *h2 = |
h->auxbfd->tdata.coff_obj_data->sym_hashes[ |
h->aux->x_sym.x_tagndx.l]; |
if (!h2 || h2->root.type == bfd_link_hash_undefined) |
{ |
sec = bfd_abs_section_ptr; |
val = 0; |
} |
else |
{ |
sec = h2->root.u.def.section; |
val = h2->root.u.def.value |
+ sec->output_section->vma + sec->output_offset; |
} |
} |
else |
/* This is a GNU extension. */ |
val = 0; |
} |
else if (! info->relocatable) |
{ |
if (! ((*info->callbacks->undefined_symbol) |
(info, h->root.root.string, input_bfd, input_section, |
rel->r_vaddr - input_section->vma, TRUE))) |
return FALSE; |
} |
} |
if (info->base_file) |
{ |
/* Emit a reloc if the backend thinks it needs it. */ |
if (sym && pe_data (output_bfd)->in_reloc_p (output_bfd, howto)) |
{ |
/* Relocation to a symbol in a section which isn't |
absolute. We output the address here to a file. |
This file is then read by dlltool when generating the |
reloc section. Note that the base file is not |
portable between systems. We write out a bfd_vma here, |
and dlltool reads in a bfd_vma. */ |
bfd_vma addr = (rel->r_vaddr |
- input_section->vma |
+ input_section->output_offset |
+ input_section->output_section->vma); |
if (coff_data (output_bfd)->pe) |
addr -= pe_data(output_bfd)->pe_opthdr.ImageBase; |
if (fwrite (&addr, 1, sizeof (bfd_vma), (FILE *) info->base_file) |
!= sizeof (bfd_vma)) |
{ |
bfd_set_error (bfd_error_system_call); |
return FALSE; |
} |
} |
} |
rstat = _bfd_final_link_relocate (howto, input_bfd, input_section, |
contents, |
rel->r_vaddr - input_section->vma, |
val, addend); |
switch (rstat) |
{ |
default: |
abort (); |
case bfd_reloc_ok: |
break; |
case bfd_reloc_outofrange: |
(*_bfd_error_handler) |
(_("%B: bad reloc address 0x%lx in section `%A'"), |
input_bfd, input_section, (unsigned long) rel->r_vaddr); |
return FALSE; |
case bfd_reloc_overflow: |
{ |
const char *name; |
char buf[SYMNMLEN + 1]; |
if (symndx == -1) |
name = "*ABS*"; |
else if (h != NULL) |
name = NULL; |
else |
{ |
name = _bfd_coff_internal_syment_name (input_bfd, sym, buf); |
if (name == NULL) |
return FALSE; |
} |
if (! ((*info->callbacks->reloc_overflow) |
(info, (h ? &h->root : NULL), name, howto->name, |
(bfd_vma) 0, input_bfd, input_section, |
rel->r_vaddr - input_section->vma))) |
return FALSE; |
} |
} |
} |
return TRUE; |
} |
/contrib/toolchain/binutils/bfd/compress.c |
---|
0,0 → 1,429 |
/* Compressed section support (intended for debug sections). |
Copyright 2008, 2010, 2011, 2012 |
Free Software Foundation, Inc. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
#ifdef HAVE_ZLIB_H |
#include <zlib.h> |
#endif |
#ifdef HAVE_ZLIB_H |
static bfd_boolean |
decompress_contents (bfd_byte *compressed_buffer, |
bfd_size_type compressed_size, |
bfd_byte *uncompressed_buffer, |
bfd_size_type uncompressed_size) |
{ |
z_stream strm; |
int rc; |
/* It is possible the section consists of several compressed |
buffers concatenated together, so we uncompress in a loop. */ |
strm.zalloc = NULL; |
strm.zfree = NULL; |
strm.opaque = NULL; |
strm.avail_in = compressed_size - 12; |
strm.next_in = (Bytef*) compressed_buffer + 12; |
strm.avail_out = uncompressed_size; |
BFD_ASSERT (Z_OK == 0); |
rc = inflateInit (&strm); |
while (strm.avail_in > 0 && strm.avail_out > 0) |
{ |
if (rc != Z_OK) |
break; |
strm.next_out = ((Bytef*) uncompressed_buffer |
+ (uncompressed_size - strm.avail_out)); |
rc = inflate (&strm, Z_FINISH); |
if (rc != Z_STREAM_END) |
break; |
rc = inflateReset (&strm); |
} |
rc |= inflateEnd (&strm); |
return rc == Z_OK && strm.avail_out == 0; |
} |
#endif |
/* |
FUNCTION |
bfd_compress_section_contents |
SYNOPSIS |
bfd_boolean bfd_compress_section_contents |
(bfd *abfd, asection *section, bfd_byte *uncompressed_buffer, |
bfd_size_type uncompressed_size); |
DESCRIPTION |
Compress data of the size specified in @var{uncompressed_size} |
and pointed to by @var{uncompressed_buffer} using zlib and store |
as the contents field. This function assumes the contents |
field was allocated using bfd_malloc() or equivalent. If zlib |
is not installed on this machine, the input is unmodified. |
Return @code{TRUE} if the full section contents is compressed |
successfully. |
*/ |
bfd_boolean |
bfd_compress_section_contents (bfd *abfd ATTRIBUTE_UNUSED, |
sec_ptr sec ATTRIBUTE_UNUSED, |
bfd_byte *uncompressed_buffer ATTRIBUTE_UNUSED, |
bfd_size_type uncompressed_size ATTRIBUTE_UNUSED) |
{ |
#ifndef HAVE_ZLIB_H |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
#else |
uLong compressed_size; |
bfd_byte *compressed_buffer; |
compressed_size = compressBound (uncompressed_size) + 12; |
compressed_buffer = (bfd_byte *) bfd_malloc (compressed_size); |
if (compressed_buffer == NULL) |
return FALSE; |
if (compress ((Bytef*) compressed_buffer + 12, |
&compressed_size, |
(const Bytef*) uncompressed_buffer, |
uncompressed_size) != Z_OK) |
{ |
free (compressed_buffer); |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
/* Write the zlib header. In this case, it should be "ZLIB" followed |
by the uncompressed section size, 8 bytes in big-endian order. */ |
memcpy (compressed_buffer, "ZLIB", 4); |
compressed_buffer[11] = uncompressed_size; uncompressed_size >>= 8; |
compressed_buffer[10] = uncompressed_size; uncompressed_size >>= 8; |
compressed_buffer[9] = uncompressed_size; uncompressed_size >>= 8; |
compressed_buffer[8] = uncompressed_size; uncompressed_size >>= 8; |
compressed_buffer[7] = uncompressed_size; uncompressed_size >>= 8; |
compressed_buffer[6] = uncompressed_size; uncompressed_size >>= 8; |
compressed_buffer[5] = uncompressed_size; uncompressed_size >>= 8; |
compressed_buffer[4] = uncompressed_size; |
compressed_size += 12; |
/* Free the uncompressed contents if we compress in place. */ |
if (uncompressed_buffer == sec->contents) |
free (uncompressed_buffer); |
sec->contents = compressed_buffer; |
sec->size = compressed_size; |
sec->compress_status = COMPRESS_SECTION_DONE; |
return TRUE; |
#endif /* HAVE_ZLIB_H */ |
} |
/* |
FUNCTION |
bfd_get_full_section_contents |
SYNOPSIS |
bfd_boolean bfd_get_full_section_contents |
(bfd *abfd, asection *section, bfd_byte **ptr); |
DESCRIPTION |
Read all data from @var{section} in BFD @var{abfd}, decompress |
if needed, and store in @var{*ptr}. If @var{*ptr} is NULL, |
return @var{*ptr} with memory malloc'd by this function. |
Return @code{TRUE} if the full section contents is retrieved |
successfully. |
*/ |
bfd_boolean |
bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr) |
{ |
bfd_size_type sz; |
bfd_byte *p = *ptr; |
#ifdef HAVE_ZLIB_H |
bfd_boolean ret; |
bfd_size_type save_size; |
bfd_size_type save_rawsize; |
bfd_byte *compressed_buffer; |
#endif |
if (abfd->direction != write_direction && sec->rawsize != 0) |
sz = sec->rawsize; |
else |
sz = sec->size; |
if (sz == 0) |
return TRUE; |
switch (sec->compress_status) |
{ |
case COMPRESS_SECTION_NONE: |
if (p == NULL) |
{ |
p = (bfd_byte *) bfd_malloc (sz); |
if (p == NULL) |
return FALSE; |
} |
if (!bfd_get_section_contents (abfd, sec, p, 0, sz)) |
{ |
if (*ptr != p) |
free (p); |
return FALSE; |
} |
*ptr = p; |
return TRUE; |
case DECOMPRESS_SECTION_SIZED: |
#ifndef HAVE_ZLIB_H |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
#else |
/* Read in the full compressed section contents. */ |
compressed_buffer = (bfd_byte *) bfd_malloc (sec->compressed_size); |
if (compressed_buffer == NULL) |
return FALSE; |
save_rawsize = sec->rawsize; |
save_size = sec->size; |
/* Clear rawsize, set size to compressed size and set compress_status |
to COMPRESS_SECTION_NONE. If the compressed size is bigger than |
the uncompressed size, bfd_get_section_contents will fail. */ |
sec->rawsize = 0; |
sec->size = sec->compressed_size; |
sec->compress_status = COMPRESS_SECTION_NONE; |
ret = bfd_get_section_contents (abfd, sec, compressed_buffer, |
0, sec->compressed_size); |
/* Restore rawsize and size. */ |
sec->rawsize = save_rawsize; |
sec->size = save_size; |
sec->compress_status = DECOMPRESS_SECTION_SIZED; |
if (!ret) |
goto fail_compressed; |
if (p == NULL) |
p = (bfd_byte *) bfd_malloc (sz); |
if (p == NULL) |
goto fail_compressed; |
if (!decompress_contents (compressed_buffer, sec->compressed_size, p, sz)) |
{ |
bfd_set_error (bfd_error_bad_value); |
if (p != *ptr) |
free (p); |
fail_compressed: |
free (compressed_buffer); |
return FALSE; |
} |
free (compressed_buffer); |
*ptr = p; |
return TRUE; |
#endif |
case COMPRESS_SECTION_DONE: |
if (p == NULL) |
{ |
p = (bfd_byte *) bfd_malloc (sz); |
if (p == NULL) |
return FALSE; |
*ptr = p; |
} |
memcpy (p, sec->contents, sz); |
return TRUE; |
default: |
abort (); |
} |
} |
/* |
FUNCTION |
bfd_cache_section_contents |
SYNOPSIS |
void bfd_cache_section_contents |
(asection *sec, void *contents); |
DESCRIPTION |
Stash @var(contents) so any following reads of @var(sec) do |
not need to decompress again. |
*/ |
void |
bfd_cache_section_contents (asection *sec, void *contents) |
{ |
if (sec->compress_status == DECOMPRESS_SECTION_SIZED) |
sec->compress_status = COMPRESS_SECTION_DONE; |
sec->contents = contents; |
sec->flags |= SEC_IN_MEMORY; |
} |
/* |
FUNCTION |
bfd_is_section_compressed |
SYNOPSIS |
bfd_boolean bfd_is_section_compressed |
(bfd *abfd, asection *section); |
DESCRIPTION |
Return @code{TRUE} if @var{section} is compressed. |
*/ |
bfd_boolean |
bfd_is_section_compressed (bfd *abfd, sec_ptr sec) |
{ |
bfd_byte compressed_buffer [12]; |
unsigned int saved = sec->compress_status; |
bfd_boolean compressed; |
/* Don't decompress the section. */ |
sec->compress_status = COMPRESS_SECTION_NONE; |
/* Read the zlib header. In this case, it should be "ZLIB" followed |
by the uncompressed section size, 8 bytes in big-endian order. */ |
compressed = (bfd_get_section_contents (abfd, sec, compressed_buffer, 0, 12) |
&& CONST_STRNEQ ((char*) compressed_buffer, "ZLIB")); |
/* Restore compress_status. */ |
sec->compress_status = saved; |
return compressed; |
} |
/* |
FUNCTION |
bfd_init_section_decompress_status |
SYNOPSIS |
bfd_boolean bfd_init_section_decompress_status |
(bfd *abfd, asection *section); |
DESCRIPTION |
Record compressed section size, update section size with |
decompressed size and set compress_status to |
DECOMPRESS_SECTION_SIZED. |
Return @code{FALSE} if the section is not a valid compressed |
section or zlib is not installed on this machine. Otherwise, |
return @code{TRUE}. |
*/ |
bfd_boolean |
bfd_init_section_decompress_status (bfd *abfd ATTRIBUTE_UNUSED, |
sec_ptr sec ATTRIBUTE_UNUSED) |
{ |
#ifndef HAVE_ZLIB_H |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
#else |
bfd_byte compressed_buffer [12]; |
bfd_size_type uncompressed_size; |
if (sec->rawsize != 0 |
|| sec->contents != NULL |
|| sec->compress_status != COMPRESS_SECTION_NONE |
|| !bfd_get_section_contents (abfd, sec, compressed_buffer, 0, 12)) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
/* Read the zlib header. In this case, it should be "ZLIB" followed |
by the uncompressed section size, 8 bytes in big-endian order. */ |
if (! CONST_STRNEQ ((char*) compressed_buffer, "ZLIB")) |
{ |
bfd_set_error (bfd_error_wrong_format); |
return FALSE; |
} |
uncompressed_size = compressed_buffer[4]; uncompressed_size <<= 8; |
uncompressed_size += compressed_buffer[5]; uncompressed_size <<= 8; |
uncompressed_size += compressed_buffer[6]; uncompressed_size <<= 8; |
uncompressed_size += compressed_buffer[7]; uncompressed_size <<= 8; |
uncompressed_size += compressed_buffer[8]; uncompressed_size <<= 8; |
uncompressed_size += compressed_buffer[9]; uncompressed_size <<= 8; |
uncompressed_size += compressed_buffer[10]; uncompressed_size <<= 8; |
uncompressed_size += compressed_buffer[11]; |
sec->compressed_size = sec->size; |
sec->size = uncompressed_size; |
sec->compress_status = DECOMPRESS_SECTION_SIZED; |
return TRUE; |
#endif |
} |
/* |
FUNCTION |
bfd_init_section_compress_status |
SYNOPSIS |
bfd_boolean bfd_init_section_compress_status |
(bfd *abfd, asection *section); |
DESCRIPTION |
If open for read, compress section, update section size with |
compressed size and set compress_status to COMPRESS_SECTION_DONE. |
Return @code{FALSE} if the section is not a valid compressed |
section or zlib is not installed on this machine. Otherwise, |
return @code{TRUE}. |
*/ |
bfd_boolean |
bfd_init_section_compress_status (bfd *abfd ATTRIBUTE_UNUSED, |
sec_ptr sec ATTRIBUTE_UNUSED) |
{ |
#ifndef HAVE_ZLIB_H |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
#else |
bfd_size_type uncompressed_size; |
bfd_byte *uncompressed_buffer; |
bfd_boolean ret; |
/* Error if not opened for read. */ |
if (abfd->direction != read_direction |
|| sec->size == 0 |
|| sec->rawsize != 0 |
|| sec->contents != NULL |
|| sec->compress_status != COMPRESS_SECTION_NONE) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
/* Read in the full section contents and compress it. */ |
uncompressed_size = sec->size; |
uncompressed_buffer = (bfd_byte *) bfd_malloc (uncompressed_size); |
if (!bfd_get_section_contents (abfd, sec, uncompressed_buffer, |
0, uncompressed_size)) |
ret = FALSE; |
else |
ret = bfd_compress_section_contents (abfd, sec, |
uncompressed_buffer, |
uncompressed_size); |
free (uncompressed_buffer); |
return ret; |
#endif |
} |
/contrib/toolchain/binutils/bfd/config.h |
---|
0,0 → 1,380 |
/* config.h. Generated from config.in by configure. */ |
/* config.in. Generated from configure.in by autoheader. */ |
/* Check that config.h is #included before system headers |
(this works only for glibc, but that should be enough). */ |
#if defined(__GLIBC__) && !defined(__FreeBSD_kernel__) && !defined(__CONFIG_H__) |
# error config.h must be #included before system headers |
#endif |
#define __CONFIG_H__ 1 |
/* Name of host specific core header file to include in elf.c. */ |
/* #undef CORE_HEADER */ |
/* Define to 1 if translation of program messages to the user's native |
language is requested. */ |
/* #undef ENABLE_NLS */ |
/* Define to 1 if you have the <alloca.h> header file. */ |
/* #undef HAVE_ALLOCA_H */ |
/* Define to 1 if you have the declaration of `basename', and to 0 if you |
don't. */ |
#define HAVE_DECL_BASENAME 0 |
/* Define to 1 if you have the declaration of `ffs', and to 0 if you don't. */ |
#define HAVE_DECL_FFS 0 |
/* Define to 1 if you have the declaration of `free', and to 0 if you don't. |
*/ |
#define HAVE_DECL_FREE 1 |
/* Define to 1 if you have the declaration of `fseeko', and to 0 if you don't. |
*/ |
#define HAVE_DECL_FSEEKO 0 |
/* Define to 1 if you have the declaration of `fseeko64', and to 0 if you |
don't. */ |
#define HAVE_DECL_FSEEKO64 0 |
/* Define to 1 if you have the declaration of `ftello', and to 0 if you don't. |
*/ |
#define HAVE_DECL_FTELLO 0 |
/* Define to 1 if you have the declaration of `ftello64', and to 0 if you |
don't. */ |
#define HAVE_DECL_FTELLO64 0 |
/* Define to 1 if you have the declaration of `getenv', and to 0 if you don't. |
*/ |
#define HAVE_DECL_GETENV 1 |
/* Define to 1 if you have the declaration of `malloc', and to 0 if you don't. |
*/ |
#define HAVE_DECL_MALLOC 1 |
/* Define to 1 if you have the declaration of `realloc', and to 0 if you |
don't. */ |
#define HAVE_DECL_REALLOC 1 |
/* Define to 1 if you have the declaration of `snprintf', and to 0 if you |
don't. */ |
#define HAVE_DECL_SNPRINTF 1 |
/* Define to 1 if you have the declaration of `stpcpy', and to 0 if you don't. |
*/ |
#define HAVE_DECL_STPCPY 0 |
/* Define to 1 if you have the declaration of `strstr', and to 0 if you don't. |
*/ |
#define HAVE_DECL_STRSTR 1 |
/* Define to 1 if you have the declaration of `vsnprintf', and to 0 if you |
don't. */ |
#define HAVE_DECL_VSNPRINTF 1 |
/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'. |
*/ |
#define HAVE_DIRENT_H 1 |
/* Define to 1 if you have the <dlfcn.h> header file. */ |
/* #undef HAVE_DLFCN_H */ |
/* Define to 1 if you have the `fcntl' function. */ |
/* #undef HAVE_FCNTL */ |
/* Define to 1 if you have the <fcntl.h> header file. */ |
#define HAVE_FCNTL_H 1 |
/* Define to 1 if you have the `fdopen' function. */ |
#define HAVE_FDOPEN 1 |
/* Define to 1 if you have the `fileno' function. */ |
#define HAVE_FILENO 1 |
/* Define to 1 if you have the `fopen64' function. */ |
//#define HAVE_FOPEN64 0 |
/* Define to 1 if you have the `fseeko' function. */ |
/* #undef HAVE_FSEEKO */ |
/* Define to 1 if you have the `fseeko64' function. */ |
//#define HAVE_FSEEKO64 0 |
/* Define to 1 if you have the `ftello' function. */ |
/* #undef HAVE_FTELLO */ |
/* Define to 1 if you have the `ftello64' function. */ |
//#define HAVE_FTELLO64 0 |
/* Define to 1 if you have the `getgid' function. */ |
/* #undef HAVE_GETGID */ |
/* Define to 1 if you have the `getpagesize' function. */ |
//#define HAVE_GETPAGESIZE 1 |
/* Define to 1 if you have the `getrlimit' function. */ |
/* #undef HAVE_GETRLIMIT */ |
/* Define to 1 if you have the `getuid' function. */ |
/* #undef HAVE_GETUID */ |
/* Define to 1 if you have the <inttypes.h> header file. */ |
#define HAVE_INTTYPES_H 1 |
/* Define if <sys/procfs.h> has lwpstatus_t. */ |
/* #undef HAVE_LWPSTATUS_T */ |
/* Define if <sys/procfs.h> has lwpstatus_t.pr_context. */ |
/* #undef HAVE_LWPSTATUS_T_PR_CONTEXT */ |
/* Define if <sys/procfs.h> has lwpstatus_t.pr_fpreg. */ |
/* #undef HAVE_LWPSTATUS_T_PR_FPREG */ |
/* Define if <sys/procfs.h> has lwpstatus_t.pr_reg. */ |
/* #undef HAVE_LWPSTATUS_T_PR_REG */ |
/* Define if <sys/procfs.h> has lwpxstatus_t. */ |
/* #undef HAVE_LWPXSTATUS_T */ |
/* Define to 1 if you have the `madvise' function. */ |
/* #undef HAVE_MADVISE */ |
/* Define to 1 if you have the <memory.h> header file. */ |
#define HAVE_MEMORY_H 1 |
/* Define to 1 if you have a working `mmap' system call. */ |
/* #undef HAVE_MMAP */ |
/* Define to 1 if you have the `mprotect' function. */ |
//#define HAVE_MPROTECT 0 |
/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */ |
/* #undef HAVE_NDIR_H */ |
/* Define if <sys/procfs.h> has prpsinfo32_t. */ |
/* #undef HAVE_PRPSINFO32_T */ |
/* Define if <sys/procfs.h> has prpsinfo32_t.pr_pid. */ |
/* #undef HAVE_PRPSINFO32_T_PR_PID */ |
/* Define if <sys/procfs.h> has prpsinfo_t. */ |
/* #undef HAVE_PRPSINFO_T */ |
/* Define if <sys/procfs.h> has prpsinfo_t.pr_pid. */ |
/* #undef HAVE_PRPSINFO_T_PR_PID */ |
/* Define if <sys/procfs.h> has prstatus32_t. */ |
/* #undef HAVE_PRSTATUS32_T */ |
/* Define if <sys/procfs.h> has prstatus32_t.pr_who. */ |
/* #undef HAVE_PRSTATUS32_T_PR_WHO */ |
/* Define if <sys/procfs.h> has prstatus_t. */ |
/* #undef HAVE_PRSTATUS_T */ |
/* Define if <sys/procfs.h> has prstatus_t.pr_who. */ |
/* #undef HAVE_PRSTATUS_T_PR_WHO */ |
/* Define if <sys/procfs.h> has psinfo32_t. */ |
/* #undef HAVE_PSINFO32_T */ |
/* Define if <sys/procfs.h> has psinfo32_t.pr_pid. */ |
/* #undef HAVE_PSINFO32_T_PR_PID */ |
/* Define if <sys/procfs.h> has psinfo_t. */ |
/* #undef HAVE_PSINFO_T */ |
/* Define if <sys/procfs.h> has psinfo_t.pr_pid. */ |
/* #undef HAVE_PSINFO_T_PR_PID */ |
/* Define if <sys/procfs.h> has pstatus32_t. */ |
/* #undef HAVE_PSTATUS32_T */ |
/* Define if <sys/procfs.h> has pstatus_t. */ |
/* #undef HAVE_PSTATUS_T */ |
/* Define if <sys/procfs.h> has pxstatus_t. */ |
/* #undef HAVE_PXSTATUS_T */ |
/* Define to 1 if you have the `setitimer' function. */ |
/* #undef HAVE_SETITIMER */ |
/* Define to 1 if you have the <stddef.h> header file. */ |
#define HAVE_STDDEF_H 1 |
/* Define to 1 if you have the <stdint.h> header file. */ |
#define HAVE_STDINT_H 1 |
/* Define to 1 if you have the <stdlib.h> header file. */ |
#define HAVE_STDLIB_H 1 |
/* Define to 1 if you have the <strings.h> header file. */ |
#define HAVE_STRINGS_H 1 |
/* Define to 1 if you have the <string.h> header file. */ |
#define HAVE_STRING_H 1 |
/* Define to 1 if you have the `strtoull' function. */ |
#define HAVE_STRTOULL 1 |
/* Define if struct core_dumpx has member c_impl */ |
/* #undef HAVE_ST_C_IMPL */ |
/* Define to 1 if you have the `sysconf' function. */ |
/* #undef HAVE_SYSCONF */ |
/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'. |
*/ |
/* #undef HAVE_SYS_DIR_H */ |
/* Define to 1 if you have the <sys/file.h> header file. */ |
#define HAVE_SYS_FILE_H 1 |
/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'. |
*/ |
/* #undef HAVE_SYS_NDIR_H */ |
/* Define to 1 if you have the <sys/procfs.h> header file. */ |
/* #undef HAVE_SYS_PROCFS_H */ |
/* Define to 1 if you have the <sys/resource.h> header file. */ |
/* #undef HAVE_SYS_RESOURCE_H */ |
/* Define to 1 if you have the <sys/stat.h> header file. */ |
#define HAVE_SYS_STAT_H 1 |
/* Define to 1 if you have the <sys/time.h> header file. */ |
#define HAVE_SYS_TIME_H 1 |
/* Define to 1 if you have the <sys/types.h> header file. */ |
#define HAVE_SYS_TYPES_H 1 |
/* Define to 1 if you have the <time.h> header file. */ |
#define HAVE_TIME_H 1 |
/* Define to 1 if you have the <unistd.h> header file. */ |
#define HAVE_UNISTD_H 1 |
/* Define if <sys/procfs.h> has win32_pstatus_t. */ |
/* #undef HAVE_WIN32_PSTATUS_T */ |
/* Define to 1 if you have the <windows.h> header file. */ |
//#define HAVE_WINDOWS_H 1 |
/* Define to 1 if you have the <zlib.h> header file. */ |
#define HAVE_ZLIB_H 1 |
/* Define to the sub-directory in which libtool stores uninstalled libraries. |
*/ |
#define LT_OBJDIR ".libs/" |
/* Name of package */ |
#define PACKAGE "bfd" |
/* Define to the address where bug reports for this package should be sent. */ |
#define PACKAGE_BUGREPORT "" |
/* Define to the full name of this package. */ |
#define PACKAGE_NAME "bfd" |
/* Define to the full name and version of this package. */ |
#define PACKAGE_STRING "bfd 2.24" |
/* Define to the one symbol short name of this package. */ |
#define PACKAGE_TARNAME "bfd" |
/* Define to the home page for this package. */ |
#define PACKAGE_URL "" |
/* Define to the version of this package. */ |
#define PACKAGE_VERSION "2.24" |
/* The size of `char', as computed by sizeof. */ |
/* #undef SIZEOF_CHAR */ |
/* The size of `int', as computed by sizeof. */ |
/* #undef SIZEOF_INT */ |
/* The size of `long', as computed by sizeof. */ |
#define SIZEOF_LONG 4 |
/* The size of `long long', as computed by sizeof. */ |
#define SIZEOF_LONG_LONG 8 |
/* The size of `off_t', as computed by sizeof. */ |
/* #undef SIZEOF_OFF_T */ |
/* The size of `short', as computed by sizeof. */ |
/* #undef SIZEOF_SHORT */ |
/* The size of `void *', as computed by sizeof. */ |
#define SIZEOF_VOID_P 4 |
/* Define to 1 if you have the ANSI C header files. */ |
#define STDC_HEADERS 1 |
/* Define if you can safely include both <string.h> and <strings.h>. */ |
#define STRING_WITH_STRINGS 1 |
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */ |
#define TIME_WITH_SYS_TIME 1 |
/* Name of host specific header file to include in trad-core.c. */ |
/* #undef TRAD_HEADER */ |
/* Use b modifier when opening binary files? */ |
#define USE_BINARY_FOPEN 1 |
/* Define if we should use leading underscore on 64 bit mingw targets */ |
/* #undef USE_MINGW64_LEADING_UNDERSCORES */ |
/* Use mmap if it's available? */ |
/* #undef USE_MMAP */ |
/* Define if we should default to creating read-only plt entries */ |
/* #undef USE_SECUREPLT */ |
/* Define if we may generate symbols with ELF's STT_COMMON type */ |
/* #undef USE_STT_COMMON */ |
/* Enable extensions on AIX 3, Interix. */ |
#ifndef _ALL_SOURCE |
# define _ALL_SOURCE 1 |
#endif |
/* Enable GNU extensions on systems that have them. */ |
#ifndef _GNU_SOURCE |
# define _GNU_SOURCE 1 |
#endif |
/* Enable threading extensions on Solaris. */ |
#ifndef _POSIX_PTHREAD_SEMANTICS |
# define _POSIX_PTHREAD_SEMANTICS 1 |
#endif |
/* Enable extensions on HP NonStop. */ |
#ifndef _TANDEM_SOURCE |
# define _TANDEM_SOURCE 1 |
#endif |
/* Enable general extensions on Solaris. */ |
#ifndef __EXTENSIONS__ |
# define __EXTENSIONS__ 1 |
#endif |
/* Version number of package */ |
#define VERSION "2.24" |
/* Number of bits in a file offset, on hosts where this is settable. */ |
/* #undef _FILE_OFFSET_BITS */ |
/* Define for large files, on AIX-style hosts. */ |
/* #undef _LARGE_FILES */ |
/* Define to 1 if on MINIX. */ |
/* #undef _MINIX */ |
/* Define to 2 if the system does not provide POSIX.1 features except with |
this defined. */ |
/* #undef _POSIX_1_SOURCE */ |
/* Define to 1 if you need to in order for `stat' and other things to work. */ |
/* #undef _POSIX_SOURCE */ |
/contrib/toolchain/binutils/bfd/corefile.c |
---|
0,0 → 1,191 |
/* Core file generic interface routines for BFD. |
Copyright 1990, 1991, 1992, 1993, 1994, 2000, 2001, 2002, 2003, 2005, |
2007 Free Software Foundation, Inc. |
Written by Cygnus Support. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* |
SECTION |
Core files |
SUBSECTION |
Core file functions |
DESCRIPTION |
These are functions pertaining to core files. |
*/ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
/* |
FUNCTION |
bfd_core_file_failing_command |
SYNOPSIS |
const char *bfd_core_file_failing_command (bfd *abfd); |
DESCRIPTION |
Return a read-only string explaining which program was running |
when it failed and produced the core file @var{abfd}. |
*/ |
const char * |
bfd_core_file_failing_command (bfd *abfd) |
{ |
if (abfd->format != bfd_core) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return NULL; |
} |
return BFD_SEND (abfd, _core_file_failing_command, (abfd)); |
} |
/* |
FUNCTION |
bfd_core_file_failing_signal |
SYNOPSIS |
int bfd_core_file_failing_signal (bfd *abfd); |
DESCRIPTION |
Returns the signal number which caused the core dump which |
generated the file the BFD @var{abfd} is attached to. |
*/ |
int |
bfd_core_file_failing_signal (bfd *abfd) |
{ |
if (abfd->format != bfd_core) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return 0; |
} |
return BFD_SEND (abfd, _core_file_failing_signal, (abfd)); |
} |
/* |
FUNCTION |
bfd_core_file_pid |
SYNOPSIS |
int bfd_core_file_pid (bfd *abfd); |
DESCRIPTION |
Returns the PID of the process the core dump the BFD |
@var{abfd} is attached to was generated from. |
*/ |
int |
bfd_core_file_pid (bfd *abfd) |
{ |
if (abfd->format != bfd_core) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return 0; |
} |
return BFD_SEND (abfd, _core_file_pid, (abfd)); |
} |
/* |
FUNCTION |
core_file_matches_executable_p |
SYNOPSIS |
bfd_boolean core_file_matches_executable_p |
(bfd *core_bfd, bfd *exec_bfd); |
DESCRIPTION |
Return <<TRUE>> if the core file attached to @var{core_bfd} |
was generated by a run of the executable file attached to |
@var{exec_bfd}, <<FALSE>> otherwise. |
*/ |
bfd_boolean |
core_file_matches_executable_p (bfd *core_bfd, bfd *exec_bfd) |
{ |
if (core_bfd->format != bfd_core || exec_bfd->format != bfd_object) |
{ |
bfd_set_error (bfd_error_wrong_format); |
return FALSE; |
} |
return BFD_SEND (core_bfd, _core_file_matches_executable_p, |
(core_bfd, exec_bfd)); |
} |
/* |
FUNCTION |
generic_core_file_matches_executable_p |
SYNOPSIS |
bfd_boolean generic_core_file_matches_executable_p |
(bfd *core_bfd, bfd *exec_bfd); |
DESCRIPTION |
Return TRUE if the core file attached to @var{core_bfd} |
was generated by a run of the executable file attached |
to @var{exec_bfd}. The match is based on executable |
basenames only. |
Note: When not able to determine the core file failing |
command or the executable name, we still return TRUE even |
though we're not sure that core file and executable match. |
This is to avoid generating a false warning in situations |
where we really don't know whether they match or not. |
*/ |
bfd_boolean |
generic_core_file_matches_executable_p (bfd *core_bfd, bfd *exec_bfd) |
{ |
char *exec; |
char *core; |
char *last_slash; |
if (exec_bfd == NULL || core_bfd == NULL) |
return TRUE; |
/* The cast below is to avoid a compiler warning due to the assignment |
of the const char * returned by bfd_core_file_failing_command to a |
non-const char *. In this case, the assignement does not lead to |
breaking the const, as we're only reading the string. */ |
core = (char *) bfd_core_file_failing_command (core_bfd); |
if (core == NULL) |
return TRUE; |
exec = bfd_get_filename (exec_bfd); |
if (exec == NULL) |
return TRUE; |
last_slash = strrchr (core, '/'); |
if (last_slash != NULL) |
core = last_slash + 1; |
last_slash = strrchr (exec, '/'); |
if (last_slash != NULL) |
exec = last_slash + 1; |
return filename_cmp (exec, core) == 0; |
} |
/contrib/toolchain/binutils/bfd/cpu-i386.c |
---|
0,0 → 1,304 |
/* BFD support for the Intel 386 architecture. |
Copyright 1992, 1994, 1995, 1996, 1998, 2000, 2001, 2002, 2004, 2005, |
2007, 2009, 2010, 2011, 2013 |
Free Software Foundation, Inc. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
#include "libiberty.h" |
extern void * bfd_arch_i386_short_nop_fill (bfd_size_type, bfd_boolean, |
bfd_boolean); |
static const bfd_arch_info_type * |
bfd_i386_compatible (const bfd_arch_info_type *a, |
const bfd_arch_info_type *b) |
{ |
const bfd_arch_info_type *compat = bfd_default_compatible (a, b); |
/* Don't allow mixing x64_32 with x86_64. */ |
if (compat |
&& (a->mach & bfd_mach_x64_32) != (b->mach & bfd_mach_x64_32)) |
compat = NULL; |
return compat; |
} |
/* Fill the buffer with zero or nop instruction if CODE is TRUE. Use |
multi byte nop instructions if LONG_NOP is TRUE. */ |
static void * |
bfd_arch_i386_fill (bfd_size_type count, bfd_boolean code, |
bfd_boolean long_nop) |
{ |
/* nop */ |
static const char nop_1[] = { 0x90 }; |
/* xchg %ax,%ax */ |
static const char nop_2[] = { 0x66, 0x90 }; |
/* nopl (%[re]ax) */ |
static const char nop_3[] = { 0x0f, 0x1f, 0x00 }; |
/* nopl 0(%[re]ax) */ |
static const char nop_4[] = { 0x0f, 0x1f, 0x40, 0x00 }; |
/* nopl 0(%[re]ax,%[re]ax,1) */ |
static const char nop_5[] = { 0x0f, 0x1f, 0x44, 0x00, 0x00 }; |
/* nopw 0(%[re]ax,%[re]ax,1) */ |
static const char nop_6[] = { 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00 }; |
/* nopl 0L(%[re]ax) */ |
static const char nop_7[] = { 0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00 }; |
/* nopl 0L(%[re]ax,%[re]ax,1) */ |
static const char nop_8[] = |
{ 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}; |
/* nopw 0L(%[re]ax,%[re]ax,1) */ |
static const char nop_9[] = |
{ 0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 }; |
/* nopw %cs:0L(%[re]ax,%[re]ax,1) */ |
static const char nop_10[] = |
{ 0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 }; |
static const char *const nops[] = |
{ nop_1, nop_2, nop_3, nop_4, nop_5, |
nop_6, nop_7, nop_8, nop_9, nop_10 }; |
bfd_size_type nop_size = long_nop ? ARRAY_SIZE (nops) : 2; |
void *fill = bfd_malloc (count); |
if (fill == NULL) |
return fill; |
if (code) |
{ |
bfd_byte *p = fill; |
while (count >= nop_size) |
{ |
memcpy (p, nops[nop_size - 1], nop_size); |
p += nop_size; |
count -= nop_size; |
} |
if (count != 0) |
memcpy (p, nops[count - 1], count); |
} |
else |
memset (fill, 0, count); |
return fill; |
} |
/* Fill the buffer with zero or short nop instruction if CODE is TRUE. */ |
void * |
bfd_arch_i386_short_nop_fill (bfd_size_type count, |
bfd_boolean is_bigendian ATTRIBUTE_UNUSED, |
bfd_boolean code) |
{ |
return bfd_arch_i386_fill (count, code, FALSE); |
} |
/* Fill the buffer with zero or long nop instruction if CODE is TRUE. */ |
static void * |
bfd_arch_i386_long_nop_fill (bfd_size_type count, |
bfd_boolean is_bigendian ATTRIBUTE_UNUSED, |
bfd_boolean code) |
{ |
return bfd_arch_i386_fill (count, code, TRUE); |
} |
/* Fill the buffer with zero, or one-byte nop instructions if CODE is TRUE. */ |
static void * |
bfd_arch_i386_onebyte_nop_fill (bfd_size_type count, |
bfd_boolean is_bigendian ATTRIBUTE_UNUSED, |
bfd_boolean code) |
{ |
void *fill = bfd_malloc (count); |
if (fill != NULL) |
memset (fill, code ? 0x90 : 0, count); |
return fill; |
} |
static const bfd_arch_info_type bfd_x64_32_nacl_arch = |
{ |
64, /* 64 bits in a word */ |
64, /* 64 bits in an address */ |
8, /* 8 bits in a byte */ |
bfd_arch_i386, |
bfd_mach_x64_32_nacl, |
"i386", |
"i386:x64-32:nacl", |
3, |
FALSE, |
bfd_i386_compatible, |
bfd_default_scan, |
bfd_arch_i386_onebyte_nop_fill, |
NULL |
}; |
static const bfd_arch_info_type bfd_x86_64_nacl_arch = |
{ |
64, /* 64 bits in a word */ |
64, /* 64 bits in an address */ |
8, /* 8 bits in a byte */ |
bfd_arch_i386, |
bfd_mach_x86_64_nacl, |
"i386", |
"i386:x86-64:nacl", |
3, |
FALSE, |
bfd_i386_compatible, |
bfd_default_scan, |
bfd_arch_i386_onebyte_nop_fill, |
&bfd_x64_32_nacl_arch |
}; |
const bfd_arch_info_type bfd_i386_nacl_arch = |
{ |
32, /* 32 bits in a word */ |
32, /* 32 bits in an address */ |
8, /* 8 bits in a byte */ |
bfd_arch_i386, |
bfd_mach_i386_i386_nacl, |
"i386", |
"i386:nacl", |
3, |
TRUE, |
bfd_i386_compatible, |
bfd_default_scan, |
bfd_arch_i386_onebyte_nop_fill, |
&bfd_x86_64_nacl_arch |
}; |
static const bfd_arch_info_type bfd_x64_32_arch_intel_syntax = |
{ |
64, /* 64 bits in a word */ |
64, /* 64 bits in an address */ |
8, /* 8 bits in a byte */ |
bfd_arch_i386, |
bfd_mach_x64_32_intel_syntax, |
"i386:intel", |
"i386:x64-32:intel", |
3, |
FALSE, |
bfd_i386_compatible, |
bfd_default_scan, |
bfd_arch_i386_long_nop_fill, |
&bfd_i386_nacl_arch |
}; |
static const bfd_arch_info_type bfd_x86_64_arch_intel_syntax = |
{ |
64, /* 64 bits in a word */ |
64, /* 64 bits in an address */ |
8, /* 8 bits in a byte */ |
bfd_arch_i386, |
bfd_mach_x86_64_intel_syntax, |
"i386:intel", |
"i386:x86-64:intel", |
3, |
FALSE, |
bfd_i386_compatible, |
bfd_default_scan, |
bfd_arch_i386_long_nop_fill, |
&bfd_x64_32_arch_intel_syntax, |
}; |
static const bfd_arch_info_type bfd_i386_arch_intel_syntax = |
{ |
32, /* 32 bits in a word */ |
32, /* 32 bits in an address */ |
8, /* 8 bits in a byte */ |
bfd_arch_i386, |
bfd_mach_i386_i386_intel_syntax, |
"i386:intel", |
"i386:intel", |
3, |
TRUE, |
bfd_i386_compatible, |
bfd_default_scan, |
bfd_arch_i386_short_nop_fill, |
&bfd_x86_64_arch_intel_syntax |
}; |
static const bfd_arch_info_type i8086_arch = |
{ |
32, /* 32 bits in a word */ |
32, /* 32 bits in an address (well, not really) */ |
8, /* 8 bits in a byte */ |
bfd_arch_i386, |
bfd_mach_i386_i8086, |
"i8086", |
"i8086", |
3, |
FALSE, |
bfd_i386_compatible, |
bfd_default_scan, |
bfd_arch_i386_short_nop_fill, |
&bfd_i386_arch_intel_syntax |
}; |
static const bfd_arch_info_type bfd_x64_32_arch = |
{ |
64, /* 64 bits in a word */ |
64, /* 64 bits in an address */ |
8, /* 8 bits in a byte */ |
bfd_arch_i386, |
bfd_mach_x64_32, |
"i386", |
"i386:x64-32", |
3, |
FALSE, |
bfd_i386_compatible, |
bfd_default_scan, |
bfd_arch_i386_long_nop_fill, |
&i8086_arch |
}; |
static const bfd_arch_info_type bfd_x86_64_arch = |
{ |
64, /* 64 bits in a word */ |
64, /* 64 bits in an address */ |
8, /* 8 bits in a byte */ |
bfd_arch_i386, |
bfd_mach_x86_64, |
"i386", |
"i386:x86-64", |
3, |
FALSE, |
bfd_i386_compatible, |
bfd_default_scan, |
bfd_arch_i386_long_nop_fill, |
&bfd_x64_32_arch |
}; |
const bfd_arch_info_type bfd_i386_arch = |
{ |
32, /* 32 bits in a word */ |
32, /* 32 bits in an address */ |
8, /* 8 bits in a byte */ |
bfd_arch_i386, |
bfd_mach_i386_i386, |
"i386", |
"i386", |
3, |
TRUE, |
bfd_i386_compatible, |
bfd_default_scan, |
bfd_arch_i386_short_nop_fill, |
&bfd_x86_64_arch |
}; |
/contrib/toolchain/binutils/bfd/dwarf1.c |
---|
0,0 → 1,564 |
/* DWARF 1 find nearest line (_bfd_dwarf1_find_nearest_line). |
Copyright 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2007, 2008, 2009, 2010 |
Free Software Foundation, Inc. |
Written by Gavin Romig-Koch of Cygnus Solutions (gavin@cygnus.com). |
This file is part of BFD. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or (at |
your option) any later version. |
This program is distributed in the hope that it will be useful, but |
WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libiberty.h" |
#include "libbfd.h" |
#include "elf-bfd.h" |
#include "elf/dwarf.h" |
/* dwarf1_debug is the starting point for all dwarf1 info. */ |
struct dwarf1_debug |
{ |
/* The bfd we are working with. */ |
bfd* abfd; |
/* Pointer to the symbol table. */ |
asymbol** syms; |
/* List of already parsed compilation units. */ |
struct dwarf1_unit* lastUnit; |
/* The buffer for the .debug section. |
Zero indicates that the .debug section failed to load. */ |
bfd_byte *debug_section; |
/* Pointer to the end of the .debug_info section memory buffer. */ |
bfd_byte *debug_section_end; |
/* The buffer for the .line section. */ |
bfd_byte *line_section; |
/* End of that buffer. */ |
bfd_byte *line_section_end; |
/* The current or next unread die within the .debug section. */ |
bfd_byte *currentDie; |
}; |
/* One dwarf1_unit for each parsed compilation unit die. */ |
struct dwarf1_unit |
{ |
/* Linked starting from stash->lastUnit. */ |
struct dwarf1_unit* prev; |
/* Name of the compilation unit. */ |
char *name; |
/* The highest and lowest address used in the compilation unit. */ |
unsigned long low_pc; |
unsigned long high_pc; |
/* Does this unit have a statement list? */ |
int has_stmt_list; |
/* If any, the offset of the line number table in the .line section. */ |
unsigned long stmt_list_offset; |
/* If non-zero, a pointer to the first child of this unit. */ |
bfd_byte *first_child; |
/* How many line entries? */ |
unsigned long line_count; |
/* The decoded line number table (line_count entries). */ |
struct linenumber* linenumber_table; |
/* The list of functions in this unit. */ |
struct dwarf1_func* func_list; |
}; |
/* One dwarf1_func for each parsed function die. */ |
struct dwarf1_func |
{ |
/* Linked starting from aUnit->func_list. */ |
struct dwarf1_func* prev; |
/* Name of function. */ |
char* name; |
/* The highest and lowest address used in the compilation unit. */ |
unsigned long low_pc; |
unsigned long high_pc; |
}; |
/* Used to return info about a parsed die. */ |
struct die_info |
{ |
unsigned long length; |
unsigned long sibling; |
unsigned long low_pc; |
unsigned long high_pc; |
unsigned long stmt_list_offset; |
char* name; |
int has_stmt_list; |
unsigned short tag; |
}; |
/* Parsed line number information. */ |
struct linenumber |
{ |
/* First address in the line. */ |
unsigned long addr; |
/* The line number. */ |
unsigned long linenumber; |
}; |
/* Find the form of an attr, from the attr field. */ |
#define FORM_FROM_ATTR(attr) ((attr) & 0xF) /* Implicitly specified. */ |
/* Return a newly allocated dwarf1_unit. It should be cleared and |
then attached into the 'stash' at 'stash->lastUnit'. */ |
static struct dwarf1_unit* |
alloc_dwarf1_unit (struct dwarf1_debug* stash) |
{ |
bfd_size_type amt = sizeof (struct dwarf1_unit); |
struct dwarf1_unit* x = (struct dwarf1_unit *) bfd_zalloc (stash->abfd, amt); |
if (x) |
{ |
x->prev = stash->lastUnit; |
stash->lastUnit = x; |
} |
return x; |
} |
/* Return a newly allocated dwarf1_func. It must be cleared and |
attached into 'aUnit' at 'aUnit->func_list'. */ |
static struct dwarf1_func * |
alloc_dwarf1_func (struct dwarf1_debug* stash, struct dwarf1_unit* aUnit) |
{ |
bfd_size_type amt = sizeof (struct dwarf1_func); |
struct dwarf1_func* x = (struct dwarf1_func *) bfd_zalloc (stash->abfd, amt); |
if (x) |
{ |
x->prev = aUnit->func_list; |
aUnit->func_list = x; |
} |
return x; |
} |
/* parse_die - parse a Dwarf1 die. |
Parse the die starting at 'aDiePtr' into 'aDieInfo'. |
'abfd' must be the bfd from which the section that 'aDiePtr' |
points to was pulled from. |
Return FALSE if the die is invalidly formatted; TRUE otherwise. */ |
static bfd_boolean |
parse_die (bfd * abfd, |
struct die_info * aDieInfo, |
bfd_byte * aDiePtr, |
bfd_byte * aDiePtrEnd) |
{ |
bfd_byte *this_die = aDiePtr; |
bfd_byte *xptr = this_die; |
memset (aDieInfo, 0, sizeof (* aDieInfo)); |
/* First comes the length. */ |
aDieInfo->length = bfd_get_32 (abfd, (bfd_byte *) xptr); |
xptr += 4; |
if (aDieInfo->length == 0 |
|| (this_die + aDieInfo->length) >= aDiePtrEnd) |
return FALSE; |
if (aDieInfo->length < 6) |
{ |
/* Just padding bytes. */ |
aDieInfo->tag = TAG_padding; |
return TRUE; |
} |
/* Then the tag. */ |
aDieInfo->tag = bfd_get_16 (abfd, (bfd_byte *) xptr); |
xptr += 2; |
/* Then the attributes. */ |
while (xptr < (this_die + aDieInfo->length)) |
{ |
unsigned short attr; |
/* Parse the attribute based on its form. This section |
must handle all dwarf1 forms, but need only handle the |
actual attributes that we care about. */ |
attr = bfd_get_16 (abfd, (bfd_byte *) xptr); |
xptr += 2; |
switch (FORM_FROM_ATTR (attr)) |
{ |
case FORM_DATA2: |
xptr += 2; |
break; |
case FORM_DATA4: |
case FORM_REF: |
if (attr == AT_sibling) |
aDieInfo->sibling = bfd_get_32 (abfd, (bfd_byte *) xptr); |
else if (attr == AT_stmt_list) |
{ |
aDieInfo->stmt_list_offset = bfd_get_32 (abfd, (bfd_byte *) xptr); |
aDieInfo->has_stmt_list = 1; |
} |
xptr += 4; |
break; |
case FORM_DATA8: |
xptr += 8; |
break; |
case FORM_ADDR: |
if (attr == AT_low_pc) |
aDieInfo->low_pc = bfd_get_32 (abfd, (bfd_byte *) xptr); |
else if (attr == AT_high_pc) |
aDieInfo->high_pc = bfd_get_32 (abfd, (bfd_byte *) xptr); |
xptr += 4; |
break; |
case FORM_BLOCK2: |
xptr += 2 + bfd_get_16 (abfd, (bfd_byte *) xptr); |
break; |
case FORM_BLOCK4: |
xptr += 4 + bfd_get_32 (abfd, (bfd_byte *) xptr); |
break; |
case FORM_STRING: |
if (attr == AT_name) |
aDieInfo->name = (char *) xptr; |
xptr += strlen ((char *) xptr) + 1; |
break; |
} |
} |
return TRUE; |
} |
/* Parse a dwarf1 line number table for 'aUnit->stmt_list_offset' |
into 'aUnit->linenumber_table'. Return FALSE if an error |
occurs; TRUE otherwise. */ |
static bfd_boolean |
parse_line_table (struct dwarf1_debug* stash, struct dwarf1_unit* aUnit) |
{ |
bfd_byte *xptr; |
/* Load the ".line" section from the bfd if we haven't already. */ |
if (stash->line_section == 0) |
{ |
asection *msec; |
bfd_size_type size; |
msec = bfd_get_section_by_name (stash->abfd, ".line"); |
if (! msec) |
return FALSE; |
size = msec->rawsize ? msec->rawsize : msec->size; |
stash->line_section |
= bfd_simple_get_relocated_section_contents |
(stash->abfd, msec, NULL, stash->syms); |
if (! stash->line_section) |
return FALSE; |
stash->line_section_end = stash->line_section + size; |
} |
xptr = stash->line_section + aUnit->stmt_list_offset; |
if (xptr < stash->line_section_end) |
{ |
unsigned long eachLine; |
bfd_byte *tblend; |
unsigned long base; |
bfd_size_type amt; |
/* First comes the length. */ |
tblend = bfd_get_32 (stash->abfd, (bfd_byte *) xptr) + xptr; |
xptr += 4; |
/* Then the base address for each address in the table. */ |
base = bfd_get_32 (stash->abfd, (bfd_byte *) xptr); |
xptr += 4; |
/* How many line entrys? |
10 = 4 (line number) + 2 (pos in line) + 4 (address in line). */ |
aUnit->line_count = (tblend - xptr) / 10; |
/* Allocate an array for the entries. */ |
amt = sizeof (struct linenumber) * aUnit->line_count; |
aUnit->linenumber_table = (struct linenumber *) bfd_alloc (stash->abfd, |
amt); |
if (!aUnit->linenumber_table) |
return FALSE; |
for (eachLine = 0; eachLine < aUnit->line_count; eachLine++) |
{ |
/* A line number. */ |
aUnit->linenumber_table[eachLine].linenumber |
= bfd_get_32 (stash->abfd, (bfd_byte *) xptr); |
xptr += 4; |
/* Skip the position within the line. */ |
xptr += 2; |
/* And finally the address. */ |
aUnit->linenumber_table[eachLine].addr |
= base + bfd_get_32 (stash->abfd, (bfd_byte *) xptr); |
xptr += 4; |
} |
} |
return TRUE; |
} |
/* Parse each function die in a compilation unit 'aUnit'. |
The first child die of 'aUnit' should be in 'aUnit->first_child', |
the result is placed in 'aUnit->func_list'. |
Return FALSE if error; TRUE otherwise. */ |
static bfd_boolean |
parse_functions_in_unit (struct dwarf1_debug* stash, struct dwarf1_unit* aUnit) |
{ |
bfd_byte *eachDie; |
if (aUnit->first_child) |
for (eachDie = aUnit->first_child; |
eachDie < stash->debug_section_end; |
) |
{ |
struct die_info eachDieInfo; |
if (! parse_die (stash->abfd, &eachDieInfo, eachDie, |
stash->debug_section_end)) |
return FALSE; |
if (eachDieInfo.tag == TAG_global_subroutine |
|| eachDieInfo.tag == TAG_subroutine |
|| eachDieInfo.tag == TAG_inlined_subroutine |
|| eachDieInfo.tag == TAG_entry_point) |
{ |
struct dwarf1_func* aFunc = alloc_dwarf1_func (stash,aUnit); |
if (!aFunc) |
return FALSE; |
aFunc->name = eachDieInfo.name; |
aFunc->low_pc = eachDieInfo.low_pc; |
aFunc->high_pc = eachDieInfo.high_pc; |
} |
/* Move to next sibling, if none, end loop */ |
if (eachDieInfo.sibling) |
eachDie = stash->debug_section + eachDieInfo.sibling; |
else |
break; |
} |
return TRUE; |
} |
/* Find the nearest line to 'addr' in 'aUnit'. |
Return whether we found the line (or a function) without error. */ |
static bfd_boolean |
dwarf1_unit_find_nearest_line (struct dwarf1_debug* stash, |
struct dwarf1_unit* aUnit, |
unsigned long addr, |
const char **filename_ptr, |
const char **functionname_ptr, |
unsigned int *linenumber_ptr) |
{ |
int line_p = FALSE; |
int func_p = FALSE; |
if (aUnit->low_pc <= addr && addr < aUnit->high_pc) |
{ |
if (aUnit->has_stmt_list) |
{ |
unsigned long i; |
struct dwarf1_func* eachFunc; |
if (! aUnit->linenumber_table) |
{ |
if (! parse_line_table (stash, aUnit)) |
return FALSE; |
} |
if (! aUnit->func_list) |
{ |
if (! parse_functions_in_unit (stash, aUnit)) |
return FALSE; |
} |
for (i = 0; i < aUnit->line_count; i++) |
{ |
if (aUnit->linenumber_table[i].addr <= addr |
&& addr < aUnit->linenumber_table[i+1].addr) |
{ |
*filename_ptr = aUnit->name; |
*linenumber_ptr = aUnit->linenumber_table[i].linenumber; |
line_p = TRUE; |
break; |
} |
} |
for (eachFunc = aUnit->func_list; |
eachFunc; |
eachFunc = eachFunc->prev) |
{ |
if (eachFunc->low_pc <= addr |
&& addr < eachFunc->high_pc) |
{ |
*functionname_ptr = eachFunc->name; |
func_p = TRUE; |
break; |
} |
} |
} |
} |
return line_p || func_p; |
} |
/* The DWARF 1 version of find_nearest line. |
Return TRUE if the line is found without error. */ |
bfd_boolean |
_bfd_dwarf1_find_nearest_line (bfd *abfd, |
asection *section, |
asymbol **symbols, |
bfd_vma offset, |
const char **filename_ptr, |
const char **functionname_ptr, |
unsigned int *linenumber_ptr) |
{ |
struct dwarf1_debug *stash = elf_tdata (abfd)->dwarf1_find_line_info; |
struct dwarf1_unit* eachUnit; |
/* What address are we looking for? */ |
unsigned long addr = (unsigned long)(offset + section->vma); |
*filename_ptr = NULL; |
*functionname_ptr = NULL; |
*linenumber_ptr = 0; |
if (! stash) |
{ |
asection *msec; |
bfd_size_type size = sizeof (struct dwarf1_debug); |
stash = elf_tdata (abfd)->dwarf1_find_line_info |
= (struct dwarf1_debug *) bfd_zalloc (abfd, size); |
if (! stash) |
return FALSE; |
msec = bfd_get_section_by_name (abfd, ".debug"); |
if (! msec) |
/* No dwarf1 info. Note that at this point the stash |
has been allocated, but contains zeros, this lets |
future calls to this function fail quicker. */ |
return FALSE; |
size = msec->rawsize ? msec->rawsize : msec->size; |
stash->debug_section |
= bfd_simple_get_relocated_section_contents (abfd, msec, NULL, |
symbols); |
if (! stash->debug_section) |
return FALSE; |
stash->debug_section_end = stash->debug_section + size; |
stash->currentDie = stash->debug_section; |
stash->abfd = abfd; |
stash->syms = symbols; |
} |
/* A null debug_section indicates that there was no dwarf1 info |
or that an error occured while setting up the stash. */ |
if (! stash->debug_section) |
return FALSE; |
/* Look at the previously parsed units to see if any contain |
the addr. */ |
for (eachUnit = stash->lastUnit; eachUnit; eachUnit = eachUnit->prev) |
if (eachUnit->low_pc <= addr && addr < eachUnit->high_pc) |
return dwarf1_unit_find_nearest_line (stash, eachUnit, addr, |
filename_ptr, |
functionname_ptr, |
linenumber_ptr); |
while (stash->currentDie < stash->debug_section_end) |
{ |
struct die_info aDieInfo; |
if (! parse_die (stash->abfd, &aDieInfo, stash->currentDie, |
stash->debug_section_end)) |
return FALSE; |
if (aDieInfo.tag == TAG_compile_unit) |
{ |
struct dwarf1_unit* aUnit |
= alloc_dwarf1_unit (stash); |
if (!aUnit) |
return FALSE; |
aUnit->name = aDieInfo.name; |
aUnit->low_pc = aDieInfo.low_pc; |
aUnit->high_pc = aDieInfo.high_pc; |
aUnit->has_stmt_list = aDieInfo.has_stmt_list; |
aUnit->stmt_list_offset = aDieInfo.stmt_list_offset; |
/* A die has a child if it's followed by a die that is |
not it's sibling. */ |
if (aDieInfo.sibling |
&& stash->currentDie + aDieInfo.length |
< stash->debug_section_end |
&& stash->currentDie + aDieInfo.length |
!= stash->debug_section + aDieInfo.sibling) |
aUnit->first_child = stash->currentDie + aDieInfo.length; |
else |
aUnit->first_child = 0; |
if (aUnit->low_pc <= addr && addr < aUnit->high_pc) |
return dwarf1_unit_find_nearest_line (stash, aUnit, addr, |
filename_ptr, |
functionname_ptr, |
linenumber_ptr); |
} |
if (aDieInfo.sibling != 0) |
stash->currentDie = stash->debug_section + aDieInfo.sibling; |
else |
stash->currentDie += aDieInfo.length; |
} |
return FALSE; |
} |
/contrib/toolchain/binutils/bfd/dwarf2.c |
---|
0,0 → 1,3833 |
/* DWARF 2 support. |
Copyright 1994-2013 Free Software Foundation, Inc. |
Adapted from gdb/dwarf2read.c by Gavin Koch of Cygnus Solutions |
(gavin@cygnus.com). |
From the dwarf2read.c header: |
Adapted by Gary Funck (gary@intrepid.com), Intrepid Technology, |
Inc. with support from Florida State University (under contract |
with the Ada Joint Program Office), and Silicon Graphics, Inc. |
Initial contribution by Brent Benson, Harris Computer Systems, Inc., |
based on Fred Fish's (Cygnus Support) implementation of DWARF 1 |
support in dwarfread.c |
This file is part of BFD. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or (at |
your option) any later version. |
This program is distributed in the hope that it will be useful, but |
WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libiberty.h" |
#include "libbfd.h" |
#include "elf-bfd.h" |
#include "dwarf2.h" |
/* The data in the .debug_line statement prologue looks like this. */ |
struct line_head |
{ |
bfd_vma total_length; |
unsigned short version; |
bfd_vma prologue_length; |
unsigned char minimum_instruction_length; |
unsigned char maximum_ops_per_insn; |
unsigned char default_is_stmt; |
int line_base; |
unsigned char line_range; |
unsigned char opcode_base; |
unsigned char *standard_opcode_lengths; |
}; |
/* Attributes have a name and a value. */ |
struct attribute |
{ |
enum dwarf_attribute name; |
enum dwarf_form form; |
union |
{ |
char *str; |
struct dwarf_block *blk; |
bfd_uint64_t val; |
bfd_int64_t sval; |
} |
u; |
}; |
/* Blocks are a bunch of untyped bytes. */ |
struct dwarf_block |
{ |
unsigned int size; |
bfd_byte *data; |
}; |
struct adjusted_section |
{ |
asection *section; |
bfd_vma adj_vma; |
}; |
struct dwarf2_debug |
{ |
/* A list of all previously read comp_units. */ |
struct comp_unit *all_comp_units; |
/* Last comp unit in list above. */ |
struct comp_unit *last_comp_unit; |
/* Names of the debug sections. */ |
const struct dwarf_debug_section *debug_sections; |
/* The next unread compilation unit within the .debug_info section. |
Zero indicates that the .debug_info section has not been loaded |
into a buffer yet. */ |
bfd_byte *info_ptr; |
/* Pointer to the end of the .debug_info section memory buffer. */ |
bfd_byte *info_ptr_end; |
/* Pointer to the bfd, section and address of the beginning of the |
section. The bfd might be different than expected because of |
gnu_debuglink sections. */ |
bfd *bfd_ptr; |
asection *sec; |
bfd_byte *sec_info_ptr; |
/* Support for alternate debug info sections created by the DWZ utility: |
This includes a pointer to an alternate bfd which contains *extra*, |
possibly duplicate debug sections, and pointers to the loaded |
.debug_str and .debug_info sections from this bfd. */ |
bfd * alt_bfd_ptr; |
bfd_byte * alt_dwarf_str_buffer; |
bfd_size_type alt_dwarf_str_size; |
bfd_byte * alt_dwarf_info_buffer; |
bfd_size_type alt_dwarf_info_size; |
/* A pointer to the memory block allocated for info_ptr. Neither |
info_ptr nor sec_info_ptr are guaranteed to stay pointing to the |
beginning of the malloc block. This is used only to free the |
memory later. */ |
bfd_byte *info_ptr_memory; |
/* Pointer to the symbol table. */ |
asymbol **syms; |
/* Pointer to the .debug_abbrev section loaded into memory. */ |
bfd_byte *dwarf_abbrev_buffer; |
/* Length of the loaded .debug_abbrev section. */ |
bfd_size_type dwarf_abbrev_size; |
/* Buffer for decode_line_info. */ |
bfd_byte *dwarf_line_buffer; |
/* Length of the loaded .debug_line section. */ |
bfd_size_type dwarf_line_size; |
/* Pointer to the .debug_str section loaded into memory. */ |
bfd_byte *dwarf_str_buffer; |
/* Length of the loaded .debug_str section. */ |
bfd_size_type dwarf_str_size; |
/* Pointer to the .debug_ranges section loaded into memory. */ |
bfd_byte *dwarf_ranges_buffer; |
/* Length of the loaded .debug_ranges section. */ |
bfd_size_type dwarf_ranges_size; |
/* If the most recent call to bfd_find_nearest_line was given an |
address in an inlined function, preserve a pointer into the |
calling chain for subsequent calls to bfd_find_inliner_info to |
use. */ |
struct funcinfo *inliner_chain; |
/* Number of sections whose VMA we must adjust. */ |
unsigned int adjusted_section_count; |
/* Array of sections with adjusted VMA. */ |
struct adjusted_section *adjusted_sections; |
/* Number of times find_line is called. This is used in |
the heuristic for enabling the info hash tables. */ |
int info_hash_count; |
#define STASH_INFO_HASH_TRIGGER 100 |
/* Hash table mapping symbol names to function infos. */ |
struct info_hash_table *funcinfo_hash_table; |
/* Hash table mapping symbol names to variable infos. */ |
struct info_hash_table *varinfo_hash_table; |
/* Head of comp_unit list in the last hash table update. */ |
struct comp_unit *hash_units_head; |
/* Status of info hash. */ |
int info_hash_status; |
#define STASH_INFO_HASH_OFF 0 |
#define STASH_INFO_HASH_ON 1 |
#define STASH_INFO_HASH_DISABLED 2 |
/* True if we opened bfd_ptr. */ |
bfd_boolean close_on_cleanup; |
}; |
struct arange |
{ |
struct arange *next; |
bfd_vma low; |
bfd_vma high; |
}; |
/* A minimal decoding of DWARF2 compilation units. We only decode |
what's needed to get to the line number information. */ |
struct comp_unit |
{ |
/* Chain the previously read compilation units. */ |
struct comp_unit *next_unit; |
/* Likewise, chain the compilation unit read after this one. |
The comp units are stored in reversed reading order. */ |
struct comp_unit *prev_unit; |
/* Keep the bfd convenient (for memory allocation). */ |
bfd *abfd; |
/* The lowest and highest addresses contained in this compilation |
unit as specified in the compilation unit header. */ |
struct arange arange; |
/* The DW_AT_name attribute (for error messages). */ |
char *name; |
/* The abbrev hash table. */ |
struct abbrev_info **abbrevs; |
/* Note that an error was found by comp_unit_find_nearest_line. */ |
int error; |
/* The DW_AT_comp_dir attribute. */ |
char *comp_dir; |
/* TRUE if there is a line number table associated with this comp. unit. */ |
int stmtlist; |
/* Pointer to the current comp_unit so that we can find a given entry |
by its reference. */ |
bfd_byte *info_ptr_unit; |
/* Pointer to the start of the debug section, for DW_FORM_ref_addr. */ |
bfd_byte *sec_info_ptr; |
/* The offset into .debug_line of the line number table. */ |
unsigned long line_offset; |
/* Pointer to the first child die for the comp unit. */ |
bfd_byte *first_child_die_ptr; |
/* The end of the comp unit. */ |
bfd_byte *end_ptr; |
/* The decoded line number, NULL if not yet decoded. */ |
struct line_info_table *line_table; |
/* A list of the functions found in this comp. unit. */ |
struct funcinfo *function_table; |
/* A list of the variables found in this comp. unit. */ |
struct varinfo *variable_table; |
/* Pointer to dwarf2_debug structure. */ |
struct dwarf2_debug *stash; |
/* DWARF format version for this unit - from unit header. */ |
int version; |
/* Address size for this unit - from unit header. */ |
unsigned char addr_size; |
/* Offset size for this unit - from unit header. */ |
unsigned char offset_size; |
/* Base address for this unit - from DW_AT_low_pc attribute of |
DW_TAG_compile_unit DIE */ |
bfd_vma base_address; |
/* TRUE if symbols are cached in hash table for faster lookup by name. */ |
bfd_boolean cached; |
}; |
/* This data structure holds the information of an abbrev. */ |
struct abbrev_info |
{ |
unsigned int number; /* Number identifying abbrev. */ |
enum dwarf_tag tag; /* DWARF tag. */ |
int has_children; /* Boolean. */ |
unsigned int num_attrs; /* Number of attributes. */ |
struct attr_abbrev *attrs; /* An array of attribute descriptions. */ |
struct abbrev_info *next; /* Next in chain. */ |
}; |
struct attr_abbrev |
{ |
enum dwarf_attribute name; |
enum dwarf_form form; |
}; |
/* Map of uncompressed DWARF debug section name to compressed one. It |
is terminated by NULL uncompressed_name. */ |
const struct dwarf_debug_section dwarf_debug_sections[] = |
{ |
{ ".debug_abbrev", ".zdebug_abbrev" }, |
{ ".debug_aranges", ".zdebug_aranges" }, |
{ ".debug_frame", ".zdebug_frame" }, |
{ ".debug_info", ".zdebug_info" }, |
{ ".debug_info", ".zdebug_info" }, |
{ ".debug_line", ".zdebug_line" }, |
{ ".debug_loc", ".zdebug_loc" }, |
{ ".debug_macinfo", ".zdebug_macinfo" }, |
{ ".debug_macro", ".zdebug_macro" }, |
{ ".debug_pubnames", ".zdebug_pubnames" }, |
{ ".debug_pubtypes", ".zdebug_pubtypes" }, |
{ ".debug_ranges", ".zdebug_ranges" }, |
{ ".debug_static_func", ".zdebug_static_func" }, |
{ ".debug_static_vars", ".zdebug_static_vars" }, |
{ ".debug_str", ".zdebug_str", }, |
{ ".debug_str", ".zdebug_str", }, |
{ ".debug_types", ".zdebug_types" }, |
/* GNU DWARF 1 extensions */ |
{ ".debug_sfnames", ".zdebug_sfnames" }, |
{ ".debug_srcinfo", ".zebug_srcinfo" }, |
/* SGI/MIPS DWARF 2 extensions */ |
{ ".debug_funcnames", ".zdebug_funcnames" }, |
{ ".debug_typenames", ".zdebug_typenames" }, |
{ ".debug_varnames", ".zdebug_varnames" }, |
{ ".debug_weaknames", ".zdebug_weaknames" }, |
{ NULL, NULL }, |
}; |
/* NB/ Numbers in this enum must match up with indicies |
into the dwarf_debug_sections[] array above. */ |
enum dwarf_debug_section_enum |
{ |
debug_abbrev = 0, |
debug_aranges, |
debug_frame, |
debug_info, |
debug_info_alt, |
debug_line, |
debug_loc, |
debug_macinfo, |
debug_macro, |
debug_pubnames, |
debug_pubtypes, |
debug_ranges, |
debug_static_func, |
debug_static_vars, |
debug_str, |
debug_str_alt, |
debug_types, |
debug_sfnames, |
debug_srcinfo, |
debug_funcnames, |
debug_typenames, |
debug_varnames, |
debug_weaknames |
}; |
#ifndef ABBREV_HASH_SIZE |
#define ABBREV_HASH_SIZE 121 |
#endif |
#ifndef ATTR_ALLOC_CHUNK |
#define ATTR_ALLOC_CHUNK 4 |
#endif |
/* Variable and function hash tables. This is used to speed up look-up |
in lookup_symbol_in_var_table() and lookup_symbol_in_function_table(). |
In order to share code between variable and function infos, we use |
a list of untyped pointer for all variable/function info associated with |
a symbol. We waste a bit of memory for list with one node but that |
simplifies the code. */ |
struct info_list_node |
{ |
struct info_list_node *next; |
void *info; |
}; |
/* Info hash entry. */ |
struct info_hash_entry |
{ |
struct bfd_hash_entry root; |
struct info_list_node *head; |
}; |
struct info_hash_table |
{ |
struct bfd_hash_table base; |
}; |
/* Function to create a new entry in info hash table. */ |
static struct bfd_hash_entry * |
info_hash_table_newfunc (struct bfd_hash_entry *entry, |
struct bfd_hash_table *table, |
const char *string) |
{ |
struct info_hash_entry *ret = (struct info_hash_entry *) entry; |
/* Allocate the structure if it has not already been allocated by a |
derived class. */ |
if (ret == NULL) |
{ |
ret = (struct info_hash_entry *) bfd_hash_allocate (table, |
sizeof (* ret)); |
if (ret == NULL) |
return NULL; |
} |
/* Call the allocation method of the base class. */ |
ret = ((struct info_hash_entry *) |
bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); |
/* Initialize the local fields here. */ |
if (ret) |
ret->head = NULL; |
return (struct bfd_hash_entry *) ret; |
} |
/* Function to create a new info hash table. It returns a pointer to the |
newly created table or NULL if there is any error. We need abfd |
solely for memory allocation. */ |
static struct info_hash_table * |
create_info_hash_table (bfd *abfd) |
{ |
struct info_hash_table *hash_table; |
hash_table = ((struct info_hash_table *) |
bfd_alloc (abfd, sizeof (struct info_hash_table))); |
if (!hash_table) |
return hash_table; |
if (!bfd_hash_table_init (&hash_table->base, info_hash_table_newfunc, |
sizeof (struct info_hash_entry))) |
{ |
bfd_release (abfd, hash_table); |
return NULL; |
} |
return hash_table; |
} |
/* Insert an info entry into an info hash table. We do not check of |
duplicate entries. Also, the caller need to guarantee that the |
right type of info in inserted as info is passed as a void* pointer. |
This function returns true if there is no error. */ |
static bfd_boolean |
insert_info_hash_table (struct info_hash_table *hash_table, |
const char *key, |
void *info, |
bfd_boolean copy_p) |
{ |
struct info_hash_entry *entry; |
struct info_list_node *node; |
entry = (struct info_hash_entry*) bfd_hash_lookup (&hash_table->base, |
key, TRUE, copy_p); |
if (!entry) |
return FALSE; |
node = (struct info_list_node *) bfd_hash_allocate (&hash_table->base, |
sizeof (*node)); |
if (!node) |
return FALSE; |
node->info = info; |
node->next = entry->head; |
entry->head = node; |
return TRUE; |
} |
/* Look up an info entry list from an info hash table. Return NULL |
if there is none. */ |
static struct info_list_node * |
lookup_info_hash_table (struct info_hash_table *hash_table, const char *key) |
{ |
struct info_hash_entry *entry; |
entry = (struct info_hash_entry*) bfd_hash_lookup (&hash_table->base, key, |
FALSE, FALSE); |
return entry ? entry->head : NULL; |
} |
/* Read a section into its appropriate place in the dwarf2_debug |
struct (indicated by SECTION_BUFFER and SECTION_SIZE). If SYMS is |
not NULL, use bfd_simple_get_relocated_section_contents to read the |
section contents, otherwise use bfd_get_section_contents. Fail if |
the located section does not contain at least OFFSET bytes. */ |
static bfd_boolean |
read_section (bfd * abfd, |
const struct dwarf_debug_section *sec, |
asymbol ** syms, |
bfd_uint64_t offset, |
bfd_byte ** section_buffer, |
bfd_size_type * section_size) |
{ |
asection *msec; |
const char *section_name = sec->uncompressed_name; |
/* The section may have already been read. */ |
if (*section_buffer == NULL) |
{ |
msec = bfd_get_section_by_name (abfd, section_name); |
if (! msec) |
{ |
section_name = sec->compressed_name; |
if (section_name != NULL) |
msec = bfd_get_section_by_name (abfd, section_name); |
} |
if (! msec) |
{ |
(*_bfd_error_handler) (_("Dwarf Error: Can't find %s section."), |
sec->uncompressed_name); |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
*section_size = msec->rawsize ? msec->rawsize : msec->size; |
if (syms) |
{ |
*section_buffer |
= bfd_simple_get_relocated_section_contents (abfd, msec, NULL, syms); |
if (! *section_buffer) |
return FALSE; |
} |
else |
{ |
*section_buffer = (bfd_byte *) bfd_malloc (*section_size); |
if (! *section_buffer) |
return FALSE; |
if (! bfd_get_section_contents (abfd, msec, *section_buffer, |
0, *section_size)) |
return FALSE; |
} |
} |
/* It is possible to get a bad value for the offset into the section |
that the client wants. Validate it here to avoid trouble later. */ |
if (offset != 0 && offset >= *section_size) |
{ |
(*_bfd_error_handler) (_("Dwarf Error: Offset (%lu)" |
" greater than or equal to %s size (%lu)."), |
(long) offset, section_name, *section_size); |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
return TRUE; |
} |
/* VERBATIM |
The following function up to the END VERBATIM mark are |
copied directly from dwarf2read.c. */ |
/* Read dwarf information from a buffer. */ |
static unsigned int |
read_1_byte (bfd *abfd ATTRIBUTE_UNUSED, bfd_byte *buf) |
{ |
return bfd_get_8 (abfd, buf); |
} |
static int |
read_1_signed_byte (bfd *abfd ATTRIBUTE_UNUSED, bfd_byte *buf) |
{ |
return bfd_get_signed_8 (abfd, buf); |
} |
static unsigned int |
read_2_bytes (bfd *abfd, bfd_byte *buf) |
{ |
return bfd_get_16 (abfd, buf); |
} |
static unsigned int |
read_4_bytes (bfd *abfd, bfd_byte *buf) |
{ |
return bfd_get_32 (abfd, buf); |
} |
static bfd_uint64_t |
read_8_bytes (bfd *abfd, bfd_byte *buf) |
{ |
return bfd_get_64 (abfd, buf); |
} |
static bfd_byte * |
read_n_bytes (bfd *abfd ATTRIBUTE_UNUSED, |
bfd_byte *buf, |
unsigned int size ATTRIBUTE_UNUSED) |
{ |
return buf; |
} |
static char * |
read_string (bfd *abfd ATTRIBUTE_UNUSED, |
bfd_byte *buf, |
unsigned int *bytes_read_ptr) |
{ |
/* Return a pointer to the embedded string. */ |
char *str = (char *) buf; |
if (*str == '\0') |
{ |
*bytes_read_ptr = 1; |
return NULL; |
} |
*bytes_read_ptr = strlen (str) + 1; |
return str; |
} |
/* END VERBATIM */ |
static char * |
read_indirect_string (struct comp_unit * unit, |
bfd_byte * buf, |
unsigned int * bytes_read_ptr) |
{ |
bfd_uint64_t offset; |
struct dwarf2_debug *stash = unit->stash; |
char *str; |
if (unit->offset_size == 4) |
offset = read_4_bytes (unit->abfd, buf); |
else |
offset = read_8_bytes (unit->abfd, buf); |
*bytes_read_ptr = unit->offset_size; |
if (! read_section (unit->abfd, &stash->debug_sections[debug_str], |
stash->syms, offset, |
&stash->dwarf_str_buffer, &stash->dwarf_str_size)) |
return NULL; |
str = (char *) stash->dwarf_str_buffer + offset; |
if (*str == '\0') |
return NULL; |
return str; |
} |
/* Like read_indirect_string but uses a .debug_str located in |
an alternate filepointed to by the .gnu_debuglink section. |
Used to impement DW_FORM_GNU_strp_alt. */ |
static char * |
read_alt_indirect_string (struct comp_unit * unit, |
bfd_byte * buf, |
unsigned int * bytes_read_ptr) |
{ |
bfd_uint64_t offset; |
struct dwarf2_debug *stash = unit->stash; |
char *str; |
if (unit->offset_size == 4) |
offset = read_4_bytes (unit->abfd, buf); |
else |
offset = read_8_bytes (unit->abfd, buf); |
*bytes_read_ptr = unit->offset_size; |
if (stash->alt_bfd_ptr == NULL) |
{ |
bfd * debug_bfd; |
char * debug_filename = bfd_follow_gnu_debugaltlink (unit->abfd, DEBUGDIR); |
if (debug_filename == NULL) |
return NULL; |
if ((debug_bfd = bfd_openr (debug_filename, NULL)) == NULL |
|| ! bfd_check_format (debug_bfd, bfd_object)) |
{ |
if (debug_bfd) |
bfd_close (debug_bfd); |
/* FIXME: Should we report our failure to follow the debuglink ? */ |
free (debug_filename); |
return NULL; |
} |
stash->alt_bfd_ptr = debug_bfd; |
} |
if (! read_section (unit->stash->alt_bfd_ptr, |
stash->debug_sections + debug_str_alt, |
NULL, /* FIXME: Do we need to load alternate symbols ? */ |
offset, |
&stash->alt_dwarf_str_buffer, |
&stash->alt_dwarf_str_size)) |
return NULL; |
str = (char *) stash->alt_dwarf_str_buffer + offset; |
if (*str == '\0') |
return NULL; |
return str; |
} |
/* Resolve an alternate reference from UNIT at OFFSET. |
Returns a pointer into the loaded alternate CU upon success |
or NULL upon failure. */ |
static bfd_byte * |
read_alt_indirect_ref (struct comp_unit * unit, |
bfd_uint64_t offset) |
{ |
struct dwarf2_debug *stash = unit->stash; |
if (stash->alt_bfd_ptr == NULL) |
{ |
bfd * debug_bfd; |
char * debug_filename = bfd_follow_gnu_debugaltlink (unit->abfd, DEBUGDIR); |
if (debug_filename == NULL) |
return FALSE; |
if ((debug_bfd = bfd_openr (debug_filename, NULL)) == NULL |
|| ! bfd_check_format (debug_bfd, bfd_object)) |
{ |
if (debug_bfd) |
bfd_close (debug_bfd); |
/* FIXME: Should we report our failure to follow the debuglink ? */ |
free (debug_filename); |
return NULL; |
} |
stash->alt_bfd_ptr = debug_bfd; |
} |
if (! read_section (unit->stash->alt_bfd_ptr, |
stash->debug_sections + debug_info_alt, |
NULL, /* FIXME: Do we need to load alternate symbols ? */ |
offset, |
&stash->alt_dwarf_info_buffer, |
&stash->alt_dwarf_info_size)) |
return NULL; |
return stash->alt_dwarf_info_buffer + offset; |
} |
static bfd_uint64_t |
read_address (struct comp_unit *unit, bfd_byte *buf) |
{ |
int signed_vma = get_elf_backend_data (unit->abfd)->sign_extend_vma; |
if (signed_vma) |
{ |
switch (unit->addr_size) |
{ |
case 8: |
return bfd_get_signed_64 (unit->abfd, buf); |
case 4: |
return bfd_get_signed_32 (unit->abfd, buf); |
case 2: |
return bfd_get_signed_16 (unit->abfd, buf); |
default: |
abort (); |
} |
} |
else |
{ |
switch (unit->addr_size) |
{ |
case 8: |
return bfd_get_64 (unit->abfd, buf); |
case 4: |
return bfd_get_32 (unit->abfd, buf); |
case 2: |
return bfd_get_16 (unit->abfd, buf); |
default: |
abort (); |
} |
} |
} |
/* Lookup an abbrev_info structure in the abbrev hash table. */ |
static struct abbrev_info * |
lookup_abbrev (unsigned int number, struct abbrev_info **abbrevs) |
{ |
unsigned int hash_number; |
struct abbrev_info *abbrev; |
hash_number = number % ABBREV_HASH_SIZE; |
abbrev = abbrevs[hash_number]; |
while (abbrev) |
{ |
if (abbrev->number == number) |
return abbrev; |
else |
abbrev = abbrev->next; |
} |
return NULL; |
} |
/* In DWARF version 2, the description of the debugging information is |
stored in a separate .debug_abbrev section. Before we read any |
dies from a section we read in all abbreviations and install them |
in a hash table. */ |
static struct abbrev_info** |
read_abbrevs (bfd *abfd, bfd_uint64_t offset, struct dwarf2_debug *stash) |
{ |
struct abbrev_info **abbrevs; |
bfd_byte *abbrev_ptr; |
struct abbrev_info *cur_abbrev; |
unsigned int abbrev_number, bytes_read, abbrev_name; |
unsigned int abbrev_form, hash_number; |
bfd_size_type amt; |
if (! read_section (abfd, &stash->debug_sections[debug_abbrev], |
stash->syms, offset, |
&stash->dwarf_abbrev_buffer, &stash->dwarf_abbrev_size)) |
return NULL; |
amt = sizeof (struct abbrev_info*) * ABBREV_HASH_SIZE; |
abbrevs = (struct abbrev_info **) bfd_zalloc (abfd, amt); |
if (abbrevs == NULL) |
return NULL; |
abbrev_ptr = stash->dwarf_abbrev_buffer + offset; |
abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); |
abbrev_ptr += bytes_read; |
/* Loop until we reach an abbrev number of 0. */ |
while (abbrev_number) |
{ |
amt = sizeof (struct abbrev_info); |
cur_abbrev = (struct abbrev_info *) bfd_zalloc (abfd, amt); |
if (cur_abbrev == NULL) |
return NULL; |
/* Read in abbrev header. */ |
cur_abbrev->number = abbrev_number; |
cur_abbrev->tag = (enum dwarf_tag) |
read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); |
abbrev_ptr += bytes_read; |
cur_abbrev->has_children = read_1_byte (abfd, abbrev_ptr); |
abbrev_ptr += 1; |
/* Now read in declarations. */ |
abbrev_name = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); |
abbrev_ptr += bytes_read; |
abbrev_form = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); |
abbrev_ptr += bytes_read; |
while (abbrev_name) |
{ |
if ((cur_abbrev->num_attrs % ATTR_ALLOC_CHUNK) == 0) |
{ |
struct attr_abbrev *tmp; |
amt = cur_abbrev->num_attrs + ATTR_ALLOC_CHUNK; |
amt *= sizeof (struct attr_abbrev); |
tmp = (struct attr_abbrev *) bfd_realloc (cur_abbrev->attrs, amt); |
if (tmp == NULL) |
{ |
size_t i; |
for (i = 0; i < ABBREV_HASH_SIZE; i++) |
{ |
struct abbrev_info *abbrev = abbrevs[i]; |
while (abbrev) |
{ |
free (abbrev->attrs); |
abbrev = abbrev->next; |
} |
} |
return NULL; |
} |
cur_abbrev->attrs = tmp; |
} |
cur_abbrev->attrs[cur_abbrev->num_attrs].name |
= (enum dwarf_attribute) abbrev_name; |
cur_abbrev->attrs[cur_abbrev->num_attrs++].form |
= (enum dwarf_form) abbrev_form; |
abbrev_name = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); |
abbrev_ptr += bytes_read; |
abbrev_form = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); |
abbrev_ptr += bytes_read; |
} |
hash_number = abbrev_number % ABBREV_HASH_SIZE; |
cur_abbrev->next = abbrevs[hash_number]; |
abbrevs[hash_number] = cur_abbrev; |
/* Get next abbreviation. |
Under Irix6 the abbreviations for a compilation unit are not |
always properly terminated with an abbrev number of 0. |
Exit loop if we encounter an abbreviation which we have |
already read (which means we are about to read the abbreviations |
for the next compile unit) or if the end of the abbreviation |
table is reached. */ |
if ((unsigned int) (abbrev_ptr - stash->dwarf_abbrev_buffer) |
>= stash->dwarf_abbrev_size) |
break; |
abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); |
abbrev_ptr += bytes_read; |
if (lookup_abbrev (abbrev_number,abbrevs) != NULL) |
break; |
} |
return abbrevs; |
} |
/* Read an attribute value described by an attribute form. */ |
static bfd_byte * |
read_attribute_value (struct attribute *attr, |
unsigned form, |
struct comp_unit *unit, |
bfd_byte *info_ptr) |
{ |
bfd *abfd = unit->abfd; |
unsigned int bytes_read; |
struct dwarf_block *blk; |
bfd_size_type amt; |
attr->form = (enum dwarf_form) form; |
switch (form) |
{ |
case DW_FORM_ref_addr: |
/* DW_FORM_ref_addr is an address in DWARF2, and an offset in |
DWARF3. */ |
if (unit->version == 3 || unit->version == 4) |
{ |
if (unit->offset_size == 4) |
attr->u.val = read_4_bytes (unit->abfd, info_ptr); |
else |
attr->u.val = read_8_bytes (unit->abfd, info_ptr); |
info_ptr += unit->offset_size; |
break; |
} |
/* FALLTHROUGH */ |
case DW_FORM_addr: |
attr->u.val = read_address (unit, info_ptr); |
info_ptr += unit->addr_size; |
break; |
case DW_FORM_GNU_ref_alt: |
case DW_FORM_sec_offset: |
if (unit->offset_size == 4) |
attr->u.val = read_4_bytes (unit->abfd, info_ptr); |
else |
attr->u.val = read_8_bytes (unit->abfd, info_ptr); |
info_ptr += unit->offset_size; |
break; |
case DW_FORM_block2: |
amt = sizeof (struct dwarf_block); |
blk = (struct dwarf_block *) bfd_alloc (abfd, amt); |
if (blk == NULL) |
return NULL; |
blk->size = read_2_bytes (abfd, info_ptr); |
info_ptr += 2; |
blk->data = read_n_bytes (abfd, info_ptr, blk->size); |
info_ptr += blk->size; |
attr->u.blk = blk; |
break; |
case DW_FORM_block4: |
amt = sizeof (struct dwarf_block); |
blk = (struct dwarf_block *) bfd_alloc (abfd, amt); |
if (blk == NULL) |
return NULL; |
blk->size = read_4_bytes (abfd, info_ptr); |
info_ptr += 4; |
blk->data = read_n_bytes (abfd, info_ptr, blk->size); |
info_ptr += blk->size; |
attr->u.blk = blk; |
break; |
case DW_FORM_data2: |
attr->u.val = read_2_bytes (abfd, info_ptr); |
info_ptr += 2; |
break; |
case DW_FORM_data4: |
attr->u.val = read_4_bytes (abfd, info_ptr); |
info_ptr += 4; |
break; |
case DW_FORM_data8: |
attr->u.val = read_8_bytes (abfd, info_ptr); |
info_ptr += 8; |
break; |
case DW_FORM_string: |
attr->u.str = read_string (abfd, info_ptr, &bytes_read); |
info_ptr += bytes_read; |
break; |
case DW_FORM_strp: |
attr->u.str = read_indirect_string (unit, info_ptr, &bytes_read); |
info_ptr += bytes_read; |
break; |
case DW_FORM_GNU_strp_alt: |
attr->u.str = read_alt_indirect_string (unit, info_ptr, &bytes_read); |
info_ptr += bytes_read; |
break; |
case DW_FORM_exprloc: |
case DW_FORM_block: |
amt = sizeof (struct dwarf_block); |
blk = (struct dwarf_block *) bfd_alloc (abfd, amt); |
if (blk == NULL) |
return NULL; |
blk->size = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); |
info_ptr += bytes_read; |
blk->data = read_n_bytes (abfd, info_ptr, blk->size); |
info_ptr += blk->size; |
attr->u.blk = blk; |
break; |
case DW_FORM_block1: |
amt = sizeof (struct dwarf_block); |
blk = (struct dwarf_block *) bfd_alloc (abfd, amt); |
if (blk == NULL) |
return NULL; |
blk->size = read_1_byte (abfd, info_ptr); |
info_ptr += 1; |
blk->data = read_n_bytes (abfd, info_ptr, blk->size); |
info_ptr += blk->size; |
attr->u.blk = blk; |
break; |
case DW_FORM_data1: |
attr->u.val = read_1_byte (abfd, info_ptr); |
info_ptr += 1; |
break; |
case DW_FORM_flag: |
attr->u.val = read_1_byte (abfd, info_ptr); |
info_ptr += 1; |
break; |
case DW_FORM_flag_present: |
attr->u.val = 1; |
break; |
case DW_FORM_sdata: |
attr->u.sval = read_signed_leb128 (abfd, info_ptr, &bytes_read); |
info_ptr += bytes_read; |
break; |
case DW_FORM_udata: |
attr->u.val = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); |
info_ptr += bytes_read; |
break; |
case DW_FORM_ref1: |
attr->u.val = read_1_byte (abfd, info_ptr); |
info_ptr += 1; |
break; |
case DW_FORM_ref2: |
attr->u.val = read_2_bytes (abfd, info_ptr); |
info_ptr += 2; |
break; |
case DW_FORM_ref4: |
attr->u.val = read_4_bytes (abfd, info_ptr); |
info_ptr += 4; |
break; |
case DW_FORM_ref8: |
attr->u.val = read_8_bytes (abfd, info_ptr); |
info_ptr += 8; |
break; |
case DW_FORM_ref_sig8: |
attr->u.val = read_8_bytes (abfd, info_ptr); |
info_ptr += 8; |
break; |
case DW_FORM_ref_udata: |
attr->u.val = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); |
info_ptr += bytes_read; |
break; |
case DW_FORM_indirect: |
form = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); |
info_ptr += bytes_read; |
info_ptr = read_attribute_value (attr, form, unit, info_ptr); |
break; |
default: |
(*_bfd_error_handler) (_("Dwarf Error: Invalid or unhandled FORM value: %#x."), |
form); |
bfd_set_error (bfd_error_bad_value); |
return NULL; |
} |
return info_ptr; |
} |
/* Read an attribute described by an abbreviated attribute. */ |
static bfd_byte * |
read_attribute (struct attribute *attr, |
struct attr_abbrev *abbrev, |
struct comp_unit *unit, |
bfd_byte *info_ptr) |
{ |
attr->name = abbrev->name; |
info_ptr = read_attribute_value (attr, abbrev->form, unit, info_ptr); |
return info_ptr; |
} |
/* Source line information table routines. */ |
#define FILE_ALLOC_CHUNK 5 |
#define DIR_ALLOC_CHUNK 5 |
struct line_info |
{ |
struct line_info* prev_line; |
bfd_vma address; |
char *filename; |
unsigned int line; |
unsigned int column; |
unsigned int discriminator; |
unsigned char op_index; |
unsigned char end_sequence; /* End of (sequential) code sequence. */ |
}; |
struct fileinfo |
{ |
char *name; |
unsigned int dir; |
unsigned int time; |
unsigned int size; |
}; |
struct line_sequence |
{ |
bfd_vma low_pc; |
struct line_sequence* prev_sequence; |
struct line_info* last_line; /* Largest VMA. */ |
}; |
struct line_info_table |
{ |
bfd* abfd; |
unsigned int num_files; |
unsigned int num_dirs; |
unsigned int num_sequences; |
char * comp_dir; |
char ** dirs; |
struct fileinfo* files; |
struct line_sequence* sequences; |
struct line_info* lcl_head; /* Local head; used in 'add_line_info'. */ |
}; |
/* Remember some information about each function. If the function is |
inlined (DW_TAG_inlined_subroutine) it may have two additional |
attributes, DW_AT_call_file and DW_AT_call_line, which specify the |
source code location where this function was inlined. */ |
struct funcinfo |
{ |
/* Pointer to previous function in list of all functions. */ |
struct funcinfo *prev_func; |
/* Pointer to function one scope higher. */ |
struct funcinfo *caller_func; |
/* Source location file name where caller_func inlines this func. */ |
char *caller_file; |
/* Source location line number where caller_func inlines this func. */ |
int caller_line; |
/* Source location file name. */ |
char *file; |
/* Source location line number. */ |
int line; |
int tag; |
char *name; |
struct arange arange; |
/* Where the symbol is defined. */ |
asection *sec; |
}; |
struct varinfo |
{ |
/* Pointer to previous variable in list of all variables */ |
struct varinfo *prev_var; |
/* Source location file name */ |
char *file; |
/* Source location line number */ |
int line; |
int tag; |
char *name; |
bfd_vma addr; |
/* Where the symbol is defined */ |
asection *sec; |
/* Is this a stack variable? */ |
unsigned int stack: 1; |
}; |
/* Return TRUE if NEW_LINE should sort after LINE. */ |
static inline bfd_boolean |
new_line_sorts_after (struct line_info *new_line, struct line_info *line) |
{ |
return (new_line->address > line->address |
|| (new_line->address == line->address |
&& (new_line->op_index > line->op_index |
|| (new_line->op_index == line->op_index |
&& new_line->end_sequence < line->end_sequence)))); |
} |
/* Adds a new entry to the line_info list in the line_info_table, ensuring |
that the list is sorted. Note that the line_info list is sorted from |
highest to lowest VMA (with possible duplicates); that is, |
line_info->prev_line always accesses an equal or smaller VMA. */ |
static bfd_boolean |
add_line_info (struct line_info_table *table, |
bfd_vma address, |
unsigned char op_index, |
char *filename, |
unsigned int line, |
unsigned int column, |
unsigned int discriminator, |
int end_sequence) |
{ |
bfd_size_type amt = sizeof (struct line_info); |
struct line_sequence* seq = table->sequences; |
struct line_info* info = (struct line_info *) bfd_alloc (table->abfd, amt); |
if (info == NULL) |
return FALSE; |
/* Set member data of 'info'. */ |
info->prev_line = NULL; |
info->address = address; |
info->op_index = op_index; |
info->line = line; |
info->column = column; |
info->discriminator = discriminator; |
info->end_sequence = end_sequence; |
if (filename && filename[0]) |
{ |
info->filename = (char *) bfd_alloc (table->abfd, strlen (filename) + 1); |
if (info->filename == NULL) |
return FALSE; |
strcpy (info->filename, filename); |
} |
else |
info->filename = NULL; |
/* Find the correct location for 'info'. Normally we will receive |
new line_info data 1) in order and 2) with increasing VMAs. |
However some compilers break the rules (cf. decode_line_info) and |
so we include some heuristics for quickly finding the correct |
location for 'info'. In particular, these heuristics optimize for |
the common case in which the VMA sequence that we receive is a |
list of locally sorted VMAs such as |
p...z a...j (where a < j < p < z) |
Note: table->lcl_head is used to head an *actual* or *possible* |
sub-sequence within the list (such as a...j) that is not directly |
headed by table->last_line |
Note: we may receive duplicate entries from 'decode_line_info'. */ |
if (seq |
&& seq->last_line->address == address |
&& seq->last_line->op_index == op_index |
&& seq->last_line->end_sequence == end_sequence) |
{ |
/* We only keep the last entry with the same address and end |
sequence. See PR ld/4986. */ |
if (table->lcl_head == seq->last_line) |
table->lcl_head = info; |
info->prev_line = seq->last_line->prev_line; |
seq->last_line = info; |
} |
else if (!seq || seq->last_line->end_sequence) |
{ |
/* Start a new line sequence. */ |
amt = sizeof (struct line_sequence); |
seq = (struct line_sequence *) bfd_malloc (amt); |
if (seq == NULL) |
return FALSE; |
seq->low_pc = address; |
seq->prev_sequence = table->sequences; |
seq->last_line = info; |
table->lcl_head = info; |
table->sequences = seq; |
table->num_sequences++; |
} |
else if (new_line_sorts_after (info, seq->last_line)) |
{ |
/* Normal case: add 'info' to the beginning of the current sequence. */ |
info->prev_line = seq->last_line; |
seq->last_line = info; |
/* lcl_head: initialize to head a *possible* sequence at the end. */ |
if (!table->lcl_head) |
table->lcl_head = info; |
} |
else if (!new_line_sorts_after (info, table->lcl_head) |
&& (!table->lcl_head->prev_line |
|| new_line_sorts_after (info, table->lcl_head->prev_line))) |
{ |
/* Abnormal but easy: lcl_head is the head of 'info'. */ |
info->prev_line = table->lcl_head->prev_line; |
table->lcl_head->prev_line = info; |
} |
else |
{ |
/* Abnormal and hard: Neither 'last_line' nor 'lcl_head' |
are valid heads for 'info'. Reset 'lcl_head'. */ |
struct line_info* li2 = seq->last_line; /* Always non-NULL. */ |
struct line_info* li1 = li2->prev_line; |
while (li1) |
{ |
if (!new_line_sorts_after (info, li2) |
&& new_line_sorts_after (info, li1)) |
break; |
li2 = li1; /* always non-NULL */ |
li1 = li1->prev_line; |
} |
table->lcl_head = li2; |
info->prev_line = table->lcl_head->prev_line; |
table->lcl_head->prev_line = info; |
if (address < seq->low_pc) |
seq->low_pc = address; |
} |
return TRUE; |
} |
/* Extract a fully qualified filename from a line info table. |
The returned string has been malloc'ed and it is the caller's |
responsibility to free it. */ |
static char * |
concat_filename (struct line_info_table *table, unsigned int file) |
{ |
char *filename; |
if (file - 1 >= table->num_files) |
{ |
/* FILE == 0 means unknown. */ |
if (file) |
(*_bfd_error_handler) |
(_("Dwarf Error: mangled line number section (bad file number).")); |
return strdup ("<unknown>"); |
} |
filename = table->files[file - 1].name; |
if (!IS_ABSOLUTE_PATH (filename)) |
{ |
char *dir_name = NULL; |
char *subdir_name = NULL; |
char *name; |
size_t len; |
if (table->files[file - 1].dir) |
subdir_name = table->dirs[table->files[file - 1].dir - 1]; |
if (!subdir_name || !IS_ABSOLUTE_PATH (subdir_name)) |
dir_name = table->comp_dir; |
if (!dir_name) |
{ |
dir_name = subdir_name; |
subdir_name = NULL; |
} |
if (!dir_name) |
return strdup (filename); |
len = strlen (dir_name) + strlen (filename) + 2; |
if (subdir_name) |
{ |
len += strlen (subdir_name) + 1; |
name = (char *) bfd_malloc (len); |
if (name) |
sprintf (name, "%s/%s/%s", dir_name, subdir_name, filename); |
} |
else |
{ |
name = (char *) bfd_malloc (len); |
if (name) |
sprintf (name, "%s/%s", dir_name, filename); |
} |
return name; |
} |
return strdup (filename); |
} |
static bfd_boolean |
arange_add (const struct comp_unit *unit, struct arange *first_arange, |
bfd_vma low_pc, bfd_vma high_pc) |
{ |
struct arange *arange; |
/* Ignore empty ranges. */ |
if (low_pc == high_pc) |
return TRUE; |
/* If the first arange is empty, use it. */ |
if (first_arange->high == 0) |
{ |
first_arange->low = low_pc; |
first_arange->high = high_pc; |
return TRUE; |
} |
/* Next see if we can cheaply extend an existing range. */ |
arange = first_arange; |
do |
{ |
if (low_pc == arange->high) |
{ |
arange->high = high_pc; |
return TRUE; |
} |
if (high_pc == arange->low) |
{ |
arange->low = low_pc; |
return TRUE; |
} |
arange = arange->next; |
} |
while (arange); |
/* Need to allocate a new arange and insert it into the arange list. |
Order isn't significant, so just insert after the first arange. */ |
arange = (struct arange *) bfd_alloc (unit->abfd, sizeof (*arange)); |
if (arange == NULL) |
return FALSE; |
arange->low = low_pc; |
arange->high = high_pc; |
arange->next = first_arange->next; |
first_arange->next = arange; |
return TRUE; |
} |
/* Compare function for line sequences. */ |
static int |
compare_sequences (const void* a, const void* b) |
{ |
const struct line_sequence* seq1 = a; |
const struct line_sequence* seq2 = b; |
/* Sort by low_pc as the primary key. */ |
if (seq1->low_pc < seq2->low_pc) |
return -1; |
if (seq1->low_pc > seq2->low_pc) |
return 1; |
/* If low_pc values are equal, sort in reverse order of |
high_pc, so that the largest region comes first. */ |
if (seq1->last_line->address < seq2->last_line->address) |
return 1; |
if (seq1->last_line->address > seq2->last_line->address) |
return -1; |
if (seq1->last_line->op_index < seq2->last_line->op_index) |
return 1; |
if (seq1->last_line->op_index > seq2->last_line->op_index) |
return -1; |
return 0; |
} |
/* Sort the line sequences for quick lookup. */ |
static bfd_boolean |
sort_line_sequences (struct line_info_table* table) |
{ |
bfd_size_type amt; |
struct line_sequence* sequences; |
struct line_sequence* seq; |
unsigned int n = 0; |
unsigned int num_sequences = table->num_sequences; |
bfd_vma last_high_pc; |
if (num_sequences == 0) |
return TRUE; |
/* Allocate space for an array of sequences. */ |
amt = sizeof (struct line_sequence) * num_sequences; |
sequences = (struct line_sequence *) bfd_alloc (table->abfd, amt); |
if (sequences == NULL) |
return FALSE; |
/* Copy the linked list into the array, freeing the original nodes. */ |
seq = table->sequences; |
for (n = 0; n < num_sequences; n++) |
{ |
struct line_sequence* last_seq = seq; |
BFD_ASSERT (seq); |
sequences[n].low_pc = seq->low_pc; |
sequences[n].prev_sequence = NULL; |
sequences[n].last_line = seq->last_line; |
seq = seq->prev_sequence; |
free (last_seq); |
} |
BFD_ASSERT (seq == NULL); |
qsort (sequences, n, sizeof (struct line_sequence), compare_sequences); |
/* Make the list binary-searchable by trimming overlapping entries |
and removing nested entries. */ |
num_sequences = 1; |
last_high_pc = sequences[0].last_line->address; |
for (n = 1; n < table->num_sequences; n++) |
{ |
if (sequences[n].low_pc < last_high_pc) |
{ |
if (sequences[n].last_line->address <= last_high_pc) |
/* Skip nested entries. */ |
continue; |
/* Trim overlapping entries. */ |
sequences[n].low_pc = last_high_pc; |
} |
last_high_pc = sequences[n].last_line->address; |
if (n > num_sequences) |
{ |
/* Close up the gap. */ |
sequences[num_sequences].low_pc = sequences[n].low_pc; |
sequences[num_sequences].last_line = sequences[n].last_line; |
} |
num_sequences++; |
} |
table->sequences = sequences; |
table->num_sequences = num_sequences; |
return TRUE; |
} |
/* Decode the line number information for UNIT. */ |
static struct line_info_table* |
decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) |
{ |
bfd *abfd = unit->abfd; |
struct line_info_table* table; |
bfd_byte *line_ptr; |
bfd_byte *line_end; |
struct line_head lh; |
unsigned int i, bytes_read, offset_size; |
char *cur_file, *cur_dir; |
unsigned char op_code, extended_op, adj_opcode; |
unsigned int exop_len; |
bfd_size_type amt; |
if (! read_section (abfd, &stash->debug_sections[debug_line], |
stash->syms, unit->line_offset, |
&stash->dwarf_line_buffer, &stash->dwarf_line_size)) |
return NULL; |
amt = sizeof (struct line_info_table); |
table = (struct line_info_table *) bfd_alloc (abfd, amt); |
if (table == NULL) |
return NULL; |
table->abfd = abfd; |
table->comp_dir = unit->comp_dir; |
table->num_files = 0; |
table->files = NULL; |
table->num_dirs = 0; |
table->dirs = NULL; |
table->num_sequences = 0; |
table->sequences = NULL; |
table->lcl_head = NULL; |
line_ptr = stash->dwarf_line_buffer + unit->line_offset; |
/* Read in the prologue. */ |
lh.total_length = read_4_bytes (abfd, line_ptr); |
line_ptr += 4; |
offset_size = 4; |
if (lh.total_length == 0xffffffff) |
{ |
lh.total_length = read_8_bytes (abfd, line_ptr); |
line_ptr += 8; |
offset_size = 8; |
} |
else if (lh.total_length == 0 && unit->addr_size == 8) |
{ |
/* Handle (non-standard) 64-bit DWARF2 formats. */ |
lh.total_length = read_4_bytes (abfd, line_ptr); |
line_ptr += 4; |
offset_size = 8; |
} |
line_end = line_ptr + lh.total_length; |
lh.version = read_2_bytes (abfd, line_ptr); |
if (lh.version < 2 || lh.version > 4) |
{ |
(*_bfd_error_handler) |
(_("Dwarf Error: Unhandled .debug_line version %d."), lh.version); |
bfd_set_error (bfd_error_bad_value); |
return NULL; |
} |
line_ptr += 2; |
if (offset_size == 4) |
lh.prologue_length = read_4_bytes (abfd, line_ptr); |
else |
lh.prologue_length = read_8_bytes (abfd, line_ptr); |
line_ptr += offset_size; |
lh.minimum_instruction_length = read_1_byte (abfd, line_ptr); |
line_ptr += 1; |
if (lh.version >= 4) |
{ |
lh.maximum_ops_per_insn = read_1_byte (abfd, line_ptr); |
line_ptr += 1; |
} |
else |
lh.maximum_ops_per_insn = 1; |
if (lh.maximum_ops_per_insn == 0) |
{ |
(*_bfd_error_handler) |
(_("Dwarf Error: Invalid maximum operations per instruction.")); |
bfd_set_error (bfd_error_bad_value); |
return NULL; |
} |
lh.default_is_stmt = read_1_byte (abfd, line_ptr); |
line_ptr += 1; |
lh.line_base = read_1_signed_byte (abfd, line_ptr); |
line_ptr += 1; |
lh.line_range = read_1_byte (abfd, line_ptr); |
line_ptr += 1; |
lh.opcode_base = read_1_byte (abfd, line_ptr); |
line_ptr += 1; |
amt = lh.opcode_base * sizeof (unsigned char); |
lh.standard_opcode_lengths = (unsigned char *) bfd_alloc (abfd, amt); |
lh.standard_opcode_lengths[0] = 1; |
for (i = 1; i < lh.opcode_base; ++i) |
{ |
lh.standard_opcode_lengths[i] = read_1_byte (abfd, line_ptr); |
line_ptr += 1; |
} |
/* Read directory table. */ |
while ((cur_dir = read_string (abfd, line_ptr, &bytes_read)) != NULL) |
{ |
line_ptr += bytes_read; |
if ((table->num_dirs % DIR_ALLOC_CHUNK) == 0) |
{ |
char **tmp; |
amt = table->num_dirs + DIR_ALLOC_CHUNK; |
amt *= sizeof (char *); |
tmp = (char **) bfd_realloc (table->dirs, amt); |
if (tmp == NULL) |
goto fail; |
table->dirs = tmp; |
} |
table->dirs[table->num_dirs++] = cur_dir; |
} |
line_ptr += bytes_read; |
/* Read file name table. */ |
while ((cur_file = read_string (abfd, line_ptr, &bytes_read)) != NULL) |
{ |
line_ptr += bytes_read; |
if ((table->num_files % FILE_ALLOC_CHUNK) == 0) |
{ |
struct fileinfo *tmp; |
amt = table->num_files + FILE_ALLOC_CHUNK; |
amt *= sizeof (struct fileinfo); |
tmp = (struct fileinfo *) bfd_realloc (table->files, amt); |
if (tmp == NULL) |
goto fail; |
table->files = tmp; |
} |
table->files[table->num_files].name = cur_file; |
table->files[table->num_files].dir = |
read_unsigned_leb128 (abfd, line_ptr, &bytes_read); |
line_ptr += bytes_read; |
table->files[table->num_files].time = |
read_unsigned_leb128 (abfd, line_ptr, &bytes_read); |
line_ptr += bytes_read; |
table->files[table->num_files].size = |
read_unsigned_leb128 (abfd, line_ptr, &bytes_read); |
line_ptr += bytes_read; |
table->num_files++; |
} |
line_ptr += bytes_read; |
/* Read the statement sequences until there's nothing left. */ |
while (line_ptr < line_end) |
{ |
/* State machine registers. */ |
bfd_vma address = 0; |
unsigned char op_index = 0; |
char * filename = table->num_files ? concat_filename (table, 1) : NULL; |
unsigned int line = 1; |
unsigned int column = 0; |
unsigned int discriminator = 0; |
int is_stmt = lh.default_is_stmt; |
int end_sequence = 0; |
/* eraxxon@alumni.rice.edu: Against the DWARF2 specs, some |
compilers generate address sequences that are wildly out of |
order using DW_LNE_set_address (e.g. Intel C++ 6.0 compiler |
for ia64-Linux). Thus, to determine the low and high |
address, we must compare on every DW_LNS_copy, etc. */ |
bfd_vma low_pc = (bfd_vma) -1; |
bfd_vma high_pc = 0; |
/* Decode the table. */ |
while (! end_sequence) |
{ |
op_code = read_1_byte (abfd, line_ptr); |
line_ptr += 1; |
if (op_code >= lh.opcode_base) |
{ |
/* Special operand. */ |
adj_opcode = op_code - lh.opcode_base; |
if (lh.maximum_ops_per_insn == 1) |
address += (adj_opcode / lh.line_range |
* lh.minimum_instruction_length); |
else |
{ |
address += ((op_index + adj_opcode / lh.line_range) |
/ lh.maximum_ops_per_insn |
* lh.minimum_instruction_length); |
op_index = ((op_index + adj_opcode / lh.line_range) |
% lh.maximum_ops_per_insn); |
} |
line += lh.line_base + (adj_opcode % lh.line_range); |
/* Append row to matrix using current values. */ |
if (!add_line_info (table, address, op_index, filename, |
line, column, discriminator, 0)) |
goto line_fail; |
discriminator = 0; |
if (address < low_pc) |
low_pc = address; |
if (address > high_pc) |
high_pc = address; |
} |
else switch (op_code) |
{ |
case DW_LNS_extended_op: |
exop_len = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); |
line_ptr += bytes_read; |
extended_op = read_1_byte (abfd, line_ptr); |
line_ptr += 1; |
switch (extended_op) |
{ |
case DW_LNE_end_sequence: |
end_sequence = 1; |
if (!add_line_info (table, address, op_index, filename, line, |
column, discriminator, end_sequence)) |
goto line_fail; |
discriminator = 0; |
if (address < low_pc) |
low_pc = address; |
if (address > high_pc) |
high_pc = address; |
if (!arange_add (unit, &unit->arange, low_pc, high_pc)) |
goto line_fail; |
break; |
case DW_LNE_set_address: |
address = read_address (unit, line_ptr); |
op_index = 0; |
line_ptr += unit->addr_size; |
break; |
case DW_LNE_define_file: |
cur_file = read_string (abfd, line_ptr, &bytes_read); |
line_ptr += bytes_read; |
if ((table->num_files % FILE_ALLOC_CHUNK) == 0) |
{ |
struct fileinfo *tmp; |
amt = table->num_files + FILE_ALLOC_CHUNK; |
amt *= sizeof (struct fileinfo); |
tmp = (struct fileinfo *) bfd_realloc (table->files, amt); |
if (tmp == NULL) |
goto line_fail; |
table->files = tmp; |
} |
table->files[table->num_files].name = cur_file; |
table->files[table->num_files].dir = |
read_unsigned_leb128 (abfd, line_ptr, &bytes_read); |
line_ptr += bytes_read; |
table->files[table->num_files].time = |
read_unsigned_leb128 (abfd, line_ptr, &bytes_read); |
line_ptr += bytes_read; |
table->files[table->num_files].size = |
read_unsigned_leb128 (abfd, line_ptr, &bytes_read); |
line_ptr += bytes_read; |
table->num_files++; |
break; |
case DW_LNE_set_discriminator: |
discriminator = |
read_unsigned_leb128 (abfd, line_ptr, &bytes_read); |
line_ptr += bytes_read; |
break; |
case DW_LNE_HP_source_file_correlation: |
line_ptr += exop_len - 1; |
break; |
default: |
(*_bfd_error_handler) |
(_("Dwarf Error: mangled line number section.")); |
bfd_set_error (bfd_error_bad_value); |
line_fail: |
if (filename != NULL) |
free (filename); |
goto fail; |
} |
break; |
case DW_LNS_copy: |
if (!add_line_info (table, address, op_index, |
filename, line, column, discriminator, 0)) |
goto line_fail; |
discriminator = 0; |
if (address < low_pc) |
low_pc = address; |
if (address > high_pc) |
high_pc = address; |
break; |
case DW_LNS_advance_pc: |
if (lh.maximum_ops_per_insn == 1) |
address += (lh.minimum_instruction_length |
* read_unsigned_leb128 (abfd, line_ptr, |
&bytes_read)); |
else |
{ |
bfd_vma adjust = read_unsigned_leb128 (abfd, line_ptr, |
&bytes_read); |
address = ((op_index + adjust) / lh.maximum_ops_per_insn |
* lh.minimum_instruction_length); |
op_index = (op_index + adjust) % lh.maximum_ops_per_insn; |
} |
line_ptr += bytes_read; |
break; |
case DW_LNS_advance_line: |
line += read_signed_leb128 (abfd, line_ptr, &bytes_read); |
line_ptr += bytes_read; |
break; |
case DW_LNS_set_file: |
{ |
unsigned int file; |
/* The file and directory tables are 0 |
based, the references are 1 based. */ |
file = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); |
line_ptr += bytes_read; |
if (filename) |
free (filename); |
filename = concat_filename (table, file); |
break; |
} |
case DW_LNS_set_column: |
column = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); |
line_ptr += bytes_read; |
break; |
case DW_LNS_negate_stmt: |
is_stmt = (!is_stmt); |
break; |
case DW_LNS_set_basic_block: |
break; |
case DW_LNS_const_add_pc: |
if (lh.maximum_ops_per_insn == 1) |
address += (lh.minimum_instruction_length |
* ((255 - lh.opcode_base) / lh.line_range)); |
else |
{ |
bfd_vma adjust = ((255 - lh.opcode_base) / lh.line_range); |
address += (lh.minimum_instruction_length |
* ((op_index + adjust) |
/ lh.maximum_ops_per_insn)); |
op_index = (op_index + adjust) % lh.maximum_ops_per_insn; |
} |
break; |
case DW_LNS_fixed_advance_pc: |
address += read_2_bytes (abfd, line_ptr); |
op_index = 0; |
line_ptr += 2; |
break; |
default: |
/* Unknown standard opcode, ignore it. */ |
for (i = 0; i < lh.standard_opcode_lengths[op_code]; i++) |
{ |
(void) read_unsigned_leb128 (abfd, line_ptr, &bytes_read); |
line_ptr += bytes_read; |
} |
break; |
} |
} |
if (filename) |
free (filename); |
} |
if (sort_line_sequences (table)) |
return table; |
fail: |
if (table->sequences != NULL) |
free (table->sequences); |
if (table->files != NULL) |
free (table->files); |
if (table->dirs != NULL) |
free (table->dirs); |
return NULL; |
} |
/* If ADDR is within TABLE set the output parameters and return TRUE, |
otherwise return FALSE. The output parameters, FILENAME_PTR and |
LINENUMBER_PTR, are pointers to the objects to be filled in. */ |
static bfd_boolean |
lookup_address_in_line_info_table (struct line_info_table *table, |
bfd_vma addr, |
const char **filename_ptr, |
unsigned int *linenumber_ptr, |
unsigned int *discriminator_ptr) |
{ |
struct line_sequence *seq = NULL; |
struct line_info *each_line; |
int low, high, mid; |
/* Binary search the array of sequences. */ |
low = 0; |
high = table->num_sequences; |
while (low < high) |
{ |
mid = (low + high) / 2; |
seq = &table->sequences[mid]; |
if (addr < seq->low_pc) |
high = mid; |
else if (addr >= seq->last_line->address) |
low = mid + 1; |
else |
break; |
} |
if (seq && addr >= seq->low_pc && addr < seq->last_line->address) |
{ |
/* Note: seq->last_line should be a descendingly sorted list. */ |
for (each_line = seq->last_line; |
each_line; |
each_line = each_line->prev_line) |
if (addr >= each_line->address) |
break; |
if (each_line |
&& !(each_line->end_sequence || each_line == seq->last_line)) |
{ |
*filename_ptr = each_line->filename; |
*linenumber_ptr = each_line->line; |
if (discriminator_ptr) |
*discriminator_ptr = each_line->discriminator; |
return TRUE; |
} |
} |
*filename_ptr = NULL; |
return FALSE; |
} |
/* Read in the .debug_ranges section for future reference. */ |
static bfd_boolean |
read_debug_ranges (struct comp_unit *unit) |
{ |
struct dwarf2_debug *stash = unit->stash; |
return read_section (unit->abfd, &stash->debug_sections[debug_ranges], |
stash->syms, 0, |
&stash->dwarf_ranges_buffer, &stash->dwarf_ranges_size); |
} |
/* Function table functions. */ |
/* If ADDR is within TABLE, set FUNCTIONNAME_PTR, and return TRUE. |
Note that we need to find the function that has the smallest |
range that contains ADDR, to handle inlined functions without |
depending upon them being ordered in TABLE by increasing range. */ |
static bfd_boolean |
lookup_address_in_function_table (struct comp_unit *unit, |
bfd_vma addr, |
struct funcinfo **function_ptr, |
const char **functionname_ptr) |
{ |
struct funcinfo* each_func; |
struct funcinfo* best_fit = NULL; |
struct arange *arange; |
for (each_func = unit->function_table; |
each_func; |
each_func = each_func->prev_func) |
{ |
for (arange = &each_func->arange; |
arange; |
arange = arange->next) |
{ |
if (addr >= arange->low && addr < arange->high) |
{ |
if (!best_fit |
|| (arange->high - arange->low |
< best_fit->arange.high - best_fit->arange.low)) |
best_fit = each_func; |
} |
} |
} |
if (best_fit) |
{ |
*functionname_ptr = best_fit->name; |
*function_ptr = best_fit; |
return TRUE; |
} |
else |
{ |
return FALSE; |
} |
} |
/* If SYM at ADDR is within function table of UNIT, set FILENAME_PTR |
and LINENUMBER_PTR, and return TRUE. */ |
static bfd_boolean |
lookup_symbol_in_function_table (struct comp_unit *unit, |
asymbol *sym, |
bfd_vma addr, |
const char **filename_ptr, |
unsigned int *linenumber_ptr) |
{ |
struct funcinfo* each_func; |
struct funcinfo* best_fit = NULL; |
struct arange *arange; |
const char *name = bfd_asymbol_name (sym); |
asection *sec = bfd_get_section (sym); |
for (each_func = unit->function_table; |
each_func; |
each_func = each_func->prev_func) |
{ |
for (arange = &each_func->arange; |
arange; |
arange = arange->next) |
{ |
if ((!each_func->sec || each_func->sec == sec) |
&& addr >= arange->low |
&& addr < arange->high |
&& each_func->name |
&& strcmp (name, each_func->name) == 0 |
&& (!best_fit |
|| (arange->high - arange->low |
< best_fit->arange.high - best_fit->arange.low))) |
best_fit = each_func; |
} |
} |
if (best_fit) |
{ |
best_fit->sec = sec; |
*filename_ptr = best_fit->file; |
*linenumber_ptr = best_fit->line; |
return TRUE; |
} |
else |
return FALSE; |
} |
/* Variable table functions. */ |
/* If SYM is within variable table of UNIT, set FILENAME_PTR and |
LINENUMBER_PTR, and return TRUE. */ |
static bfd_boolean |
lookup_symbol_in_variable_table (struct comp_unit *unit, |
asymbol *sym, |
bfd_vma addr, |
const char **filename_ptr, |
unsigned int *linenumber_ptr) |
{ |
const char *name = bfd_asymbol_name (sym); |
asection *sec = bfd_get_section (sym); |
struct varinfo* each; |
for (each = unit->variable_table; each; each = each->prev_var) |
if (each->stack == 0 |
&& each->file != NULL |
&& each->name != NULL |
&& each->addr == addr |
&& (!each->sec || each->sec == sec) |
&& strcmp (name, each->name) == 0) |
break; |
if (each) |
{ |
each->sec = sec; |
*filename_ptr = each->file; |
*linenumber_ptr = each->line; |
return TRUE; |
} |
else |
return FALSE; |
} |
static char * |
find_abstract_instance_name (struct comp_unit *unit, |
struct attribute *attr_ptr) |
{ |
bfd *abfd = unit->abfd; |
bfd_byte *info_ptr; |
unsigned int abbrev_number, bytes_read, i; |
struct abbrev_info *abbrev; |
bfd_uint64_t die_ref = attr_ptr->u.val; |
struct attribute attr; |
char *name = NULL; |
/* DW_FORM_ref_addr can reference an entry in a different CU. It |
is an offset from the .debug_info section, not the current CU. */ |
if (attr_ptr->form == DW_FORM_ref_addr) |
{ |
/* We only support DW_FORM_ref_addr within the same file, so |
any relocations should be resolved already. */ |
if (!die_ref) |
abort (); |
info_ptr = unit->sec_info_ptr + die_ref; |
} |
else if (attr_ptr->form == DW_FORM_GNU_ref_alt) |
{ |
info_ptr = read_alt_indirect_ref (unit, die_ref); |
if (info_ptr == NULL) |
{ |
(*_bfd_error_handler) |
(_("Dwarf Error: Unable to read alt ref %u."), die_ref); |
bfd_set_error (bfd_error_bad_value); |
return name; |
} |
} |
else |
info_ptr = unit->info_ptr_unit + die_ref; |
abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); |
info_ptr += bytes_read; |
if (abbrev_number) |
{ |
abbrev = lookup_abbrev (abbrev_number, unit->abbrevs); |
if (! abbrev) |
{ |
(*_bfd_error_handler) |
(_("Dwarf Error: Could not find abbrev number %u."), abbrev_number); |
bfd_set_error (bfd_error_bad_value); |
} |
else |
{ |
for (i = 0; i < abbrev->num_attrs; ++i) |
{ |
info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, |
info_ptr); |
if (info_ptr == NULL) |
break; |
switch (attr.name) |
{ |
case DW_AT_name: |
/* Prefer DW_AT_MIPS_linkage_name or DW_AT_linkage_name |
over DW_AT_name. */ |
if (name == NULL) |
name = attr.u.str; |
break; |
case DW_AT_specification: |
name = find_abstract_instance_name (unit, &attr); |
break; |
case DW_AT_linkage_name: |
case DW_AT_MIPS_linkage_name: |
name = attr.u.str; |
break; |
default: |
break; |
} |
} |
} |
} |
return name; |
} |
static bfd_boolean |
read_rangelist (struct comp_unit *unit, struct arange *arange, |
bfd_uint64_t offset) |
{ |
bfd_byte *ranges_ptr; |
bfd_vma base_address = unit->base_address; |
if (! unit->stash->dwarf_ranges_buffer) |
{ |
if (! read_debug_ranges (unit)) |
return FALSE; |
} |
ranges_ptr = unit->stash->dwarf_ranges_buffer + offset; |
for (;;) |
{ |
bfd_vma low_pc; |
bfd_vma high_pc; |
low_pc = read_address (unit, ranges_ptr); |
ranges_ptr += unit->addr_size; |
high_pc = read_address (unit, ranges_ptr); |
ranges_ptr += unit->addr_size; |
if (low_pc == 0 && high_pc == 0) |
break; |
if (low_pc == -1UL && high_pc != -1UL) |
base_address = high_pc; |
else |
{ |
if (!arange_add (unit, arange, |
base_address + low_pc, base_address + high_pc)) |
return FALSE; |
} |
} |
return TRUE; |
} |
/* DWARF2 Compilation unit functions. */ |
/* Scan over each die in a comp. unit looking for functions to add |
to the function table and variables to the variable table. */ |
static bfd_boolean |
scan_unit_for_symbols (struct comp_unit *unit) |
{ |
bfd *abfd = unit->abfd; |
bfd_byte *info_ptr = unit->first_child_die_ptr; |
int nesting_level = 1; |
struct funcinfo **nested_funcs; |
int nested_funcs_size; |
/* Maintain a stack of in-scope functions and inlined functions, which we |
can use to set the caller_func field. */ |
nested_funcs_size = 32; |
nested_funcs = (struct funcinfo **) |
bfd_malloc (nested_funcs_size * sizeof (struct funcinfo *)); |
if (nested_funcs == NULL) |
return FALSE; |
nested_funcs[nesting_level] = 0; |
while (nesting_level) |
{ |
unsigned int abbrev_number, bytes_read, i; |
struct abbrev_info *abbrev; |
struct attribute attr; |
struct funcinfo *func; |
struct varinfo *var; |
bfd_vma low_pc = 0; |
bfd_vma high_pc = 0; |
bfd_boolean high_pc_relative = FALSE; |
abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); |
info_ptr += bytes_read; |
if (! abbrev_number) |
{ |
nesting_level--; |
continue; |
} |
abbrev = lookup_abbrev (abbrev_number,unit->abbrevs); |
if (! abbrev) |
{ |
(*_bfd_error_handler) |
(_("Dwarf Error: Could not find abbrev number %u."), |
abbrev_number); |
bfd_set_error (bfd_error_bad_value); |
goto fail; |
} |
var = NULL; |
if (abbrev->tag == DW_TAG_subprogram |
|| abbrev->tag == DW_TAG_entry_point |
|| abbrev->tag == DW_TAG_inlined_subroutine) |
{ |
bfd_size_type amt = sizeof (struct funcinfo); |
func = (struct funcinfo *) bfd_zalloc (abfd, amt); |
if (func == NULL) |
goto fail; |
func->tag = abbrev->tag; |
func->prev_func = unit->function_table; |
unit->function_table = func; |
BFD_ASSERT (!unit->cached); |
if (func->tag == DW_TAG_inlined_subroutine) |
for (i = nesting_level - 1; i >= 1; i--) |
if (nested_funcs[i]) |
{ |
func->caller_func = nested_funcs[i]; |
break; |
} |
nested_funcs[nesting_level] = func; |
} |
else |
{ |
func = NULL; |
if (abbrev->tag == DW_TAG_variable) |
{ |
bfd_size_type amt = sizeof (struct varinfo); |
var = (struct varinfo *) bfd_zalloc (abfd, amt); |
if (var == NULL) |
goto fail; |
var->tag = abbrev->tag; |
var->stack = 1; |
var->prev_var = unit->variable_table; |
unit->variable_table = var; |
BFD_ASSERT (!unit->cached); |
} |
/* No inline function in scope at this nesting level. */ |
nested_funcs[nesting_level] = 0; |
} |
for (i = 0; i < abbrev->num_attrs; ++i) |
{ |
info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr); |
if (info_ptr == NULL) |
goto fail; |
if (func) |
{ |
switch (attr.name) |
{ |
case DW_AT_call_file: |
func->caller_file = concat_filename (unit->line_table, |
attr.u.val); |
break; |
case DW_AT_call_line: |
func->caller_line = attr.u.val; |
break; |
case DW_AT_abstract_origin: |
case DW_AT_specification: |
func->name = find_abstract_instance_name (unit, &attr); |
break; |
case DW_AT_name: |
/* Prefer DW_AT_MIPS_linkage_name or DW_AT_linkage_name |
over DW_AT_name. */ |
if (func->name == NULL) |
func->name = attr.u.str; |
break; |
case DW_AT_linkage_name: |
case DW_AT_MIPS_linkage_name: |
func->name = attr.u.str; |
break; |
case DW_AT_low_pc: |
low_pc = attr.u.val; |
break; |
case DW_AT_high_pc: |
high_pc = attr.u.val; |
high_pc_relative = attr.form != DW_FORM_addr; |
break; |
case DW_AT_ranges: |
if (!read_rangelist (unit, &func->arange, attr.u.val)) |
goto fail; |
break; |
case DW_AT_decl_file: |
func->file = concat_filename (unit->line_table, |
attr.u.val); |
break; |
case DW_AT_decl_line: |
func->line = attr.u.val; |
break; |
default: |
break; |
} |
} |
else if (var) |
{ |
switch (attr.name) |
{ |
case DW_AT_name: |
var->name = attr.u.str; |
break; |
case DW_AT_decl_file: |
var->file = concat_filename (unit->line_table, |
attr.u.val); |
break; |
case DW_AT_decl_line: |
var->line = attr.u.val; |
break; |
case DW_AT_external: |
if (attr.u.val != 0) |
var->stack = 0; |
break; |
case DW_AT_location: |
switch (attr.form) |
{ |
case DW_FORM_block: |
case DW_FORM_block1: |
case DW_FORM_block2: |
case DW_FORM_block4: |
case DW_FORM_exprloc: |
if (*attr.u.blk->data == DW_OP_addr) |
{ |
var->stack = 0; |
/* Verify that DW_OP_addr is the only opcode in the |
location, in which case the block size will be 1 |
plus the address size. */ |
/* ??? For TLS variables, gcc can emit |
DW_OP_addr <addr> DW_OP_GNU_push_tls_address |
which we don't handle here yet. */ |
if (attr.u.blk->size == unit->addr_size + 1U) |
var->addr = bfd_get (unit->addr_size * 8, |
unit->abfd, |
attr.u.blk->data + 1); |
} |
break; |
default: |
break; |
} |
break; |
default: |
break; |
} |
} |
} |
if (high_pc_relative) |
high_pc += low_pc; |
if (func && high_pc != 0) |
{ |
if (!arange_add (unit, &func->arange, low_pc, high_pc)) |
goto fail; |
} |
if (abbrev->has_children) |
{ |
nesting_level++; |
if (nesting_level >= nested_funcs_size) |
{ |
struct funcinfo **tmp; |
nested_funcs_size *= 2; |
tmp = (struct funcinfo **) |
bfd_realloc (nested_funcs, |
nested_funcs_size * sizeof (struct funcinfo *)); |
if (tmp == NULL) |
goto fail; |
nested_funcs = tmp; |
} |
nested_funcs[nesting_level] = 0; |
} |
} |
free (nested_funcs); |
return TRUE; |
fail: |
free (nested_funcs); |
return FALSE; |
} |
/* Parse a DWARF2 compilation unit starting at INFO_PTR. This |
includes the compilation unit header that proceeds the DIE's, but |
does not include the length field that precedes each compilation |
unit header. END_PTR points one past the end of this comp unit. |
OFFSET_SIZE is the size of DWARF2 offsets (either 4 or 8 bytes). |
This routine does not read the whole compilation unit; only enough |
to get to the line number information for the compilation unit. */ |
static struct comp_unit * |
parse_comp_unit (struct dwarf2_debug *stash, |
bfd_vma unit_length, |
bfd_byte *info_ptr_unit, |
unsigned int offset_size) |
{ |
struct comp_unit* unit; |
unsigned int version; |
bfd_uint64_t abbrev_offset = 0; |
unsigned int addr_size; |
struct abbrev_info** abbrevs; |
unsigned int abbrev_number, bytes_read, i; |
struct abbrev_info *abbrev; |
struct attribute attr; |
bfd_byte *info_ptr = stash->info_ptr; |
bfd_byte *end_ptr = info_ptr + unit_length; |
bfd_size_type amt; |
bfd_vma low_pc = 0; |
bfd_vma high_pc = 0; |
bfd *abfd = stash->bfd_ptr; |
bfd_boolean high_pc_relative = FALSE; |
version = read_2_bytes (abfd, info_ptr); |
info_ptr += 2; |
BFD_ASSERT (offset_size == 4 || offset_size == 8); |
if (offset_size == 4) |
abbrev_offset = read_4_bytes (abfd, info_ptr); |
else |
abbrev_offset = read_8_bytes (abfd, info_ptr); |
info_ptr += offset_size; |
addr_size = read_1_byte (abfd, info_ptr); |
info_ptr += 1; |
if (version != 2 && version != 3 && version != 4) |
{ |
(*_bfd_error_handler) |
(_("Dwarf Error: found dwarf version '%u', this reader" |
" only handles version 2, 3 and 4 information."), version); |
bfd_set_error (bfd_error_bad_value); |
return 0; |
} |
if (addr_size > sizeof (bfd_vma)) |
{ |
(*_bfd_error_handler) |
(_("Dwarf Error: found address size '%u', this reader" |
" can not handle sizes greater than '%u'."), |
addr_size, |
(unsigned int) sizeof (bfd_vma)); |
bfd_set_error (bfd_error_bad_value); |
return 0; |
} |
if (addr_size != 2 && addr_size != 4 && addr_size != 8) |
{ |
(*_bfd_error_handler) |
("Dwarf Error: found address size '%u', this reader" |
" can only handle address sizes '2', '4' and '8'.", addr_size); |
bfd_set_error (bfd_error_bad_value); |
return 0; |
} |
/* Read the abbrevs for this compilation unit into a table. */ |
abbrevs = read_abbrevs (abfd, abbrev_offset, stash); |
if (! abbrevs) |
return 0; |
abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); |
info_ptr += bytes_read; |
if (! abbrev_number) |
{ |
(*_bfd_error_handler) (_("Dwarf Error: Bad abbrev number: %u."), |
abbrev_number); |
bfd_set_error (bfd_error_bad_value); |
return 0; |
} |
abbrev = lookup_abbrev (abbrev_number, abbrevs); |
if (! abbrev) |
{ |
(*_bfd_error_handler) (_("Dwarf Error: Could not find abbrev number %u."), |
abbrev_number); |
bfd_set_error (bfd_error_bad_value); |
return 0; |
} |
amt = sizeof (struct comp_unit); |
unit = (struct comp_unit *) bfd_zalloc (abfd, amt); |
if (unit == NULL) |
return NULL; |
unit->abfd = abfd; |
unit->version = version; |
unit->addr_size = addr_size; |
unit->offset_size = offset_size; |
unit->abbrevs = abbrevs; |
unit->end_ptr = end_ptr; |
unit->stash = stash; |
unit->info_ptr_unit = info_ptr_unit; |
unit->sec_info_ptr = stash->sec_info_ptr; |
for (i = 0; i < abbrev->num_attrs; ++i) |
{ |
info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr); |
if (info_ptr == NULL) |
return NULL; |
/* Store the data if it is of an attribute we want to keep in a |
partial symbol table. */ |
switch (attr.name) |
{ |
case DW_AT_stmt_list: |
unit->stmtlist = 1; |
unit->line_offset = attr.u.val; |
break; |
case DW_AT_name: |
unit->name = attr.u.str; |
break; |
case DW_AT_low_pc: |
low_pc = attr.u.val; |
/* If the compilation unit DIE has a DW_AT_low_pc attribute, |
this is the base address to use when reading location |
lists or range lists. */ |
if (abbrev->tag == DW_TAG_compile_unit) |
unit->base_address = low_pc; |
break; |
case DW_AT_high_pc: |
high_pc = attr.u.val; |
high_pc_relative = attr.form != DW_FORM_addr; |
break; |
case DW_AT_ranges: |
if (!read_rangelist (unit, &unit->arange, attr.u.val)) |
return NULL; |
break; |
case DW_AT_comp_dir: |
{ |
char *comp_dir = attr.u.str; |
if (comp_dir) |
{ |
/* Irix 6.2 native cc prepends <machine>.: to the compilation |
directory, get rid of it. */ |
char *cp = strchr (comp_dir, ':'); |
if (cp && cp != comp_dir && cp[-1] == '.' && cp[1] == '/') |
comp_dir = cp + 1; |
} |
unit->comp_dir = comp_dir; |
break; |
} |
default: |
break; |
} |
} |
if (high_pc_relative) |
high_pc += low_pc; |
if (high_pc != 0) |
{ |
if (!arange_add (unit, &unit->arange, low_pc, high_pc)) |
return NULL; |
} |
unit->first_child_die_ptr = info_ptr; |
return unit; |
} |
/* Return TRUE if UNIT may contain the address given by ADDR. When |
there are functions written entirely with inline asm statements, the |
range info in the compilation unit header may not be correct. We |
need to consult the line info table to see if a compilation unit |
really contains the given address. */ |
static bfd_boolean |
comp_unit_contains_address (struct comp_unit *unit, bfd_vma addr) |
{ |
struct arange *arange; |
if (unit->error) |
return FALSE; |
arange = &unit->arange; |
do |
{ |
if (addr >= arange->low && addr < arange->high) |
return TRUE; |
arange = arange->next; |
} |
while (arange); |
return FALSE; |
} |
/* If UNIT contains ADDR, set the output parameters to the values for |
the line containing ADDR. The output parameters, FILENAME_PTR, |
FUNCTIONNAME_PTR, and LINENUMBER_PTR, are pointers to the objects |
to be filled in. |
Return TRUE if UNIT contains ADDR, and no errors were encountered; |
FALSE otherwise. */ |
static bfd_boolean |
comp_unit_find_nearest_line (struct comp_unit *unit, |
bfd_vma addr, |
const char **filename_ptr, |
const char **functionname_ptr, |
unsigned int *linenumber_ptr, |
unsigned int *discriminator_ptr, |
struct dwarf2_debug *stash) |
{ |
bfd_boolean line_p; |
bfd_boolean func_p; |
struct funcinfo *function; |
if (unit->error) |
return FALSE; |
if (! unit->line_table) |
{ |
if (! unit->stmtlist) |
{ |
unit->error = 1; |
return FALSE; |
} |
unit->line_table = decode_line_info (unit, stash); |
if (! unit->line_table) |
{ |
unit->error = 1; |
return FALSE; |
} |
if (unit->first_child_die_ptr < unit->end_ptr |
&& ! scan_unit_for_symbols (unit)) |
{ |
unit->error = 1; |
return FALSE; |
} |
} |
function = NULL; |
func_p = lookup_address_in_function_table (unit, addr, |
&function, functionname_ptr); |
if (func_p && (function->tag == DW_TAG_inlined_subroutine)) |
stash->inliner_chain = function; |
line_p = lookup_address_in_line_info_table (unit->line_table, addr, |
filename_ptr, |
linenumber_ptr, |
discriminator_ptr); |
return line_p || func_p; |
} |
/* Check to see if line info is already decoded in a comp_unit. |
If not, decode it. Returns TRUE if no errors were encountered; |
FALSE otherwise. */ |
static bfd_boolean |
comp_unit_maybe_decode_line_info (struct comp_unit *unit, |
struct dwarf2_debug *stash) |
{ |
if (unit->error) |
return FALSE; |
if (! unit->line_table) |
{ |
if (! unit->stmtlist) |
{ |
unit->error = 1; |
return FALSE; |
} |
unit->line_table = decode_line_info (unit, stash); |
if (! unit->line_table) |
{ |
unit->error = 1; |
return FALSE; |
} |
if (unit->first_child_die_ptr < unit->end_ptr |
&& ! scan_unit_for_symbols (unit)) |
{ |
unit->error = 1; |
return FALSE; |
} |
} |
return TRUE; |
} |
/* If UNIT contains SYM at ADDR, set the output parameters to the |
values for the line containing SYM. The output parameters, |
FILENAME_PTR, and LINENUMBER_PTR, are pointers to the objects to be |
filled in. |
Return TRUE if UNIT contains SYM, and no errors were encountered; |
FALSE otherwise. */ |
static bfd_boolean |
comp_unit_find_line (struct comp_unit *unit, |
asymbol *sym, |
bfd_vma addr, |
const char **filename_ptr, |
unsigned int *linenumber_ptr, |
struct dwarf2_debug *stash) |
{ |
if (!comp_unit_maybe_decode_line_info (unit, stash)) |
return FALSE; |
if (sym->flags & BSF_FUNCTION) |
return lookup_symbol_in_function_table (unit, sym, addr, |
filename_ptr, |
linenumber_ptr); |
return lookup_symbol_in_variable_table (unit, sym, addr, |
filename_ptr, |
linenumber_ptr); |
} |
static struct funcinfo * |
reverse_funcinfo_list (struct funcinfo *head) |
{ |
struct funcinfo *rhead; |
struct funcinfo *temp; |
for (rhead = NULL; head; head = temp) |
{ |
temp = head->prev_func; |
head->prev_func = rhead; |
rhead = head; |
} |
return rhead; |
} |
static struct varinfo * |
reverse_varinfo_list (struct varinfo *head) |
{ |
struct varinfo *rhead; |
struct varinfo *temp; |
for (rhead = NULL; head; head = temp) |
{ |
temp = head->prev_var; |
head->prev_var = rhead; |
rhead = head; |
} |
return rhead; |
} |
/* Extract all interesting funcinfos and varinfos of a compilation |
unit into hash tables for faster lookup. Returns TRUE if no |
errors were enountered; FALSE otherwise. */ |
static bfd_boolean |
comp_unit_hash_info (struct dwarf2_debug *stash, |
struct comp_unit *unit, |
struct info_hash_table *funcinfo_hash_table, |
struct info_hash_table *varinfo_hash_table) |
{ |
struct funcinfo* each_func; |
struct varinfo* each_var; |
bfd_boolean okay = TRUE; |
BFD_ASSERT (stash->info_hash_status != STASH_INFO_HASH_DISABLED); |
if (!comp_unit_maybe_decode_line_info (unit, stash)) |
return FALSE; |
BFD_ASSERT (!unit->cached); |
/* To preserve the original search order, we went to visit the function |
infos in the reversed order of the list. However, making the list |
bi-directional use quite a bit of extra memory. So we reverse |
the list first, traverse the list in the now reversed order and |
finally reverse the list again to get back the original order. */ |
unit->function_table = reverse_funcinfo_list (unit->function_table); |
for (each_func = unit->function_table; |
each_func && okay; |
each_func = each_func->prev_func) |
{ |
/* Skip nameless functions. */ |
if (each_func->name) |
/* There is no need to copy name string into hash table as |
name string is either in the dwarf string buffer or |
info in the stash. */ |
okay = insert_info_hash_table (funcinfo_hash_table, each_func->name, |
(void*) each_func, FALSE); |
} |
unit->function_table = reverse_funcinfo_list (unit->function_table); |
if (!okay) |
return FALSE; |
/* We do the same for variable infos. */ |
unit->variable_table = reverse_varinfo_list (unit->variable_table); |
for (each_var = unit->variable_table; |
each_var && okay; |
each_var = each_var->prev_var) |
{ |
/* Skip stack vars and vars with no files or names. */ |
if (each_var->stack == 0 |
&& each_var->file != NULL |
&& each_var->name != NULL) |
/* There is no need to copy name string into hash table as |
name string is either in the dwarf string buffer or |
info in the stash. */ |
okay = insert_info_hash_table (varinfo_hash_table, each_var->name, |
(void*) each_var, FALSE); |
} |
unit->variable_table = reverse_varinfo_list (unit->variable_table); |
unit->cached = TRUE; |
return okay; |
} |
/* Locate a section in a BFD containing debugging info. The search starts |
from the section after AFTER_SEC, or from the first section in the BFD if |
AFTER_SEC is NULL. The search works by examining the names of the |
sections. There are three permissiable names. The first two are given |
by DEBUG_SECTIONS[debug_info] (whose standard DWARF2 names are .debug_info |
and .zdebug_info). The third is a prefix .gnu.linkonce.wi. |
This is a variation on the .debug_info section which has a checksum |
describing the contents appended onto the name. This allows the linker to |
identify and discard duplicate debugging sections for different |
compilation units. */ |
#define GNU_LINKONCE_INFO ".gnu.linkonce.wi." |
static asection * |
find_debug_info (bfd *abfd, const struct dwarf_debug_section *debug_sections, |
asection *after_sec) |
{ |
asection *msec; |
const char *look; |
if (after_sec == NULL) |
{ |
look = debug_sections[debug_info].uncompressed_name; |
msec = bfd_get_section_by_name (abfd, look); |
if (msec != NULL) |
return msec; |
look = debug_sections[debug_info].compressed_name; |
if (look != NULL) |
{ |
msec = bfd_get_section_by_name (abfd, look); |
if (msec != NULL) |
return msec; |
} |
for (msec = abfd->sections; msec != NULL; msec = msec->next) |
if (CONST_STRNEQ (msec->name, GNU_LINKONCE_INFO)) |
return msec; |
return NULL; |
} |
for (msec = after_sec->next; msec != NULL; msec = msec->next) |
{ |
look = debug_sections[debug_info].uncompressed_name; |
if (strcmp (msec->name, look) == 0) |
return msec; |
look = debug_sections[debug_info].compressed_name; |
if (look != NULL && strcmp (msec->name, look) == 0) |
return msec; |
if (CONST_STRNEQ (msec->name, GNU_LINKONCE_INFO)) |
return msec; |
} |
return NULL; |
} |
/* Unset vmas for adjusted sections in STASH. */ |
static void |
unset_sections (struct dwarf2_debug *stash) |
{ |
unsigned int i; |
struct adjusted_section *p; |
i = stash->adjusted_section_count; |
p = stash->adjusted_sections; |
for (; i > 0; i--, p++) |
p->section->vma = 0; |
} |
/* Set unique VMAs for loadable and DWARF sections in ABFD and save |
VMAs in STASH for unset_sections. */ |
static bfd_boolean |
place_sections (bfd *abfd, struct dwarf2_debug *stash) |
{ |
struct adjusted_section *p; |
unsigned int i; |
if (stash->adjusted_section_count != 0) |
{ |
i = stash->adjusted_section_count; |
p = stash->adjusted_sections; |
for (; i > 0; i--, p++) |
p->section->vma = p->adj_vma; |
} |
else |
{ |
asection *sect; |
bfd_vma last_vma = 0, last_dwarf = 0; |
bfd_size_type amt; |
const char *debug_info_name; |
debug_info_name = stash->debug_sections[debug_info].uncompressed_name; |
i = 0; |
for (sect = abfd->sections; sect != NULL; sect = sect->next) |
{ |
bfd_size_type sz; |
int is_debug_info; |
if (sect->vma != 0) |
continue; |
/* We need to adjust the VMAs of any .debug_info sections. |
Skip compressed ones, since no relocations could target |
them - they should not appear in object files anyway. */ |
if (strcmp (sect->name, debug_info_name) == 0) |
is_debug_info = 1; |
else if (CONST_STRNEQ (sect->name, GNU_LINKONCE_INFO)) |
is_debug_info = 1; |
else |
is_debug_info = 0; |
if (!is_debug_info && (sect->flags & SEC_LOAD) == 0) |
continue; |
sz = sect->rawsize ? sect->rawsize : sect->size; |
if (sz == 0) |
continue; |
i++; |
} |
amt = i * sizeof (struct adjusted_section); |
p = (struct adjusted_section *) bfd_alloc (abfd, amt); |
if (! p) |
return FALSE; |
stash->adjusted_sections = p; |
stash->adjusted_section_count = i; |
for (sect = abfd->sections; sect != NULL; sect = sect->next) |
{ |
bfd_size_type sz; |
int is_debug_info; |
if (sect->vma != 0) |
continue; |
/* We need to adjust the VMAs of any .debug_info sections. |
Skip compressed ones, since no relocations could target |
them - they should not appear in object files anyway. */ |
if (strcmp (sect->name, debug_info_name) == 0) |
is_debug_info = 1; |
else if (CONST_STRNEQ (sect->name, GNU_LINKONCE_INFO)) |
is_debug_info = 1; |
else |
is_debug_info = 0; |
if (!is_debug_info && (sect->flags & SEC_LOAD) == 0) |
continue; |
sz = sect->rawsize ? sect->rawsize : sect->size; |
if (sz == 0) |
continue; |
p->section = sect; |
if (is_debug_info) |
{ |
BFD_ASSERT (sect->alignment_power == 0); |
sect->vma = last_dwarf; |
last_dwarf += sz; |
} |
else if (last_vma != 0) |
{ |
/* Align the new address to the current section |
alignment. */ |
last_vma = ((last_vma |
+ ~((bfd_vma) -1 << sect->alignment_power)) |
& ((bfd_vma) -1 << sect->alignment_power)); |
sect->vma = last_vma; |
last_vma += sect->vma + sz; |
} |
else |
last_vma += sect->vma + sz; |
p->adj_vma = sect->vma; |
p++; |
} |
} |
return TRUE; |
} |
/* Look up a funcinfo by name using the given info hash table. If found, |
also update the locations pointed to by filename_ptr and linenumber_ptr. |
This function returns TRUE if a funcinfo that matches the given symbol |
and address is found with any error; otherwise it returns FALSE. */ |
static bfd_boolean |
info_hash_lookup_funcinfo (struct info_hash_table *hash_table, |
asymbol *sym, |
bfd_vma addr, |
const char **filename_ptr, |
unsigned int *linenumber_ptr) |
{ |
struct funcinfo* each_func; |
struct funcinfo* best_fit = NULL; |
struct info_list_node *node; |
struct arange *arange; |
const char *name = bfd_asymbol_name (sym); |
asection *sec = bfd_get_section (sym); |
for (node = lookup_info_hash_table (hash_table, name); |
node; |
node = node->next) |
{ |
each_func = (struct funcinfo *) node->info; |
for (arange = &each_func->arange; |
arange; |
arange = arange->next) |
{ |
if ((!each_func->sec || each_func->sec == sec) |
&& addr >= arange->low |
&& addr < arange->high |
&& (!best_fit |
|| (arange->high - arange->low |
< best_fit->arange.high - best_fit->arange.low))) |
best_fit = each_func; |
} |
} |
if (best_fit) |
{ |
best_fit->sec = sec; |
*filename_ptr = best_fit->file; |
*linenumber_ptr = best_fit->line; |
return TRUE; |
} |
return FALSE; |
} |
/* Look up a varinfo by name using the given info hash table. If found, |
also update the locations pointed to by filename_ptr and linenumber_ptr. |
This function returns TRUE if a varinfo that matches the given symbol |
and address is found with any error; otherwise it returns FALSE. */ |
static bfd_boolean |
info_hash_lookup_varinfo (struct info_hash_table *hash_table, |
asymbol *sym, |
bfd_vma addr, |
const char **filename_ptr, |
unsigned int *linenumber_ptr) |
{ |
const char *name = bfd_asymbol_name (sym); |
asection *sec = bfd_get_section (sym); |
struct varinfo* each; |
struct info_list_node *node; |
for (node = lookup_info_hash_table (hash_table, name); |
node; |
node = node->next) |
{ |
each = (struct varinfo *) node->info; |
if (each->addr == addr |
&& (!each->sec || each->sec == sec)) |
{ |
each->sec = sec; |
*filename_ptr = each->file; |
*linenumber_ptr = each->line; |
return TRUE; |
} |
} |
return FALSE; |
} |
/* Update the funcinfo and varinfo info hash tables if they are |
not up to date. Returns TRUE if there is no error; otherwise |
returns FALSE and disable the info hash tables. */ |
static bfd_boolean |
stash_maybe_update_info_hash_tables (struct dwarf2_debug *stash) |
{ |
struct comp_unit *each; |
/* Exit if hash tables are up-to-date. */ |
if (stash->all_comp_units == stash->hash_units_head) |
return TRUE; |
if (stash->hash_units_head) |
each = stash->hash_units_head->prev_unit; |
else |
each = stash->last_comp_unit; |
while (each) |
{ |
if (!comp_unit_hash_info (stash, each, stash->funcinfo_hash_table, |
stash->varinfo_hash_table)) |
{ |
stash->info_hash_status = STASH_INFO_HASH_DISABLED; |
return FALSE; |
} |
each = each->prev_unit; |
} |
stash->hash_units_head = stash->all_comp_units; |
return TRUE; |
} |
/* Check consistency of info hash tables. This is for debugging only. */ |
static void ATTRIBUTE_UNUSED |
stash_verify_info_hash_table (struct dwarf2_debug *stash) |
{ |
struct comp_unit *each_unit; |
struct funcinfo *each_func; |
struct varinfo *each_var; |
struct info_list_node *node; |
bfd_boolean found; |
for (each_unit = stash->all_comp_units; |
each_unit; |
each_unit = each_unit->next_unit) |
{ |
for (each_func = each_unit->function_table; |
each_func; |
each_func = each_func->prev_func) |
{ |
if (!each_func->name) |
continue; |
node = lookup_info_hash_table (stash->funcinfo_hash_table, |
each_func->name); |
BFD_ASSERT (node); |
found = FALSE; |
while (node && !found) |
{ |
found = node->info == each_func; |
node = node->next; |
} |
BFD_ASSERT (found); |
} |
for (each_var = each_unit->variable_table; |
each_var; |
each_var = each_var->prev_var) |
{ |
if (!each_var->name || !each_var->file || each_var->stack) |
continue; |
node = lookup_info_hash_table (stash->varinfo_hash_table, |
each_var->name); |
BFD_ASSERT (node); |
found = FALSE; |
while (node && !found) |
{ |
found = node->info == each_var; |
node = node->next; |
} |
BFD_ASSERT (found); |
} |
} |
} |
/* Check to see if we want to enable the info hash tables, which consume |
quite a bit of memory. Currently we only check the number times |
bfd_dwarf2_find_line is called. In the future, we may also want to |
take the number of symbols into account. */ |
static void |
stash_maybe_enable_info_hash_tables (bfd *abfd, struct dwarf2_debug *stash) |
{ |
BFD_ASSERT (stash->info_hash_status == STASH_INFO_HASH_OFF); |
if (stash->info_hash_count++ < STASH_INFO_HASH_TRIGGER) |
return; |
/* FIXME: Maybe we should check the reduce_memory_overheads |
and optimize fields in the bfd_link_info structure ? */ |
/* Create hash tables. */ |
stash->funcinfo_hash_table = create_info_hash_table (abfd); |
stash->varinfo_hash_table = create_info_hash_table (abfd); |
if (!stash->funcinfo_hash_table || !stash->varinfo_hash_table) |
{ |
/* Turn off info hashes if any allocation above fails. */ |
stash->info_hash_status = STASH_INFO_HASH_DISABLED; |
return; |
} |
/* We need a forced update so that the info hash tables will |
be created even though there is no compilation unit. That |
happens if STASH_INFO_HASH_TRIGGER is 0. */ |
stash_maybe_update_info_hash_tables (stash); |
stash->info_hash_status = STASH_INFO_HASH_ON; |
} |
/* Find the file and line associated with a symbol and address using the |
info hash tables of a stash. If there is a match, the function returns |
TRUE and update the locations pointed to by filename_ptr and linenumber_ptr; |
otherwise it returns FALSE. */ |
static bfd_boolean |
stash_find_line_fast (struct dwarf2_debug *stash, |
asymbol *sym, |
bfd_vma addr, |
const char **filename_ptr, |
unsigned int *linenumber_ptr) |
{ |
BFD_ASSERT (stash->info_hash_status == STASH_INFO_HASH_ON); |
if (sym->flags & BSF_FUNCTION) |
return info_hash_lookup_funcinfo (stash->funcinfo_hash_table, sym, addr, |
filename_ptr, linenumber_ptr); |
return info_hash_lookup_varinfo (stash->varinfo_hash_table, sym, addr, |
filename_ptr, linenumber_ptr); |
} |
/* Read debug information from DEBUG_BFD when DEBUG_BFD is specified. |
If DEBUG_BFD is not specified, we read debug information from ABFD |
or its gnu_debuglink. The results will be stored in PINFO. |
The function returns TRUE iff debug information is ready. */ |
bfd_boolean |
_bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd, |
const struct dwarf_debug_section *debug_sections, |
asymbol **symbols, |
void **pinfo) |
{ |
bfd_size_type amt = sizeof (struct dwarf2_debug); |
bfd_size_type total_size; |
asection *msec; |
struct dwarf2_debug *stash = (struct dwarf2_debug *) *pinfo; |
if (stash != NULL) |
return TRUE; |
stash = (struct dwarf2_debug *) bfd_zalloc (abfd, amt); |
if (! stash) |
return FALSE; |
stash->debug_sections = debug_sections; |
stash->syms = symbols; |
*pinfo = stash; |
if (debug_bfd == NULL) |
debug_bfd = abfd; |
msec = find_debug_info (debug_bfd, debug_sections, NULL); |
if (msec == NULL && abfd == debug_bfd) |
{ |
char * debug_filename = bfd_follow_gnu_debuglink (abfd, DEBUGDIR); |
if (debug_filename == NULL) |
/* No dwarf2 info, and no gnu_debuglink to follow. |
Note that at this point the stash has been allocated, but |
contains zeros. This lets future calls to this function |
fail more quickly. */ |
return FALSE; |
if ((debug_bfd = bfd_openr (debug_filename, NULL)) == NULL |
|| ! bfd_check_format (debug_bfd, bfd_object) |
|| (msec = find_debug_info (debug_bfd, |
debug_sections, NULL)) == NULL) |
{ |
if (debug_bfd) |
bfd_close (debug_bfd); |
/* FIXME: Should we report our failure to follow the debuglink ? */ |
free (debug_filename); |
return FALSE; |
} |
stash->close_on_cleanup = TRUE; |
} |
stash->bfd_ptr = debug_bfd; |
/* There can be more than one DWARF2 info section in a BFD these |
days. First handle the easy case when there's only one. If |
there's more than one, try case two: none of the sections is |
compressed. In that case, read them all in and produce one |
large stash. We do this in two passes - in the first pass we |
just accumulate the section sizes, and in the second pass we |
read in the section's contents. (The allows us to avoid |
reallocing the data as we add sections to the stash.) If |
some or all sections are compressed, then do things the slow |
way, with a bunch of reallocs. */ |
if (! find_debug_info (debug_bfd, debug_sections, msec)) |
{ |
/* Case 1: only one info section. */ |
total_size = msec->size; |
if (! read_section (debug_bfd, &stash->debug_sections[debug_info], |
symbols, 0, |
&stash->info_ptr_memory, &total_size)) |
return FALSE; |
} |
else |
{ |
/* Case 2: multiple sections. */ |
for (total_size = 0; |
msec; |
msec = find_debug_info (debug_bfd, debug_sections, msec)) |
total_size += msec->size; |
stash->info_ptr_memory = (bfd_byte *) bfd_malloc (total_size); |
if (stash->info_ptr_memory == NULL) |
return FALSE; |
total_size = 0; |
for (msec = find_debug_info (debug_bfd, debug_sections, NULL); |
msec; |
msec = find_debug_info (debug_bfd, debug_sections, msec)) |
{ |
bfd_size_type size; |
size = msec->size; |
if (size == 0) |
continue; |
if (!(bfd_simple_get_relocated_section_contents |
(debug_bfd, msec, stash->info_ptr_memory + total_size, |
symbols))) |
return FALSE; |
total_size += size; |
} |
} |
stash->info_ptr = stash->info_ptr_memory; |
stash->info_ptr_end = stash->info_ptr + total_size; |
stash->sec = find_debug_info (debug_bfd, debug_sections, NULL); |
stash->sec_info_ptr = stash->info_ptr; |
return TRUE; |
} |
/* Find the source code location of SYMBOL. If SYMBOL is NULL |
then find the nearest source code location corresponding to |
the address SECTION + OFFSET. |
Returns TRUE if the line is found without error and fills in |
FILENAME_PTR and LINENUMBER_PTR. In the case where SYMBOL was |
NULL the FUNCTIONNAME_PTR is also filled in. |
SYMBOLS contains the symbol table for ABFD. |
DEBUG_SECTIONS contains the name of the dwarf debug sections. |
ADDR_SIZE is the number of bytes in the initial .debug_info length |
field and in the abbreviation offset, or zero to indicate that the |
default value should be used. */ |
static bfd_boolean |
find_line (bfd *abfd, |
const struct dwarf_debug_section *debug_sections, |
asection *section, |
bfd_vma offset, |
asymbol *symbol, |
asymbol **symbols, |
const char **filename_ptr, |
const char **functionname_ptr, |
unsigned int *linenumber_ptr, |
unsigned int *discriminator_ptr, |
unsigned int addr_size, |
void **pinfo) |
{ |
/* Read each compilation unit from the section .debug_info, and check |
to see if it contains the address we are searching for. If yes, |
lookup the address, and return the line number info. If no, go |
on to the next compilation unit. |
We keep a list of all the previously read compilation units, and |
a pointer to the next un-read compilation unit. Check the |
previously read units before reading more. */ |
struct dwarf2_debug *stash; |
/* What address are we looking for? */ |
bfd_vma addr; |
struct comp_unit* each; |
bfd_vma found = FALSE; |
bfd_boolean do_line; |
*filename_ptr = NULL; |
if (functionname_ptr != NULL) |
*functionname_ptr = NULL; |
*linenumber_ptr = 0; |
if (discriminator_ptr) |
*discriminator_ptr = 0; |
if (! _bfd_dwarf2_slurp_debug_info (abfd, NULL, |
debug_sections, symbols, pinfo)) |
return FALSE; |
stash = (struct dwarf2_debug *) *pinfo; |
/* In a relocatable file, 2 functions may have the same address. |
We change the section vma so that they won't overlap. */ |
if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) |
{ |
if (! place_sections (abfd, stash)) |
return FALSE; |
} |
do_line = (section == NULL |
&& offset == 0 |
&& functionname_ptr == NULL |
&& symbol != NULL); |
if (do_line) |
{ |
addr = symbol->value; |
section = bfd_get_section (symbol); |
} |
else if (section != NULL |
&& functionname_ptr != NULL |
&& symbol == NULL) |
addr = offset; |
else |
abort (); |
if (section->output_section) |
addr += section->output_section->vma + section->output_offset; |
else |
addr += section->vma; |
/* A null info_ptr indicates that there is no dwarf2 info |
(or that an error occured while setting up the stash). */ |
if (! stash->info_ptr) |
return FALSE; |
stash->inliner_chain = NULL; |
/* Check the previously read comp. units first. */ |
if (do_line) |
{ |
/* The info hash tables use quite a bit of memory. We may not want to |
always use them. We use some heuristics to decide if and when to |
turn it on. */ |
if (stash->info_hash_status == STASH_INFO_HASH_OFF) |
stash_maybe_enable_info_hash_tables (abfd, stash); |
/* Keep info hash table up to date if they are available. Note that we |
may disable the hash tables if there is any error duing update. */ |
if (stash->info_hash_status == STASH_INFO_HASH_ON) |
stash_maybe_update_info_hash_tables (stash); |
if (stash->info_hash_status == STASH_INFO_HASH_ON) |
{ |
found = stash_find_line_fast (stash, symbol, addr, filename_ptr, |
linenumber_ptr); |
if (found) |
goto done; |
} |
else |
{ |
/* Check the previously read comp. units first. */ |
for (each = stash->all_comp_units; each; each = each->next_unit) |
if ((symbol->flags & BSF_FUNCTION) == 0 |
|| each->arange.high == 0 |
|| comp_unit_contains_address (each, addr)) |
{ |
found = comp_unit_find_line (each, symbol, addr, filename_ptr, |
linenumber_ptr, stash); |
if (found) |
goto done; |
} |
} |
} |
else |
{ |
for (each = stash->all_comp_units; each; each = each->next_unit) |
{ |
found = ((each->arange.high == 0 |
|| comp_unit_contains_address (each, addr)) |
&& comp_unit_find_nearest_line (each, addr, |
filename_ptr, |
functionname_ptr, |
linenumber_ptr, |
discriminator_ptr, |
stash)); |
if (found) |
goto done; |
} |
} |
/* The DWARF2 spec says that the initial length field, and the |
offset of the abbreviation table, should both be 4-byte values. |
However, some compilers do things differently. */ |
if (addr_size == 0) |
addr_size = 4; |
BFD_ASSERT (addr_size == 4 || addr_size == 8); |
/* Read each remaining comp. units checking each as they are read. */ |
while (stash->info_ptr < stash->info_ptr_end) |
{ |
bfd_vma length; |
unsigned int offset_size = addr_size; |
bfd_byte *info_ptr_unit = stash->info_ptr; |
length = read_4_bytes (stash->bfd_ptr, stash->info_ptr); |
/* A 0xffffff length is the DWARF3 way of indicating |
we use 64-bit offsets, instead of 32-bit offsets. */ |
if (length == 0xffffffff) |
{ |
offset_size = 8; |
length = read_8_bytes (stash->bfd_ptr, stash->info_ptr + 4); |
stash->info_ptr += 12; |
} |
/* A zero length is the IRIX way of indicating 64-bit offsets, |
mostly because the 64-bit length will generally fit in 32 |
bits, and the endianness helps. */ |
else if (length == 0) |
{ |
offset_size = 8; |
length = read_4_bytes (stash->bfd_ptr, stash->info_ptr + 4); |
stash->info_ptr += 8; |
} |
/* In the absence of the hints above, we assume 32-bit DWARF2 |
offsets even for targets with 64-bit addresses, because: |
a) most of the time these targets will not have generated |
more than 2Gb of debug info and so will not need 64-bit |
offsets, |
and |
b) if they do use 64-bit offsets but they are not using |
the size hints that are tested for above then they are |
not conforming to the DWARF3 standard anyway. */ |
else if (addr_size == 8) |
{ |
offset_size = 4; |
stash->info_ptr += 4; |
} |
else |
stash->info_ptr += 4; |
if (length > 0) |
{ |
each = parse_comp_unit (stash, length, info_ptr_unit, |
offset_size); |
if (!each) |
/* The dwarf information is damaged, don't trust it any |
more. */ |
break; |
stash->info_ptr += length; |
if (stash->all_comp_units) |
stash->all_comp_units->prev_unit = each; |
else |
stash->last_comp_unit = each; |
each->next_unit = stash->all_comp_units; |
stash->all_comp_units = each; |
/* DW_AT_low_pc and DW_AT_high_pc are optional for |
compilation units. If we don't have them (i.e., |
unit->high == 0), we need to consult the line info table |
to see if a compilation unit contains the given |
address. */ |
if (do_line) |
found = (((symbol->flags & BSF_FUNCTION) == 0 |
|| each->arange.high == 0 |
|| comp_unit_contains_address (each, addr)) |
&& comp_unit_find_line (each, symbol, addr, |
filename_ptr, |
linenumber_ptr, |
stash)); |
else |
found = ((each->arange.high == 0 |
|| comp_unit_contains_address (each, addr)) |
&& comp_unit_find_nearest_line (each, addr, |
filename_ptr, |
functionname_ptr, |
linenumber_ptr, |
discriminator_ptr, |
stash)); |
if ((bfd_vma) (stash->info_ptr - stash->sec_info_ptr) |
== stash->sec->size) |
{ |
stash->sec = find_debug_info (stash->bfd_ptr, debug_sections, |
stash->sec); |
stash->sec_info_ptr = stash->info_ptr; |
} |
if (found) |
goto done; |
} |
} |
done: |
if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) |
unset_sections (stash); |
return found; |
} |
/* The DWARF2 version of find_nearest_line. |
Return TRUE if the line is found without error. */ |
bfd_boolean |
_bfd_dwarf2_find_nearest_line (bfd *abfd, |
const struct dwarf_debug_section *debug_sections, |
asection *section, |
asymbol **symbols, |
bfd_vma offset, |
const char **filename_ptr, |
const char **functionname_ptr, |
unsigned int *linenumber_ptr, |
unsigned int *discriminator_ptr, |
unsigned int addr_size, |
void **pinfo) |
{ |
return find_line (abfd, debug_sections, section, offset, NULL, symbols, |
filename_ptr, functionname_ptr, linenumber_ptr, |
discriminator_ptr, addr_size, pinfo); |
} |
/* The DWARF2 version of find_line. |
Return TRUE if the line is found without error. */ |
bfd_boolean |
_bfd_dwarf2_find_line (bfd *abfd, |
asymbol **symbols, |
asymbol *symbol, |
const char **filename_ptr, |
unsigned int *linenumber_ptr, |
unsigned int *discriminator_ptr, |
unsigned int addr_size, |
void **pinfo) |
{ |
return find_line (abfd, dwarf_debug_sections, NULL, 0, symbol, symbols, |
filename_ptr, NULL, linenumber_ptr, discriminator_ptr, |
addr_size, pinfo); |
} |
bfd_boolean |
_bfd_dwarf2_find_inliner_info (bfd *abfd ATTRIBUTE_UNUSED, |
const char **filename_ptr, |
const char **functionname_ptr, |
unsigned int *linenumber_ptr, |
void **pinfo) |
{ |
struct dwarf2_debug *stash; |
stash = (struct dwarf2_debug *) *pinfo; |
if (stash) |
{ |
struct funcinfo *func = stash->inliner_chain; |
if (func && func->caller_func) |
{ |
*filename_ptr = func->caller_file; |
*functionname_ptr = func->caller_func->name; |
*linenumber_ptr = func->caller_line; |
stash->inliner_chain = func->caller_func; |
return TRUE; |
} |
} |
return FALSE; |
} |
void |
_bfd_dwarf2_cleanup_debug_info (bfd *abfd, void **pinfo) |
{ |
struct dwarf2_debug *stash = (struct dwarf2_debug *) *pinfo; |
struct comp_unit *each; |
if (abfd == NULL || stash == NULL) |
return; |
for (each = stash->all_comp_units; each; each = each->next_unit) |
{ |
struct abbrev_info **abbrevs = each->abbrevs; |
struct funcinfo *function_table = each->function_table; |
struct varinfo *variable_table = each->variable_table; |
size_t i; |
for (i = 0; i < ABBREV_HASH_SIZE; i++) |
{ |
struct abbrev_info *abbrev = abbrevs[i]; |
while (abbrev) |
{ |
free (abbrev->attrs); |
abbrev = abbrev->next; |
} |
} |
if (each->line_table) |
{ |
free (each->line_table->dirs); |
free (each->line_table->files); |
} |
while (function_table) |
{ |
if (function_table->file) |
{ |
free (function_table->file); |
function_table->file = NULL; |
} |
if (function_table->caller_file) |
{ |
free (function_table->caller_file); |
function_table->caller_file = NULL; |
} |
function_table = function_table->prev_func; |
} |
while (variable_table) |
{ |
if (variable_table->file) |
{ |
free (variable_table->file); |
variable_table->file = NULL; |
} |
variable_table = variable_table->prev_var; |
} |
} |
if (stash->dwarf_abbrev_buffer) |
free (stash->dwarf_abbrev_buffer); |
if (stash->dwarf_line_buffer) |
free (stash->dwarf_line_buffer); |
if (stash->dwarf_str_buffer) |
free (stash->dwarf_str_buffer); |
if (stash->dwarf_ranges_buffer) |
free (stash->dwarf_ranges_buffer); |
if (stash->info_ptr_memory) |
free (stash->info_ptr_memory); |
if (stash->close_on_cleanup) |
bfd_close (stash->bfd_ptr); |
if (stash->alt_dwarf_str_buffer) |
free (stash->alt_dwarf_str_buffer); |
if (stash->alt_dwarf_info_buffer) |
free (stash->alt_dwarf_info_buffer); |
if (stash->alt_bfd_ptr) |
bfd_close (stash->alt_bfd_ptr); |
} |
/contrib/toolchain/binutils/bfd/elf-attrs.c |
---|
0,0 → 1,703 |
/* ELF attributes support (based on ARM EABI attributes). |
Copyright 2005, 2006, 2007, 2009, 2010, 2012 |
Free Software Foundation, Inc. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libiberty.h" |
#include "libbfd.h" |
#include "elf-bfd.h" |
/* Return the number of bytes needed by I in uleb128 format. */ |
static int |
uleb128_size (unsigned int i) |
{ |
int size; |
size = 1; |
while (i >= 0x80) |
{ |
i >>= 7; |
size++; |
} |
return size; |
} |
/* Return TRUE if the attribute has the default value (0/""). */ |
static bfd_boolean |
is_default_attr (obj_attribute *attr) |
{ |
if (ATTR_TYPE_HAS_INT_VAL (attr->type) && attr->i != 0) |
return FALSE; |
if (ATTR_TYPE_HAS_STR_VAL (attr->type) && attr->s && *attr->s) |
return FALSE; |
if (ATTR_TYPE_HAS_NO_DEFAULT (attr->type)) |
return FALSE; |
return TRUE; |
} |
/* Return the size of a single attribute. */ |
static bfd_vma |
obj_attr_size (int tag, obj_attribute *attr) |
{ |
bfd_vma size; |
if (is_default_attr (attr)) |
return 0; |
size = uleb128_size (tag); |
if (ATTR_TYPE_HAS_INT_VAL (attr->type)) |
size += uleb128_size (attr->i); |
if (ATTR_TYPE_HAS_STR_VAL (attr->type)) |
size += strlen ((char *)attr->s) + 1; |
return size; |
} |
/* Return the vendor name for a given object attributes section. */ |
static const char * |
vendor_obj_attr_name (bfd *abfd, int vendor) |
{ |
return (vendor == OBJ_ATTR_PROC |
? get_elf_backend_data (abfd)->obj_attrs_vendor |
: "gnu"); |
} |
/* Return the size of the object attributes section for VENDOR |
(OBJ_ATTR_PROC or OBJ_ATTR_GNU), or 0 if there are no attributes |
for that vendor to record and the vendor is OBJ_ATTR_GNU. */ |
static bfd_vma |
vendor_obj_attr_size (bfd *abfd, int vendor) |
{ |
bfd_vma size; |
obj_attribute *attr; |
obj_attribute_list *list; |
int i; |
const char *vendor_name = vendor_obj_attr_name (abfd, vendor); |
if (!vendor_name) |
return 0; |
attr = elf_known_obj_attributes (abfd)[vendor]; |
size = 0; |
for (i = LEAST_KNOWN_OBJ_ATTRIBUTE; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++) |
size += obj_attr_size (i, &attr[i]); |
for (list = elf_other_obj_attributes (abfd)[vendor]; |
list; |
list = list->next) |
size += obj_attr_size (list->tag, &list->attr); |
/* <size> <vendor_name> NUL 0x1 <size> */ |
return ((size || vendor == OBJ_ATTR_PROC) |
? size + 10 + strlen (vendor_name) |
: 0); |
} |
/* Return the size of the object attributes section. */ |
bfd_vma |
bfd_elf_obj_attr_size (bfd *abfd) |
{ |
bfd_vma size; |
size = vendor_obj_attr_size (abfd, OBJ_ATTR_PROC); |
size += vendor_obj_attr_size (abfd, OBJ_ATTR_GNU); |
/* 'A' <sections for each vendor> */ |
return (size ? size + 1 : 0); |
} |
/* Write VAL in uleb128 format to P, returning a pointer to the |
following byte. */ |
static bfd_byte * |
write_uleb128 (bfd_byte *p, unsigned int val) |
{ |
bfd_byte c; |
do |
{ |
c = val & 0x7f; |
val >>= 7; |
if (val) |
c |= 0x80; |
*(p++) = c; |
} |
while (val); |
return p; |
} |
/* Write attribute ATTR to butter P, and return a pointer to the following |
byte. */ |
static bfd_byte * |
write_obj_attribute (bfd_byte *p, int tag, obj_attribute *attr) |
{ |
/* Suppress default entries. */ |
if (is_default_attr (attr)) |
return p; |
p = write_uleb128 (p, tag); |
if (ATTR_TYPE_HAS_INT_VAL (attr->type)) |
p = write_uleb128 (p, attr->i); |
if (ATTR_TYPE_HAS_STR_VAL (attr->type)) |
{ |
int len; |
len = strlen (attr->s) + 1; |
memcpy (p, attr->s, len); |
p += len; |
} |
return p; |
} |
/* Write the contents of the object attributes section (length SIZE) |
for VENDOR to CONTENTS. */ |
static void |
vendor_set_obj_attr_contents (bfd *abfd, bfd_byte *contents, bfd_vma size, |
int vendor) |
{ |
bfd_byte *p; |
obj_attribute *attr; |
obj_attribute_list *list; |
int i; |
const char *vendor_name = vendor_obj_attr_name (abfd, vendor); |
size_t vendor_length = strlen (vendor_name) + 1; |
p = contents; |
bfd_put_32 (abfd, size, p); |
p += 4; |
memcpy (p, vendor_name, vendor_length); |
p += vendor_length; |
*(p++) = Tag_File; |
bfd_put_32 (abfd, size - 4 - vendor_length, p); |
p += 4; |
attr = elf_known_obj_attributes (abfd)[vendor]; |
for (i = LEAST_KNOWN_OBJ_ATTRIBUTE; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++) |
{ |
int tag = i; |
if (get_elf_backend_data (abfd)->obj_attrs_order) |
tag = get_elf_backend_data (abfd)->obj_attrs_order (i); |
p = write_obj_attribute (p, tag, &attr[tag]); |
} |
for (list = elf_other_obj_attributes (abfd)[vendor]; |
list; |
list = list->next) |
p = write_obj_attribute (p, list->tag, &list->attr); |
} |
/* Write the contents of the object attributes section to CONTENTS. */ |
void |
bfd_elf_set_obj_attr_contents (bfd *abfd, bfd_byte *contents, bfd_vma size) |
{ |
bfd_byte *p; |
int vendor; |
bfd_vma my_size; |
p = contents; |
*(p++) = 'A'; |
my_size = 1; |
for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++) |
{ |
bfd_vma vendor_size = vendor_obj_attr_size (abfd, vendor); |
if (vendor_size) |
vendor_set_obj_attr_contents (abfd, p, vendor_size, vendor); |
p += vendor_size; |
my_size += vendor_size; |
} |
if (size != my_size) |
abort (); |
} |
/* Allocate/find an object attribute. */ |
static obj_attribute * |
elf_new_obj_attr (bfd *abfd, int vendor, int tag) |
{ |
obj_attribute *attr; |
obj_attribute_list *list; |
obj_attribute_list *p; |
obj_attribute_list **lastp; |
if (tag < NUM_KNOWN_OBJ_ATTRIBUTES) |
{ |
/* Known tags are preallocated. */ |
attr = &elf_known_obj_attributes (abfd)[vendor][tag]; |
} |
else |
{ |
/* Create a new tag. */ |
list = (obj_attribute_list *) |
bfd_alloc (abfd, sizeof (obj_attribute_list)); |
memset (list, 0, sizeof (obj_attribute_list)); |
list->tag = tag; |
/* Keep the tag list in order. */ |
lastp = &elf_other_obj_attributes (abfd)[vendor]; |
for (p = *lastp; p; p = p->next) |
{ |
if (tag < p->tag) |
break; |
lastp = &p->next; |
} |
list->next = *lastp; |
*lastp = list; |
attr = &list->attr; |
} |
return attr; |
} |
/* Return the value of an integer object attribute. */ |
int |
bfd_elf_get_obj_attr_int (bfd *abfd, int vendor, int tag) |
{ |
obj_attribute_list *p; |
if (tag < NUM_KNOWN_OBJ_ATTRIBUTES) |
{ |
/* Known tags are preallocated. */ |
return elf_known_obj_attributes (abfd)[vendor][tag].i; |
} |
else |
{ |
for (p = elf_other_obj_attributes (abfd)[vendor]; |
p; |
p = p->next) |
{ |
if (tag == p->tag) |
return p->attr.i; |
if (tag < p->tag) |
break; |
} |
return 0; |
} |
} |
/* Add an integer object attribute. */ |
void |
bfd_elf_add_obj_attr_int (bfd *abfd, int vendor, int tag, unsigned int i) |
{ |
obj_attribute *attr; |
attr = elf_new_obj_attr (abfd, vendor, tag); |
attr->type = _bfd_elf_obj_attrs_arg_type (abfd, vendor, tag); |
attr->i = i; |
} |
/* Duplicate an object attribute string value. */ |
char * |
_bfd_elf_attr_strdup (bfd *abfd, const char * s) |
{ |
char * p; |
int len; |
len = strlen (s) + 1; |
p = (char *) bfd_alloc (abfd, len); |
return (char *) memcpy (p, s, len); |
} |
/* Add a string object attribute. */ |
void |
bfd_elf_add_obj_attr_string (bfd *abfd, int vendor, int tag, const char *s) |
{ |
obj_attribute *attr; |
attr = elf_new_obj_attr (abfd, vendor, tag); |
attr->type = _bfd_elf_obj_attrs_arg_type (abfd, vendor, tag); |
attr->s = _bfd_elf_attr_strdup (abfd, s); |
} |
/* Add a int+string object attribute. */ |
void |
bfd_elf_add_obj_attr_int_string (bfd *abfd, int vendor, int tag, |
unsigned int i, const char *s) |
{ |
obj_attribute *attr; |
attr = elf_new_obj_attr (abfd, vendor, tag); |
attr->type = _bfd_elf_obj_attrs_arg_type (abfd, vendor, tag); |
attr->i = i; |
attr->s = _bfd_elf_attr_strdup (abfd, s); |
} |
/* Copy the object attributes from IBFD to OBFD. */ |
void |
_bfd_elf_copy_obj_attributes (bfd *ibfd, bfd *obfd) |
{ |
obj_attribute *in_attr; |
obj_attribute *out_attr; |
obj_attribute_list *list; |
int i; |
int vendor; |
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour |
|| bfd_get_flavour (obfd) != bfd_target_elf_flavour) |
return; |
for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++) |
{ |
in_attr |
= &elf_known_obj_attributes (ibfd)[vendor][LEAST_KNOWN_OBJ_ATTRIBUTE]; |
out_attr |
= &elf_known_obj_attributes (obfd)[vendor][LEAST_KNOWN_OBJ_ATTRIBUTE]; |
for (i = LEAST_KNOWN_OBJ_ATTRIBUTE; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++) |
{ |
out_attr->type = in_attr->type; |
out_attr->i = in_attr->i; |
if (in_attr->s && *in_attr->s) |
out_attr->s = _bfd_elf_attr_strdup (obfd, in_attr->s); |
in_attr++; |
out_attr++; |
} |
for (list = elf_other_obj_attributes (ibfd)[vendor]; |
list; |
list = list->next) |
{ |
in_attr = &list->attr; |
switch (in_attr->type & (ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL)) |
{ |
case ATTR_TYPE_FLAG_INT_VAL: |
bfd_elf_add_obj_attr_int (obfd, vendor, list->tag, in_attr->i); |
break; |
case ATTR_TYPE_FLAG_STR_VAL: |
bfd_elf_add_obj_attr_string (obfd, vendor, list->tag, |
in_attr->s); |
break; |
case ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL: |
bfd_elf_add_obj_attr_int_string (obfd, vendor, list->tag, |
in_attr->i, in_attr->s); |
break; |
default: |
abort (); |
} |
} |
} |
} |
/* Determine whether a GNU object attribute tag takes an integer, a |
string or both. */ |
static int |
gnu_obj_attrs_arg_type (int tag) |
{ |
/* Except for Tag_compatibility, for GNU attributes we follow the |
same rule ARM ones > 32 follow: odd-numbered tags take strings |
and even-numbered tags take integers. In addition, tag & 2 is |
nonzero for architecture-independent tags and zero for |
architecture-dependent ones. */ |
if (tag == Tag_compatibility) |
return 3; |
else |
return (tag & 1) != 0 ? 2 : 1; |
} |
/* Determine what arguments an attribute tag takes. */ |
int |
_bfd_elf_obj_attrs_arg_type (bfd *abfd, int vendor, int tag) |
{ |
switch (vendor) |
{ |
case OBJ_ATTR_PROC: |
return get_elf_backend_data (abfd)->obj_attrs_arg_type (tag); |
break; |
case OBJ_ATTR_GNU: |
return gnu_obj_attrs_arg_type (tag); |
break; |
default: |
abort (); |
} |
} |
/* Parse an object attributes section. */ |
void |
_bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr) |
{ |
bfd_byte *contents; |
bfd_byte *p; |
bfd_vma len; |
const char *std_sec; |
contents = (bfd_byte *) bfd_malloc (hdr->sh_size); |
if (!contents) |
return; |
if (!bfd_get_section_contents (abfd, hdr->bfd_section, contents, 0, |
hdr->sh_size)) |
{ |
free (contents); |
return; |
} |
p = contents; |
std_sec = get_elf_backend_data (abfd)->obj_attrs_vendor; |
if (*(p++) == 'A') |
{ |
len = hdr->sh_size - 1; |
while (len > 0) |
{ |
int namelen; |
bfd_vma section_len; |
int vendor; |
section_len = bfd_get_32 (abfd, p); |
p += 4; |
if (section_len > len) |
section_len = len; |
len -= section_len; |
namelen = strlen ((char *) p) + 1; |
section_len -= namelen + 4; |
if (std_sec && strcmp ((char *) p, std_sec) == 0) |
vendor = OBJ_ATTR_PROC; |
else if (strcmp ((char *) p, "gnu") == 0) |
vendor = OBJ_ATTR_GNU; |
else |
{ |
/* Other vendor section. Ignore it. */ |
p += namelen + section_len; |
continue; |
} |
p += namelen; |
while (section_len > 0) |
{ |
int tag; |
unsigned int n; |
unsigned int val; |
bfd_vma subsection_len; |
bfd_byte *end; |
tag = read_unsigned_leb128 (abfd, p, &n); |
p += n; |
subsection_len = bfd_get_32 (abfd, p); |
p += 4; |
if (subsection_len > section_len) |
subsection_len = section_len; |
section_len -= subsection_len; |
subsection_len -= n + 4; |
end = p + subsection_len; |
switch (tag) |
{ |
case Tag_File: |
while (p < end) |
{ |
int type; |
tag = read_unsigned_leb128 (abfd, p, &n); |
p += n; |
type = _bfd_elf_obj_attrs_arg_type (abfd, vendor, tag); |
switch (type & (ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL)) |
{ |
case ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL: |
val = read_unsigned_leb128 (abfd, p, &n); |
p += n; |
bfd_elf_add_obj_attr_int_string (abfd, vendor, tag, |
val, (char *)p); |
p += strlen ((char *)p) + 1; |
break; |
case ATTR_TYPE_FLAG_STR_VAL: |
bfd_elf_add_obj_attr_string (abfd, vendor, tag, |
(char *)p); |
p += strlen ((char *)p) + 1; |
break; |
case ATTR_TYPE_FLAG_INT_VAL: |
val = read_unsigned_leb128 (abfd, p, &n); |
p += n; |
bfd_elf_add_obj_attr_int (abfd, vendor, tag, val); |
break; |
default: |
abort (); |
} |
} |
break; |
case Tag_Section: |
case Tag_Symbol: |
/* Don't have anywhere convenient to attach these. |
Fall through for now. */ |
default: |
/* Ignore things we don't kow about. */ |
p += subsection_len; |
subsection_len = 0; |
break; |
} |
} |
} |
} |
free (contents); |
} |
/* Merge common object attributes from IBFD into OBFD. Raise an error |
if there are conflicting attributes. Any processor-specific |
attributes have already been merged. This must be called from the |
bfd_elfNN_bfd_merge_private_bfd_data hook for each individual |
target, along with any target-specific merging. Because there are |
no common attributes other than Tag_compatibility at present, and |
non-"gnu" Tag_compatibility is not expected in "gnu" sections, this |
is not presently called for targets without their own |
attributes. */ |
bfd_boolean |
_bfd_elf_merge_object_attributes (bfd *ibfd, bfd *obfd) |
{ |
obj_attribute *in_attr; |
obj_attribute *out_attr; |
int vendor; |
/* The only common attribute is currently Tag_compatibility, |
accepted in both processor and "gnu" sections. */ |
for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++) |
{ |
/* Handle Tag_compatibility. The tags are only compatible if the flags |
are identical and, if the flags are '1', the strings are identical. |
If the flags are non-zero, then we can only use the string "gnu". */ |
in_attr = &elf_known_obj_attributes (ibfd)[vendor][Tag_compatibility]; |
out_attr = &elf_known_obj_attributes (obfd)[vendor][Tag_compatibility]; |
if (in_attr->i > 0 && strcmp (in_attr->s, "gnu") != 0) |
{ |
_bfd_error_handler |
(_("error: %B: Object has vendor-specific contents that " |
"must be processed by the '%s' toolchain"), |
ibfd, in_attr->s); |
return FALSE; |
} |
if (in_attr->i != out_attr->i |
|| (in_attr->i != 0 && strcmp (in_attr->s, out_attr->s) != 0)) |
{ |
_bfd_error_handler (_("error: %B: Object tag '%d, %s' is " |
"incompatible with tag '%d, %s'"), |
ibfd, |
in_attr->i, in_attr->s ? in_attr->s : "", |
out_attr->i, out_attr->s ? out_attr->s : ""); |
return FALSE; |
} |
} |
return TRUE; |
} |
/* Merge an unknown processor-specific attribute TAG, within the range |
of known attributes, from IBFD into OBFD; return TRUE if the link |
is OK, FALSE if it must fail. */ |
bfd_boolean |
_bfd_elf_merge_unknown_attribute_low (bfd *ibfd, bfd *obfd, int tag) |
{ |
obj_attribute *in_attr; |
obj_attribute *out_attr; |
bfd *err_bfd = NULL; |
bfd_boolean result = TRUE; |
in_attr = elf_known_obj_attributes_proc (ibfd); |
out_attr = elf_known_obj_attributes_proc (obfd); |
if (out_attr[tag].i != 0 || out_attr[tag].s != NULL) |
err_bfd = obfd; |
else if (in_attr[tag].i != 0 || in_attr[tag].s != NULL) |
err_bfd = ibfd; |
if (err_bfd != NULL) |
result |
= get_elf_backend_data (err_bfd)->obj_attrs_handle_unknown (err_bfd, tag); |
/* Only pass on attributes that match in both inputs. */ |
if (in_attr[tag].i != out_attr[tag].i |
|| (in_attr[tag].s == NULL) != (out_attr[tag].s == NULL) |
|| (in_attr[tag].s != NULL && out_attr[tag].s != NULL |
&& strcmp (in_attr[tag].s, out_attr[tag].s) != 0)) |
{ |
out_attr[tag].i = 0; |
out_attr[tag].s = NULL; |
} |
return result; |
} |
/* Merge the lists of unknown processor-specific attributes, outside |
the known range, from IBFD into OBFD; return TRUE if the link is |
OK, FALSE if it must fail. */ |
bfd_boolean |
_bfd_elf_merge_unknown_attribute_list (bfd *ibfd, bfd *obfd) |
{ |
obj_attribute_list *in_list; |
obj_attribute_list *out_list; |
obj_attribute_list **out_listp; |
bfd_boolean result = TRUE; |
in_list = elf_other_obj_attributes_proc (ibfd); |
out_listp = &elf_other_obj_attributes_proc (obfd); |
out_list = *out_listp; |
for (; in_list || out_list; ) |
{ |
bfd *err_bfd = NULL; |
int err_tag = 0; |
/* The tags for each list are in numerical order. */ |
/* If the tags are equal, then merge. */ |
if (out_list && (!in_list || in_list->tag > out_list->tag)) |
{ |
/* This attribute only exists in obfd. We can't merge, and we don't |
know what the tag means, so delete it. */ |
err_bfd = obfd; |
err_tag = out_list->tag; |
*out_listp = out_list->next; |
out_list = *out_listp; |
} |
else if (in_list && (!out_list || in_list->tag < out_list->tag)) |
{ |
/* This attribute only exists in ibfd. We can't merge, and we don't |
know what the tag means, so ignore it. */ |
err_bfd = ibfd; |
err_tag = in_list->tag; |
in_list = in_list->next; |
} |
else /* The tags are equal. */ |
{ |
/* As present, all attributes in the list are unknown, and |
therefore can't be merged meaningfully. */ |
err_bfd = obfd; |
err_tag = out_list->tag; |
/* Only pass on attributes that match in both inputs. */ |
if (in_list->attr.i != out_list->attr.i |
|| (in_list->attr.s == NULL) != (out_list->attr.s == NULL) |
|| (in_list->attr.s && out_list->attr.s |
&& strcmp (in_list->attr.s, out_list->attr.s) != 0)) |
{ |
/* No match. Delete the attribute. */ |
*out_listp = out_list->next; |
out_list = *out_listp; |
} |
else |
{ |
/* Matched. Keep the attribute and move to the next. */ |
out_list = out_list->next; |
in_list = in_list->next; |
} |
} |
if (err_bfd) |
result = result |
&& get_elf_backend_data (err_bfd)->obj_attrs_handle_unknown (err_bfd, |
err_tag); |
} |
return result; |
} |
/contrib/toolchain/binutils/bfd/elf-bfd.h |
---|
0,0 → 1,2530 |
/* BFD back-end data structures for ELF files. |
Copyright 1992-2013 Free Software Foundation, Inc. |
Written by Cygnus Support. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#ifndef _LIBELF_H_ |
#define _LIBELF_H_ 1 |
#include "elf/common.h" |
#include "elf/external.h" |
#include "elf/internal.h" |
#include "bfdlink.h" |
/* The number of entries in a section is its size divided by the size |
of a single entry. This is normally only applicable to reloc and |
symbol table sections. |
PR 9934: It is possible to have relocations that do not refer to |
symbols, thus it is also possible to have a relocation section in |
an object file, but no symbol table. */ |
#define NUM_SHDR_ENTRIES(shdr) ((shdr)->sh_entsize > 0 ? (shdr)->sh_size / (shdr)->sh_entsize : 0) |
/* If size isn't specified as 64 or 32, NAME macro should fail. */ |
#ifndef NAME |
#if ARCH_SIZE == 64 |
#define NAME(x, y) x ## 64 ## _ ## y |
#endif |
#if ARCH_SIZE == 32 |
#define NAME(x, y) x ## 32 ## _ ## y |
#endif |
#endif |
#ifndef NAME |
#define NAME(x, y) x ## NOSIZE ## _ ## y |
#endif |
#define ElfNAME(X) NAME(Elf,X) |
#define elfNAME(X) NAME(elf,X) |
/* Information held for an ELF symbol. The first field is the |
corresponding asymbol. Every symbol is an ELF file is actually a |
pointer to this structure, although it is often handled as a |
pointer to an asymbol. */ |
typedef struct |
{ |
/* The BFD symbol. */ |
asymbol symbol; |
/* ELF symbol information. */ |
Elf_Internal_Sym internal_elf_sym; |
/* Backend specific information. */ |
union |
{ |
unsigned int hppa_arg_reloc; |
void *mips_extr; |
void *any; |
} |
tc_data; |
/* Version information. This is from an Elf_Internal_Versym |
structure in a SHT_GNU_versym section. It is zero if there is no |
version information. */ |
unsigned short version; |
} elf_symbol_type; |
struct elf_strtab_hash; |
struct got_entry; |
struct plt_entry; |
union gotplt_union |
{ |
bfd_signed_vma refcount; |
bfd_vma offset; |
struct got_entry *glist; |
struct plt_entry *plist; |
}; |
struct elf_link_virtual_table_entry |
{ |
/* Virtual table entry use information. This array is nominally of size |
size/sizeof(target_void_pointer), though we have to be able to assume |
and track a size while the symbol is still undefined. It is indexed |
via offset/sizeof(target_void_pointer). */ |
size_t size; |
bfd_boolean *used; |
/* Virtual table derivation info. */ |
struct elf_link_hash_entry *parent; |
}; |
/* ELF linker hash table entries. */ |
struct elf_link_hash_entry |
{ |
struct bfd_link_hash_entry root; |
/* Symbol index in output file. This is initialized to -1. It is |
set to -2 if the symbol is used by a reloc. */ |
long indx; |
/* Symbol index as a dynamic symbol. Initialized to -1, and remains |
-1 if this is not a dynamic symbol. */ |
/* ??? Note that this is consistently used as a synonym for tests |
against whether we can perform various simplifying transformations |
to the code. (E.g. changing a pc-relative jump to a PLT entry |
into a pc-relative jump to the target function.) That test, which |
is often relatively complex, and someplaces wrong or incomplete, |
should really be replaced by a predicate in elflink.c. |
End result: this field -1 does not indicate that the symbol is |
not in the dynamic symbol table, but rather that the symbol is |
not visible outside this DSO. */ |
long dynindx; |
/* If this symbol requires an entry in the global offset table, the |
processor specific backend uses this field to track usage and |
final offset. Two schemes are supported: The first assumes that |
a symbol may only have one GOT entry, and uses REFCOUNT until |
size_dynamic_sections, at which point the contents of the .got is |
fixed. Afterward, if OFFSET is -1, then the symbol does not |
require a global offset table entry. The second scheme allows |
multiple GOT entries per symbol, managed via a linked list |
pointed to by GLIST. */ |
union gotplt_union got; |
/* Same, but tracks a procedure linkage table entry. */ |
union gotplt_union plt; |
/* Symbol size. */ |
bfd_size_type size; |
/* Symbol type (STT_NOTYPE, STT_OBJECT, etc.). */ |
unsigned int type : 8; |
/* Symbol st_other value, symbol visibility. */ |
unsigned int other : 8; |
/* The symbol's st_target_internal value (see Elf_Internal_Sym). */ |
unsigned int target_internal : 8; |
/* Symbol is referenced by a non-shared object (other than the object |
in which it is defined). */ |
unsigned int ref_regular : 1; |
/* Symbol is defined by a non-shared object. */ |
unsigned int def_regular : 1; |
/* Symbol is referenced by a shared object. */ |
unsigned int ref_dynamic : 1; |
/* Symbol is defined by a shared object. */ |
unsigned int def_dynamic : 1; |
/* Symbol has a non-weak reference from a non-shared object (other than |
the object in which it is defined). */ |
unsigned int ref_regular_nonweak : 1; |
/* Dynamic symbol has been adjustd. */ |
unsigned int dynamic_adjusted : 1; |
/* Symbol needs a copy reloc. */ |
unsigned int needs_copy : 1; |
/* Symbol needs a procedure linkage table entry. */ |
unsigned int needs_plt : 1; |
/* Symbol appears in a non-ELF input file. */ |
unsigned int non_elf : 1; |
/* Symbol should be marked as hidden in the version information. */ |
unsigned int hidden : 1; |
/* Symbol was forced to local scope due to a version script file. */ |
unsigned int forced_local : 1; |
/* Symbol was forced to be dynamic due to a version script file. */ |
unsigned int dynamic : 1; |
/* Symbol was marked during garbage collection. */ |
unsigned int mark : 1; |
/* Symbol is referenced by a non-GOT/non-PLT relocation. This is |
not currently set by all the backends. */ |
unsigned int non_got_ref : 1; |
/* Symbol has a definition in a shared object. |
FIXME: There is no real need for this field if def_dynamic is never |
cleared and all places that test def_dynamic also test def_regular. */ |
unsigned int dynamic_def : 1; |
/* Symbol has a non-weak reference from a shared object. */ |
unsigned int ref_dynamic_nonweak : 1; |
/* Symbol is referenced with a relocation where C/C++ pointer equality |
matters. */ |
unsigned int pointer_equality_needed : 1; |
/* Symbol is a unique global symbol. */ |
unsigned int unique_global : 1; |
/* String table index in .dynstr if this is a dynamic symbol. */ |
unsigned long dynstr_index; |
union |
{ |
/* If this is a weak defined symbol from a dynamic object, this |
field points to a defined symbol with the same value, if there is |
one. Otherwise it is NULL. */ |
struct elf_link_hash_entry *weakdef; |
/* Hash value of the name computed using the ELF hash function. |
Used part way through size_dynamic_sections, after we've finished |
with weakdefs. */ |
unsigned long elf_hash_value; |
} u; |
/* Version information. */ |
union |
{ |
/* This field is used for a symbol which is not defined in a |
regular object. It points to the version information read in |
from the dynamic object. */ |
Elf_Internal_Verdef *verdef; |
/* This field is used for a symbol which is defined in a regular |
object. It is set up in size_dynamic_sections. It points to |
the version information we should write out for this symbol. */ |
struct bfd_elf_version_tree *vertree; |
} verinfo; |
struct elf_link_virtual_table_entry *vtable; |
}; |
/* Will references to this symbol always reference the symbol |
in this object? */ |
#define SYMBOL_REFERENCES_LOCAL(INFO, H) \ |
_bfd_elf_symbol_refs_local_p (H, INFO, 0) |
/* Will _calls_ to this symbol always call the version in this object? */ |
#define SYMBOL_CALLS_LOCAL(INFO, H) \ |
_bfd_elf_symbol_refs_local_p (H, INFO, 1) |
/* Common symbols that are turned into definitions don't have the |
DEF_REGULAR flag set, so they might appear to be undefined. */ |
#define ELF_COMMON_DEF_P(H) \ |
(!(H)->def_regular \ |
&& !(H)->def_dynamic \ |
&& (H)->root.type == bfd_link_hash_defined) |
/* Records local symbols to be emitted in the dynamic symbol table. */ |
struct elf_link_local_dynamic_entry |
{ |
struct elf_link_local_dynamic_entry *next; |
/* The input bfd this symbol came from. */ |
bfd *input_bfd; |
/* The index of the local symbol being copied. */ |
long input_indx; |
/* The index in the outgoing dynamic symbol table. */ |
long dynindx; |
/* A copy of the input symbol. */ |
Elf_Internal_Sym isym; |
}; |
struct elf_link_loaded_list |
{ |
struct elf_link_loaded_list *next; |
bfd *abfd; |
}; |
/* Structures used by the eh_frame optimization code. */ |
struct eh_cie_fde |
{ |
union { |
struct { |
/* If REMOVED == 1, this is the CIE that the FDE originally used. |
The CIE belongs to the same .eh_frame input section as the FDE. |
If REMOVED == 0, this is the CIE that we have chosen to use for |
the output FDE. The CIE's REMOVED field is also 0, but the CIE |
might belong to a different .eh_frame input section from the FDE. */ |
struct eh_cie_fde *cie_inf; |
struct eh_cie_fde *next_for_section; |
} fde; |
struct { |
/* CIEs have three states: |
- REMOVED && !MERGED: Slated for removal because we haven't yet |
proven that an FDE needs it. FULL_CIE, if nonnull, points to |
more detailed information about the CIE. |
- REMOVED && MERGED: We have merged this CIE with MERGED_WITH, |
which may not belong to the same input section. |
- !REMOVED: We have decided to keep this CIE. SEC is the |
.eh_frame input section that contains the CIE. */ |
union { |
struct cie *full_cie; |
struct eh_cie_fde *merged_with; |
asection *sec; |
} u; |
/* The offset of the personality data from the start of the CIE, |
or 0 if the CIE doesn't have any. */ |
unsigned int personality_offset : 8; |
/* True if we have marked relocations associated with this CIE. */ |
unsigned int gc_mark : 1; |
/* True if we have decided to turn an absolute LSDA encoding into |
a PC-relative one. */ |
unsigned int make_lsda_relative : 1; |
/* True if we have decided to turn an absolute personality |
encoding into a PC-relative one. */ |
unsigned int make_per_encoding_relative : 1; |
/* True if the CIE contains personality data and if that |
data uses a PC-relative encoding. Always true when |
make_per_encoding_relative is. */ |
unsigned int per_encoding_relative : 1; |
/* True if we need to add an 'R' (FDE encoding) entry to the |
CIE's augmentation data. */ |
unsigned int add_fde_encoding : 1; |
/* True if we have merged this CIE with another. */ |
unsigned int merged : 1; |
/* Unused bits. */ |
unsigned int pad1 : 18; |
} cie; |
} u; |
unsigned int reloc_index; |
unsigned int size; |
unsigned int offset; |
unsigned int new_offset; |
unsigned int fde_encoding : 8; |
unsigned int lsda_encoding : 8; |
unsigned int lsda_offset : 8; |
/* True if this entry represents a CIE, false if it represents an FDE. */ |
unsigned int cie : 1; |
/* True if this entry is currently marked for removal. */ |
unsigned int removed : 1; |
/* True if we need to add a 'z' (augmentation size) entry to the CIE's |
augmentation data, and an associated byte to each of the CIE's FDEs. */ |
unsigned int add_augmentation_size : 1; |
/* True if we have decided to convert absolute FDE relocations into |
relative ones. This applies to the first relocation in the FDE, |
which is against the code that the FDE describes. */ |
unsigned int make_relative : 1; |
/* Unused bits. */ |
unsigned int pad1 : 4; |
unsigned int *set_loc; |
}; |
struct eh_frame_sec_info |
{ |
unsigned int count; |
struct cie *cies; |
struct eh_cie_fde entry[1]; |
}; |
struct eh_frame_array_ent |
{ |
bfd_vma initial_loc; |
bfd_vma fde; |
}; |
struct htab; |
struct eh_frame_hdr_info |
{ |
struct htab *cies; |
asection *hdr_sec; |
unsigned int fde_count, array_count; |
struct eh_frame_array_ent *array; |
/* TRUE if we should try to merge CIEs between input sections. */ |
bfd_boolean merge_cies; |
/* TRUE if all .eh_frames have been parsd. */ |
bfd_boolean parsed_eh_frames; |
/* TRUE if .eh_frame_hdr should contain the sorted search table. |
We build it if we successfully read all .eh_frame input sections |
and recognize them. */ |
bfd_boolean table; |
}; |
/* Enum used to identify target specific extensions to the elf_obj_tdata |
and elf_link_hash_table structures. Note the enums deliberately start |
from 1 so that we can detect an uninitialized field. The generic value |
is last so that additions to this enum do not need to modify more than |
one line. */ |
enum elf_target_id |
{ |
AARCH64_ELF_DATA = 1, |
ALPHA_ELF_DATA, |
ARM_ELF_DATA, |
AVR_ELF_DATA, |
BFIN_ELF_DATA, |
CRIS_ELF_DATA, |
FRV_ELF_DATA, |
HPPA32_ELF_DATA, |
HPPA64_ELF_DATA, |
I386_ELF_DATA, |
IA64_ELF_DATA, |
LM32_ELF_DATA, |
M32R_ELF_DATA, |
M68HC11_ELF_DATA, |
M68K_ELF_DATA, |
METAG_ELF_DATA, |
MICROBLAZE_ELF_DATA, |
MIPS_ELF_DATA, |
MN10300_ELF_DATA, |
NIOS2_ELF_DATA, |
PPC32_ELF_DATA, |
PPC64_ELF_DATA, |
S390_ELF_DATA, |
SH_ELF_DATA, |
SPARC_ELF_DATA, |
SPU_ELF_DATA, |
TIC6X_ELF_DATA, |
X86_64_ELF_DATA, |
XTENSA_ELF_DATA, |
XGATE_ELF_DATA, |
TILEGX_ELF_DATA, |
TILEPRO_ELF_DATA, |
GENERIC_ELF_DATA |
}; |
/* ELF linker hash table. */ |
struct elf_link_hash_table |
{ |
struct bfd_link_hash_table root; |
/* An identifier used to distinguish different target |
specific extensions to this structure. */ |
enum elf_target_id hash_table_id; |
/* Whether we have created the special dynamic sections required |
when linking against or generating a shared object. */ |
bfd_boolean dynamic_sections_created; |
/* True if this target has relocatable executables, so needs dynamic |
section symbols. */ |
bfd_boolean is_relocatable_executable; |
/* The BFD used to hold special sections created by the linker. |
This will be the first BFD found which requires these sections to |
be created. */ |
bfd *dynobj; |
/* The value to use when initialising got.refcount/offset and |
plt.refcount/offset in an elf_link_hash_entry. Set to zero when |
the values are refcounts. Set to init_got_offset/init_plt_offset |
in size_dynamic_sections when the values may be offsets. */ |
union gotplt_union init_got_refcount; |
union gotplt_union init_plt_refcount; |
/* The value to use for got.refcount/offset and plt.refcount/offset |
when the values may be offsets. Normally (bfd_vma) -1. */ |
union gotplt_union init_got_offset; |
union gotplt_union init_plt_offset; |
/* The number of symbols found in the link which must be put into |
the .dynsym section. */ |
bfd_size_type dynsymcount; |
/* The string table of dynamic symbols, which becomes the .dynstr |
section. */ |
struct elf_strtab_hash *dynstr; |
/* The number of buckets in the hash table in the .hash section. |
This is based on the number of dynamic symbols. */ |
bfd_size_type bucketcount; |
/* A linked list of DT_NEEDED names found in dynamic objects |
included in the link. */ |
struct bfd_link_needed_list *needed; |
/* Sections in the output bfd that provides a section symbol |
to be used by relocations emitted against local symbols. |
Most targets will not use data_index_section. */ |
asection *text_index_section; |
asection *data_index_section; |
/* The _GLOBAL_OFFSET_TABLE_ symbol. */ |
struct elf_link_hash_entry *hgot; |
/* The _PROCEDURE_LINKAGE_TABLE_ symbol. */ |
struct elf_link_hash_entry *hplt; |
/* The _DYNAMIC symbol. */ |
struct elf_link_hash_entry *hdynamic; |
/* A pointer to information used to merge SEC_MERGE sections. */ |
void *merge_info; |
/* Used to link stabs in sections. */ |
struct stab_info stab_info; |
/* Used by eh_frame code when editing .eh_frame. */ |
struct eh_frame_hdr_info eh_info; |
/* A linked list of local symbols to be added to .dynsym. */ |
struct elf_link_local_dynamic_entry *dynlocal; |
/* A linked list of DT_RPATH/DT_RUNPATH names found in dynamic |
objects included in the link. */ |
struct bfd_link_needed_list *runpath; |
/* Cached first output tls section and size of PT_TLS segment. */ |
asection *tls_sec; |
bfd_size_type tls_size; |
/* A linked list of BFD's loaded in the link. */ |
struct elf_link_loaded_list *loaded; |
/* Short-cuts to get to dynamic linker sections. */ |
asection *sgot; |
asection *sgotplt; |
asection *srelgot; |
asection *splt; |
asection *srelplt; |
asection *igotplt; |
asection *iplt; |
asection *irelplt; |
asection *irelifunc; |
}; |
/* Look up an entry in an ELF linker hash table. */ |
#define elf_link_hash_lookup(table, string, create, copy, follow) \ |
((struct elf_link_hash_entry *) \ |
bfd_link_hash_lookup (&(table)->root, (string), (create), \ |
(copy), (follow))) |
/* Traverse an ELF linker hash table. */ |
#define elf_link_hash_traverse(table, func, info) \ |
(bfd_link_hash_traverse \ |
(&(table)->root, \ |
(bfd_boolean (*) (struct bfd_link_hash_entry *, void *)) (func), \ |
(info))) |
/* Get the ELF linker hash table from a link_info structure. */ |
#define elf_hash_table(p) ((struct elf_link_hash_table *) ((p)->hash)) |
#define elf_hash_table_id(table) ((table) -> hash_table_id) |
/* Returns TRUE if the hash table is a struct elf_link_hash_table. */ |
#define is_elf_hash_table(htab) \ |
(((struct bfd_link_hash_table *) (htab))->type == bfd_link_elf_hash_table) |
/* Used by bfd_sym_from_r_symndx to cache a small number of local |
symbols. */ |
#define LOCAL_SYM_CACHE_SIZE 32 |
struct sym_cache |
{ |
bfd *abfd; |
unsigned long indx[LOCAL_SYM_CACHE_SIZE]; |
Elf_Internal_Sym sym[LOCAL_SYM_CACHE_SIZE]; |
}; |
/* Constant information held for an ELF backend. */ |
struct elf_size_info { |
unsigned char sizeof_ehdr, sizeof_phdr, sizeof_shdr; |
unsigned char sizeof_rel, sizeof_rela, sizeof_sym, sizeof_dyn, sizeof_note; |
/* The size of entries in the .hash section. */ |
unsigned char sizeof_hash_entry; |
/* The number of internal relocations to allocate per external |
relocation entry. */ |
unsigned char int_rels_per_ext_rel; |
/* We use some fixed size arrays. This should be large enough to |
handle all back-ends. */ |
#define MAX_INT_RELS_PER_EXT_REL 3 |
unsigned char arch_size, log_file_align; |
unsigned char elfclass, ev_current; |
int (*write_out_phdrs) |
(bfd *, const Elf_Internal_Phdr *, unsigned int); |
bfd_boolean |
(*write_shdrs_and_ehdr) (bfd *); |
bfd_boolean (*checksum_contents) |
(bfd * , void (*) (const void *, size_t, void *), void *); |
void (*write_relocs) |
(bfd *, asection *, void *); |
bfd_boolean (*swap_symbol_in) |
(bfd *, const void *, const void *, Elf_Internal_Sym *); |
void (*swap_symbol_out) |
(bfd *, const Elf_Internal_Sym *, void *, void *); |
bfd_boolean (*slurp_reloc_table) |
(bfd *, asection *, asymbol **, bfd_boolean); |
long (*slurp_symbol_table) |
(bfd *, asymbol **, bfd_boolean); |
void (*swap_dyn_in) |
(bfd *, const void *, Elf_Internal_Dyn *); |
void (*swap_dyn_out) |
(bfd *, const Elf_Internal_Dyn *, void *); |
/* This function is called to swap in a REL relocation. If an |
external relocation corresponds to more than one internal |
relocation, then all relocations are swapped in at once. */ |
void (*swap_reloc_in) |
(bfd *, const bfd_byte *, Elf_Internal_Rela *); |
/* This function is called to swap out a REL relocation. */ |
void (*swap_reloc_out) |
(bfd *, const Elf_Internal_Rela *, bfd_byte *); |
/* This function is called to swap in a RELA relocation. If an |
external relocation corresponds to more than one internal |
relocation, then all relocations are swapped in at once. */ |
void (*swap_reloca_in) |
(bfd *, const bfd_byte *, Elf_Internal_Rela *); |
/* This function is called to swap out a RELA relocation. */ |
void (*swap_reloca_out) |
(bfd *, const Elf_Internal_Rela *, bfd_byte *); |
}; |
#define elf_symbol_from(ABFD,S) \ |
(((S)->the_bfd->xvec->flavour == bfd_target_elf_flavour \ |
&& (S)->the_bfd->tdata.elf_obj_data != 0) \ |
? (elf_symbol_type *) (S) \ |
: 0) |
enum elf_reloc_type_class { |
reloc_class_normal, |
reloc_class_relative, |
reloc_class_plt, |
reloc_class_copy, |
reloc_class_ifunc |
}; |
struct elf_reloc_cookie |
{ |
Elf_Internal_Rela *rels, *rel, *relend; |
Elf_Internal_Sym *locsyms; |
bfd *abfd; |
size_t locsymcount; |
size_t extsymoff; |
struct elf_link_hash_entry **sym_hashes; |
int r_sym_shift; |
bfd_boolean bad_symtab; |
}; |
/* The level of IRIX compatibility we're striving for. */ |
typedef enum { |
ict_none, |
ict_irix5, |
ict_irix6 |
} irix_compat_t; |
/* Mapping of ELF section names and types. */ |
struct bfd_elf_special_section |
{ |
const char *prefix; |
int prefix_length; |
/* 0 means name must match PREFIX exactly. |
-1 means name must start with PREFIX followed by an arbitrary string. |
-2 means name must match PREFIX exactly or consist of PREFIX followed |
by a dot then anything. |
> 0 means name must start with the first PREFIX_LENGTH chars of |
PREFIX and finish with the last SUFFIX_LENGTH chars of PREFIX. */ |
int suffix_length; |
int type; |
bfd_vma attr; |
}; |
enum action_discarded |
{ |
COMPLAIN = 1, |
PRETEND = 2 |
}; |
typedef asection * (*elf_gc_mark_hook_fn) |
(asection *, struct bfd_link_info *, Elf_Internal_Rela *, |
struct elf_link_hash_entry *, Elf_Internal_Sym *); |
struct elf_backend_data |
{ |
/* The architecture for this backend. */ |
enum bfd_architecture arch; |
/* An identifier used to distinguish different target specific |
extensions to elf_obj_tdata and elf_link_hash_table structures. */ |
enum elf_target_id target_id; |
/* The ELF machine code (EM_xxxx) for this backend. */ |
int elf_machine_code; |
/* EI_OSABI. */ |
int elf_osabi; |
/* The maximum page size for this backend. */ |
bfd_vma maxpagesize; |
/* The minimum page size for this backend. An input object will not be |
considered page aligned unless its sections are correctly aligned for |
pages at least this large. May be smaller than maxpagesize. */ |
bfd_vma minpagesize; |
/* The common page size for this backend. */ |
bfd_vma commonpagesize; |
/* The BFD flags applied to sections created for dynamic linking. */ |
flagword dynamic_sec_flags; |
/* Architecture-specific data for this backend. |
This is actually a pointer to some type like struct elf_ARCH_data. */ |
const void *arch_data; |
/* A function to translate an ELF RELA relocation to a BFD arelent |
structure. */ |
void (*elf_info_to_howto) |
(bfd *, arelent *, Elf_Internal_Rela *); |
/* A function to translate an ELF REL relocation to a BFD arelent |
structure. */ |
void (*elf_info_to_howto_rel) |
(bfd *, arelent *, Elf_Internal_Rela *); |
/* A function to determine whether a symbol is global when |
partitioning the symbol table into local and global symbols. |
This should be NULL for most targets, in which case the correct |
thing will be done. MIPS ELF, at least on the Irix 5, has |
special requirements. */ |
bfd_boolean (*elf_backend_sym_is_global) |
(bfd *, asymbol *); |
/* The remaining functions are hooks which are called only if they |
are not NULL. */ |
/* A function to permit a backend specific check on whether a |
particular BFD format is relevant for an object file, and to |
permit the backend to set any global information it wishes. When |
this is called elf_elfheader is set, but anything else should be |
used with caution. If this returns FALSE, the check_format |
routine will return a bfd_error_wrong_format error. */ |
bfd_boolean (*elf_backend_object_p) |
(bfd *); |
/* A function to do additional symbol processing when reading the |
ELF symbol table. This is where any processor-specific special |
section indices are handled. */ |
void (*elf_backend_symbol_processing) |
(bfd *, asymbol *); |
/* A function to do additional symbol processing after reading the |
entire ELF symbol table. */ |
bfd_boolean (*elf_backend_symbol_table_processing) |
(bfd *, elf_symbol_type *, unsigned int); |
/* A function to set the type of the info field. Processor-specific |
types should be handled here. */ |
int (*elf_backend_get_symbol_type) |
(Elf_Internal_Sym *, int); |
/* A function to return the linker hash table entry of a symbol that |
might be satisfied by an archive symbol. */ |
struct elf_link_hash_entry * (*elf_backend_archive_symbol_lookup) |
(bfd *, struct bfd_link_info *, const char *); |
/* Return true if local section symbols should have a non-null st_name. |
NULL implies false. */ |
bfd_boolean (*elf_backend_name_local_section_symbols) |
(bfd *); |
/* A function to do additional processing on the ELF section header |
just before writing it out. This is used to set the flags and |
type fields for some sections, or to actually write out data for |
unusual sections. */ |
bfd_boolean (*elf_backend_section_processing) |
(bfd *, Elf_Internal_Shdr *); |
/* A function to handle unusual section types when creating BFD |
sections from ELF sections. */ |
bfd_boolean (*elf_backend_section_from_shdr) |
(bfd *, Elf_Internal_Shdr *, const char *, int); |
/* A function to convert machine dependent ELF section header flags to |
BFD internal section header flags. */ |
bfd_boolean (*elf_backend_section_flags) |
(flagword *, const Elf_Internal_Shdr *); |
/* A function that returns a struct containing ELF section flags and |
type for the given BFD section. */ |
const struct bfd_elf_special_section * (*get_sec_type_attr) |
(bfd *, asection *); |
/* A function to handle unusual program segment types when creating BFD |
sections from ELF program segments. */ |
bfd_boolean (*elf_backend_section_from_phdr) |
(bfd *, Elf_Internal_Phdr *, int, const char *); |
/* A function to set up the ELF section header for a BFD section in |
preparation for writing it out. This is where the flags and type |
fields are set for unusual sections. */ |
bfd_boolean (*elf_backend_fake_sections) |
(bfd *, Elf_Internal_Shdr *, asection *); |
/* A function to get the ELF section index for a BFD section. If |
this returns TRUE, the section was found. If it is a normal ELF |
section, *RETVAL should be left unchanged. If it is not a normal |
ELF section *RETVAL should be set to the SHN_xxxx index. */ |
bfd_boolean (*elf_backend_section_from_bfd_section) |
(bfd *, asection *, int *retval); |
/* If this field is not NULL, it is called by the add_symbols phase |
of a link just before adding a symbol to the global linker hash |
table. It may modify any of the fields as it wishes. If *NAME |
is set to NULL, the symbol will be skipped rather than being |
added to the hash table. This function is responsible for |
handling all processor dependent symbol bindings and section |
indices, and must set at least *FLAGS and *SEC for each processor |
dependent case; failure to do so will cause a link error. */ |
bfd_boolean (*elf_add_symbol_hook) |
(bfd *abfd, struct bfd_link_info *info, Elf_Internal_Sym *, |
const char **name, flagword *flags, asection **sec, bfd_vma *value); |
/* If this field is not NULL, it is called by the elf_link_output_sym |
phase of a link for each symbol which will appear in the object file. |
On error, this function returns 0. 1 is returned when the symbol |
should be output, 2 is returned when the symbol should be discarded. */ |
int (*elf_backend_link_output_symbol_hook) |
(struct bfd_link_info *info, const char *, Elf_Internal_Sym *, |
asection *, struct elf_link_hash_entry *); |
/* The CREATE_DYNAMIC_SECTIONS function is called by the ELF backend |
linker the first time it encounters a dynamic object in the link. |
This function must create any sections required for dynamic |
linking. The ABFD argument is a dynamic object. The .interp, |
.dynamic, .dynsym, .dynstr, and .hash functions have already been |
created, and this function may modify the section flags if |
desired. This function will normally create the .got and .plt |
sections, but different backends have different requirements. */ |
bfd_boolean (*elf_backend_create_dynamic_sections) |
(bfd *abfd, struct bfd_link_info *info); |
/* When creating a shared library, determine whether to omit the |
dynamic symbol for the section. */ |
bfd_boolean (*elf_backend_omit_section_dynsym) |
(bfd *output_bfd, struct bfd_link_info *info, asection *osec); |
/* Return TRUE if relocations of targets are compatible to the extent |
that CHECK_RELOCS will properly process them. PR 4424. */ |
bfd_boolean (*relocs_compatible) (const bfd_target *, const bfd_target *); |
/* The CHECK_RELOCS function is called by the add_symbols phase of |
the ELF backend linker. It is called once for each section with |
relocs of an object file, just after the symbols for the object |
file have been added to the global linker hash table. The |
function must look through the relocs and do any special handling |
required. This generally means allocating space in the global |
offset table, and perhaps allocating space for a reloc. The |
relocs are always passed as Rela structures; if the section |
actually uses Rel structures, the r_addend field will always be |
zero. */ |
bfd_boolean (*check_relocs) |
(bfd *abfd, struct bfd_link_info *info, asection *o, |
const Elf_Internal_Rela *relocs); |
/* The CHECK_DIRECTIVES function is called once per input file by |
the add_symbols phase of the ELF backend linker. The function |
must inspect the bfd and create any additional symbols according |
to any custom directives in the bfd. */ |
bfd_boolean (*check_directives) |
(bfd *abfd, struct bfd_link_info *info); |
/* The NOTICE_AS_NEEDED function is called as the linker is about to |
handle an as-needed lib (ACT = notice_as_needed), and after the |
linker has decided to keep the lib (ACT = notice_needed) or when |
the lib is not needed (ACT = notice_not_needed). */ |
bfd_boolean (*notice_as_needed) |
(bfd *abfd, struct bfd_link_info *info, enum notice_asneeded_action act); |
/* The ADJUST_DYNAMIC_SYMBOL function is called by the ELF backend |
linker for every symbol which is defined by a dynamic object and |
referenced by a regular object. This is called after all the |
input files have been seen, but before the SIZE_DYNAMIC_SECTIONS |
function has been called. The hash table entry should be |
bfd_link_hash_defined ore bfd_link_hash_defweak, and it should be |
defined in a section from a dynamic object. Dynamic object |
sections are not included in the final link, and this function is |
responsible for changing the value to something which the rest of |
the link can deal with. This will normally involve adding an |
entry to the .plt or .got or some such section, and setting the |
symbol to point to that. */ |
bfd_boolean (*elf_backend_adjust_dynamic_symbol) |
(struct bfd_link_info *info, struct elf_link_hash_entry *h); |
/* The ALWAYS_SIZE_SECTIONS function is called by the backend linker |
after all the linker input files have been seen but before the |
section sizes have been set. This is called after |
ADJUST_DYNAMIC_SYMBOL, but before SIZE_DYNAMIC_SECTIONS. */ |
bfd_boolean (*elf_backend_always_size_sections) |
(bfd *output_bfd, struct bfd_link_info *info); |
/* The SIZE_DYNAMIC_SECTIONS function is called by the ELF backend |
linker after all the linker input files have been seen but before |
the sections sizes have been set. This is called after |
ADJUST_DYNAMIC_SYMBOL has been called on all appropriate symbols. |
It is only called when linking against a dynamic object. It must |
set the sizes of the dynamic sections, and may fill in their |
contents as well. The generic ELF linker can handle the .dynsym, |
.dynstr and .hash sections. This function must handle the |
.interp section and any sections created by the |
CREATE_DYNAMIC_SECTIONS entry point. */ |
bfd_boolean (*elf_backend_size_dynamic_sections) |
(bfd *output_bfd, struct bfd_link_info *info); |
/* Set TEXT_INDEX_SECTION and DATA_INDEX_SECTION, the output sections |
we keep to use as a base for relocs and symbols. */ |
void (*elf_backend_init_index_section) |
(bfd *output_bfd, struct bfd_link_info *info); |
/* The RELOCATE_SECTION function is called by the ELF backend linker |
to handle the relocations for a section. |
The relocs are always passed as Rela structures; if the section |
actually uses Rel structures, the r_addend field will always be |
zero. |
This function is responsible for adjust the section contents as |
necessary, and (if using Rela relocs and generating a |
relocatable output file) adjusting the reloc addend as |
necessary. |
This function does not have to worry about setting the reloc |
address or the reloc symbol index. |
LOCAL_SYMS is a pointer to the swapped in local symbols. |
LOCAL_SECTIONS is an array giving the section in the input file |
corresponding to the st_shndx field of each local symbol. |
The global hash table entry for the global symbols can be found |
via elf_sym_hashes (input_bfd). |
When generating relocatable output, this function must handle |
STB_LOCAL/STT_SECTION symbols specially. The output symbol is |
going to be the section symbol corresponding to the output |
section, which means that the addend must be adjusted |
accordingly. |
Returns FALSE on error, TRUE on success, 2 if successful and |
relocations should be written for this section. */ |
int (*elf_backend_relocate_section) |
(bfd *output_bfd, struct bfd_link_info *info, bfd *input_bfd, |
asection *input_section, bfd_byte *contents, Elf_Internal_Rela *relocs, |
Elf_Internal_Sym *local_syms, asection **local_sections); |
/* The FINISH_DYNAMIC_SYMBOL function is called by the ELF backend |
linker just before it writes a symbol out to the .dynsym section. |
The processor backend may make any required adjustment to the |
symbol. It may also take the opportunity to set contents of the |
dynamic sections. Note that FINISH_DYNAMIC_SYMBOL is called on |
all .dynsym symbols, while ADJUST_DYNAMIC_SYMBOL is only called |
on those symbols which are defined by a dynamic object. */ |
bfd_boolean (*elf_backend_finish_dynamic_symbol) |
(bfd *output_bfd, struct bfd_link_info *info, |
struct elf_link_hash_entry *h, Elf_Internal_Sym *sym); |
/* The FINISH_DYNAMIC_SECTIONS function is called by the ELF backend |
linker just before it writes all the dynamic sections out to the |
output file. The FINISH_DYNAMIC_SYMBOL will have been called on |
all dynamic symbols. */ |
bfd_boolean (*elf_backend_finish_dynamic_sections) |
(bfd *output_bfd, struct bfd_link_info *info); |
/* A function to do any beginning processing needed for the ELF file |
before building the ELF headers and computing file positions. */ |
void (*elf_backend_begin_write_processing) |
(bfd *, struct bfd_link_info *); |
/* A function to do any final processing needed for the ELF file |
before writing it out. The LINKER argument is TRUE if this BFD |
was created by the ELF backend linker. */ |
void (*elf_backend_final_write_processing) |
(bfd *, bfd_boolean linker); |
/* This function is called by get_program_header_size. It should |
return the number of additional program segments which this BFD |
will need. It should return -1 on error. */ |
int (*elf_backend_additional_program_headers) |
(bfd *, struct bfd_link_info *); |
/* This function is called to modify an existing segment map in a |
backend specific fashion. */ |
bfd_boolean (*elf_backend_modify_segment_map) |
(bfd *, struct bfd_link_info *); |
/* This function is called to modify program headers just before |
they are written. */ |
bfd_boolean (*elf_backend_modify_program_headers) |
(bfd *, struct bfd_link_info *); |
/* This function is called before section garbage collection to |
mark entry symbol sections. */ |
void (*gc_keep) |
(struct bfd_link_info *); |
/* This function is called during section garbage collection to |
mark sections that define global symbols. */ |
bfd_boolean (*gc_mark_dynamic_ref) |
(struct elf_link_hash_entry *, void *); |
/* This function is called during section gc to discover the section a |
particular relocation refers to. */ |
elf_gc_mark_hook_fn gc_mark_hook; |
/* This function, if defined, is called after the first gc marking pass |
to allow the backend to mark additional sections. */ |
bfd_boolean (*gc_mark_extra_sections) |
(struct bfd_link_info *, elf_gc_mark_hook_fn); |
/* This function, if defined, is called during the sweep phase of gc |
in order that a backend might update any data structures it might |
be maintaining. */ |
bfd_boolean (*gc_sweep_hook) |
(bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *); |
/* This function, if defined, is called after the ELF headers have |
been created. This allows for things like the OS and ABI versions |
to be changed. */ |
void (*elf_backend_post_process_headers) |
(bfd *, struct bfd_link_info *); |
/* This function, if defined, prints a symbol to file and returns the |
name of the symbol to be printed. It should return NULL to fall |
back to default symbol printing. */ |
const char *(*elf_backend_print_symbol_all) |
(bfd *, void *, asymbol *); |
/* This function, if defined, is called after all local symbols and |
global symbols converted to locals are emitted into the symtab |
section. It allows the backend to emit special local symbols |
not handled in the hash table. */ |
bfd_boolean (*elf_backend_output_arch_local_syms) |
(bfd *, struct bfd_link_info *, void *, |
bfd_boolean (*) (void *, const char *, Elf_Internal_Sym *, asection *, |
struct elf_link_hash_entry *)); |
/* This function, if defined, is called after all symbols are emitted |
into the symtab section. It allows the backend to emit special |
global symbols not handled in the hash table. */ |
bfd_boolean (*elf_backend_output_arch_syms) |
(bfd *, struct bfd_link_info *, void *, |
bfd_boolean (*) (void *, const char *, Elf_Internal_Sym *, asection *, |
struct elf_link_hash_entry *)); |
/* Copy any information related to dynamic linking from a pre-existing |
symbol to a newly created symbol. Also called to copy flags and |
other back-end info to a weakdef, in which case the symbol is not |
newly created and plt/got refcounts and dynamic indices should not |
be copied. */ |
void (*elf_backend_copy_indirect_symbol) |
(struct bfd_link_info *, struct elf_link_hash_entry *, |
struct elf_link_hash_entry *); |
/* Modify any information related to dynamic linking such that the |
symbol is not exported. */ |
void (*elf_backend_hide_symbol) |
(struct bfd_link_info *, struct elf_link_hash_entry *, bfd_boolean); |
/* A function to do additional symbol fixup, called by |
_bfd_elf_fix_symbol_flags. */ |
bfd_boolean (*elf_backend_fixup_symbol) |
(struct bfd_link_info *, struct elf_link_hash_entry *); |
/* Merge the backend specific symbol attribute. */ |
void (*elf_backend_merge_symbol_attribute) |
(struct elf_link_hash_entry *, const Elf_Internal_Sym *, bfd_boolean, |
bfd_boolean); |
/* This function, if defined, will return a string containing the |
name of a target-specific dynamic tag. */ |
char *(*elf_backend_get_target_dtag) |
(bfd_vma); |
/* Decide whether an undefined symbol is special and can be ignored. |
This is the case for OPTIONAL symbols on IRIX. */ |
bfd_boolean (*elf_backend_ignore_undef_symbol) |
(struct elf_link_hash_entry *); |
/* Emit relocations. Overrides default routine for emitting relocs, |
except during a relocatable link, or if all relocs are being emitted. */ |
bfd_boolean (*elf_backend_emit_relocs) |
(bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *, |
struct elf_link_hash_entry **); |
/* Count relocations. Not called for relocatable links |
or if all relocs are being preserved in the output. */ |
unsigned int (*elf_backend_count_relocs) |
(struct bfd_link_info *, asection *); |
/* This function, if defined, is called when an NT_PRSTATUS note is found |
in a core file. */ |
bfd_boolean (*elf_backend_grok_prstatus) |
(bfd *, Elf_Internal_Note *); |
/* This function, if defined, is called when an NT_PSINFO or NT_PRPSINFO |
note is found in a core file. */ |
bfd_boolean (*elf_backend_grok_psinfo) |
(bfd *, Elf_Internal_Note *); |
/* This function, if defined, is called to write a note to a corefile. */ |
char *(*elf_backend_write_core_note) |
(bfd *abfd, char *buf, int *bufsiz, int note_type, ...); |
/* This function, if defined, is called to convert target-specific |
section flag names into hex values. */ |
flagword (*elf_backend_lookup_section_flags_hook) |
(char *); |
/* This function returns class of a reloc type. */ |
enum elf_reloc_type_class (*elf_backend_reloc_type_class) |
(const struct bfd_link_info *, const asection *, const Elf_Internal_Rela *); |
/* This function, if defined, removes information about discarded functions |
from other sections which mention them. */ |
bfd_boolean (*elf_backend_discard_info) |
(bfd *, struct elf_reloc_cookie *, struct bfd_link_info *); |
/* This function, if defined, signals that the function above has removed |
the discarded relocations for this section. */ |
bfd_boolean (*elf_backend_ignore_discarded_relocs) |
(asection *); |
/* What to do when ld finds relocations against symbols defined in |
discarded sections. */ |
unsigned int (*action_discarded) |
(asection *); |
/* This function returns the width of FDE pointers in bytes, or 0 if |
that can't be determined for some reason. The default definition |
goes by the bfd's EI_CLASS. */ |
unsigned int (*elf_backend_eh_frame_address_size) |
(bfd *, asection *); |
/* These functions tell elf-eh-frame whether to attempt to turn |
absolute or lsda encodings into pc-relative ones. The default |
definition enables these transformations. */ |
bfd_boolean (*elf_backend_can_make_relative_eh_frame) |
(bfd *, struct bfd_link_info *, asection *); |
bfd_boolean (*elf_backend_can_make_lsda_relative_eh_frame) |
(bfd *, struct bfd_link_info *, asection *); |
/* This function returns an encoding after computing the encoded |
value (and storing it in ENCODED) for the given OFFSET into OSEC, |
to be stored in at LOC_OFFSET into the LOC_SEC input section. |
The default definition chooses a 32-bit PC-relative encoding. */ |
bfd_byte (*elf_backend_encode_eh_address) |
(bfd *abfd, struct bfd_link_info *info, |
asection *osec, bfd_vma offset, |
asection *loc_sec, bfd_vma loc_offset, |
bfd_vma *encoded); |
/* This function, if defined, may write out the given section. |
Returns TRUE if it did so and FALSE if the caller should. */ |
bfd_boolean (*elf_backend_write_section) |
(bfd *, struct bfd_link_info *, asection *, bfd_byte *); |
/* The level of IRIX compatibility we're striving for. |
MIPS ELF specific function. */ |
irix_compat_t (*elf_backend_mips_irix_compat) |
(bfd *); |
reloc_howto_type *(*elf_backend_mips_rtype_to_howto) |
(unsigned int, bfd_boolean); |
/* The swapping table to use when dealing with ECOFF information. |
Used for the MIPS ELF .mdebug section. */ |
const struct ecoff_debug_swap *elf_backend_ecoff_debug_swap; |
/* This function implements `bfd_elf_bfd_from_remote_memory'; |
see elf.c, elfcode.h. */ |
bfd *(*elf_backend_bfd_from_remote_memory) |
(bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, |
int (*target_read_memory) (bfd_vma vma, bfd_byte *myaddr, |
bfd_size_type len)); |
/* This function is used by `_bfd_elf_get_synthetic_symtab'; |
see elf.c. */ |
bfd_vma (*plt_sym_val) (bfd_vma, const asection *, const arelent *); |
/* Is symbol defined in common section? */ |
bfd_boolean (*common_definition) (Elf_Internal_Sym *); |
/* Return a common section index for section. */ |
unsigned int (*common_section_index) (asection *); |
/* Return a common section for section. */ |
asection *(*common_section) (asection *); |
/* Return TRUE if we can merge 2 definitions. */ |
bfd_boolean (*merge_symbol) (struct elf_link_hash_entry *, |
const Elf_Internal_Sym *, asection **, |
bfd_boolean, bfd_boolean, |
bfd *, const asection *); |
/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ |
bfd_boolean (*elf_hash_symbol) (struct elf_link_hash_entry *); |
/* Return TRUE if type is a function symbol type. */ |
bfd_boolean (*is_function_type) (unsigned int type); |
/* If the ELF symbol SYM might be a function in SEC, return the |
function size and set *CODE_OFF to the function's entry point, |
otherwise return zero. */ |
bfd_size_type (*maybe_function_sym) (const asymbol *sym, asection *sec, |
bfd_vma *code_off); |
/* Used to handle bad SHF_LINK_ORDER input. */ |
bfd_error_handler_type link_order_error_handler; |
/* Name of the PLT relocation section. */ |
const char *relplt_name; |
/* Alternate EM_xxxx machine codes for this backend. */ |
int elf_machine_alt1; |
int elf_machine_alt2; |
const struct elf_size_info *s; |
/* An array of target specific special sections. */ |
const struct bfd_elf_special_section *special_sections; |
/* The size in bytes of the header for the GOT. This includes the |
so-called reserved entries on some systems. */ |
bfd_vma got_header_size; |
/* The size of the GOT entry for the symbol pointed to by H if non-NULL, |
otherwise by the local symbol with index SYMNDX in IBFD. */ |
bfd_vma (*got_elt_size) (bfd *, struct bfd_link_info *, |
struct elf_link_hash_entry *h, |
bfd *ibfd, unsigned long symndx); |
/* The vendor name to use for a processor-standard attributes section. */ |
const char *obj_attrs_vendor; |
/* The section name to use for a processor-standard attributes section. */ |
const char *obj_attrs_section; |
/* Return 1, 2 or 3 to indicate what type of arguments a |
processor-specific tag takes. */ |
int (*obj_attrs_arg_type) (int); |
/* The section type to use for an attributes section. */ |
unsigned int obj_attrs_section_type; |
/* This function determines the order in which any attributes are |
written. It must be defined for input in the range |
LEAST_KNOWN_OBJ_ATTRIBUTE..NUM_KNOWN_OBJ_ATTRIBUTES-1 (this range |
is used in order to make unity easy). The returned value is the |
actual tag number to place in the input position. */ |
int (*obj_attrs_order) (int); |
/* Handle merging unknown attributes; either warn and return TRUE, |
or give an error and return FALSE. */ |
bfd_boolean (*obj_attrs_handle_unknown) (bfd *, int); |
/* This is non-zero if static TLS segments require a special alignment. */ |
unsigned static_tls_alignment; |
/* Alignment for the PT_GNU_STACK segment. */ |
unsigned stack_align; |
/* This is TRUE if the linker should act like collect and gather |
global constructors and destructors by name. This is TRUE for |
MIPS ELF because the Irix 5 tools can not handle the .init |
section. */ |
unsigned collect : 1; |
/* This is TRUE if the linker should ignore changes to the type of a |
symbol. This is TRUE for MIPS ELF because some Irix 5 objects |
record undefined functions as STT_OBJECT although the definitions |
are STT_FUNC. */ |
unsigned type_change_ok : 1; |
/* Whether the backend may use REL relocations. (Some backends use |
both REL and RELA relocations, and this flag is set for those |
backends.) */ |
unsigned may_use_rel_p : 1; |
/* Whether the backend may use RELA relocations. (Some backends use |
both REL and RELA relocations, and this flag is set for those |
backends.) */ |
unsigned may_use_rela_p : 1; |
/* Whether the default relocation type is RELA. If a backend with |
this flag set wants REL relocations for a particular section, |
it must note that explicitly. Similarly, if this flag is clear, |
and the backend wants RELA relocations for a particular |
section. */ |
unsigned default_use_rela_p : 1; |
/* True if PLT and copy relocations should be RELA by default. */ |
unsigned rela_plts_and_copies_p : 1; |
/* Set if RELA relocations for a relocatable link can be handled by |
generic code. Backends that set this flag need do nothing in the |
backend relocate_section routine for relocatable linking. */ |
unsigned rela_normal : 1; |
/* TRUE if addresses "naturally" sign extend. This is used when |
swapping in from Elf32 when BFD64. */ |
unsigned sign_extend_vma : 1; |
unsigned want_got_plt : 1; |
unsigned plt_readonly : 1; |
unsigned want_plt_sym : 1; |
unsigned plt_not_loaded : 1; |
unsigned plt_alignment : 4; |
unsigned can_gc_sections : 1; |
unsigned can_refcount : 1; |
unsigned want_got_sym : 1; |
unsigned want_dynbss : 1; |
/* Targets which do not support physical addressing often require |
that the p_paddr field in the section header to be set to zero. |
This field indicates whether this behavior is required. */ |
unsigned want_p_paddr_set_to_zero : 1; |
/* True if an object file lacking a .note.GNU-stack section |
should be assumed to be requesting exec stack. At least one |
other file in the link needs to have a .note.GNU-stack section |
for a PT_GNU_STACK segment to be created. */ |
unsigned default_execstack : 1; |
}; |
/* Information about reloc sections associated with a bfd_elf_section_data |
structure. */ |
struct bfd_elf_section_reloc_data |
{ |
/* The ELF header for the reloc section associated with this |
section, if any. */ |
Elf_Internal_Shdr *hdr; |
/* The number of relocations currently assigned to HDR. */ |
unsigned int count; |
/* The ELF section number of the reloc section. Only used for an |
output file. */ |
int idx; |
/* Used by the backend linker to store the symbol hash table entries |
associated with relocs against global symbols. */ |
struct elf_link_hash_entry **hashes; |
}; |
/* Information stored for each BFD section in an ELF file. This |
structure is allocated by elf_new_section_hook. */ |
struct bfd_elf_section_data |
{ |
/* The ELF header for this section. */ |
Elf_Internal_Shdr this_hdr; |
/* INPUT_SECTION_FLAGS if specified in the linker script. */ |
struct flag_info *section_flag_info; |
/* Information about the REL and RELA reloc sections associated |
with this section, if any. */ |
struct bfd_elf_section_reloc_data rel, rela; |
/* The ELF section number of this section. */ |
int this_idx; |
/* Used by the backend linker when generating a shared library to |
record the dynamic symbol index for a section symbol |
corresponding to this section. A value of 0 means that there is |
no dynamic symbol for this section. */ |
int dynindx; |
/* A pointer to the linked-to section for SHF_LINK_ORDER. */ |
asection *linked_to; |
/* A pointer to the swapped relocs. If the section uses REL relocs, |
rather than RELA, all the r_addend fields will be zero. This |
pointer may be NULL. It is used by the backend linker. */ |
Elf_Internal_Rela *relocs; |
/* A pointer to a linked list tracking dynamic relocs copied for |
local symbols. */ |
void *local_dynrel; |
/* A pointer to the bfd section used for dynamic relocs. */ |
asection *sreloc; |
union { |
/* Group name, if this section is a member of a group. */ |
const char *name; |
/* Group signature sym, if this is the SHT_GROUP section. */ |
struct bfd_symbol *id; |
} group; |
/* For a member of a group, points to the SHT_GROUP section. |
NULL for the SHT_GROUP section itself and non-group sections. */ |
asection *sec_group; |
/* A linked list of member sections in the group. Circular when used by |
the linker. For the SHT_GROUP section, points at first member. */ |
asection *next_in_group; |
/* The FDEs associated with this section. The u.fde.next_in_section |
field acts as a chain pointer. */ |
struct eh_cie_fde *fde_list; |
/* A pointer used for various section optimizations. */ |
void *sec_info; |
}; |
#define elf_section_data(sec) ((struct bfd_elf_section_data*)(sec)->used_by_bfd) |
#define elf_linked_to_section(sec) (elf_section_data(sec)->linked_to) |
#define elf_section_type(sec) (elf_section_data(sec)->this_hdr.sh_type) |
#define elf_section_flags(sec) (elf_section_data(sec)->this_hdr.sh_flags) |
#define elf_group_name(sec) (elf_section_data(sec)->group.name) |
#define elf_group_id(sec) (elf_section_data(sec)->group.id) |
#define elf_next_in_group(sec) (elf_section_data(sec)->next_in_group) |
#define elf_fde_list(sec) (elf_section_data(sec)->fde_list) |
#define elf_sec_group(sec) (elf_section_data(sec)->sec_group) |
#define xvec_get_elf_backend_data(xvec) \ |
((const struct elf_backend_data *) (xvec)->backend_data) |
#define get_elf_backend_data(abfd) \ |
xvec_get_elf_backend_data ((abfd)->xvec) |
/* The least object attributes (within an attributes subsection) known |
for any target. Some code assumes that the value 0 is not used and |
the field for that attribute can instead be used as a marker to |
indicate that attributes have been initialized. */ |
#define LEAST_KNOWN_OBJ_ATTRIBUTE 2 |
/* The maximum number of known object attributes for any target. */ |
#define NUM_KNOWN_OBJ_ATTRIBUTES 71 |
/* The value of an object attribute. The type indicates whether the attribute |
holds and integer, a string, or both. It can also indicate that there can |
be no default (i.e. all values must be written to file, even zero). */ |
typedef struct obj_attribute |
{ |
#define ATTR_TYPE_FLAG_INT_VAL (1 << 0) |
#define ATTR_TYPE_FLAG_STR_VAL (1 << 1) |
#define ATTR_TYPE_FLAG_NO_DEFAULT (1 << 2) |
#define ATTR_TYPE_HAS_INT_VAL(TYPE) ((TYPE) & ATTR_TYPE_FLAG_INT_VAL) |
#define ATTR_TYPE_HAS_STR_VAL(TYPE) ((TYPE) & ATTR_TYPE_FLAG_STR_VAL) |
#define ATTR_TYPE_HAS_NO_DEFAULT(TYPE) ((TYPE) & ATTR_TYPE_FLAG_NO_DEFAULT) |
int type; |
unsigned int i; |
char *s; |
} obj_attribute; |
typedef struct obj_attribute_list |
{ |
struct obj_attribute_list *next; |
int tag; |
obj_attribute attr; |
} obj_attribute_list; |
/* Object attributes may either be defined by the processor ABI, index |
OBJ_ATTR_PROC in the *_obj_attributes arrays, or be GNU-specific |
(and possibly also processor-specific), index OBJ_ATTR_GNU. */ |
#define OBJ_ATTR_PROC 0 |
#define OBJ_ATTR_GNU 1 |
#define OBJ_ATTR_FIRST OBJ_ATTR_PROC |
#define OBJ_ATTR_LAST OBJ_ATTR_GNU |
/* The following object attribute tags are taken as generic, for all |
targets and for "gnu" where there is no target standard. */ |
enum |
{ |
Tag_NULL = 0, |
Tag_File = 1, |
Tag_Section = 2, |
Tag_Symbol = 3, |
Tag_compatibility = 32 |
}; |
/* The following struct stores information about every SystemTap section |
found in the object file. */ |
struct sdt_note |
{ |
struct sdt_note *next; |
bfd_size_type size; |
bfd_byte data[1]; |
}; |
/* NT_GNU_BUILD_ID note type info for input BFDs. */ |
struct elf_build_id |
{ |
size_t size; |
bfd_byte data[1]; |
}; |
/* tdata information grabbed from an elf core file. */ |
struct core_elf_obj_tdata |
{ |
int signal; |
int pid; |
int lwpid; |
char* program; |
char* command; |
}; |
/* Extra tdata information held for output ELF BFDs. */ |
struct output_elf_obj_tdata |
{ |
struct elf_segment_map *seg_map; |
struct elf_strtab_hash *strtab_ptr; |
/* STT_SECTION symbols for each section */ |
asymbol **section_syms; |
/* Used to determine if PT_GNU_EH_FRAME segment header should be |
created. */ |
asection *eh_frame_hdr; |
/* NT_GNU_BUILD_ID note type info. */ |
struct |
{ |
bfd_boolean (*after_write_object_contents) (bfd *); |
const char *style; |
asection *sec; |
} build_id; |
/* Records the result of `get_program_header_size'. */ |
bfd_size_type program_header_size; |
/* Used when laying out sections. */ |
file_ptr next_file_pos; |
int num_section_syms; |
unsigned int shstrtab_section, strtab_section; |
/* Segment flags for the PT_GNU_STACK segment. */ |
unsigned int stack_flags; |
/* This is set to TRUE if the object was created by the backend |
linker. */ |
bfd_boolean linker; |
/* Used to determine if the e_flags field has been initialized */ |
bfd_boolean flags_init; |
}; |
/* Some private data is stashed away for future use using the tdata pointer |
in the bfd structure. */ |
struct elf_obj_tdata |
{ |
Elf_Internal_Ehdr elf_header[1]; /* Actual data, but ref like ptr */ |
Elf_Internal_Shdr **elf_sect_ptr; |
Elf_Internal_Phdr *phdr; |
Elf_Internal_Shdr symtab_hdr; |
Elf_Internal_Shdr shstrtab_hdr; |
Elf_Internal_Shdr strtab_hdr; |
Elf_Internal_Shdr dynsymtab_hdr; |
Elf_Internal_Shdr dynstrtab_hdr; |
Elf_Internal_Shdr dynversym_hdr; |
Elf_Internal_Shdr dynverref_hdr; |
Elf_Internal_Shdr dynverdef_hdr; |
Elf_Internal_Shdr symtab_shndx_hdr; |
bfd_vma gp; /* The gp value */ |
unsigned int gp_size; /* The gp size */ |
unsigned int num_elf_sections; /* elf_sect_ptr size */ |
/* A mapping from external symbols to entries in the linker hash |
table, used when linking. This is indexed by the symbol index |
minus the sh_info field of the symbol table header. */ |
struct elf_link_hash_entry **sym_hashes; |
/* Track usage and final offsets of GOT entries for local symbols. |
This array is indexed by symbol index. Elements are used |
identically to "got" in struct elf_link_hash_entry. */ |
union |
{ |
bfd_signed_vma *refcounts; |
bfd_vma *offsets; |
struct got_entry **ents; |
} local_got; |
/* The linker ELF emulation code needs to let the backend ELF linker |
know what filename should be used for a dynamic object if the |
dynamic object is found using a search. The emulation code then |
sometimes needs to know what name was actually used. Until the |
file has been added to the linker symbol table, this field holds |
the name the linker wants. After it has been added, it holds the |
name actually used, which will be the DT_SONAME entry if there is |
one. */ |
const char *dt_name; |
/* The linker emulation needs to know what audit libs |
are used by a dynamic object. */ |
const char *dt_audit; |
/* Used by find_nearest_line entry point. */ |
void *line_info; |
/* A place to stash dwarf1 info for this bfd. */ |
struct dwarf1_debug *dwarf1_find_line_info; |
/* A place to stash dwarf2 info for this bfd. */ |
void *dwarf2_find_line_info; |
/* Stash away info for yet another find line/function variant. */ |
void *elf_find_function_cache; |
/* Number of symbol version definitions we are about to emit. */ |
unsigned int cverdefs; |
/* Number of symbol version references we are about to emit. */ |
unsigned int cverrefs; |
/* Symbol version definitions in external objects. */ |
Elf_Internal_Verdef *verdef; |
/* Symbol version references to external objects. */ |
Elf_Internal_Verneed *verref; |
/* A pointer to the .eh_frame section. */ |
asection *eh_frame_section; |
/* Symbol buffer. */ |
void *symbuf; |
obj_attribute known_obj_attributes[2][NUM_KNOWN_OBJ_ATTRIBUTES]; |
obj_attribute_list *other_obj_attributes[2]; |
/* NT_GNU_BUILD_ID note type. */ |
struct elf_build_id *build_id; |
/* Linked-list containing information about every Systemtap section |
found in the object file. Each section corresponds to one entry |
in the list. */ |
struct sdt_note *sdt_note_head; |
Elf_Internal_Shdr **group_sect_ptr; |
int num_group; |
unsigned int symtab_section, symtab_shndx_section, dynsymtab_section; |
unsigned int dynversym_section, dynverdef_section, dynverref_section; |
/* An identifier used to distinguish different target |
specific extensions to this structure. */ |
enum elf_target_id object_id; |
/* Whether a dyanmic object was specified normally on the linker |
command line, or was specified when --as-needed was in effect, |
or was found via a DT_NEEDED entry. */ |
enum dynamic_lib_link_class dyn_lib_class; |
/* Irix 5 often screws up the symbol table, sorting local symbols |
after global symbols. This flag is set if the symbol table in |
this BFD appears to be screwed up. If it is, we ignore the |
sh_info field in the symbol table header, and always read all the |
symbols. */ |
bfd_boolean bad_symtab; |
/* True if the bfd contains symbols that have the STT_GNU_IFUNC |
symbol type or STB_GNU_UNIQUE binding. Used to set the osabi |
field in the ELF header structure. */ |
bfd_boolean has_gnu_symbols; |
/* Information grabbed from an elf core file. */ |
struct core_elf_obj_tdata *core; |
/* More information held for output ELF BFDs. */ |
struct output_elf_obj_tdata *o; |
}; |
#define elf_tdata(bfd) ((bfd) -> tdata.elf_obj_data) |
#define elf_object_id(bfd) (elf_tdata(bfd) -> object_id) |
#define elf_program_header_size(bfd) (elf_tdata(bfd) -> o->program_header_size) |
#define elf_elfheader(bfd) (elf_tdata(bfd) -> elf_header) |
#define elf_elfsections(bfd) (elf_tdata(bfd) -> elf_sect_ptr) |
#define elf_numsections(bfd) (elf_tdata(bfd) -> num_elf_sections) |
#define elf_seg_map(bfd) (elf_tdata(bfd) -> o->seg_map) |
#define elf_next_file_pos(bfd) (elf_tdata(bfd) -> o->next_file_pos) |
#define elf_eh_frame_hdr(bfd) (elf_tdata(bfd) -> o->eh_frame_hdr) |
#define elf_linker(bfd) (elf_tdata(bfd) -> o->linker) |
#define elf_stack_flags(bfd) (elf_tdata(bfd) -> o->stack_flags) |
#define elf_shstrtab(bfd) (elf_tdata(bfd) -> o->strtab_ptr) |
#define elf_onesymtab(bfd) (elf_tdata(bfd) -> symtab_section) |
#define elf_symtab_shndx(bfd) (elf_tdata(bfd) -> symtab_shndx_section) |
#define elf_strtab_sec(bfd) (elf_tdata(bfd) -> o->strtab_section) |
#define elf_shstrtab_sec(bfd) (elf_tdata(bfd) -> o->shstrtab_section) |
#define elf_symtab_hdr(bfd) (elf_tdata(bfd) -> symtab_hdr) |
#define elf_dynsymtab(bfd) (elf_tdata(bfd) -> dynsymtab_section) |
#define elf_dynversym(bfd) (elf_tdata(bfd) -> dynversym_section) |
#define elf_dynverdef(bfd) (elf_tdata(bfd) -> dynverdef_section) |
#define elf_dynverref(bfd) (elf_tdata(bfd) -> dynverref_section) |
#define elf_eh_frame_section(bfd) \ |
(elf_tdata(bfd) -> eh_frame_section) |
#define elf_section_syms(bfd) (elf_tdata(bfd) -> o->section_syms) |
#define elf_num_section_syms(bfd) (elf_tdata(bfd) -> o->num_section_syms) |
#define core_prpsinfo(bfd) (elf_tdata(bfd) -> prpsinfo) |
#define core_prstatus(bfd) (elf_tdata(bfd) -> prstatus) |
#define elf_gp(bfd) (elf_tdata(bfd) -> gp) |
#define elf_gp_size(bfd) (elf_tdata(bfd) -> gp_size) |
#define elf_sym_hashes(bfd) (elf_tdata(bfd) -> sym_hashes) |
#define elf_local_got_refcounts(bfd) (elf_tdata(bfd) -> local_got.refcounts) |
#define elf_local_got_offsets(bfd) (elf_tdata(bfd) -> local_got.offsets) |
#define elf_local_got_ents(bfd) (elf_tdata(bfd) -> local_got.ents) |
#define elf_dt_name(bfd) (elf_tdata(bfd) -> dt_name) |
#define elf_dt_audit(bfd) (elf_tdata(bfd) -> dt_audit) |
#define elf_dyn_lib_class(bfd) (elf_tdata(bfd) -> dyn_lib_class) |
#define elf_bad_symtab(bfd) (elf_tdata(bfd) -> bad_symtab) |
#define elf_flags_init(bfd) (elf_tdata(bfd) -> o->flags_init) |
#define elf_known_obj_attributes(bfd) (elf_tdata (bfd) -> known_obj_attributes) |
#define elf_other_obj_attributes(bfd) (elf_tdata (bfd) -> other_obj_attributes) |
#define elf_known_obj_attributes_proc(bfd) \ |
(elf_known_obj_attributes (bfd) [OBJ_ATTR_PROC]) |
#define elf_other_obj_attributes_proc(bfd) \ |
(elf_other_obj_attributes (bfd) [OBJ_ATTR_PROC]) |
extern void _bfd_elf_swap_verdef_in |
(bfd *, const Elf_External_Verdef *, Elf_Internal_Verdef *); |
extern void _bfd_elf_swap_verdef_out |
(bfd *, const Elf_Internal_Verdef *, Elf_External_Verdef *); |
extern void _bfd_elf_swap_verdaux_in |
(bfd *, const Elf_External_Verdaux *, Elf_Internal_Verdaux *); |
extern void _bfd_elf_swap_verdaux_out |
(bfd *, const Elf_Internal_Verdaux *, Elf_External_Verdaux *); |
extern void _bfd_elf_swap_verneed_in |
(bfd *, const Elf_External_Verneed *, Elf_Internal_Verneed *); |
extern void _bfd_elf_swap_verneed_out |
(bfd *, const Elf_Internal_Verneed *, Elf_External_Verneed *); |
extern void _bfd_elf_swap_vernaux_in |
(bfd *, const Elf_External_Vernaux *, Elf_Internal_Vernaux *); |
extern void _bfd_elf_swap_vernaux_out |
(bfd *, const Elf_Internal_Vernaux *, Elf_External_Vernaux *); |
extern void _bfd_elf_swap_versym_in |
(bfd *, const Elf_External_Versym *, Elf_Internal_Versym *); |
extern void _bfd_elf_swap_versym_out |
(bfd *, const Elf_Internal_Versym *, Elf_External_Versym *); |
extern unsigned int _bfd_elf_section_from_bfd_section |
(bfd *, asection *); |
extern char *bfd_elf_string_from_elf_section |
(bfd *, unsigned, unsigned); |
extern Elf_Internal_Sym *bfd_elf_get_elf_syms |
(bfd *, Elf_Internal_Shdr *, size_t, size_t, Elf_Internal_Sym *, void *, |
Elf_External_Sym_Shndx *); |
extern const char *bfd_elf_sym_name |
(bfd *, Elf_Internal_Shdr *, Elf_Internal_Sym *, asection *); |
extern bfd_boolean _bfd_elf_copy_private_bfd_data |
(bfd *, bfd *); |
extern bfd_boolean _bfd_elf_print_private_bfd_data |
(bfd *, void *); |
extern void bfd_elf_print_symbol |
(bfd *, void *, asymbol *, bfd_print_symbol_type); |
extern unsigned int _bfd_elf_eh_frame_address_size |
(bfd *, asection *); |
extern bfd_byte _bfd_elf_encode_eh_address |
(bfd *abfd, struct bfd_link_info *info, asection *osec, bfd_vma offset, |
asection *loc_sec, bfd_vma loc_offset, bfd_vma *encoded); |
extern bfd_boolean _bfd_elf_can_make_relative |
(bfd *input_bfd, struct bfd_link_info *info, asection *eh_frame_section); |
extern enum elf_reloc_type_class _bfd_elf_reloc_type_class |
(const struct bfd_link_info *, const asection *, |
const Elf_Internal_Rela *); |
extern bfd_vma _bfd_elf_rela_local_sym |
(bfd *, Elf_Internal_Sym *, asection **, Elf_Internal_Rela *); |
extern bfd_vma _bfd_elf_rel_local_sym |
(bfd *, Elf_Internal_Sym *, asection **, bfd_vma); |
extern bfd_vma _bfd_elf_section_offset |
(bfd *, struct bfd_link_info *, asection *, bfd_vma); |
extern unsigned long bfd_elf_hash |
(const char *); |
extern unsigned long bfd_elf_gnu_hash |
(const char *); |
extern bfd_reloc_status_type bfd_elf_generic_reloc |
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); |
extern bfd_boolean bfd_elf_allocate_object |
(bfd *, size_t, enum elf_target_id); |
extern bfd_boolean bfd_elf_make_object |
(bfd *); |
extern bfd_boolean bfd_elf_mkcorefile |
(bfd *); |
extern bfd_boolean _bfd_elf_make_section_from_shdr |
(bfd *, Elf_Internal_Shdr *, const char *, int); |
extern bfd_boolean _bfd_elf_make_section_from_phdr |
(bfd *, Elf_Internal_Phdr *, int, const char *); |
extern struct bfd_hash_entry *_bfd_elf_link_hash_newfunc |
(struct bfd_hash_entry *, struct bfd_hash_table *, const char *); |
extern struct bfd_link_hash_table *_bfd_elf_link_hash_table_create |
(bfd *); |
extern void _bfd_elf_link_hash_table_free |
(struct bfd_link_hash_table *); |
extern void _bfd_elf_link_hash_copy_indirect |
(struct bfd_link_info *, struct elf_link_hash_entry *, |
struct elf_link_hash_entry *); |
extern void _bfd_elf_link_hash_hide_symbol |
(struct bfd_link_info *, struct elf_link_hash_entry *, bfd_boolean); |
extern bfd_boolean _bfd_elf_link_hash_fixup_symbol |
(struct bfd_link_info *, struct elf_link_hash_entry *); |
extern bfd_boolean _bfd_elf_link_hash_table_init |
(struct elf_link_hash_table *, bfd *, |
struct bfd_hash_entry *(*) |
(struct bfd_hash_entry *, struct bfd_hash_table *, const char *), |
unsigned int, enum elf_target_id); |
extern bfd_boolean _bfd_elf_slurp_version_tables |
(bfd *, bfd_boolean); |
extern bfd_boolean _bfd_elf_merge_sections |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean _bfd_elf_match_sections_by_type |
(bfd *, const asection *, bfd *, const asection *); |
extern bfd_boolean bfd_elf_is_group_section |
(bfd *, const struct bfd_section *); |
extern bfd_boolean _bfd_elf_section_already_linked |
(bfd *, asection *, struct bfd_link_info *); |
extern void bfd_elf_set_group_contents |
(bfd *, asection *, void *); |
extern asection *_bfd_elf_check_kept_section |
(asection *, struct bfd_link_info *); |
#define _bfd_elf_link_just_syms _bfd_generic_link_just_syms |
extern void _bfd_elf_copy_link_hash_symbol_type |
(bfd *, struct bfd_link_hash_entry *, struct bfd_link_hash_entry *); |
extern bfd_boolean _bfd_elf_size_group_sections |
(struct bfd_link_info *); |
extern bfd_boolean _bfd_elf_fixup_group_sections |
(bfd *, asection *); |
extern bfd_boolean _bfd_elf_copy_private_header_data |
(bfd *, bfd *); |
extern bfd_boolean _bfd_elf_copy_private_symbol_data |
(bfd *, asymbol *, bfd *, asymbol *); |
#define _bfd_generic_init_private_section_data \ |
_bfd_elf_init_private_section_data |
extern bfd_boolean _bfd_elf_init_private_section_data |
(bfd *, asection *, bfd *, asection *, struct bfd_link_info *); |
extern bfd_boolean _bfd_elf_copy_private_section_data |
(bfd *, asection *, bfd *, asection *); |
extern bfd_boolean _bfd_elf_write_object_contents |
(bfd *); |
extern bfd_boolean _bfd_elf_write_corefile_contents |
(bfd *); |
extern bfd_boolean _bfd_elf_set_section_contents |
(bfd *, sec_ptr, const void *, file_ptr, bfd_size_type); |
extern long _bfd_elf_get_symtab_upper_bound |
(bfd *); |
extern long _bfd_elf_canonicalize_symtab |
(bfd *, asymbol **); |
extern long _bfd_elf_get_dynamic_symtab_upper_bound |
(bfd *); |
extern long _bfd_elf_canonicalize_dynamic_symtab |
(bfd *, asymbol **); |
extern long _bfd_elf_get_synthetic_symtab |
(bfd *, long, asymbol **, long, asymbol **, asymbol **); |
extern long _bfd_elf_get_reloc_upper_bound |
(bfd *, sec_ptr); |
extern long _bfd_elf_canonicalize_reloc |
(bfd *, sec_ptr, arelent **, asymbol **); |
extern asection * _bfd_elf_get_dynamic_reloc_section |
(bfd *, asection *, bfd_boolean); |
extern asection * _bfd_elf_make_dynamic_reloc_section |
(asection *, bfd *, unsigned int, bfd *, bfd_boolean); |
extern long _bfd_elf_get_dynamic_reloc_upper_bound |
(bfd *); |
extern long _bfd_elf_canonicalize_dynamic_reloc |
(bfd *, arelent **, asymbol **); |
extern asymbol *_bfd_elf_make_empty_symbol |
(bfd *); |
extern void _bfd_elf_get_symbol_info |
(bfd *, asymbol *, symbol_info *); |
extern bfd_boolean _bfd_elf_is_local_label_name |
(bfd *, const char *); |
extern alent *_bfd_elf_get_lineno |
(bfd *, asymbol *); |
extern bfd_boolean _bfd_elf_set_arch_mach |
(bfd *, enum bfd_architecture, unsigned long); |
extern bfd_boolean _bfd_elf_find_nearest_line |
(bfd *, asection *, asymbol **, bfd_vma, const char **, const char **, |
unsigned int *); |
extern bfd_boolean _bfd_elf_find_nearest_line_discriminator |
(bfd *, asection *, asymbol **, bfd_vma, const char **, const char **, |
unsigned int *, unsigned int *); |
extern bfd_boolean _bfd_elf_find_line |
(bfd *, asymbol **, asymbol *, const char **, unsigned int *); |
extern bfd_boolean _bfd_elf_find_line_discriminator |
(bfd *, asymbol **, asymbol *, const char **, unsigned int *, unsigned int *); |
#define _bfd_generic_find_line _bfd_elf_find_line |
#define _bfd_generic_find_nearest_line_discriminator \ |
_bfd_elf_find_nearest_line_discriminator |
extern bfd_boolean _bfd_elf_find_inliner_info |
(bfd *, const char **, const char **, unsigned int *); |
#define _bfd_elf_read_minisymbols _bfd_generic_read_minisymbols |
#define _bfd_elf_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol |
extern int _bfd_elf_sizeof_headers |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean _bfd_elf_new_section_hook |
(bfd *, asection *); |
extern const struct bfd_elf_special_section *_bfd_elf_get_special_section |
(const char *, const struct bfd_elf_special_section *, unsigned int); |
extern const struct bfd_elf_special_section *_bfd_elf_get_sec_type_attr |
(bfd *, asection *); |
/* If the target doesn't have reloc handling written yet: */ |
extern void _bfd_elf_no_info_to_howto |
(bfd *, arelent *, Elf_Internal_Rela *); |
extern bfd_boolean bfd_section_from_shdr |
(bfd *, unsigned int shindex); |
extern bfd_boolean bfd_section_from_phdr |
(bfd *, Elf_Internal_Phdr *, int); |
extern int _bfd_elf_symbol_from_bfd_symbol |
(bfd *, asymbol **); |
extern Elf_Internal_Sym *bfd_sym_from_r_symndx |
(struct sym_cache *, bfd *, unsigned long); |
extern asection *bfd_section_from_elf_index |
(bfd *, unsigned int); |
extern struct bfd_strtab_hash *_bfd_elf_stringtab_init |
(void); |
extern struct elf_strtab_hash * _bfd_elf_strtab_init |
(void); |
extern void _bfd_elf_strtab_free |
(struct elf_strtab_hash *); |
extern bfd_size_type _bfd_elf_strtab_add |
(struct elf_strtab_hash *, const char *, bfd_boolean); |
extern void _bfd_elf_strtab_addref |
(struct elf_strtab_hash *, bfd_size_type); |
extern void _bfd_elf_strtab_delref |
(struct elf_strtab_hash *, bfd_size_type); |
extern unsigned int _bfd_elf_strtab_refcount |
(struct elf_strtab_hash *, bfd_size_type); |
extern void _bfd_elf_strtab_clear_all_refs |
(struct elf_strtab_hash *tab); |
extern void _bfd_elf_strtab_restore_size |
(struct elf_strtab_hash *, bfd_size_type); |
extern bfd_size_type _bfd_elf_strtab_size |
(struct elf_strtab_hash *); |
extern bfd_size_type _bfd_elf_strtab_offset |
(struct elf_strtab_hash *, bfd_size_type); |
extern bfd_boolean _bfd_elf_strtab_emit |
(bfd *, struct elf_strtab_hash *); |
extern void _bfd_elf_strtab_finalize |
(struct elf_strtab_hash *); |
extern void _bfd_elf_begin_eh_frame_parsing |
(struct bfd_link_info *info); |
extern void _bfd_elf_parse_eh_frame |
(bfd *, struct bfd_link_info *, asection *, struct elf_reloc_cookie *); |
extern void _bfd_elf_end_eh_frame_parsing |
(struct bfd_link_info *info); |
extern bfd_boolean _bfd_elf_discard_section_eh_frame |
(bfd *, struct bfd_link_info *, asection *, |
bfd_boolean (*) (bfd_vma, void *), struct elf_reloc_cookie *); |
extern bfd_boolean _bfd_elf_discard_section_eh_frame_hdr |
(bfd *, struct bfd_link_info *); |
extern bfd_vma _bfd_elf_eh_frame_section_offset |
(bfd *, struct bfd_link_info *, asection *, bfd_vma); |
extern bfd_boolean _bfd_elf_write_section_eh_frame |
(bfd *, struct bfd_link_info *, asection *, bfd_byte *); |
extern bfd_boolean _bfd_elf_write_section_eh_frame_hdr |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean _bfd_elf_eh_frame_present |
(struct bfd_link_info *); |
extern bfd_boolean _bfd_elf_maybe_strip_eh_frame_hdr |
(struct bfd_link_info *); |
extern bfd_boolean _bfd_elf_hash_symbol (struct elf_link_hash_entry *); |
extern long _bfd_elf_link_lookup_local_dynindx |
(struct bfd_link_info *, bfd *, long); |
extern bfd_boolean _bfd_elf_compute_section_file_positions |
(bfd *, struct bfd_link_info *); |
extern void _bfd_elf_assign_file_positions_for_relocs |
(bfd *); |
extern file_ptr _bfd_elf_assign_file_position_for_section |
(Elf_Internal_Shdr *, file_ptr, bfd_boolean); |
extern bfd_boolean _bfd_elf_validate_reloc |
(bfd *, arelent *); |
extern bfd_boolean _bfd_elf_link_create_dynamic_sections |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean _bfd_elf_link_omit_section_dynsym |
(bfd *, struct bfd_link_info *, asection *); |
extern bfd_boolean _bfd_elf_create_dynamic_sections |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean _bfd_elf_create_got_section |
(bfd *, struct bfd_link_info *); |
extern struct elf_link_hash_entry *_bfd_elf_define_linkage_sym |
(bfd *, struct bfd_link_info *, asection *, const char *); |
extern void _bfd_elf_init_1_index_section |
(bfd *, struct bfd_link_info *); |
extern void _bfd_elf_init_2_index_sections |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean _bfd_elfcore_make_pseudosection |
(bfd *, char *, size_t, ufile_ptr); |
extern char *_bfd_elfcore_strndup |
(bfd *, char *, size_t); |
extern Elf_Internal_Rela *_bfd_elf_link_read_relocs |
(bfd *, asection *, void *, Elf_Internal_Rela *, bfd_boolean); |
extern bfd_boolean _bfd_elf_link_output_relocs |
(bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *, |
struct elf_link_hash_entry **); |
extern bfd_boolean _bfd_elf_adjust_dynamic_copy |
(struct elf_link_hash_entry *, asection *); |
extern bfd_boolean _bfd_elf_dynamic_symbol_p |
(struct elf_link_hash_entry *, struct bfd_link_info *, bfd_boolean); |
extern bfd_boolean _bfd_elf_symbol_refs_local_p |
(struct elf_link_hash_entry *, struct bfd_link_info *, bfd_boolean); |
extern bfd_reloc_status_type bfd_elf_perform_complex_relocation |
(bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, bfd_vma); |
extern bfd_boolean _bfd_elf_setup_sections |
(bfd *); |
extern void _bfd_elf_set_osabi (bfd * , struct bfd_link_info *); |
extern const bfd_target *bfd_elf32_object_p |
(bfd *); |
extern const bfd_target *bfd_elf32_core_file_p |
(bfd *); |
extern char *bfd_elf32_core_file_failing_command |
(bfd *); |
extern int bfd_elf32_core_file_failing_signal |
(bfd *); |
extern bfd_boolean bfd_elf32_core_file_matches_executable_p |
(bfd *, bfd *); |
extern int bfd_elf32_core_file_pid |
(bfd *); |
extern bfd_boolean bfd_elf32_swap_symbol_in |
(bfd *, const void *, const void *, Elf_Internal_Sym *); |
extern void bfd_elf32_swap_symbol_out |
(bfd *, const Elf_Internal_Sym *, void *, void *); |
extern void bfd_elf32_swap_reloc_in |
(bfd *, const bfd_byte *, Elf_Internal_Rela *); |
extern void bfd_elf32_swap_reloc_out |
(bfd *, const Elf_Internal_Rela *, bfd_byte *); |
extern void bfd_elf32_swap_reloca_in |
(bfd *, const bfd_byte *, Elf_Internal_Rela *); |
extern void bfd_elf32_swap_reloca_out |
(bfd *, const Elf_Internal_Rela *, bfd_byte *); |
extern void bfd_elf32_swap_phdr_in |
(bfd *, const Elf32_External_Phdr *, Elf_Internal_Phdr *); |
extern void bfd_elf32_swap_phdr_out |
(bfd *, const Elf_Internal_Phdr *, Elf32_External_Phdr *); |
extern void bfd_elf32_swap_dyn_in |
(bfd *, const void *, Elf_Internal_Dyn *); |
extern void bfd_elf32_swap_dyn_out |
(bfd *, const Elf_Internal_Dyn *, void *); |
extern long bfd_elf32_slurp_symbol_table |
(bfd *, asymbol **, bfd_boolean); |
extern bfd_boolean bfd_elf32_write_shdrs_and_ehdr |
(bfd *); |
extern int bfd_elf32_write_out_phdrs |
(bfd *, const Elf_Internal_Phdr *, unsigned int); |
extern bfd_boolean bfd_elf32_checksum_contents |
(bfd * , void (*) (const void *, size_t, void *), void *); |
extern void bfd_elf32_write_relocs |
(bfd *, asection *, void *); |
extern bfd_boolean bfd_elf32_slurp_reloc_table |
(bfd *, asection *, asymbol **, bfd_boolean); |
extern const bfd_target *bfd_elf64_object_p |
(bfd *); |
extern const bfd_target *bfd_elf64_core_file_p |
(bfd *); |
extern char *bfd_elf64_core_file_failing_command |
(bfd *); |
extern int bfd_elf64_core_file_failing_signal |
(bfd *); |
extern bfd_boolean bfd_elf64_core_file_matches_executable_p |
(bfd *, bfd *); |
extern int bfd_elf64_core_file_pid |
(bfd *); |
extern bfd_boolean bfd_elf64_swap_symbol_in |
(bfd *, const void *, const void *, Elf_Internal_Sym *); |
extern void bfd_elf64_swap_symbol_out |
(bfd *, const Elf_Internal_Sym *, void *, void *); |
extern void bfd_elf64_swap_reloc_in |
(bfd *, const bfd_byte *, Elf_Internal_Rela *); |
extern void bfd_elf64_swap_reloc_out |
(bfd *, const Elf_Internal_Rela *, bfd_byte *); |
extern void bfd_elf64_swap_reloca_in |
(bfd *, const bfd_byte *, Elf_Internal_Rela *); |
extern void bfd_elf64_swap_reloca_out |
(bfd *, const Elf_Internal_Rela *, bfd_byte *); |
extern void bfd_elf64_swap_phdr_in |
(bfd *, const Elf64_External_Phdr *, Elf_Internal_Phdr *); |
extern void bfd_elf64_swap_phdr_out |
(bfd *, const Elf_Internal_Phdr *, Elf64_External_Phdr *); |
extern void bfd_elf64_swap_dyn_in |
(bfd *, const void *, Elf_Internal_Dyn *); |
extern void bfd_elf64_swap_dyn_out |
(bfd *, const Elf_Internal_Dyn *, void *); |
extern long bfd_elf64_slurp_symbol_table |
(bfd *, asymbol **, bfd_boolean); |
extern bfd_boolean bfd_elf64_write_shdrs_and_ehdr |
(bfd *); |
extern int bfd_elf64_write_out_phdrs |
(bfd *, const Elf_Internal_Phdr *, unsigned int); |
extern bfd_boolean bfd_elf64_checksum_contents |
(bfd * , void (*) (const void *, size_t, void *), void *); |
extern void bfd_elf64_write_relocs |
(bfd *, asection *, void *); |
extern bfd_boolean bfd_elf64_slurp_reloc_table |
(bfd *, asection *, asymbol **, bfd_boolean); |
extern bfd_boolean _bfd_elf_default_relocs_compatible |
(const bfd_target *, const bfd_target *); |
extern bfd_boolean _bfd_elf_relocs_compatible |
(const bfd_target *, const bfd_target *); |
extern bfd_boolean _bfd_elf_notice_as_needed |
(bfd *, struct bfd_link_info *, enum notice_asneeded_action); |
extern struct elf_link_hash_entry *_bfd_elf_archive_symbol_lookup |
(bfd *, struct bfd_link_info *, const char *); |
extern bfd_boolean bfd_elf_link_add_symbols |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean _bfd_elf_add_dynamic_entry |
(struct bfd_link_info *, bfd_vma, bfd_vma); |
extern bfd_boolean bfd_elf_link_record_dynamic_symbol |
(struct bfd_link_info *, struct elf_link_hash_entry *); |
extern int bfd_elf_link_record_local_dynamic_symbol |
(struct bfd_link_info *, bfd *, long); |
extern bfd_boolean _bfd_elf_close_and_cleanup |
(bfd *); |
extern bfd_boolean _bfd_elf_common_definition |
(Elf_Internal_Sym *); |
extern unsigned int _bfd_elf_common_section_index |
(asection *); |
extern asection *_bfd_elf_common_section |
(asection *); |
extern bfd_vma _bfd_elf_default_got_elt_size |
(bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, bfd *, |
unsigned long); |
extern bfd_reloc_status_type _bfd_elf_rel_vtable_reloc_fn |
(bfd *, arelent *, struct bfd_symbol *, void *, |
asection *, bfd *, char **); |
extern bfd_boolean bfd_elf_final_link |
(bfd *, struct bfd_link_info *); |
extern void _bfd_elf_gc_keep |
(struct bfd_link_info *info); |
extern bfd_boolean bfd_elf_gc_mark_dynamic_ref_symbol |
(struct elf_link_hash_entry *h, void *inf); |
extern bfd_boolean bfd_elf_gc_sections |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean bfd_elf_gc_record_vtinherit |
(bfd *, asection *, struct elf_link_hash_entry *, bfd_vma); |
extern bfd_boolean bfd_elf_gc_record_vtentry |
(bfd *, asection *, struct elf_link_hash_entry *, bfd_vma); |
extern asection *_bfd_elf_gc_mark_hook |
(asection *, struct bfd_link_info *, Elf_Internal_Rela *, |
struct elf_link_hash_entry *, Elf_Internal_Sym *); |
extern asection *_bfd_elf_gc_mark_rsec |
(struct bfd_link_info *, asection *, elf_gc_mark_hook_fn, |
struct elf_reloc_cookie *); |
extern bfd_boolean _bfd_elf_gc_mark_reloc |
(struct bfd_link_info *, asection *, elf_gc_mark_hook_fn, |
struct elf_reloc_cookie *); |
extern bfd_boolean _bfd_elf_gc_mark_fdes |
(struct bfd_link_info *, asection *, asection *, elf_gc_mark_hook_fn, |
struct elf_reloc_cookie *); |
extern bfd_boolean _bfd_elf_gc_mark |
(struct bfd_link_info *, asection *, elf_gc_mark_hook_fn); |
extern bfd_boolean _bfd_elf_gc_mark_extra_sections |
(struct bfd_link_info *, elf_gc_mark_hook_fn); |
extern bfd_boolean bfd_elf_gc_common_finalize_got_offsets |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean bfd_elf_gc_common_final_link |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean bfd_elf_reloc_symbol_deleted_p |
(bfd_vma, void *); |
extern struct elf_segment_map * _bfd_elf_make_dynamic_segment |
(bfd *, asection *); |
extern bfd_boolean _bfd_elf_map_sections_to_segments |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean _bfd_elf_is_function_type (unsigned int); |
extern bfd_size_type _bfd_elf_maybe_function_sym (const asymbol *, asection *, |
bfd_vma *); |
extern int bfd_elf_get_default_section_type (flagword); |
extern bfd_boolean bfd_elf_lookup_section_flags |
(struct bfd_link_info *, struct flag_info *, asection *); |
extern Elf_Internal_Phdr * _bfd_elf_find_segment_containing_section |
(bfd * abfd, asection * section); |
/* Exported interface for writing elf corefile notes. */ |
extern char *elfcore_write_note |
(bfd *, char *, int *, const char *, int, const void *, int); |
extern char *elfcore_write_prpsinfo |
(bfd *, char *, int *, const char *, const char *); |
extern char *elfcore_write_prstatus |
(bfd *, char *, int *, long, int, const void *); |
extern char * elfcore_write_pstatus |
(bfd *, char *, int *, long, int, const void *); |
extern char *elfcore_write_prfpreg |
(bfd *, char *, int *, const void *, int); |
extern char *elfcore_write_prxfpreg |
(bfd *, char *, int *, const void *, int); |
extern char *elfcore_write_xstatereg |
(bfd *, char *, int *, const void *, int); |
extern char *elfcore_write_ppc_vmx |
(bfd *, char *, int *, const void *, int); |
extern char *elfcore_write_ppc_vsx |
(bfd *, char *, int *, const void *, int); |
extern char *elfcore_write_s390_timer |
(bfd *, char *, int *, const void *, int); |
extern char *elfcore_write_s390_todcmp |
(bfd *, char *, int *, const void *, int); |
extern char *elfcore_write_s390_todpreg |
(bfd *, char *, int *, const void *, int); |
extern char *elfcore_write_s390_ctrs |
(bfd *, char *, int *, const void *, int); |
extern char *elfcore_write_s390_prefix |
(bfd *, char *, int *, const void *, int); |
extern char *elfcore_write_s390_last_break |
(bfd *, char *, int *, const void *, int); |
extern char *elfcore_write_s390_system_call |
(bfd *, char *, int *, const void *, int); |
extern char *elfcore_write_s390_tdb |
(bfd *, char *, int *, const void *, int); |
extern char *elfcore_write_arm_vfp |
(bfd *, char *, int *, const void *, int); |
extern char *elfcore_write_aarch_tls |
(bfd *, char *, int *, const void *, int); |
extern char *elfcore_write_aarch_hw_break |
(bfd *, char *, int *, const void *, int); |
extern char *elfcore_write_aarch_hw_watch |
(bfd *, char *, int *, const void *, int); |
extern char *elfcore_write_lwpstatus |
(bfd *, char *, int *, long, int, const void *); |
extern char *elfcore_write_register_note |
(bfd *, char *, int *, const char *, const void *, int); |
/* Internal structure which holds information to be included in the |
PRPSINFO section of Linux core files. |
This is an "internal" structure in the sense that it should be used |
to pass information to BFD (via the `elfcore_write_linux_prpsinfo' |
function), so things like endianess shouldn't be an issue. This |
structure will eventually be converted in one of the |
`elf_external_linux_*' structures and written out to an output bfd |
by one of the functions declared below. */ |
struct elf_internal_linux_prpsinfo |
{ |
char pr_state; /* Numeric process state. */ |
char pr_sname; /* Char for pr_state. */ |
char pr_zomb; /* Zombie. */ |
char pr_nice; /* Nice val. */ |
unsigned long pr_flag; /* Flags. */ |
unsigned int pr_uid; |
unsigned int pr_gid; |
int pr_pid, pr_ppid, pr_pgrp, pr_sid; |
char pr_fname[16 + 1]; /* Filename of executable. */ |
char pr_psargs[80 + 1]; /* Initial part of arg list. */ |
}; |
/* Linux/most 32-bit archs. */ |
extern char *elfcore_write_linux_prpsinfo32 |
(bfd *, char *, int *, const struct elf_internal_linux_prpsinfo *); |
/* Linux/most 64-bit archs. */ |
extern char *elfcore_write_linux_prpsinfo64 |
(bfd *, char *, int *, const struct elf_internal_linux_prpsinfo *); |
/* Linux/PPC32 uses different layout compared to most archs. */ |
extern char *elfcore_write_ppc_linux_prpsinfo32 |
(bfd *, char *, int *, const struct elf_internal_linux_prpsinfo *); |
extern bfd *_bfd_elf32_bfd_from_remote_memory |
(bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, |
int (*target_read_memory) (bfd_vma, bfd_byte *, bfd_size_type)); |
extern bfd *_bfd_elf64_bfd_from_remote_memory |
(bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, |
int (*target_read_memory) (bfd_vma, bfd_byte *, bfd_size_type)); |
extern bfd_vma bfd_elf_obj_attr_size (bfd *); |
extern void bfd_elf_set_obj_attr_contents (bfd *, bfd_byte *, bfd_vma); |
extern int bfd_elf_get_obj_attr_int (bfd *, int, int); |
extern void bfd_elf_add_obj_attr_int (bfd *, int, int, unsigned int); |
#define bfd_elf_add_proc_attr_int(BFD, TAG, VALUE) \ |
bfd_elf_add_obj_attr_int ((BFD), OBJ_ATTR_PROC, (TAG), (VALUE)) |
extern void bfd_elf_add_obj_attr_string (bfd *, int, int, const char *); |
#define bfd_elf_add_proc_attr_string(BFD, TAG, VALUE) \ |
bfd_elf_add_obj_attr_string ((BFD), OBJ_ATTR_PROC, (TAG), (VALUE)) |
extern void bfd_elf_add_obj_attr_int_string (bfd *, int, int, unsigned int, |
const char *); |
#define bfd_elf_add_proc_attr_int_string(BFD, TAG, INTVAL, STRVAL) \ |
bfd_elf_add_obj_attr_int_string ((BFD), OBJ_ATTR_PROC, (TAG), \ |
(INTVAL), (STRVAL)) |
extern char *_bfd_elf_attr_strdup (bfd *, const char *); |
extern void _bfd_elf_copy_obj_attributes (bfd *, bfd *); |
extern int _bfd_elf_obj_attrs_arg_type (bfd *, int, int); |
extern void _bfd_elf_parse_attributes (bfd *, Elf_Internal_Shdr *); |
extern bfd_boolean _bfd_elf_merge_object_attributes (bfd *, bfd *); |
extern bfd_boolean _bfd_elf_merge_unknown_attribute_low (bfd *, bfd *, int); |
extern bfd_boolean _bfd_elf_merge_unknown_attribute_list (bfd *, bfd *); |
extern Elf_Internal_Shdr *_bfd_elf_single_rel_hdr (asection *sec); |
/* The linker may need to keep track of the number of relocs that it |
decides to copy as dynamic relocs in check_relocs for each symbol. |
This is so that it can later discard them if they are found to be |
unnecessary. We can store the information in a field extending the |
regular ELF linker hash table. */ |
struct elf_dyn_relocs |
{ |
struct elf_dyn_relocs *next; |
/* The input section of the reloc. */ |
asection *sec; |
/* Total number of relocs copied for the input section. */ |
bfd_size_type count; |
/* Number of pc-relative relocs copied for the input section. */ |
bfd_size_type pc_count; |
}; |
extern bfd_boolean _bfd_elf_create_ifunc_sections |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean _bfd_elf_allocate_ifunc_dyn_relocs |
(struct bfd_link_info *, struct elf_link_hash_entry *, |
struct elf_dyn_relocs **, unsigned int, unsigned int, unsigned int); |
extern void elf_append_rela (bfd *, asection *, Elf_Internal_Rela *); |
extern void elf_append_rel (bfd *, asection *, Elf_Internal_Rela *); |
extern bfd_vma elf64_r_info (bfd_vma, bfd_vma); |
extern bfd_vma elf64_r_sym (bfd_vma); |
extern bfd_vma elf32_r_info (bfd_vma, bfd_vma); |
extern bfd_vma elf32_r_sym (bfd_vma); |
/* Large common section. */ |
extern asection _bfd_elf_large_com_section; |
/* Hash for local symbol with the first section id, ID, in the input |
file and the local symbol index, SYM. */ |
#define ELF_LOCAL_SYMBOL_HASH(ID, SYM) \ |
(((((ID) & 0xff) << 24) | (((ID) & 0xff00) << 8)) \ |
^ (SYM) ^ ((ID) >> 16)) |
/* This is the condition under which finish_dynamic_symbol will be called. |
If our finish_dynamic_symbol isn't called, we'll need to do something |
about initializing any .plt and .got entries in relocate_section. */ |
#define WILL_CALL_FINISH_DYNAMIC_SYMBOL(DYN, SHARED, H) \ |
((DYN) \ |
&& ((SHARED) || !(H)->forced_local) \ |
&& ((H)->dynindx != -1 || (H)->forced_local)) |
/* This macro is to avoid lots of duplicated code in the body |
of xxx_relocate_section() in the various elfxx-xxxx.c files. */ |
#define RELOC_FOR_GLOBAL_SYMBOL(info, input_bfd, input_section, rel, \ |
r_symndx, symtab_hdr, sym_hashes, \ |
h, sec, relocation, \ |
unresolved_reloc, warned) \ |
do \ |
{ \ |
/* It seems this can happen with erroneous or unsupported \ |
input (mixing a.out and elf in an archive, for example.) */ \ |
if (sym_hashes == NULL) \ |
return FALSE; \ |
\ |
h = sym_hashes[r_symndx - symtab_hdr->sh_info]; \ |
\ |
while (h->root.type == bfd_link_hash_indirect \ |
|| h->root.type == bfd_link_hash_warning) \ |
h = (struct elf_link_hash_entry *) h->root.u.i.link; \ |
\ |
warned = FALSE; \ |
unresolved_reloc = FALSE; \ |
relocation = 0; \ |
if (h->root.type == bfd_link_hash_defined \ |
|| h->root.type == bfd_link_hash_defweak) \ |
{ \ |
sec = h->root.u.def.section; \ |
if (sec == NULL \ |
|| sec->output_section == NULL) \ |
/* Set a flag that will be cleared later if we find a \ |
relocation value for this symbol. output_section \ |
is typically NULL for symbols satisfied by a shared \ |
library. */ \ |
unresolved_reloc = TRUE; \ |
else \ |
relocation = (h->root.u.def.value \ |
+ sec->output_section->vma \ |
+ sec->output_offset); \ |
} \ |
else if (h->root.type == bfd_link_hash_undefweak) \ |
; \ |
else if (info->unresolved_syms_in_objects == RM_IGNORE \ |
&& ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) \ |
; \ |
else if (!info->relocatable) \ |
{ \ |
bfd_boolean err; \ |
err = (info->unresolved_syms_in_objects == RM_GENERATE_ERROR \ |
|| ELF_ST_VISIBILITY (h->other) != STV_DEFAULT); \ |
if (!info->callbacks->undefined_symbol (info, \ |
h->root.root.string, \ |
input_bfd, \ |
input_section, \ |
rel->r_offset, err)) \ |
return FALSE; \ |
warned = TRUE; \ |
} \ |
(void) unresolved_reloc; \ |
(void) warned; \ |
} \ |
while (0) |
/* This macro is to avoid lots of duplicated code in the body of the |
loop over relocations in xxx_relocate_section() in the various |
elfxx-xxxx.c files. |
Handle relocations against symbols from removed linkonce sections, |
or sections discarded by a linker script. When doing a relocatable |
link, we remove such relocations. Otherwise, we just want the |
section contents zeroed and avoid any special processing. */ |
#define RELOC_AGAINST_DISCARDED_SECTION(info, input_bfd, input_section, \ |
rel, count, relend, \ |
howto, index, contents) \ |
{ \ |
int i_; \ |
_bfd_clear_contents (howto, input_bfd, input_section, \ |
contents + rel[index].r_offset); \ |
\ |
if (info->relocatable \ |
&& (input_section->flags & SEC_DEBUGGING)) \ |
{ \ |
/* Only remove relocations in debug sections since other \ |
sections may require relocations. */ \ |
Elf_Internal_Shdr *rel_hdr; \ |
\ |
rel_hdr = _bfd_elf_single_rel_hdr (input_section->output_section); \ |
\ |
/* Avoid empty output section. */ \ |
if (rel_hdr->sh_size > rel_hdr->sh_entsize) \ |
{ \ |
rel_hdr->sh_size -= rel_hdr->sh_entsize; \ |
rel_hdr = _bfd_elf_single_rel_hdr (input_section); \ |
rel_hdr->sh_size -= rel_hdr->sh_entsize; \ |
\ |
memmove (rel, rel + count, \ |
(relend - rel - count) * sizeof (*rel)); \ |
\ |
input_section->reloc_count--; \ |
relend -= count; \ |
rel--; \ |
continue; \ |
} \ |
} \ |
\ |
for (i_ = 0; i_ < count; i_++) \ |
{ \ |
rel[i_].r_info = 0; \ |
rel[i_].r_addend = 0; \ |
} \ |
rel += count - 1; \ |
continue; \ |
} |
/* Will a symbol be bound to the definition within the shared |
library, if any. A unique symbol can never be bound locally. */ |
#define SYMBOLIC_BIND(INFO, H) \ |
(!(H)->unique_global \ |
&& ((INFO)->symbolic || ((INFO)->dynamic && !(H)->dynamic))) |
#endif /* _LIBELF_H_ */ |
/contrib/toolchain/binutils/bfd/elf-eh-frame.c |
---|
0,0 → 1,1883 |
/* .eh_frame section optimization. |
Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, |
2012 Free Software Foundation, Inc. |
Written by Jakub Jelinek <jakub@redhat.com>. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
#include "elf-bfd.h" |
#include "dwarf2.h" |
#define EH_FRAME_HDR_SIZE 8 |
struct cie |
{ |
unsigned int length; |
unsigned int hash; |
unsigned char version; |
unsigned char local_personality; |
char augmentation[20]; |
bfd_vma code_align; |
bfd_signed_vma data_align; |
bfd_vma ra_column; |
bfd_vma augmentation_size; |
union { |
struct elf_link_hash_entry *h; |
bfd_vma val; |
unsigned int reloc_index; |
} personality; |
asection *output_sec; |
struct eh_cie_fde *cie_inf; |
unsigned char per_encoding; |
unsigned char lsda_encoding; |
unsigned char fde_encoding; |
unsigned char initial_insn_length; |
unsigned char can_make_lsda_relative; |
unsigned char initial_instructions[50]; |
}; |
/* If *ITER hasn't reached END yet, read the next byte into *RESULT and |
move onto the next byte. Return true on success. */ |
static inline bfd_boolean |
read_byte (bfd_byte **iter, bfd_byte *end, unsigned char *result) |
{ |
if (*iter >= end) |
return FALSE; |
*result = *((*iter)++); |
return TRUE; |
} |
/* Move *ITER over LENGTH bytes, or up to END, whichever is closer. |
Return true it was possible to move LENGTH bytes. */ |
static inline bfd_boolean |
skip_bytes (bfd_byte **iter, bfd_byte *end, bfd_size_type length) |
{ |
if ((bfd_size_type) (end - *iter) < length) |
{ |
*iter = end; |
return FALSE; |
} |
*iter += length; |
return TRUE; |
} |
/* Move *ITER over an leb128, stopping at END. Return true if the end |
of the leb128 was found. */ |
static bfd_boolean |
skip_leb128 (bfd_byte **iter, bfd_byte *end) |
{ |
unsigned char byte; |
do |
if (!read_byte (iter, end, &byte)) |
return FALSE; |
while (byte & 0x80); |
return TRUE; |
} |
/* Like skip_leb128, but treat the leb128 as an unsigned value and |
store it in *VALUE. */ |
static bfd_boolean |
read_uleb128 (bfd_byte **iter, bfd_byte *end, bfd_vma *value) |
{ |
bfd_byte *start, *p; |
start = *iter; |
if (!skip_leb128 (iter, end)) |
return FALSE; |
p = *iter; |
*value = *--p; |
while (p > start) |
*value = (*value << 7) | (*--p & 0x7f); |
return TRUE; |
} |
/* Like read_uleb128, but for signed values. */ |
static bfd_boolean |
read_sleb128 (bfd_byte **iter, bfd_byte *end, bfd_signed_vma *value) |
{ |
bfd_byte *start, *p; |
start = *iter; |
if (!skip_leb128 (iter, end)) |
return FALSE; |
p = *iter; |
*value = ((*--p & 0x7f) ^ 0x40) - 0x40; |
while (p > start) |
*value = (*value << 7) | (*--p & 0x7f); |
return TRUE; |
} |
/* Return 0 if either encoding is variable width, or not yet known to bfd. */ |
static |
int get_DW_EH_PE_width (int encoding, int ptr_size) |
{ |
/* DW_EH_PE_ values of 0x60 and 0x70 weren't defined at the time .eh_frame |
was added to bfd. */ |
if ((encoding & 0x60) == 0x60) |
return 0; |
switch (encoding & 7) |
{ |
case DW_EH_PE_udata2: return 2; |
case DW_EH_PE_udata4: return 4; |
case DW_EH_PE_udata8: return 8; |
case DW_EH_PE_absptr: return ptr_size; |
default: |
break; |
} |
return 0; |
} |
#define get_DW_EH_PE_signed(encoding) (((encoding) & DW_EH_PE_signed) != 0) |
/* Read a width sized value from memory. */ |
static bfd_vma |
read_value (bfd *abfd, bfd_byte *buf, int width, int is_signed) |
{ |
bfd_vma value; |
switch (width) |
{ |
case 2: |
if (is_signed) |
value = bfd_get_signed_16 (abfd, buf); |
else |
value = bfd_get_16 (abfd, buf); |
break; |
case 4: |
if (is_signed) |
value = bfd_get_signed_32 (abfd, buf); |
else |
value = bfd_get_32 (abfd, buf); |
break; |
case 8: |
if (is_signed) |
value = bfd_get_signed_64 (abfd, buf); |
else |
value = bfd_get_64 (abfd, buf); |
break; |
default: |
BFD_FAIL (); |
return 0; |
} |
return value; |
} |
/* Store a width sized value to memory. */ |
static void |
write_value (bfd *abfd, bfd_byte *buf, bfd_vma value, int width) |
{ |
switch (width) |
{ |
case 2: bfd_put_16 (abfd, value, buf); break; |
case 4: bfd_put_32 (abfd, value, buf); break; |
case 8: bfd_put_64 (abfd, value, buf); break; |
default: BFD_FAIL (); |
} |
} |
/* Return one if C1 and C2 CIEs can be merged. */ |
static int |
cie_eq (const void *e1, const void *e2) |
{ |
const struct cie *c1 = (const struct cie *) e1; |
const struct cie *c2 = (const struct cie *) e2; |
if (c1->hash == c2->hash |
&& c1->length == c2->length |
&& c1->version == c2->version |
&& c1->local_personality == c2->local_personality |
&& strcmp (c1->augmentation, c2->augmentation) == 0 |
&& strcmp (c1->augmentation, "eh") != 0 |
&& c1->code_align == c2->code_align |
&& c1->data_align == c2->data_align |
&& c1->ra_column == c2->ra_column |
&& c1->augmentation_size == c2->augmentation_size |
&& memcmp (&c1->personality, &c2->personality, |
sizeof (c1->personality)) == 0 |
&& c1->output_sec == c2->output_sec |
&& c1->per_encoding == c2->per_encoding |
&& c1->lsda_encoding == c2->lsda_encoding |
&& c1->fde_encoding == c2->fde_encoding |
&& c1->initial_insn_length == c2->initial_insn_length |
&& memcmp (c1->initial_instructions, |
c2->initial_instructions, |
c1->initial_insn_length) == 0) |
return 1; |
return 0; |
} |
static hashval_t |
cie_hash (const void *e) |
{ |
const struct cie *c = (const struct cie *) e; |
return c->hash; |
} |
static hashval_t |
cie_compute_hash (struct cie *c) |
{ |
hashval_t h = 0; |
h = iterative_hash_object (c->length, h); |
h = iterative_hash_object (c->version, h); |
h = iterative_hash (c->augmentation, strlen (c->augmentation) + 1, h); |
h = iterative_hash_object (c->code_align, h); |
h = iterative_hash_object (c->data_align, h); |
h = iterative_hash_object (c->ra_column, h); |
h = iterative_hash_object (c->augmentation_size, h); |
h = iterative_hash_object (c->personality, h); |
h = iterative_hash_object (c->output_sec, h); |
h = iterative_hash_object (c->per_encoding, h); |
h = iterative_hash_object (c->lsda_encoding, h); |
h = iterative_hash_object (c->fde_encoding, h); |
h = iterative_hash_object (c->initial_insn_length, h); |
h = iterative_hash (c->initial_instructions, c->initial_insn_length, h); |
c->hash = h; |
return h; |
} |
/* Return the number of extra bytes that we'll be inserting into |
ENTRY's augmentation string. */ |
static INLINE unsigned int |
extra_augmentation_string_bytes (struct eh_cie_fde *entry) |
{ |
unsigned int size = 0; |
if (entry->cie) |
{ |
if (entry->add_augmentation_size) |
size++; |
if (entry->u.cie.add_fde_encoding) |
size++; |
} |
return size; |
} |
/* Likewise ENTRY's augmentation data. */ |
static INLINE unsigned int |
extra_augmentation_data_bytes (struct eh_cie_fde *entry) |
{ |
unsigned int size = 0; |
if (entry->add_augmentation_size) |
size++; |
if (entry->cie && entry->u.cie.add_fde_encoding) |
size++; |
return size; |
} |
/* Return the size that ENTRY will have in the output. ALIGNMENT is the |
required alignment of ENTRY in bytes. */ |
static unsigned int |
size_of_output_cie_fde (struct eh_cie_fde *entry, unsigned int alignment) |
{ |
if (entry->removed) |
return 0; |
if (entry->size == 4) |
return 4; |
return (entry->size |
+ extra_augmentation_string_bytes (entry) |
+ extra_augmentation_data_bytes (entry) |
+ alignment - 1) & -alignment; |
} |
/* Assume that the bytes between *ITER and END are CFA instructions. |
Try to move *ITER past the first instruction and return true on |
success. ENCODED_PTR_WIDTH gives the width of pointer entries. */ |
static bfd_boolean |
skip_cfa_op (bfd_byte **iter, bfd_byte *end, unsigned int encoded_ptr_width) |
{ |
bfd_byte op; |
bfd_vma length; |
if (!read_byte (iter, end, &op)) |
return FALSE; |
switch (op & 0xc0 ? op & 0xc0 : op) |
{ |
case DW_CFA_nop: |
case DW_CFA_advance_loc: |
case DW_CFA_restore: |
case DW_CFA_remember_state: |
case DW_CFA_restore_state: |
case DW_CFA_GNU_window_save: |
/* No arguments. */ |
return TRUE; |
case DW_CFA_offset: |
case DW_CFA_restore_extended: |
case DW_CFA_undefined: |
case DW_CFA_same_value: |
case DW_CFA_def_cfa_register: |
case DW_CFA_def_cfa_offset: |
case DW_CFA_def_cfa_offset_sf: |
case DW_CFA_GNU_args_size: |
/* One leb128 argument. */ |
return skip_leb128 (iter, end); |
case DW_CFA_val_offset: |
case DW_CFA_val_offset_sf: |
case DW_CFA_offset_extended: |
case DW_CFA_register: |
case DW_CFA_def_cfa: |
case DW_CFA_offset_extended_sf: |
case DW_CFA_GNU_negative_offset_extended: |
case DW_CFA_def_cfa_sf: |
/* Two leb128 arguments. */ |
return (skip_leb128 (iter, end) |
&& skip_leb128 (iter, end)); |
case DW_CFA_def_cfa_expression: |
/* A variable-length argument. */ |
return (read_uleb128 (iter, end, &length) |
&& skip_bytes (iter, end, length)); |
case DW_CFA_expression: |
case DW_CFA_val_expression: |
/* A leb128 followed by a variable-length argument. */ |
return (skip_leb128 (iter, end) |
&& read_uleb128 (iter, end, &length) |
&& skip_bytes (iter, end, length)); |
case DW_CFA_set_loc: |
return skip_bytes (iter, end, encoded_ptr_width); |
case DW_CFA_advance_loc1: |
return skip_bytes (iter, end, 1); |
case DW_CFA_advance_loc2: |
return skip_bytes (iter, end, 2); |
case DW_CFA_advance_loc4: |
return skip_bytes (iter, end, 4); |
case DW_CFA_MIPS_advance_loc8: |
return skip_bytes (iter, end, 8); |
default: |
return FALSE; |
} |
} |
/* Try to interpret the bytes between BUF and END as CFA instructions. |
If every byte makes sense, return a pointer to the first DW_CFA_nop |
padding byte, or END if there is no padding. Return null otherwise. |
ENCODED_PTR_WIDTH is as for skip_cfa_op. */ |
static bfd_byte * |
skip_non_nops (bfd_byte *buf, bfd_byte *end, unsigned int encoded_ptr_width, |
unsigned int *set_loc_count) |
{ |
bfd_byte *last; |
last = buf; |
while (buf < end) |
if (*buf == DW_CFA_nop) |
buf++; |
else |
{ |
if (*buf == DW_CFA_set_loc) |
++*set_loc_count; |
if (!skip_cfa_op (&buf, end, encoded_ptr_width)) |
return 0; |
last = buf; |
} |
return last; |
} |
/* Convert absolute encoding ENCODING into PC-relative form. |
SIZE is the size of a pointer. */ |
static unsigned char |
make_pc_relative (unsigned char encoding, unsigned int ptr_size) |
{ |
if ((encoding & 0x7f) == DW_EH_PE_absptr) |
switch (ptr_size) |
{ |
case 2: |
encoding |= DW_EH_PE_sdata2; |
break; |
case 4: |
encoding |= DW_EH_PE_sdata4; |
break; |
case 8: |
encoding |= DW_EH_PE_sdata8; |
break; |
} |
return encoding | DW_EH_PE_pcrel; |
} |
/* Called before calling _bfd_elf_parse_eh_frame on every input bfd's |
.eh_frame section. */ |
void |
_bfd_elf_begin_eh_frame_parsing (struct bfd_link_info *info) |
{ |
struct eh_frame_hdr_info *hdr_info; |
hdr_info = &elf_hash_table (info)->eh_info; |
hdr_info->merge_cies = !info->relocatable; |
} |
/* Try to parse .eh_frame section SEC, which belongs to ABFD. Store the |
information in the section's sec_info field on success. COOKIE |
describes the relocations in SEC. */ |
void |
_bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, |
asection *sec, struct elf_reloc_cookie *cookie) |
{ |
#define REQUIRE(COND) \ |
do \ |
if (!(COND)) \ |
goto free_no_table; \ |
while (0) |
bfd_byte *ehbuf = NULL, *buf, *end; |
bfd_byte *last_fde; |
struct eh_cie_fde *this_inf; |
unsigned int hdr_length, hdr_id; |
unsigned int cie_count; |
struct cie *cie, *local_cies = NULL; |
struct elf_link_hash_table *htab; |
struct eh_frame_hdr_info *hdr_info; |
struct eh_frame_sec_info *sec_info = NULL; |
unsigned int ptr_size; |
unsigned int num_cies; |
unsigned int num_entries; |
elf_gc_mark_hook_fn gc_mark_hook; |
htab = elf_hash_table (info); |
hdr_info = &htab->eh_info; |
if (hdr_info->parsed_eh_frames) |
return; |
if (sec->size == 0 |
|| sec->sec_info_type != SEC_INFO_TYPE_NONE) |
{ |
/* This file does not contain .eh_frame information. */ |
return; |
} |
if (bfd_is_abs_section (sec->output_section)) |
{ |
/* At least one of the sections is being discarded from the |
link, so we should just ignore them. */ |
return; |
} |
/* Read the frame unwind information from abfd. */ |
REQUIRE (bfd_malloc_and_get_section (abfd, sec, &ehbuf)); |
if (sec->size >= 4 |
&& bfd_get_32 (abfd, ehbuf) == 0 |
&& cookie->rel == cookie->relend) |
{ |
/* Empty .eh_frame section. */ |
free (ehbuf); |
return; |
} |
/* If .eh_frame section size doesn't fit into int, we cannot handle |
it (it would need to use 64-bit .eh_frame format anyway). */ |
REQUIRE (sec->size == (unsigned int) sec->size); |
ptr_size = (get_elf_backend_data (abfd) |
->elf_backend_eh_frame_address_size (abfd, sec)); |
REQUIRE (ptr_size != 0); |
/* Go through the section contents and work out how many FDEs and |
CIEs there are. */ |
buf = ehbuf; |
end = ehbuf + sec->size; |
num_cies = 0; |
num_entries = 0; |
while (buf != end) |
{ |
num_entries++; |
/* Read the length of the entry. */ |
REQUIRE (skip_bytes (&buf, end, 4)); |
hdr_length = bfd_get_32 (abfd, buf - 4); |
/* 64-bit .eh_frame is not supported. */ |
REQUIRE (hdr_length != 0xffffffff); |
if (hdr_length == 0) |
break; |
REQUIRE (skip_bytes (&buf, end, 4)); |
hdr_id = bfd_get_32 (abfd, buf - 4); |
if (hdr_id == 0) |
num_cies++; |
REQUIRE (skip_bytes (&buf, end, hdr_length - 4)); |
} |
sec_info = (struct eh_frame_sec_info *) |
bfd_zmalloc (sizeof (struct eh_frame_sec_info) |
+ (num_entries - 1) * sizeof (struct eh_cie_fde)); |
REQUIRE (sec_info); |
/* We need to have a "struct cie" for each CIE in this section. */ |
local_cies = (struct cie *) bfd_zmalloc (num_cies * sizeof (*local_cies)); |
REQUIRE (local_cies); |
/* FIXME: octets_per_byte. */ |
#define ENSURE_NO_RELOCS(buf) \ |
REQUIRE (!(cookie->rel < cookie->relend \ |
&& (cookie->rel->r_offset \ |
< (bfd_size_type) ((buf) - ehbuf)) \ |
&& cookie->rel->r_info != 0)) |
/* FIXME: octets_per_byte. */ |
#define SKIP_RELOCS(buf) \ |
while (cookie->rel < cookie->relend \ |
&& (cookie->rel->r_offset \ |
< (bfd_size_type) ((buf) - ehbuf))) \ |
cookie->rel++ |
/* FIXME: octets_per_byte. */ |
#define GET_RELOC(buf) \ |
((cookie->rel < cookie->relend \ |
&& (cookie->rel->r_offset \ |
== (bfd_size_type) ((buf) - ehbuf))) \ |
? cookie->rel : NULL) |
buf = ehbuf; |
cie_count = 0; |
gc_mark_hook = get_elf_backend_data (abfd)->gc_mark_hook; |
while ((bfd_size_type) (buf - ehbuf) != sec->size) |
{ |
char *aug; |
bfd_byte *start, *insns, *insns_end; |
bfd_size_type length; |
unsigned int set_loc_count; |
this_inf = sec_info->entry + sec_info->count; |
last_fde = buf; |
/* Read the length of the entry. */ |
REQUIRE (skip_bytes (&buf, ehbuf + sec->size, 4)); |
hdr_length = bfd_get_32 (abfd, buf - 4); |
/* The CIE/FDE must be fully contained in this input section. */ |
REQUIRE ((bfd_size_type) (buf - ehbuf) + hdr_length <= sec->size); |
end = buf + hdr_length; |
this_inf->offset = last_fde - ehbuf; |
this_inf->size = 4 + hdr_length; |
this_inf->reloc_index = cookie->rel - cookie->rels; |
if (hdr_length == 0) |
{ |
/* A zero-length CIE should only be found at the end of |
the section. */ |
REQUIRE ((bfd_size_type) (buf - ehbuf) == sec->size); |
ENSURE_NO_RELOCS (buf); |
sec_info->count++; |
break; |
} |
REQUIRE (skip_bytes (&buf, end, 4)); |
hdr_id = bfd_get_32 (abfd, buf - 4); |
if (hdr_id == 0) |
{ |
unsigned int initial_insn_length; |
/* CIE */ |
this_inf->cie = 1; |
/* Point CIE to one of the section-local cie structures. */ |
cie = local_cies + cie_count++; |
cie->cie_inf = this_inf; |
cie->length = hdr_length; |
cie->output_sec = sec->output_section; |
start = buf; |
REQUIRE (read_byte (&buf, end, &cie->version)); |
/* Cannot handle unknown versions. */ |
REQUIRE (cie->version == 1 |
|| cie->version == 3 |
|| cie->version == 4); |
REQUIRE (strlen ((char *) buf) < sizeof (cie->augmentation)); |
strcpy (cie->augmentation, (char *) buf); |
buf = (bfd_byte *) strchr ((char *) buf, '\0') + 1; |
ENSURE_NO_RELOCS (buf); |
if (buf[0] == 'e' && buf[1] == 'h') |
{ |
/* GCC < 3.0 .eh_frame CIE */ |
/* We cannot merge "eh" CIEs because __EXCEPTION_TABLE__ |
is private to each CIE, so we don't need it for anything. |
Just skip it. */ |
REQUIRE (skip_bytes (&buf, end, ptr_size)); |
SKIP_RELOCS (buf); |
} |
if (cie->version >= 4) |
{ |
REQUIRE (buf + 1 < end); |
REQUIRE (buf[0] == ptr_size); |
REQUIRE (buf[1] == 0); |
buf += 2; |
} |
REQUIRE (read_uleb128 (&buf, end, &cie->code_align)); |
REQUIRE (read_sleb128 (&buf, end, &cie->data_align)); |
if (cie->version == 1) |
{ |
REQUIRE (buf < end); |
cie->ra_column = *buf++; |
} |
else |
REQUIRE (read_uleb128 (&buf, end, &cie->ra_column)); |
ENSURE_NO_RELOCS (buf); |
cie->lsda_encoding = DW_EH_PE_omit; |
cie->fde_encoding = DW_EH_PE_omit; |
cie->per_encoding = DW_EH_PE_omit; |
aug = cie->augmentation; |
if (aug[0] != 'e' || aug[1] != 'h') |
{ |
if (*aug == 'z') |
{ |
aug++; |
REQUIRE (read_uleb128 (&buf, end, &cie->augmentation_size)); |
ENSURE_NO_RELOCS (buf); |
} |
while (*aug != '\0') |
switch (*aug++) |
{ |
case 'L': |
REQUIRE (read_byte (&buf, end, &cie->lsda_encoding)); |
ENSURE_NO_RELOCS (buf); |
REQUIRE (get_DW_EH_PE_width (cie->lsda_encoding, ptr_size)); |
break; |
case 'R': |
REQUIRE (read_byte (&buf, end, &cie->fde_encoding)); |
ENSURE_NO_RELOCS (buf); |
REQUIRE (get_DW_EH_PE_width (cie->fde_encoding, ptr_size)); |
break; |
case 'S': |
break; |
case 'P': |
{ |
int per_width; |
REQUIRE (read_byte (&buf, end, &cie->per_encoding)); |
per_width = get_DW_EH_PE_width (cie->per_encoding, |
ptr_size); |
REQUIRE (per_width); |
if ((cie->per_encoding & 0x70) == DW_EH_PE_aligned) |
{ |
length = -(buf - ehbuf) & (per_width - 1); |
REQUIRE (skip_bytes (&buf, end, length)); |
} |
this_inf->u.cie.personality_offset = buf - start; |
ENSURE_NO_RELOCS (buf); |
/* Ensure we have a reloc here. */ |
REQUIRE (GET_RELOC (buf)); |
cie->personality.reloc_index |
= cookie->rel - cookie->rels; |
/* Cope with MIPS-style composite relocations. */ |
do |
cookie->rel++; |
while (GET_RELOC (buf) != NULL); |
REQUIRE (skip_bytes (&buf, end, per_width)); |
} |
break; |
default: |
/* Unrecognized augmentation. Better bail out. */ |
goto free_no_table; |
} |
} |
/* For shared libraries, try to get rid of as many RELATIVE relocs |
as possible. */ |
if (info->shared |
&& (get_elf_backend_data (abfd) |
->elf_backend_can_make_relative_eh_frame |
(abfd, info, sec))) |
{ |
if ((cie->fde_encoding & 0x70) == DW_EH_PE_absptr) |
this_inf->make_relative = 1; |
/* If the CIE doesn't already have an 'R' entry, it's fairly |
easy to add one, provided that there's no aligned data |
after the augmentation string. */ |
else if (cie->fde_encoding == DW_EH_PE_omit |
&& (cie->per_encoding & 0x70) != DW_EH_PE_aligned) |
{ |
if (*cie->augmentation == 0) |
this_inf->add_augmentation_size = 1; |
this_inf->u.cie.add_fde_encoding = 1; |
this_inf->make_relative = 1; |
} |
if ((cie->lsda_encoding & 0x70) == DW_EH_PE_absptr) |
cie->can_make_lsda_relative = 1; |
} |
/* If FDE encoding was not specified, it defaults to |
DW_EH_absptr. */ |
if (cie->fde_encoding == DW_EH_PE_omit) |
cie->fde_encoding = DW_EH_PE_absptr; |
initial_insn_length = end - buf; |
if (initial_insn_length <= sizeof (cie->initial_instructions)) |
{ |
cie->initial_insn_length = initial_insn_length; |
memcpy (cie->initial_instructions, buf, initial_insn_length); |
} |
insns = buf; |
buf += initial_insn_length; |
ENSURE_NO_RELOCS (buf); |
if (hdr_info->merge_cies) |
this_inf->u.cie.u.full_cie = cie; |
this_inf->u.cie.per_encoding_relative |
= (cie->per_encoding & 0x70) == DW_EH_PE_pcrel; |
} |
else |
{ |
/* Find the corresponding CIE. */ |
unsigned int cie_offset = this_inf->offset + 4 - hdr_id; |
for (cie = local_cies; cie < local_cies + cie_count; cie++) |
if (cie_offset == cie->cie_inf->offset) |
break; |
/* Ensure this FDE references one of the CIEs in this input |
section. */ |
REQUIRE (cie != local_cies + cie_count); |
this_inf->u.fde.cie_inf = cie->cie_inf; |
this_inf->make_relative = cie->cie_inf->make_relative; |
this_inf->add_augmentation_size |
= cie->cie_inf->add_augmentation_size; |
ENSURE_NO_RELOCS (buf); |
if ((sec->flags & SEC_LINKER_CREATED) == 0 || cookie->rels != NULL) |
{ |
asection *rsec; |
REQUIRE (GET_RELOC (buf)); |
/* Chain together the FDEs for each section. */ |
rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie); |
/* RSEC will be NULL if FDE was cleared out as it was belonging to |
a discarded SHT_GROUP. */ |
if (rsec) |
{ |
REQUIRE (rsec->owner == abfd); |
this_inf->u.fde.next_for_section = elf_fde_list (rsec); |
elf_fde_list (rsec) = this_inf; |
} |
} |
/* Skip the initial location and address range. */ |
start = buf; |
length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size); |
REQUIRE (skip_bytes (&buf, end, 2 * length)); |
/* Skip the augmentation size, if present. */ |
if (cie->augmentation[0] == 'z') |
REQUIRE (read_uleb128 (&buf, end, &length)); |
else |
length = 0; |
/* Of the supported augmentation characters above, only 'L' |
adds augmentation data to the FDE. This code would need to |
be adjusted if any future augmentations do the same thing. */ |
if (cie->lsda_encoding != DW_EH_PE_omit) |
{ |
SKIP_RELOCS (buf); |
if (cie->can_make_lsda_relative && GET_RELOC (buf)) |
cie->cie_inf->u.cie.make_lsda_relative = 1; |
this_inf->lsda_offset = buf - start; |
/* If there's no 'z' augmentation, we don't know where the |
CFA insns begin. Assume no padding. */ |
if (cie->augmentation[0] != 'z') |
length = end - buf; |
} |
/* Skip over the augmentation data. */ |
REQUIRE (skip_bytes (&buf, end, length)); |
insns = buf; |
buf = last_fde + 4 + hdr_length; |
/* For NULL RSEC (cleared FDE belonging to a discarded section) |
the relocations are commonly cleared. We do not sanity check if |
all these relocations are cleared as (1) relocations to |
.gcc_except_table will remain uncleared (they will get dropped |
with the drop of this unused FDE) and (2) BFD already safely drops |
relocations of any type to .eh_frame by |
elf_section_ignore_discarded_relocs. |
TODO: The .gcc_except_table entries should be also filtered as |
.eh_frame entries; or GCC could rather use COMDAT for them. */ |
SKIP_RELOCS (buf); |
} |
/* Try to interpret the CFA instructions and find the first |
padding nop. Shrink this_inf's size so that it doesn't |
include the padding. */ |
length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size); |
set_loc_count = 0; |
insns_end = skip_non_nops (insns, end, length, &set_loc_count); |
/* If we don't understand the CFA instructions, we can't know |
what needs to be adjusted there. */ |
if (insns_end == NULL |
/* For the time being we don't support DW_CFA_set_loc in |
CIE instructions. */ |
|| (set_loc_count && this_inf->cie)) |
goto free_no_table; |
this_inf->size -= end - insns_end; |
if (insns_end != end && this_inf->cie) |
{ |
cie->initial_insn_length -= end - insns_end; |
cie->length -= end - insns_end; |
} |
if (set_loc_count |
&& ((cie->fde_encoding & 0x70) == DW_EH_PE_pcrel |
|| this_inf->make_relative)) |
{ |
unsigned int cnt; |
bfd_byte *p; |
this_inf->set_loc = (unsigned int *) |
bfd_malloc ((set_loc_count + 1) * sizeof (unsigned int)); |
REQUIRE (this_inf->set_loc); |
this_inf->set_loc[0] = set_loc_count; |
p = insns; |
cnt = 0; |
while (p < end) |
{ |
if (*p == DW_CFA_set_loc) |
this_inf->set_loc[++cnt] = p + 1 - start; |
REQUIRE (skip_cfa_op (&p, end, length)); |
} |
} |
this_inf->removed = 1; |
this_inf->fde_encoding = cie->fde_encoding; |
this_inf->lsda_encoding = cie->lsda_encoding; |
sec_info->count++; |
} |
BFD_ASSERT (sec_info->count == num_entries); |
BFD_ASSERT (cie_count == num_cies); |
elf_section_data (sec)->sec_info = sec_info; |
sec->sec_info_type = SEC_INFO_TYPE_EH_FRAME; |
if (hdr_info->merge_cies) |
{ |
sec_info->cies = local_cies; |
local_cies = NULL; |
} |
goto success; |
free_no_table: |
(*info->callbacks->einfo) |
(_("%P: error in %B(%A); no .eh_frame_hdr table will be created.\n"), |
abfd, sec); |
hdr_info->table = FALSE; |
if (sec_info) |
free (sec_info); |
success: |
if (ehbuf) |
free (ehbuf); |
if (local_cies) |
free (local_cies); |
#undef REQUIRE |
} |
/* Finish a pass over all .eh_frame sections. */ |
void |
_bfd_elf_end_eh_frame_parsing (struct bfd_link_info *info) |
{ |
struct eh_frame_hdr_info *hdr_info; |
hdr_info = &elf_hash_table (info)->eh_info; |
hdr_info->parsed_eh_frames = TRUE; |
} |
/* Mark all relocations against CIE or FDE ENT, which occurs in |
.eh_frame section SEC. COOKIE describes the relocations in SEC; |
its "rel" field can be changed freely. */ |
static bfd_boolean |
mark_entry (struct bfd_link_info *info, asection *sec, |
struct eh_cie_fde *ent, elf_gc_mark_hook_fn gc_mark_hook, |
struct elf_reloc_cookie *cookie) |
{ |
/* FIXME: octets_per_byte. */ |
for (cookie->rel = cookie->rels + ent->reloc_index; |
cookie->rel < cookie->relend |
&& cookie->rel->r_offset < ent->offset + ent->size; |
cookie->rel++) |
if (!_bfd_elf_gc_mark_reloc (info, sec, gc_mark_hook, cookie)) |
return FALSE; |
return TRUE; |
} |
/* Mark all the relocations against FDEs that relate to code in input |
section SEC. The FDEs belong to .eh_frame section EH_FRAME, whose |
relocations are described by COOKIE. */ |
bfd_boolean |
_bfd_elf_gc_mark_fdes (struct bfd_link_info *info, asection *sec, |
asection *eh_frame, elf_gc_mark_hook_fn gc_mark_hook, |
struct elf_reloc_cookie *cookie) |
{ |
struct eh_cie_fde *fde, *cie; |
for (fde = elf_fde_list (sec); fde; fde = fde->u.fde.next_for_section) |
{ |
if (!mark_entry (info, eh_frame, fde, gc_mark_hook, cookie)) |
return FALSE; |
/* At this stage, all cie_inf fields point to local CIEs, so we |
can use the same cookie to refer to them. */ |
cie = fde->u.fde.cie_inf; |
if (!cie->u.cie.gc_mark) |
{ |
cie->u.cie.gc_mark = 1; |
if (!mark_entry (info, eh_frame, cie, gc_mark_hook, cookie)) |
return FALSE; |
} |
} |
return TRUE; |
} |
/* Input section SEC of ABFD is an .eh_frame section that contains the |
CIE described by CIE_INF. Return a version of CIE_INF that is going |
to be kept in the output, adding CIE_INF to the output if necessary. |
HDR_INFO is the .eh_frame_hdr information and COOKIE describes the |
relocations in REL. */ |
static struct eh_cie_fde * |
find_merged_cie (bfd *abfd, struct bfd_link_info *info, asection *sec, |
struct eh_frame_hdr_info *hdr_info, |
struct elf_reloc_cookie *cookie, |
struct eh_cie_fde *cie_inf) |
{ |
unsigned long r_symndx; |
struct cie *cie, *new_cie; |
Elf_Internal_Rela *rel; |
void **loc; |
/* Use CIE_INF if we have already decided to keep it. */ |
if (!cie_inf->removed) |
return cie_inf; |
/* If we have merged CIE_INF with another CIE, use that CIE instead. */ |
if (cie_inf->u.cie.merged) |
return cie_inf->u.cie.u.merged_with; |
cie = cie_inf->u.cie.u.full_cie; |
/* Assume we will need to keep CIE_INF. */ |
cie_inf->removed = 0; |
cie_inf->u.cie.u.sec = sec; |
/* If we are not merging CIEs, use CIE_INF. */ |
if (cie == NULL) |
return cie_inf; |
if (cie->per_encoding != DW_EH_PE_omit) |
{ |
bfd_boolean per_binds_local; |
/* Work out the address of personality routine, either as an absolute |
value or as a symbol. */ |
rel = cookie->rels + cie->personality.reloc_index; |
memset (&cie->personality, 0, sizeof (cie->personality)); |
#ifdef BFD64 |
if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64) |
r_symndx = ELF64_R_SYM (rel->r_info); |
else |
#endif |
r_symndx = ELF32_R_SYM (rel->r_info); |
if (r_symndx >= cookie->locsymcount |
|| ELF_ST_BIND (cookie->locsyms[r_symndx].st_info) != STB_LOCAL) |
{ |
struct elf_link_hash_entry *h; |
r_symndx -= cookie->extsymoff; |
h = cookie->sym_hashes[r_symndx]; |
while (h->root.type == bfd_link_hash_indirect |
|| h->root.type == bfd_link_hash_warning) |
h = (struct elf_link_hash_entry *) h->root.u.i.link; |
cie->personality.h = h; |
per_binds_local = SYMBOL_REFERENCES_LOCAL (info, h); |
} |
else |
{ |
Elf_Internal_Sym *sym; |
asection *sym_sec; |
sym = &cookie->locsyms[r_symndx]; |
sym_sec = bfd_section_from_elf_index (abfd, sym->st_shndx); |
if (sym_sec == NULL) |
return cie_inf; |
if (sym_sec->kept_section != NULL) |
sym_sec = sym_sec->kept_section; |
if (sym_sec->output_section == NULL) |
return cie_inf; |
cie->local_personality = 1; |
cie->personality.val = (sym->st_value |
+ sym_sec->output_offset |
+ sym_sec->output_section->vma); |
per_binds_local = TRUE; |
} |
if (per_binds_local |
&& info->shared |
&& (cie->per_encoding & 0x70) == DW_EH_PE_absptr |
&& (get_elf_backend_data (abfd) |
->elf_backend_can_make_relative_eh_frame (abfd, info, sec))) |
{ |
cie_inf->u.cie.make_per_encoding_relative = 1; |
cie_inf->u.cie.per_encoding_relative = 1; |
} |
} |
/* See if we can merge this CIE with an earlier one. */ |
cie->output_sec = sec->output_section; |
cie_compute_hash (cie); |
if (hdr_info->cies == NULL) |
{ |
hdr_info->cies = htab_try_create (1, cie_hash, cie_eq, free); |
if (hdr_info->cies == NULL) |
return cie_inf; |
} |
loc = htab_find_slot_with_hash (hdr_info->cies, cie, cie->hash, INSERT); |
if (loc == NULL) |
return cie_inf; |
new_cie = (struct cie *) *loc; |
if (new_cie == NULL) |
{ |
/* Keep CIE_INF and record it in the hash table. */ |
new_cie = (struct cie *) malloc (sizeof (struct cie)); |
if (new_cie == NULL) |
return cie_inf; |
memcpy (new_cie, cie, sizeof (struct cie)); |
*loc = new_cie; |
} |
else |
{ |
/* Merge CIE_INF with NEW_CIE->CIE_INF. */ |
cie_inf->removed = 1; |
cie_inf->u.cie.merged = 1; |
cie_inf->u.cie.u.merged_with = new_cie->cie_inf; |
if (cie_inf->u.cie.make_lsda_relative) |
new_cie->cie_inf->u.cie.make_lsda_relative = 1; |
} |
return new_cie->cie_inf; |
} |
/* This function is called for each input file before the .eh_frame |
section is relocated. It discards duplicate CIEs and FDEs for discarded |
functions. The function returns TRUE iff any entries have been |
deleted. */ |
bfd_boolean |
_bfd_elf_discard_section_eh_frame |
(bfd *abfd, struct bfd_link_info *info, asection *sec, |
bfd_boolean (*reloc_symbol_deleted_p) (bfd_vma, void *), |
struct elf_reloc_cookie *cookie) |
{ |
struct eh_cie_fde *ent; |
struct eh_frame_sec_info *sec_info; |
struct eh_frame_hdr_info *hdr_info; |
unsigned int ptr_size, offset; |
if (sec->sec_info_type != SEC_INFO_TYPE_EH_FRAME) |
return FALSE; |
sec_info = (struct eh_frame_sec_info *) elf_section_data (sec)->sec_info; |
if (sec_info == NULL) |
return FALSE; |
ptr_size = (get_elf_backend_data (sec->owner) |
->elf_backend_eh_frame_address_size (sec->owner, sec)); |
hdr_info = &elf_hash_table (info)->eh_info; |
for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) |
if (ent->size == 4) |
/* There should only be one zero terminator, on the last input |
file supplying .eh_frame (crtend.o). Remove any others. */ |
ent->removed = sec->map_head.s != NULL; |
else if (!ent->cie) |
{ |
bfd_boolean keep; |
if ((sec->flags & SEC_LINKER_CREATED) != 0 && cookie->rels == NULL) |
{ |
unsigned int width |
= get_DW_EH_PE_width (ent->fde_encoding, ptr_size); |
bfd_vma value |
= read_value (abfd, sec->contents + ent->offset + 8 + width, |
width, get_DW_EH_PE_signed (ent->fde_encoding)); |
keep = value != 0; |
} |
else |
{ |
cookie->rel = cookie->rels + ent->reloc_index; |
/* FIXME: octets_per_byte. */ |
BFD_ASSERT (cookie->rel < cookie->relend |
&& cookie->rel->r_offset == ent->offset + 8); |
keep = !(*reloc_symbol_deleted_p) (ent->offset + 8, cookie); |
} |
if (keep) |
{ |
if (info->shared |
&& (((ent->fde_encoding & 0x70) == DW_EH_PE_absptr |
&& ent->make_relative == 0) |
|| (ent->fde_encoding & 0x70) == DW_EH_PE_aligned)) |
{ |
/* If a shared library uses absolute pointers |
which we cannot turn into PC relative, |
don't create the binary search table, |
since it is affected by runtime relocations. */ |
hdr_info->table = FALSE; |
(*info->callbacks->einfo) |
(_("%P: fde encoding in %B(%A) prevents .eh_frame_hdr" |
" table being created.\n"), abfd, sec); |
} |
ent->removed = 0; |
hdr_info->fde_count++; |
ent->u.fde.cie_inf = find_merged_cie (abfd, info, sec, hdr_info, |
cookie, ent->u.fde.cie_inf); |
} |
} |
if (sec_info->cies) |
{ |
free (sec_info->cies); |
sec_info->cies = NULL; |
} |
offset = 0; |
for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) |
if (!ent->removed) |
{ |
ent->new_offset = offset; |
offset += size_of_output_cie_fde (ent, ptr_size); |
} |
sec->rawsize = sec->size; |
sec->size = offset; |
return offset != sec->rawsize; |
} |
/* This function is called for .eh_frame_hdr section after |
_bfd_elf_discard_section_eh_frame has been called on all .eh_frame |
input sections. It finalizes the size of .eh_frame_hdr section. */ |
bfd_boolean |
_bfd_elf_discard_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info) |
{ |
struct elf_link_hash_table *htab; |
struct eh_frame_hdr_info *hdr_info; |
asection *sec; |
htab = elf_hash_table (info); |
hdr_info = &htab->eh_info; |
if (hdr_info->cies != NULL) |
{ |
htab_delete (hdr_info->cies); |
hdr_info->cies = NULL; |
} |
sec = hdr_info->hdr_sec; |
if (sec == NULL) |
return FALSE; |
sec->size = EH_FRAME_HDR_SIZE; |
if (hdr_info->table) |
sec->size += 4 + hdr_info->fde_count * 8; |
elf_eh_frame_hdr (abfd) = sec; |
return TRUE; |
} |
/* Return true if there is at least one non-empty .eh_frame section in |
input files. Can only be called after ld has mapped input to |
output sections, and before sections are stripped. */ |
bfd_boolean |
_bfd_elf_eh_frame_present (struct bfd_link_info *info) |
{ |
asection *eh = bfd_get_section_by_name (info->output_bfd, ".eh_frame"); |
if (eh == NULL) |
return FALSE; |
/* Count only sections which have at least a single CIE or FDE. |
There cannot be any CIE or FDE <= 8 bytes. */ |
for (eh = eh->map_head.s; eh != NULL; eh = eh->map_head.s) |
if (eh->size > 8) |
return TRUE; |
return FALSE; |
} |
/* This function is called from size_dynamic_sections. |
It needs to decide whether .eh_frame_hdr should be output or not, |
because when the dynamic symbol table has been sized it is too late |
to strip sections. */ |
bfd_boolean |
_bfd_elf_maybe_strip_eh_frame_hdr (struct bfd_link_info *info) |
{ |
struct elf_link_hash_table *htab; |
struct eh_frame_hdr_info *hdr_info; |
htab = elf_hash_table (info); |
hdr_info = &htab->eh_info; |
if (hdr_info->hdr_sec == NULL) |
return TRUE; |
if (bfd_is_abs_section (hdr_info->hdr_sec->output_section) |
|| !info->eh_frame_hdr |
|| !_bfd_elf_eh_frame_present (info)) |
{ |
hdr_info->hdr_sec->flags |= SEC_EXCLUDE; |
hdr_info->hdr_sec = NULL; |
return TRUE; |
} |
hdr_info->table = TRUE; |
return TRUE; |
} |
/* Adjust an address in the .eh_frame section. Given OFFSET within |
SEC, this returns the new offset in the adjusted .eh_frame section, |
or -1 if the address refers to a CIE/FDE which has been removed |
or to offset with dynamic relocation which is no longer needed. */ |
bfd_vma |
_bfd_elf_eh_frame_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED, |
struct bfd_link_info *info ATTRIBUTE_UNUSED, |
asection *sec, |
bfd_vma offset) |
{ |
struct eh_frame_sec_info *sec_info; |
unsigned int lo, hi, mid; |
if (sec->sec_info_type != SEC_INFO_TYPE_EH_FRAME) |
return offset; |
sec_info = (struct eh_frame_sec_info *) elf_section_data (sec)->sec_info; |
if (offset >= sec->rawsize) |
return offset - sec->rawsize + sec->size; |
lo = 0; |
hi = sec_info->count; |
mid = 0; |
while (lo < hi) |
{ |
mid = (lo + hi) / 2; |
if (offset < sec_info->entry[mid].offset) |
hi = mid; |
else if (offset |
>= sec_info->entry[mid].offset + sec_info->entry[mid].size) |
lo = mid + 1; |
else |
break; |
} |
BFD_ASSERT (lo < hi); |
/* FDE or CIE was removed. */ |
if (sec_info->entry[mid].removed) |
return (bfd_vma) -1; |
/* If converting personality pointers to DW_EH_PE_pcrel, there will be |
no need for run-time relocation against the personality field. */ |
if (sec_info->entry[mid].cie |
&& sec_info->entry[mid].u.cie.make_per_encoding_relative |
&& offset == (sec_info->entry[mid].offset + 8 |
+ sec_info->entry[mid].u.cie.personality_offset)) |
return (bfd_vma) -2; |
/* If converting to DW_EH_PE_pcrel, there will be no need for run-time |
relocation against FDE's initial_location field. */ |
if (!sec_info->entry[mid].cie |
&& sec_info->entry[mid].make_relative |
&& offset == sec_info->entry[mid].offset + 8) |
return (bfd_vma) -2; |
/* If converting LSDA pointers to DW_EH_PE_pcrel, there will be no need |
for run-time relocation against LSDA field. */ |
if (!sec_info->entry[mid].cie |
&& sec_info->entry[mid].u.fde.cie_inf->u.cie.make_lsda_relative |
&& offset == (sec_info->entry[mid].offset + 8 |
+ sec_info->entry[mid].lsda_offset)) |
return (bfd_vma) -2; |
/* If converting to DW_EH_PE_pcrel, there will be no need for run-time |
relocation against DW_CFA_set_loc's arguments. */ |
if (sec_info->entry[mid].set_loc |
&& sec_info->entry[mid].make_relative |
&& (offset >= sec_info->entry[mid].offset + 8 |
+ sec_info->entry[mid].set_loc[1])) |
{ |
unsigned int cnt; |
for (cnt = 1; cnt <= sec_info->entry[mid].set_loc[0]; cnt++) |
if (offset == sec_info->entry[mid].offset + 8 |
+ sec_info->entry[mid].set_loc[cnt]) |
return (bfd_vma) -2; |
} |
/* Any new augmentation bytes go before the first relocation. */ |
return (offset + sec_info->entry[mid].new_offset |
- sec_info->entry[mid].offset |
+ extra_augmentation_string_bytes (sec_info->entry + mid) |
+ extra_augmentation_data_bytes (sec_info->entry + mid)); |
} |
/* Write out .eh_frame section. This is called with the relocated |
contents. */ |
bfd_boolean |
_bfd_elf_write_section_eh_frame (bfd *abfd, |
struct bfd_link_info *info, |
asection *sec, |
bfd_byte *contents) |
{ |
struct eh_frame_sec_info *sec_info; |
struct elf_link_hash_table *htab; |
struct eh_frame_hdr_info *hdr_info; |
unsigned int ptr_size; |
struct eh_cie_fde *ent; |
if (sec->sec_info_type != SEC_INFO_TYPE_EH_FRAME) |
/* FIXME: octets_per_byte. */ |
return bfd_set_section_contents (abfd, sec->output_section, contents, |
sec->output_offset, sec->size); |
ptr_size = (get_elf_backend_data (abfd) |
->elf_backend_eh_frame_address_size (abfd, sec)); |
BFD_ASSERT (ptr_size != 0); |
sec_info = (struct eh_frame_sec_info *) elf_section_data (sec)->sec_info; |
htab = elf_hash_table (info); |
hdr_info = &htab->eh_info; |
if (hdr_info->table && hdr_info->array == NULL) |
hdr_info->array = (struct eh_frame_array_ent *) |
bfd_malloc (hdr_info->fde_count * sizeof(*hdr_info->array)); |
if (hdr_info->array == NULL) |
hdr_info = NULL; |
/* The new offsets can be bigger or smaller than the original offsets. |
We therefore need to make two passes over the section: one backward |
pass to move entries up and one forward pass to move entries down. |
The two passes won't interfere with each other because entries are |
not reordered */ |
for (ent = sec_info->entry + sec_info->count; ent-- != sec_info->entry;) |
if (!ent->removed && ent->new_offset > ent->offset) |
memmove (contents + ent->new_offset, contents + ent->offset, ent->size); |
for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) |
if (!ent->removed && ent->new_offset < ent->offset) |
memmove (contents + ent->new_offset, contents + ent->offset, ent->size); |
for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) |
{ |
unsigned char *buf, *end; |
unsigned int new_size; |
if (ent->removed) |
continue; |
if (ent->size == 4) |
{ |
/* Any terminating FDE must be at the end of the section. */ |
BFD_ASSERT (ent == sec_info->entry + sec_info->count - 1); |
continue; |
} |
buf = contents + ent->new_offset; |
end = buf + ent->size; |
new_size = size_of_output_cie_fde (ent, ptr_size); |
/* Update the size. It may be shrinked. */ |
bfd_put_32 (abfd, new_size - 4, buf); |
/* Filling the extra bytes with DW_CFA_nops. */ |
if (new_size != ent->size) |
memset (end, 0, new_size - ent->size); |
if (ent->cie) |
{ |
/* CIE */ |
if (ent->make_relative |
|| ent->u.cie.make_lsda_relative |
|| ent->u.cie.per_encoding_relative) |
{ |
char *aug; |
unsigned int action, extra_string, extra_data; |
unsigned int per_width, per_encoding; |
/* Need to find 'R' or 'L' augmentation's argument and modify |
DW_EH_PE_* value. */ |
action = ((ent->make_relative ? 1 : 0) |
| (ent->u.cie.make_lsda_relative ? 2 : 0) |
| (ent->u.cie.per_encoding_relative ? 4 : 0)); |
extra_string = extra_augmentation_string_bytes (ent); |
extra_data = extra_augmentation_data_bytes (ent); |
/* Skip length, id and version. */ |
buf += 9; |
aug = (char *) buf; |
buf += strlen (aug) + 1; |
skip_leb128 (&buf, end); |
skip_leb128 (&buf, end); |
skip_leb128 (&buf, end); |
if (*aug == 'z') |
{ |
/* The uleb128 will always be a single byte for the kind |
of augmentation strings that we're prepared to handle. */ |
*buf++ += extra_data; |
aug++; |
} |
/* Make room for the new augmentation string and data bytes. */ |
memmove (buf + extra_string + extra_data, buf, end - buf); |
memmove (aug + extra_string, aug, buf - (bfd_byte *) aug); |
buf += extra_string; |
end += extra_string + extra_data; |
if (ent->add_augmentation_size) |
{ |
*aug++ = 'z'; |
*buf++ = extra_data - 1; |
} |
if (ent->u.cie.add_fde_encoding) |
{ |
BFD_ASSERT (action & 1); |
*aug++ = 'R'; |
*buf++ = make_pc_relative (DW_EH_PE_absptr, ptr_size); |
action &= ~1; |
} |
while (action) |
switch (*aug++) |
{ |
case 'L': |
if (action & 2) |
{ |
BFD_ASSERT (*buf == ent->lsda_encoding); |
*buf = make_pc_relative (*buf, ptr_size); |
action &= ~2; |
} |
buf++; |
break; |
case 'P': |
if (ent->u.cie.make_per_encoding_relative) |
*buf = make_pc_relative (*buf, ptr_size); |
per_encoding = *buf++; |
per_width = get_DW_EH_PE_width (per_encoding, ptr_size); |
BFD_ASSERT (per_width != 0); |
BFD_ASSERT (((per_encoding & 0x70) == DW_EH_PE_pcrel) |
== ent->u.cie.per_encoding_relative); |
if ((per_encoding & 0x70) == DW_EH_PE_aligned) |
buf = (contents |
+ ((buf - contents + per_width - 1) |
& ~((bfd_size_type) per_width - 1))); |
if (action & 4) |
{ |
bfd_vma val; |
val = read_value (abfd, buf, per_width, |
get_DW_EH_PE_signed (per_encoding)); |
if (ent->u.cie.make_per_encoding_relative) |
val -= (sec->output_section->vma |
+ sec->output_offset |
+ (buf - contents)); |
else |
{ |
val += (bfd_vma) ent->offset - ent->new_offset; |
val -= extra_string + extra_data; |
} |
write_value (abfd, buf, val, per_width); |
action &= ~4; |
} |
buf += per_width; |
break; |
case 'R': |
if (action & 1) |
{ |
BFD_ASSERT (*buf == ent->fde_encoding); |
*buf = make_pc_relative (*buf, ptr_size); |
action &= ~1; |
} |
buf++; |
break; |
case 'S': |
break; |
default: |
BFD_FAIL (); |
} |
} |
} |
else |
{ |
/* FDE */ |
bfd_vma value, address; |
unsigned int width; |
bfd_byte *start; |
struct eh_cie_fde *cie; |
/* Skip length. */ |
cie = ent->u.fde.cie_inf; |
buf += 4; |
value = ((ent->new_offset + sec->output_offset + 4) |
- (cie->new_offset + cie->u.cie.u.sec->output_offset)); |
bfd_put_32 (abfd, value, buf); |
buf += 4; |
width = get_DW_EH_PE_width (ent->fde_encoding, ptr_size); |
value = read_value (abfd, buf, width, |
get_DW_EH_PE_signed (ent->fde_encoding)); |
address = value; |
if (value) |
{ |
switch (ent->fde_encoding & 0x70) |
{ |
case DW_EH_PE_textrel: |
BFD_ASSERT (hdr_info == NULL); |
break; |
case DW_EH_PE_datarel: |
{ |
switch (abfd->arch_info->arch) |
{ |
case bfd_arch_ia64: |
BFD_ASSERT (elf_gp (abfd) != 0); |
address += elf_gp (abfd); |
break; |
default: |
(*info->callbacks->einfo) |
(_("%P: DW_EH_PE_datarel unspecified" |
" for this architecture.\n")); |
/* Fall thru */ |
case bfd_arch_frv: |
case bfd_arch_i386: |
BFD_ASSERT (htab->hgot != NULL |
&& ((htab->hgot->root.type |
== bfd_link_hash_defined) |
|| (htab->hgot->root.type |
== bfd_link_hash_defweak))); |
address |
+= (htab->hgot->root.u.def.value |
+ htab->hgot->root.u.def.section->output_offset |
+ (htab->hgot->root.u.def.section->output_section |
->vma)); |
break; |
} |
} |
break; |
case DW_EH_PE_pcrel: |
value += (bfd_vma) ent->offset - ent->new_offset; |
address += (sec->output_section->vma |
+ sec->output_offset |
+ ent->offset + 8); |
break; |
} |
if (ent->make_relative) |
value -= (sec->output_section->vma |
+ sec->output_offset |
+ ent->new_offset + 8); |
write_value (abfd, buf, value, width); |
} |
start = buf; |
if (hdr_info) |
{ |
/* The address calculation may overflow, giving us a |
value greater than 4G on a 32-bit target when |
dwarf_vma is 64-bit. */ |
if (sizeof (address) > 4 && ptr_size == 4) |
address &= 0xffffffff; |
hdr_info->array[hdr_info->array_count].initial_loc = address; |
hdr_info->array[hdr_info->array_count++].fde |
= (sec->output_section->vma |
+ sec->output_offset |
+ ent->new_offset); |
} |
if ((ent->lsda_encoding & 0x70) == DW_EH_PE_pcrel |
|| cie->u.cie.make_lsda_relative) |
{ |
buf += ent->lsda_offset; |
width = get_DW_EH_PE_width (ent->lsda_encoding, ptr_size); |
value = read_value (abfd, buf, width, |
get_DW_EH_PE_signed (ent->lsda_encoding)); |
if (value) |
{ |
if ((ent->lsda_encoding & 0x70) == DW_EH_PE_pcrel) |
value += (bfd_vma) ent->offset - ent->new_offset; |
else if (cie->u.cie.make_lsda_relative) |
value -= (sec->output_section->vma |
+ sec->output_offset |
+ ent->new_offset + 8 + ent->lsda_offset); |
write_value (abfd, buf, value, width); |
} |
} |
else if (ent->add_augmentation_size) |
{ |
/* Skip the PC and length and insert a zero byte for the |
augmentation size. */ |
buf += width * 2; |
memmove (buf + 1, buf, end - buf); |
*buf = 0; |
} |
if (ent->set_loc) |
{ |
/* Adjust DW_CFA_set_loc. */ |
unsigned int cnt; |
bfd_vma new_offset; |
width = get_DW_EH_PE_width (ent->fde_encoding, ptr_size); |
new_offset = ent->new_offset + 8 |
+ extra_augmentation_string_bytes (ent) |
+ extra_augmentation_data_bytes (ent); |
for (cnt = 1; cnt <= ent->set_loc[0]; cnt++) |
{ |
buf = start + ent->set_loc[cnt]; |
value = read_value (abfd, buf, width, |
get_DW_EH_PE_signed (ent->fde_encoding)); |
if (!value) |
continue; |
if ((ent->fde_encoding & 0x70) == DW_EH_PE_pcrel) |
value += (bfd_vma) ent->offset + 8 - new_offset; |
if (ent->make_relative) |
value -= (sec->output_section->vma |
+ sec->output_offset |
+ new_offset + ent->set_loc[cnt]); |
write_value (abfd, buf, value, width); |
} |
} |
} |
} |
/* We don't align the section to its section alignment since the |
runtime library only expects all CIE/FDE records aligned at |
the pointer size. _bfd_elf_discard_section_eh_frame should |
have padded CIE/FDE records to multiple of pointer size with |
size_of_output_cie_fde. */ |
if ((sec->size % ptr_size) != 0) |
abort (); |
/* FIXME: octets_per_byte. */ |
return bfd_set_section_contents (abfd, sec->output_section, |
contents, (file_ptr) sec->output_offset, |
sec->size); |
} |
/* Helper function used to sort .eh_frame_hdr search table by increasing |
VMA of FDE initial location. */ |
static int |
vma_compare (const void *a, const void *b) |
{ |
const struct eh_frame_array_ent *p = (const struct eh_frame_array_ent *) a; |
const struct eh_frame_array_ent *q = (const struct eh_frame_array_ent *) b; |
if (p->initial_loc > q->initial_loc) |
return 1; |
if (p->initial_loc < q->initial_loc) |
return -1; |
return 0; |
} |
/* Write out .eh_frame_hdr section. This must be called after |
_bfd_elf_write_section_eh_frame has been called on all input |
.eh_frame sections. |
.eh_frame_hdr format: |
ubyte version (currently 1) |
ubyte eh_frame_ptr_enc (DW_EH_PE_* encoding of pointer to start of |
.eh_frame section) |
ubyte fde_count_enc (DW_EH_PE_* encoding of total FDE count |
number (or DW_EH_PE_omit if there is no |
binary search table computed)) |
ubyte table_enc (DW_EH_PE_* encoding of binary search table, |
or DW_EH_PE_omit if not present. |
DW_EH_PE_datarel is using address of |
.eh_frame_hdr section start as base) |
[encoded] eh_frame_ptr (pointer to start of .eh_frame section) |
optionally followed by: |
[encoded] fde_count (total number of FDEs in .eh_frame section) |
fde_count x [encoded] initial_loc, fde |
(array of encoded pairs containing |
FDE initial_location field and FDE address, |
sorted by increasing initial_loc). */ |
bfd_boolean |
_bfd_elf_write_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info) |
{ |
struct elf_link_hash_table *htab; |
struct eh_frame_hdr_info *hdr_info; |
asection *sec; |
bfd_boolean retval = TRUE; |
htab = elf_hash_table (info); |
hdr_info = &htab->eh_info; |
sec = hdr_info->hdr_sec; |
if (info->eh_frame_hdr && sec != NULL) |
{ |
bfd_byte *contents; |
asection *eh_frame_sec; |
bfd_size_type size; |
bfd_vma encoded_eh_frame; |
size = EH_FRAME_HDR_SIZE; |
if (hdr_info->array && hdr_info->array_count == hdr_info->fde_count) |
size += 4 + hdr_info->fde_count * 8; |
contents = (bfd_byte *) bfd_malloc (size); |
if (contents == NULL) |
return FALSE; |
eh_frame_sec = bfd_get_section_by_name (abfd, ".eh_frame"); |
if (eh_frame_sec == NULL) |
{ |
free (contents); |
return FALSE; |
} |
memset (contents, 0, EH_FRAME_HDR_SIZE); |
/* Version. */ |
contents[0] = 1; |
/* .eh_frame offset. */ |
contents[1] = get_elf_backend_data (abfd)->elf_backend_encode_eh_address |
(abfd, info, eh_frame_sec, 0, sec, 4, &encoded_eh_frame); |
if (hdr_info->array && hdr_info->array_count == hdr_info->fde_count) |
{ |
/* FDE count encoding. */ |
contents[2] = DW_EH_PE_udata4; |
/* Search table encoding. */ |
contents[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; |
} |
else |
{ |
contents[2] = DW_EH_PE_omit; |
contents[3] = DW_EH_PE_omit; |
} |
bfd_put_32 (abfd, encoded_eh_frame, contents + 4); |
if (contents[2] != DW_EH_PE_omit) |
{ |
unsigned int i; |
bfd_put_32 (abfd, hdr_info->fde_count, contents + EH_FRAME_HDR_SIZE); |
qsort (hdr_info->array, hdr_info->fde_count, |
sizeof (*hdr_info->array), vma_compare); |
for (i = 0; i < hdr_info->fde_count; i++) |
{ |
bfd_put_32 (abfd, |
hdr_info->array[i].initial_loc |
- sec->output_section->vma, |
contents + EH_FRAME_HDR_SIZE + i * 8 + 4); |
bfd_put_32 (abfd, |
hdr_info->array[i].fde - sec->output_section->vma, |
contents + EH_FRAME_HDR_SIZE + i * 8 + 8); |
} |
} |
/* FIXME: octets_per_byte. */ |
retval = bfd_set_section_contents (abfd, sec->output_section, contents, |
(file_ptr) sec->output_offset, |
sec->size); |
free (contents); |
} |
if (hdr_info->array != NULL) |
free (hdr_info->array); |
return retval; |
} |
/* Return the width of FDE addresses. This is the default implementation. */ |
unsigned int |
_bfd_elf_eh_frame_address_size (bfd *abfd, asection *sec ATTRIBUTE_UNUSED) |
{ |
return elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64 ? 8 : 4; |
} |
/* Decide whether we can use a PC-relative encoding within the given |
EH frame section. This is the default implementation. */ |
bfd_boolean |
_bfd_elf_can_make_relative (bfd *input_bfd ATTRIBUTE_UNUSED, |
struct bfd_link_info *info ATTRIBUTE_UNUSED, |
asection *eh_frame_section ATTRIBUTE_UNUSED) |
{ |
return TRUE; |
} |
/* Select an encoding for the given address. Preference is given to |
PC-relative addressing modes. */ |
bfd_byte |
_bfd_elf_encode_eh_address (bfd *abfd ATTRIBUTE_UNUSED, |
struct bfd_link_info *info ATTRIBUTE_UNUSED, |
asection *osec, bfd_vma offset, |
asection *loc_sec, bfd_vma loc_offset, |
bfd_vma *encoded) |
{ |
*encoded = osec->vma + offset - |
(loc_sec->output_section->vma + loc_sec->output_offset + loc_offset); |
return DW_EH_PE_pcrel | DW_EH_PE_sdata4; |
} |
/contrib/toolchain/binutils/bfd/elf-ifunc.c |
---|
0,0 → 1,276 |
/* ELF STT_GNU_IFUNC support. |
Copyright 2009-2013 |
Free Software Foundation, Inc. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "bfdlink.h" |
#include "libbfd.h" |
#define ARCH_SIZE 0 |
#include "elf-bfd.h" |
#include "safe-ctype.h" |
#include "libiberty.h" |
#include "objalloc.h" |
/* Create sections needed by STT_GNU_IFUNC symbol. */ |
bfd_boolean |
_bfd_elf_create_ifunc_sections (bfd *abfd, struct bfd_link_info *info) |
{ |
flagword flags, pltflags; |
asection *s; |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
struct elf_link_hash_table *htab = elf_hash_table (info); |
if (htab->irelifunc != NULL || htab->iplt != NULL) |
return TRUE; |
flags = bed->dynamic_sec_flags; |
pltflags = flags; |
if (bed->plt_not_loaded) |
/* We do not clear SEC_ALLOC here because we still want the OS to |
allocate space for the section; it's just that there's nothing |
to read in from the object file. */ |
pltflags &= ~ (SEC_CODE | SEC_LOAD | SEC_HAS_CONTENTS); |
else |
pltflags |= SEC_ALLOC | SEC_CODE | SEC_LOAD; |
if (bed->plt_readonly) |
pltflags |= SEC_READONLY; |
if (info->shared) |
{ |
/* We need to create .rel[a].ifunc for shared objects. */ |
const char *rel_sec = (bed->rela_plts_and_copies_p |
? ".rela.ifunc" : ".rel.ifunc"); |
s = bfd_make_section_with_flags (abfd, rel_sec, |
flags | SEC_READONLY); |
if (s == NULL |
|| ! bfd_set_section_alignment (abfd, s, |
bed->s->log_file_align)) |
return FALSE; |
htab->irelifunc = s; |
} |
else |
{ |
/* We need to create .iplt, .rel[a].iplt, .igot and .igot.plt |
for static executables. */ |
s = bfd_make_section_with_flags (abfd, ".iplt", pltflags); |
if (s == NULL |
|| ! bfd_set_section_alignment (abfd, s, bed->plt_alignment)) |
return FALSE; |
htab->iplt = s; |
s = bfd_make_section_with_flags (abfd, |
(bed->rela_plts_and_copies_p |
? ".rela.iplt" : ".rel.iplt"), |
flags | SEC_READONLY); |
if (s == NULL |
|| ! bfd_set_section_alignment (abfd, s, |
bed->s->log_file_align)) |
return FALSE; |
htab->irelplt = s; |
/* We don't need the .igot section if we have the .igot.plt |
section. */ |
if (bed->want_got_plt) |
s = bfd_make_section_with_flags (abfd, ".igot.plt", flags); |
else |
s = bfd_make_section_with_flags (abfd, ".igot", flags); |
if (s == NULL |
|| !bfd_set_section_alignment (abfd, s, |
bed->s->log_file_align)) |
return FALSE; |
htab->igotplt = s; |
} |
return TRUE; |
} |
/* Allocate space in .plt, .got and associated reloc sections for |
dynamic relocs against a STT_GNU_IFUNC symbol definition. */ |
bfd_boolean |
_bfd_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info, |
struct elf_link_hash_entry *h, |
struct elf_dyn_relocs **head, |
unsigned int plt_entry_size, |
unsigned int plt_header_size, |
unsigned int got_entry_size) |
{ |
asection *plt, *gotplt, *relplt; |
struct elf_dyn_relocs *p; |
unsigned int sizeof_reloc; |
const struct elf_backend_data *bed; |
struct elf_link_hash_table *htab; |
/* When a shared library references a STT_GNU_IFUNC symbol defined |
in executable, the address of the resolved function may be used. |
But in non-shared executable, the address of its .plt slot may |
be used. Pointer equality may not work correctly. PIE should |
be used if pointer equality is required here. */ |
if (!info->shared |
&& (h->dynindx != -1 |
|| info->export_dynamic) |
&& h->pointer_equality_needed) |
{ |
info->callbacks->einfo |
(_("%F%P: dynamic STT_GNU_IFUNC symbol `%s' with pointer " |
"equality in `%B' can not be used when making an " |
"executable; recompile with -fPIE and relink with -pie\n"), |
h->root.root.string, |
h->root.u.def.section->owner); |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
htab = elf_hash_table (info); |
/* When building shared library, we need to handle the case where it is |
marked with regular reference, but not non-GOT reference since the |
non-GOT reference bit may not be set here. */ |
if (info->shared && !h->non_got_ref && h->ref_regular) |
for (p = *head; p != NULL; p = p->next) |
if (p->count) |
{ |
h->non_got_ref = 1; |
goto keep; |
} |
/* Support garbage collection against STT_GNU_IFUNC symbols. */ |
if (h->plt.refcount <= 0 && h->got.refcount <= 0) |
{ |
h->got = htab->init_got_offset; |
h->plt = htab->init_plt_offset; |
*head = NULL; |
return TRUE; |
} |
/* Return and discard space for dynamic relocations against it if |
it is never referenced in a non-shared object. */ |
if (!h->ref_regular) |
{ |
if (h->plt.refcount > 0 |
|| h->got.refcount > 0) |
abort (); |
h->got = htab->init_got_offset; |
h->plt = htab->init_plt_offset; |
*head = NULL; |
return TRUE; |
} |
keep: |
bed = get_elf_backend_data (info->output_bfd); |
if (bed->rela_plts_and_copies_p) |
sizeof_reloc = bed->s->sizeof_rela; |
else |
sizeof_reloc = bed->s->sizeof_rel; |
/* When building a static executable, use .iplt, .igot.plt and |
.rel[a].iplt sections for STT_GNU_IFUNC symbols. */ |
if (htab->splt != NULL) |
{ |
plt = htab->splt; |
gotplt = htab->sgotplt; |
relplt = htab->srelplt; |
/* If this is the first .plt entry, make room for the special |
first entry. */ |
if (plt->size == 0) |
plt->size += plt_header_size; |
} |
else |
{ |
plt = htab->iplt; |
gotplt = htab->igotplt; |
relplt = htab->irelplt; |
} |
/* Don't update value of STT_GNU_IFUNC symbol to PLT. We need |
the original value for R_*_IRELATIVE. */ |
h->plt.offset = plt->size; |
/* Make room for this entry in the .plt/.iplt section. */ |
plt->size += plt_entry_size; |
/* We also need to make an entry in the .got.plt/.got.iplt section, |
which will be placed in the .got section by the linker script. */ |
gotplt->size += got_entry_size; |
/* We also need to make an entry in the .rel[a].plt/.rel[a].iplt |
section. */ |
relplt->size += sizeof_reloc; |
relplt->reloc_count++; |
/* We need dynamic relocation for STT_GNU_IFUNC symbol only when |
there is a non-GOT reference in a shared object. */ |
if (!info->shared |
|| !h->non_got_ref) |
*head = NULL; |
/* Finally, allocate space. */ |
p = *head; |
if (p != NULL) |
{ |
bfd_size_type count = 0; |
do |
{ |
count += p->count; |
p = p->next; |
} |
while (p != NULL); |
htab->irelifunc->size += count * sizeof_reloc; |
} |
/* For STT_GNU_IFUNC symbol, .got.plt has the real function address |
and .got has the PLT entry adddress. We will load the GOT entry |
with the PLT entry in finish_dynamic_symbol if it is used. For |
branch, it uses .got.plt. For symbol value, |
1. Use .got.plt in a shared object if it is forced local or not |
dynamic. |
2. Use .got.plt in a non-shared object if pointer equality isn't |
needed. |
3. Use .got.plt in PIE. |
4. Use .got.plt if .got isn't used. |
5. Otherwise use .got so that it can be shared among different |
objects at run-time. |
We only need to relocate .got entry in shared object. */ |
if (h->got.refcount <= 0 |
|| (info->shared |
&& (h->dynindx == -1 |
|| h->forced_local)) |
|| (!info->shared |
&& !h->pointer_equality_needed) |
|| (info->executable && info->shared) |
|| htab->sgot == NULL) |
{ |
/* Use .got.plt. */ |
h->got.offset = (bfd_vma) -1; |
} |
else |
{ |
h->got.offset = htab->sgot->size; |
htab->sgot->size += got_entry_size; |
if (info->shared) |
htab->srelgot->size += sizeof_reloc; |
} |
return TRUE; |
} |
/contrib/toolchain/binutils/bfd/elf-linux-psinfo.h |
---|
0,0 → 1,127 |
/* Definitions for PRPSINFO structures under ELF on GNU/Linux. |
Copyright 2013 Free Software Foundation, Inc. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#ifndef ELF_LINUX_PSINFO_H |
#define ELF_LINUX_PSINFO_H |
/* The PRPSINFO structures defined below are used by most |
architectures, although some of them define their own versions |
(like e.g., PPC). */ |
/* External 32-bit structure for PRPSINFO. This structure is |
ABI-defined, thus we choose to use char arrays here in order to |
avoid dealing with different types in different architectures. |
This structure will ultimately be written in the corefile's note |
section, as the PRPSINFO. */ |
struct elf_external_linux_prpsinfo32 |
{ |
char pr_state; /* Numeric process state. */ |
char pr_sname; /* Char for pr_state. */ |
char pr_zomb; /* Zombie. */ |
char pr_nice; /* Nice val. */ |
char pr_flag[4]; /* Flags. */ |
char pr_uid[2]; |
char pr_gid[2]; |
char pr_pid[4]; |
char pr_ppid[4]; |
char pr_pgrp[4]; |
char pr_sid[4]; |
char pr_fname[16]; /* Filename of executable. */ |
char pr_psargs[80]; /* Initial part of arg list. */ |
}; |
/* Helper macro to swap (properly handling endianess) things from the |
`elf_internal_linux_prpsinfo' structure to the |
`elf_external_linux_prpsinfo32' structure. |
Note that FROM should be a pointer, and TO should be the explicit |
type. */ |
#define LINUX_PRPSINFO32_SWAP_FIELDS(abfd, from, to) \ |
do \ |
{ \ |
H_PUT_8 (abfd, from->pr_state, &to.pr_state); \ |
H_PUT_8 (abfd, from->pr_sname, &to.pr_sname); \ |
H_PUT_8 (abfd, from->pr_zomb, &to.pr_zomb); \ |
H_PUT_8 (abfd, from->pr_nice, &to.pr_nice); \ |
H_PUT_32 (abfd, from->pr_flag, to.pr_flag); \ |
H_PUT_16 (abfd, from->pr_uid, to.pr_uid); \ |
H_PUT_16 (abfd, from->pr_gid, to.pr_gid); \ |
H_PUT_32 (abfd, from->pr_pid, to.pr_pid); \ |
H_PUT_32 (abfd, from->pr_ppid, to.pr_ppid); \ |
H_PUT_32 (abfd, from->pr_pgrp, to.pr_pgrp); \ |
H_PUT_32 (abfd, from->pr_sid, to.pr_sid); \ |
strncpy (to.pr_fname, from->pr_fname, sizeof (to.pr_fname)); \ |
strncpy (to.pr_psargs, from->pr_psargs, sizeof (to.pr_psargs)); \ |
} while (0) |
/* External 64-bit structure for PRPSINFO. This structure is |
ABI-defined, thus we choose to use char arrays here in order to |
avoid dealing with different types in different architectures. |
This structure will ultimately be written in the corefile's note |
section, as the PRPSINFO. */ |
struct elf_external_linux_prpsinfo64 |
{ |
char pr_state; /* Numeric process state. */ |
char pr_sname; /* Char for pr_state. */ |
char pr_zomb; /* Zombie. */ |
char pr_nice; /* Nice val. */ |
char pr_flag[8]; /* Flags. */ |
char gap[4]; |
char pr_uid[4]; |
char pr_gid[4]; |
char pr_pid[4]; |
char pr_ppid[4]; |
char pr_pgrp[4]; |
char pr_sid[4]; |
char pr_fname[16]; /* Filename of executable. */ |
char pr_psargs[80]; /* Initial part of arg list. */ |
}; |
/* Helper macro to swap (properly handling endianess) things from the |
`elf_internal_linux_prpsinfo' structure to the |
`elf_external_linux_prpsinfo64' structure. |
Note that FROM should be a pointer, and TO should be the explicit |
type. */ |
#define LINUX_PRPSINFO64_SWAP_FIELDS(abfd, from, to) \ |
do \ |
{ \ |
H_PUT_8 (abfd, from->pr_state, &to.pr_state); \ |
H_PUT_8 (abfd, from->pr_sname, &to.pr_sname); \ |
H_PUT_8 (abfd, from->pr_zomb, &to.pr_zomb); \ |
H_PUT_8 (abfd, from->pr_nice, &to.pr_nice); \ |
H_PUT_64 (abfd, from->pr_flag, to.pr_flag); \ |
H_PUT_32 (abfd, from->pr_uid, to.pr_uid); \ |
H_PUT_32 (abfd, from->pr_gid, to.pr_gid); \ |
H_PUT_32 (abfd, from->pr_pid, to.pr_pid); \ |
H_PUT_32 (abfd, from->pr_ppid, to.pr_ppid); \ |
H_PUT_32 (abfd, from->pr_pgrp, to.pr_pgrp); \ |
H_PUT_32 (abfd, from->pr_sid, to.pr_sid); \ |
strncpy (to.pr_fname, from->pr_fname, sizeof (to.pr_fname)); \ |
strncpy (to.pr_psargs, from->pr_psargs, sizeof (to.pr_psargs)); \ |
} while (0) |
#endif |
/contrib/toolchain/binutils/bfd/elf-nacl.c |
---|
0,0 → 1,355 |
/* Native Client support for ELF |
Copyright 2012, 2013 Free Software Foundation, Inc. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
MA 02111-1307, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
#include "elf-bfd.h" |
#include "elf-nacl.h" |
#include "elf/common.h" |
#include "elf/internal.h" |
static bfd_boolean |
segment_executable (struct elf_segment_map *seg) |
{ |
if (seg->p_flags_valid) |
return (seg->p_flags & PF_X) != 0; |
else |
{ |
/* The p_flags value has not been computed yet, |
so we have to look through the sections. */ |
unsigned int i; |
for (i = 0; i < seg->count; ++i) |
if (seg->sections[i]->flags & SEC_CODE) |
return TRUE; |
} |
return FALSE; |
} |
/* Determine if this segment is eligible to receive the file and program |
headers. It must be read-only and non-executable. |
Its first section must start far enough past the page boundary to |
allow space for the headers. */ |
static bfd_boolean |
segment_eligible_for_headers (struct elf_segment_map *seg, |
bfd_vma minpagesize, bfd_vma sizeof_headers) |
{ |
unsigned int i; |
if (seg->count == 0 || seg->sections[0]->lma % minpagesize < sizeof_headers) |
return FALSE; |
for (i = 0; i < seg->count; ++i) |
{ |
if ((seg->sections[i]->flags & (SEC_CODE|SEC_READONLY)) != SEC_READONLY) |
return FALSE; |
} |
return TRUE; |
} |
/* We permute the segment_map to get BFD to do the file layout we want: |
The first non-executable PT_LOAD segment appears first in the file |
and contains the ELF file header and phdrs. */ |
bfd_boolean |
nacl_modify_segment_map (bfd *abfd, struct bfd_link_info *info) |
{ |
const struct elf_backend_data *const bed = get_elf_backend_data (abfd); |
struct elf_segment_map **m = &elf_seg_map (abfd); |
struct elf_segment_map **first_load = NULL; |
struct elf_segment_map **last_load = NULL; |
bfd_boolean moved_headers = FALSE; |
int sizeof_headers; |
if (info != NULL && info->user_phdrs) |
/* The linker script used PHDRS explicitly, so don't change what the |
user asked for. */ |
return TRUE; |
if (info != NULL) |
/* We're doing linking, so evalute SIZEOF_HEADERS as in a linker script. */ |
sizeof_headers = bfd_sizeof_headers (abfd, info); |
else |
{ |
/* We're not doing linking, so this is objcopy or suchlike. |
We just need to collect the size of the existing headers. */ |
struct elf_segment_map *seg; |
sizeof_headers = bed->s->sizeof_ehdr; |
for (seg = *m; seg != NULL; seg = seg->next) |
sizeof_headers += bed->s->sizeof_phdr; |
} |
while (*m != NULL) |
{ |
struct elf_segment_map *seg = *m; |
if (seg->p_type == PT_LOAD) |
{ |
bfd_boolean executable = segment_executable (seg); |
if (executable |
&& seg->count > 0 |
&& seg->sections[0]->vma % bed->minpagesize == 0) |
{ |
asection *lastsec = seg->sections[seg->count - 1]; |
bfd_vma end = lastsec->vma + lastsec->size; |
if (end % bed->minpagesize != 0) |
{ |
/* This is an executable segment that starts on a page |
boundary but does not end on a page boundary. Fill |
it out to a whole page with code fill (the tail of |
the segment will not be within any section). Thus |
the entire code segment can be mapped from the file |
as whole pages and that mapping will contain only |
valid instructions. |
To accomplish this, we must fake out the code in |
assign_file_positions_for_load_sections (elf.c) so |
that it advances past the rest of the final page, |
rather than trying to put the next (unaligned, or |
unallocated) section. We do this by appending a |
dummy section record to this element in the segment |
map. No such output section ever actually exists, |
but this gets the layout logic to advance the file |
positions past this partial page. Since we are |
lying to BFD like this, nothing will ever know to |
write the section contents. So we do that by hand |
after the fact, in nacl_final_write_processing, below. */ |
struct elf_segment_map *newseg; |
asection *sec; |
struct bfd_elf_section_data *secdata; |
BFD_ASSERT (!seg->p_size_valid); |
secdata = bfd_zalloc (abfd, sizeof *secdata); |
if (secdata == NULL) |
return FALSE; |
sec = bfd_zalloc (abfd, sizeof *sec); |
if (sec == NULL) |
return FALSE; |
/* Fill in only the fields that actually affect the logic |
in assign_file_positions_for_load_sections. */ |
sec->vma = end; |
sec->lma = lastsec->lma + lastsec->size; |
sec->size = bed->minpagesize - (end % bed->minpagesize); |
sec->flags = (SEC_ALLOC | SEC_LOAD |
| SEC_READONLY | SEC_CODE | SEC_LINKER_CREATED); |
sec->used_by_bfd = secdata; |
secdata->this_hdr.sh_type = SHT_PROGBITS; |
secdata->this_hdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR; |
secdata->this_hdr.sh_addr = sec->vma; |
secdata->this_hdr.sh_size = sec->size; |
newseg = bfd_alloc (abfd, |
sizeof *newseg + ((seg->count + 1) |
* sizeof (asection *))); |
if (newseg == NULL) |
return FALSE; |
memcpy (newseg, seg, |
sizeof *newseg + (seg->count * sizeof (asection *))); |
newseg->sections[newseg->count++] = sec; |
*m = seg = newseg; |
} |
} |
/* First, we're just finding the earliest PT_LOAD. |
By the normal rules, this will be the lowest-addressed one. |
We only have anything interesting to do if it's executable. */ |
last_load = m; |
if (first_load == NULL) |
{ |
if (!executable) |
goto next; |
first_load = m; |
} |
/* Now that we've noted the first PT_LOAD, we're looking for |
the first non-executable PT_LOAD with a nonempty p_filesz. */ |
else if (!moved_headers |
&& segment_eligible_for_headers (seg, bed->minpagesize, |
sizeof_headers)) |
{ |
/* This is the one we were looking for! |
First, clear the flags on previous segments that |
say they include the file header and phdrs. */ |
struct elf_segment_map *prevseg; |
for (prevseg = *first_load; |
prevseg != seg; |
prevseg = prevseg->next) |
if (prevseg->p_type == PT_LOAD) |
{ |
prevseg->includes_filehdr = 0; |
prevseg->includes_phdrs = 0; |
} |
/* This segment will include those headers instead. */ |
seg->includes_filehdr = 1; |
seg->includes_phdrs = 1; |
moved_headers = TRUE; |
} |
} |
next: |
m = &seg->next; |
} |
if (first_load != last_load && moved_headers) |
{ |
/* Now swap the first and last PT_LOAD segments' |
positions in segment_map. */ |
struct elf_segment_map *first = *first_load; |
struct elf_segment_map *last = *last_load; |
*first_load = first->next; |
first->next = last->next; |
last->next = first; |
} |
return TRUE; |
} |
/* After nacl_modify_segment_map has done its work, the file layout has |
been done as we wanted. But the PT_LOAD phdrs are no longer in the |
proper order for the ELF rule that they must appear in ascending address |
order. So find the two segments we swapped before, and swap them back. */ |
bfd_boolean |
nacl_modify_program_headers (bfd *abfd, struct bfd_link_info *info) |
{ |
struct elf_segment_map **m = &elf_seg_map (abfd); |
Elf_Internal_Phdr *phdr = elf_tdata (abfd)->phdr; |
Elf_Internal_Phdr *p = phdr; |
if (info != NULL && info->user_phdrs) |
/* The linker script used PHDRS explicitly, so don't change what the |
user asked for. */ |
return TRUE; |
/* Find the PT_LOAD that contains the headers (should be the first). */ |
while (*m != NULL) |
{ |
if ((*m)->p_type == PT_LOAD && (*m)->includes_filehdr) |
break; |
m = &(*m)->next; |
++p; |
} |
if (*m != NULL) |
{ |
struct elf_segment_map **first_load_seg = m; |
Elf_Internal_Phdr *first_load_phdr = p; |
struct elf_segment_map **next_load_seg = NULL; |
Elf_Internal_Phdr *next_load_phdr = NULL; |
/* Now move past that first one and find the PT_LOAD that should be |
before it by address order. */ |
m = &(*m)->next; |
++p; |
while (*m != NULL) |
{ |
if (p->p_type == PT_LOAD && p->p_vaddr < first_load_phdr->p_vaddr) |
{ |
next_load_seg = m; |
next_load_phdr = p; |
break; |
} |
m = &(*m)->next; |
++p; |
} |
/* Swap their positions in the segment_map back to how they used to be. |
The phdrs have already been set up by now, so we have to slide up |
the earlier ones to insert the one that should be first. */ |
if (next_load_seg != NULL) |
{ |
Elf_Internal_Phdr move_phdr; |
struct elf_segment_map *first_seg = *first_load_seg; |
struct elf_segment_map *next_seg = *next_load_seg; |
struct elf_segment_map *first_next = first_seg->next; |
struct elf_segment_map *next_next = next_seg->next; |
if (next_load_seg == &first_seg->next) |
{ |
*first_load_seg = next_seg; |
next_seg->next = first_seg; |
first_seg->next = next_next; |
} |
else |
{ |
*first_load_seg = first_next; |
*next_load_seg = next_next; |
first_seg->next = *next_load_seg; |
*next_load_seg = first_seg; |
next_seg->next = *first_load_seg; |
*first_load_seg = next_seg; |
} |
move_phdr = *next_load_phdr; |
memmove (first_load_phdr + 1, first_load_phdr, |
(next_load_phdr - first_load_phdr) * sizeof move_phdr); |
*first_load_phdr = move_phdr; |
} |
} |
return TRUE; |
} |
void |
nacl_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED) |
{ |
struct elf_segment_map *seg; |
for (seg = elf_seg_map (abfd); seg != NULL; seg = seg->next) |
if (seg->p_type == PT_LOAD |
&& seg->count > 1 |
&& seg->sections[seg->count - 1]->owner == NULL) |
{ |
/* This is a fake section added in nacl_modify_segment_map, above. |
It's not a real BFD section, so nothing wrote its contents. |
Now write out its contents. */ |
asection *sec = seg->sections[seg->count - 1]; |
char *fill; |
BFD_ASSERT (sec->flags & SEC_LINKER_CREATED); |
BFD_ASSERT (sec->flags & SEC_CODE); |
BFD_ASSERT (sec->size > 0); |
fill = abfd->arch_info->fill (sec->size, bfd_big_endian (abfd), TRUE); |
if (fill == NULL |
|| bfd_seek (abfd, sec->filepos, SEEK_SET) != 0 |
|| bfd_bwrite (fill, sec->size, abfd) != sec->size) |
{ |
/* We don't have a proper way to report an error here. So |
instead fudge things so that elf_write_shdrs_and_ehdr will |
fail. */ |
elf_elfheader (abfd)->e_shoff = (file_ptr) -1; |
} |
free (fill); |
} |
} |
/contrib/toolchain/binutils/bfd/elf-nacl.h |
---|
0,0 → 1,25 |
/* Native Client support for ELF |
Copyright 2012, 2013 Free Software Foundation, Inc. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
MA 02111-1307, USA. */ |
#include "bfd.h" |
bfd_boolean nacl_modify_segment_map (bfd *, struct bfd_link_info *); |
bfd_boolean nacl_modify_program_headers (bfd *, struct bfd_link_info *); |
void nacl_final_write_processing (bfd *, bfd_boolean linker); |
/contrib/toolchain/binutils/bfd/elf-strtab.c |
---|
0,0 → 1,421 |
/* ELF strtab with GC and suffix merging support. |
Copyright 2001, 2002, 2003, 2005, 2006, 2007, 2008 |
Free Software Foundation, Inc. |
Written by Jakub Jelinek <jakub@redhat.com>. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
#include "elf-bfd.h" |
#include "hashtab.h" |
#include "libiberty.h" |
/* An entry in the strtab hash table. */ |
struct elf_strtab_hash_entry |
{ |
struct bfd_hash_entry root; |
/* Length of this entry. This includes the zero terminator. */ |
int len; |
unsigned int refcount; |
union { |
/* Index within the merged section. */ |
bfd_size_type index; |
/* Entry this is a suffix of (if len < 0). */ |
struct elf_strtab_hash_entry *suffix; |
} u; |
}; |
/* The strtab hash table. */ |
struct elf_strtab_hash |
{ |
struct bfd_hash_table table; |
/* Next available index. */ |
bfd_size_type size; |
/* Number of array entries alloced. */ |
bfd_size_type alloced; |
/* Final strtab size. */ |
bfd_size_type sec_size; |
/* Array of pointers to strtab entries. */ |
struct elf_strtab_hash_entry **array; |
}; |
/* Routine to create an entry in a section merge hashtab. */ |
static struct bfd_hash_entry * |
elf_strtab_hash_newfunc (struct bfd_hash_entry *entry, |
struct bfd_hash_table *table, |
const char *string) |
{ |
/* Allocate the structure if it has not already been allocated by a |
subclass. */ |
if (entry == NULL) |
entry = (struct bfd_hash_entry *) |
bfd_hash_allocate (table, sizeof (struct elf_strtab_hash_entry)); |
if (entry == NULL) |
return NULL; |
/* Call the allocation method of the superclass. */ |
entry = bfd_hash_newfunc (entry, table, string); |
if (entry) |
{ |
/* Initialize the local fields. */ |
struct elf_strtab_hash_entry *ret; |
ret = (struct elf_strtab_hash_entry *) entry; |
ret->u.index = -1; |
ret->refcount = 0; |
ret->len = 0; |
} |
return entry; |
} |
/* Create a new hash table. */ |
struct elf_strtab_hash * |
_bfd_elf_strtab_init (void) |
{ |
struct elf_strtab_hash *table; |
bfd_size_type amt = sizeof (struct elf_strtab_hash); |
table = (struct elf_strtab_hash *) bfd_malloc (amt); |
if (table == NULL) |
return NULL; |
if (!bfd_hash_table_init (&table->table, elf_strtab_hash_newfunc, |
sizeof (struct elf_strtab_hash_entry))) |
{ |
free (table); |
return NULL; |
} |
table->sec_size = 0; |
table->size = 1; |
table->alloced = 64; |
amt = sizeof (struct elf_strtab_hasn_entry *); |
table->array = (struct elf_strtab_hash_entry **) |
bfd_malloc (table->alloced * amt); |
if (table->array == NULL) |
{ |
free (table); |
return NULL; |
} |
table->array[0] = NULL; |
return table; |
} |
/* Free a strtab. */ |
void |
_bfd_elf_strtab_free (struct elf_strtab_hash *tab) |
{ |
bfd_hash_table_free (&tab->table); |
free (tab->array); |
free (tab); |
} |
/* Get the index of an entity in a hash table, adding it if it is not |
already present. */ |
bfd_size_type |
_bfd_elf_strtab_add (struct elf_strtab_hash *tab, |
const char *str, |
bfd_boolean copy) |
{ |
register struct elf_strtab_hash_entry *entry; |
/* We handle this specially, since we don't want to do refcounting |
on it. */ |
if (*str == '\0') |
return 0; |
BFD_ASSERT (tab->sec_size == 0); |
entry = (struct elf_strtab_hash_entry *) |
bfd_hash_lookup (&tab->table, str, TRUE, copy); |
if (entry == NULL) |
return (bfd_size_type) -1; |
entry->refcount++; |
if (entry->len == 0) |
{ |
entry->len = strlen (str) + 1; |
/* 2G strings lose. */ |
BFD_ASSERT (entry->len > 0); |
if (tab->size == tab->alloced) |
{ |
bfd_size_type amt = sizeof (struct elf_strtab_hash_entry *); |
tab->alloced *= 2; |
tab->array = (struct elf_strtab_hash_entry **) |
bfd_realloc_or_free (tab->array, tab->alloced * amt); |
if (tab->array == NULL) |
return (bfd_size_type) -1; |
} |
entry->u.index = tab->size++; |
tab->array[entry->u.index] = entry; |
} |
return entry->u.index; |
} |
void |
_bfd_elf_strtab_addref (struct elf_strtab_hash *tab, bfd_size_type idx) |
{ |
if (idx == 0 || idx == (bfd_size_type) -1) |
return; |
BFD_ASSERT (tab->sec_size == 0); |
BFD_ASSERT (idx < tab->size); |
++tab->array[idx]->refcount; |
} |
void |
_bfd_elf_strtab_delref (struct elf_strtab_hash *tab, bfd_size_type idx) |
{ |
if (idx == 0 || idx == (bfd_size_type) -1) |
return; |
BFD_ASSERT (tab->sec_size == 0); |
BFD_ASSERT (idx < tab->size); |
BFD_ASSERT (tab->array[idx]->refcount > 0); |
--tab->array[idx]->refcount; |
} |
unsigned int |
_bfd_elf_strtab_refcount (struct elf_strtab_hash *tab, bfd_size_type idx) |
{ |
return tab->array[idx]->refcount; |
} |
void |
_bfd_elf_strtab_clear_all_refs (struct elf_strtab_hash *tab) |
{ |
bfd_size_type idx; |
for (idx = 1; idx < tab->size; idx++) |
tab->array[idx]->refcount = 0; |
} |
/* Downsizes strtab. Entries from IDX up to the current size are |
removed from the array. */ |
void |
_bfd_elf_strtab_restore_size (struct elf_strtab_hash *tab, bfd_size_type idx) |
{ |
bfd_size_type curr_size = tab->size; |
BFD_ASSERT (tab->sec_size == 0); |
BFD_ASSERT (idx <= curr_size); |
tab->size = idx; |
for (; idx < curr_size; ++idx) |
{ |
/* We don't remove entries from the hash table, just set their |
REFCOUNT to zero. Setting LEN zero will result in the size |
growing if the entry is added again. See _bfd_elf_strtab_add. */ |
tab->array[idx]->refcount = 0; |
tab->array[idx]->len = 0; |
} |
} |
bfd_size_type |
_bfd_elf_strtab_size (struct elf_strtab_hash *tab) |
{ |
return tab->sec_size ? tab->sec_size : tab->size; |
} |
bfd_size_type |
_bfd_elf_strtab_offset (struct elf_strtab_hash *tab, bfd_size_type idx) |
{ |
struct elf_strtab_hash_entry *entry; |
if (idx == 0) |
return 0; |
BFD_ASSERT (idx < tab->size); |
BFD_ASSERT (tab->sec_size); |
entry = tab->array[idx]; |
BFD_ASSERT (entry->refcount > 0); |
entry->refcount--; |
return tab->array[idx]->u.index; |
} |
bfd_boolean |
_bfd_elf_strtab_emit (register bfd *abfd, struct elf_strtab_hash *tab) |
{ |
bfd_size_type off = 1, i; |
if (bfd_bwrite ("", 1, abfd) != 1) |
return FALSE; |
for (i = 1; i < tab->size; ++i) |
{ |
register const char *str; |
register unsigned int len; |
BFD_ASSERT (tab->array[i]->refcount == 0); |
len = tab->array[i]->len; |
if ((int) len < 0) |
continue; |
str = tab->array[i]->root.string; |
if (bfd_bwrite (str, len, abfd) != len) |
return FALSE; |
off += len; |
} |
BFD_ASSERT (off == tab->sec_size); |
return TRUE; |
} |
/* Compare two elf_strtab_hash_entry structures. Called via qsort. */ |
static int |
strrevcmp (const void *a, const void *b) |
{ |
struct elf_strtab_hash_entry *A = *(struct elf_strtab_hash_entry **) a; |
struct elf_strtab_hash_entry *B = *(struct elf_strtab_hash_entry **) b; |
unsigned int lenA = A->len; |
unsigned int lenB = B->len; |
const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1; |
const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1; |
int l = lenA < lenB ? lenA : lenB; |
while (l) |
{ |
if (*s != *t) |
return (int) *s - (int) *t; |
s--; |
t--; |
l--; |
} |
return lenA - lenB; |
} |
static inline int |
is_suffix (const struct elf_strtab_hash_entry *A, |
const struct elf_strtab_hash_entry *B) |
{ |
if (A->len <= B->len) |
/* B cannot be a suffix of A unless A is equal to B, which is guaranteed |
not to be equal by the hash table. */ |
return 0; |
return memcmp (A->root.string + (A->len - B->len), |
B->root.string, B->len - 1) == 0; |
} |
/* This function assigns final string table offsets for used strings, |
merging strings matching suffixes of longer strings if possible. */ |
void |
_bfd_elf_strtab_finalize (struct elf_strtab_hash *tab) |
{ |
struct elf_strtab_hash_entry **array, **a, *e; |
bfd_size_type size, amt; |
/* GCC 2.91.66 (egcs-1.1.2) on i386 miscompiles this function when i is |
a 64-bit bfd_size_type: a 64-bit target or --enable-64-bit-bfd. |
Besides, indexing with a long long wouldn't give anything but extra |
cycles. */ |
size_t i; |
/* Sort the strings by suffix and length. */ |
amt = tab->size * sizeof (struct elf_strtab_hash_entry *); |
array = (struct elf_strtab_hash_entry **) bfd_malloc (amt); |
if (array == NULL) |
goto alloc_failure; |
for (i = 1, a = array; i < tab->size; ++i) |
{ |
e = tab->array[i]; |
if (e->refcount) |
{ |
*a++ = e; |
/* Adjust the length to not include the zero terminator. */ |
e->len -= 1; |
} |
else |
e->len = 0; |
} |
size = a - array; |
if (size != 0) |
{ |
qsort (array, size, sizeof (struct elf_strtab_hash_entry *), strrevcmp); |
/* Loop over the sorted array and merge suffixes. Start from the |
end because we want eg. |
s1 -> "d" |
s2 -> "bcd" |
s3 -> "abcd" |
to end up as |
s3 -> "abcd" |
s2 _____^ |
s1 _______^ |
ie. we don't want s1 pointing into the old s2. */ |
e = *--a; |
e->len += 1; |
while (--a >= array) |
{ |
struct elf_strtab_hash_entry *cmp = *a; |
cmp->len += 1; |
if (is_suffix (e, cmp)) |
{ |
cmp->u.suffix = e; |
cmp->len = -cmp->len; |
} |
else |
e = cmp; |
} |
} |
alloc_failure: |
if (array) |
free (array); |
/* Assign positions to the strings we want to keep. */ |
size = 1; |
for (i = 1; i < tab->size; ++i) |
{ |
e = tab->array[i]; |
if (e->refcount && e->len > 0) |
{ |
e->u.index = size; |
size += e->len; |
} |
} |
tab->sec_size = size; |
/* Adjust the rest. */ |
for (i = 1; i < tab->size; ++i) |
{ |
e = tab->array[i]; |
if (e->refcount && e->len < 0) |
e->u.index = e->u.suffix->u.index + (e->u.suffix->len + e->len); |
} |
} |
/contrib/toolchain/binutils/bfd/elf-vxworks.c |
---|
0,0 → 1,301 |
/* VxWorks support for ELF |
Copyright 2005, 2006, 2007, 2009, 2012 Free Software Foundation, Inc. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
MA 02111-1307, USA. */ |
/* This file provides routines used by all VxWorks targets. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
#include "elf-bfd.h" |
#include "elf-vxworks.h" |
#include "elf/vxworks.h" |
/* Return true if symbol NAME, as defined by ABFD, is one of the special |
__GOTT_BASE__ or __GOTT_INDEX__ symbols. */ |
static bfd_boolean |
elf_vxworks_gott_symbol_p (bfd *abfd, const char *name) |
{ |
char leading; |
leading = bfd_get_symbol_leading_char (abfd); |
if (leading) |
{ |
if (*name != leading) |
return FALSE; |
name++; |
} |
return (strcmp (name, "__GOTT_BASE__") == 0 |
|| strcmp (name, "__GOTT_INDEX__") == 0); |
} |
/* Tweak magic VxWorks symbols as they are loaded. */ |
bfd_boolean |
elf_vxworks_add_symbol_hook (bfd *abfd, |
struct bfd_link_info *info, |
Elf_Internal_Sym *sym, |
const char **namep, |
flagword *flagsp, |
asection **secp ATTRIBUTE_UNUSED, |
bfd_vma *valp ATTRIBUTE_UNUSED) |
{ |
/* Ideally these "magic" symbols would be exported by libc.so.1 |
which would be found via a DT_NEEDED tag, and then handled |
specially by the linker at runtime. Except shared libraries |
don't even link to libc.so.1 by default... |
If the symbol is imported from, or will be put in a shared library, |
give the symbol weak binding to get the desired samantics. |
This transformation will be undone in |
elf_i386_vxworks_link_output_symbol_hook. */ |
if ((info->shared || abfd->flags & DYNAMIC) |
&& elf_vxworks_gott_symbol_p (abfd, *namep)) |
{ |
sym->st_info = ELF_ST_INFO (STB_WEAK, ELF_ST_TYPE (sym->st_info)); |
*flagsp |= BSF_WEAK; |
} |
return TRUE; |
} |
/* Perform VxWorks-specific handling of the create_dynamic_sections hook. |
When creating an executable, set *SRELPLT2_OUT to the .rel(a).plt.unloaded |
section. */ |
bfd_boolean |
elf_vxworks_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info, |
asection **srelplt2_out) |
{ |
struct elf_link_hash_table *htab; |
const struct elf_backend_data *bed; |
asection *s; |
htab = elf_hash_table (info); |
bed = get_elf_backend_data (dynobj); |
if (!info->shared) |
{ |
s = bfd_make_section_anyway_with_flags (dynobj, |
bed->default_use_rela_p |
? ".rela.plt.unloaded" |
: ".rel.plt.unloaded", |
SEC_HAS_CONTENTS | SEC_IN_MEMORY |
| SEC_READONLY |
| SEC_LINKER_CREATED); |
if (s == NULL |
|| !bfd_set_section_alignment (dynobj, s, bed->s->log_file_align)) |
return FALSE; |
*srelplt2_out = s; |
} |
/* Mark the GOT and PLT symbols as having relocations; they might |
not, but we won't know for sure until we build the GOT in |
finish_dynamic_symbol. Also make sure that the GOT symbol |
is entered into the dynamic symbol table; the loader uses it |
to initialize __GOTT_BASE__[__GOTT_INDEX__]. */ |
if (htab->hgot) |
{ |
htab->hgot->indx = -2; |
htab->hgot->other &= ~ELF_ST_VISIBILITY (-1); |
htab->hgot->forced_local = 0; |
if (!bfd_elf_link_record_dynamic_symbol (info, htab->hgot)) |
return FALSE; |
} |
if (htab->hplt) |
{ |
htab->hplt->indx = -2; |
htab->hplt->type = STT_FUNC; |
} |
return TRUE; |
} |
/* Tweak magic VxWorks symbols as they are written to the output file. */ |
int |
elf_vxworks_link_output_symbol_hook (struct bfd_link_info *info |
ATTRIBUTE_UNUSED, |
const char *name, |
Elf_Internal_Sym *sym, |
asection *input_sec ATTRIBUTE_UNUSED, |
struct elf_link_hash_entry *h) |
{ |
/* Reverse the effects of the hack in elf_vxworks_add_symbol_hook. */ |
if (h |
&& h->root.type == bfd_link_hash_undefweak |
&& elf_vxworks_gott_symbol_p (h->root.u.undef.abfd, name)) |
sym->st_info = ELF_ST_INFO (STB_GLOBAL, ELF_ST_TYPE (sym->st_info)); |
return 1; |
} |
/* Copy relocations into the output file. Fixes up relocations against PLT |
entries, then calls the generic routine. */ |
bfd_boolean |
elf_vxworks_emit_relocs (bfd *output_bfd, |
asection *input_section, |
Elf_Internal_Shdr *input_rel_hdr, |
Elf_Internal_Rela *internal_relocs, |
struct elf_link_hash_entry **rel_hash) |
{ |
const struct elf_backend_data *bed; |
int j; |
bed = get_elf_backend_data (output_bfd); |
if (output_bfd->flags & (DYNAMIC|EXEC_P)) |
{ |
Elf_Internal_Rela *irela; |
Elf_Internal_Rela *irelaend; |
struct elf_link_hash_entry **hash_ptr; |
for (irela = internal_relocs, |
irelaend = irela + (NUM_SHDR_ENTRIES (input_rel_hdr) |
* bed->s->int_rels_per_ext_rel), |
hash_ptr = rel_hash; |
irela < irelaend; |
irela += bed->s->int_rels_per_ext_rel, |
hash_ptr++) |
{ |
if (*hash_ptr |
&& (*hash_ptr)->def_dynamic |
&& !(*hash_ptr)->def_regular |
&& ((*hash_ptr)->root.type == bfd_link_hash_defined |
|| (*hash_ptr)->root.type == bfd_link_hash_defweak) |
&& (*hash_ptr)->root.u.def.section->output_section != NULL) |
{ |
/* This is a relocation from an executable or shared |
library against a symbol in a different shared |
library. We are creating a definition in the output |
file but it does not come from any of our normal (.o) |
files. ie. a PLT stub. Normally this would be a |
relocation against against SHN_UNDEF with the VMA of |
the PLT stub. This upsets the VxWorks loader. |
Convert it to a section-relative relocation. This |
gets some other symbols (for instance .dynbss), but |
is conservatively correct. */ |
for (j = 0; j < bed->s->int_rels_per_ext_rel; j++) |
{ |
asection *sec = (*hash_ptr)->root.u.def.section; |
int this_idx = sec->output_section->target_index; |
irela[j].r_info |
= ELF32_R_INFO (this_idx, ELF32_R_TYPE (irela[j].r_info)); |
irela[j].r_addend += (*hash_ptr)->root.u.def.value; |
irela[j].r_addend += sec->output_offset; |
} |
/* Stop the generic routine adjusting this entry. */ |
*hash_ptr = NULL; |
} |
} |
} |
return _bfd_elf_link_output_relocs (output_bfd, input_section, |
input_rel_hdr, internal_relocs, |
rel_hash); |
} |
/* Set the sh_link and sh_info fields on the static plt relocation secton. */ |
void |
elf_vxworks_final_write_processing (bfd *abfd, |
bfd_boolean linker ATTRIBUTE_UNUSED) |
{ |
asection * sec; |
struct bfd_elf_section_data *d; |
sec = bfd_get_section_by_name (abfd, ".rel.plt.unloaded"); |
if (!sec) |
sec = bfd_get_section_by_name (abfd, ".rela.plt.unloaded"); |
if (!sec) |
return; |
d = elf_section_data (sec); |
d->this_hdr.sh_link = elf_onesymtab (abfd); |
sec = bfd_get_section_by_name (abfd, ".plt"); |
if (sec) |
d->this_hdr.sh_info = elf_section_data (sec)->this_idx; |
} |
/* Add the dynamic entries required by VxWorks. These point to the |
tls sections. */ |
bfd_boolean |
elf_vxworks_add_dynamic_entries (bfd *output_bfd, struct bfd_link_info *info) |
{ |
if (bfd_get_section_by_name (output_bfd, ".tls_data")) |
{ |
if (!_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_DATA_START, 0) |
|| !_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_DATA_SIZE, 0) |
|| !_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_DATA_ALIGN, 0)) |
return FALSE; |
} |
if (bfd_get_section_by_name (output_bfd, ".tls_vars")) |
{ |
if (!_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_VARS_START, 0) |
|| !_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_VARS_SIZE, 0)) |
return FALSE; |
} |
return TRUE; |
} |
/* If *DYN is one of the VxWorks-specific dynamic entries, then fill |
in the value now and return TRUE. Otherwise return FALSE. */ |
bfd_boolean |
elf_vxworks_finish_dynamic_entry (bfd *output_bfd, Elf_Internal_Dyn *dyn) |
{ |
asection *sec; |
switch (dyn->d_tag) |
{ |
default: |
return FALSE; |
case DT_VX_WRS_TLS_DATA_START: |
sec = bfd_get_section_by_name (output_bfd, ".tls_data"); |
dyn->d_un.d_ptr = sec->vma; |
break; |
case DT_VX_WRS_TLS_DATA_SIZE: |
sec = bfd_get_section_by_name (output_bfd, ".tls_data"); |
dyn->d_un.d_val = sec->size; |
break; |
case DT_VX_WRS_TLS_DATA_ALIGN: |
sec = bfd_get_section_by_name (output_bfd, ".tls_data"); |
dyn->d_un.d_val |
= (bfd_size_type)1 << bfd_get_section_alignment (output_bfd, |
sec); |
break; |
case DT_VX_WRS_TLS_VARS_START: |
sec = bfd_get_section_by_name (output_bfd, ".tls_vars"); |
dyn->d_un.d_ptr = sec->vma; |
break; |
case DT_VX_WRS_TLS_VARS_SIZE: |
sec = bfd_get_section_by_name (output_bfd, ".tls_vars"); |
dyn->d_un.d_val = sec->size; |
break; |
} |
return TRUE; |
} |
/contrib/toolchain/binutils/bfd/elf-vxworks.h |
---|
0,0 → 1,38 |
/* VxWorks support for ELF |
Copyright 2005, 2006, 2007 Free Software Foundation, Inc. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
MA 02111-1307, USA. */ |
#include "elf/common.h" |
#include "elf/internal.h" |
bfd_boolean elf_vxworks_add_symbol_hook |
(bfd *, struct bfd_link_info *, Elf_Internal_Sym *, const char **, |
flagword *, asection **, bfd_vma *); |
bfd_boolean elf_vxworks_link_output_symbol_hook |
(struct bfd_link_info *, const char *name, Elf_Internal_Sym *, |
asection *, struct elf_link_hash_entry *); |
bfd_boolean elf_vxworks_emit_relocs |
(bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *, |
struct elf_link_hash_entry **); |
void elf_vxworks_final_write_processing (bfd *, bfd_boolean); |
bfd_boolean elf_vxworks_create_dynamic_sections |
(bfd *, struct bfd_link_info *, asection **); |
bfd_boolean elf_vxworks_add_dynamic_entries (bfd *, struct bfd_link_info *); |
bfd_boolean elf_vxworks_finish_dynamic_entry (bfd *, Elf_Internal_Dyn *); |
/contrib/toolchain/binutils/bfd/elf.c |
---|
0,0 → 1,10045 |
/* ELF executable support for BFD. |
Copyright 1993-2013 Free Software Foundation, Inc. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* |
SECTION |
ELF backends |
BFD support for ELF formats is being worked on. |
Currently, the best supported back ends are for sparc and i386 |
(running svr4 or Solaris 2). |
Documentation of the internals of the support code still needs |
to be written. The code is changing quickly enough that we |
haven't bothered yet. */ |
/* For sparc64-cross-sparc32. */ |
#define _SYSCALL32 |
#include "sysdep.h" |
#include "bfd.h" |
#include "bfdlink.h" |
#include "libbfd.h" |
#define ARCH_SIZE 0 |
#include "elf-bfd.h" |
#include "libiberty.h" |
#include "safe-ctype.h" |
#include "elf-linux-psinfo.h" |
#ifdef CORE_HEADER |
#include CORE_HEADER |
#endif |
static int elf_sort_sections (const void *, const void *); |
static bfd_boolean assign_file_positions_except_relocs (bfd *, struct bfd_link_info *); |
static bfd_boolean prep_headers (bfd *); |
static bfd_boolean swap_out_syms (bfd *, struct bfd_strtab_hash **, int) ; |
static bfd_boolean elf_read_notes (bfd *, file_ptr, bfd_size_type) ; |
static bfd_boolean elf_parse_notes (bfd *abfd, char *buf, size_t size, |
file_ptr offset); |
/* Swap version information in and out. The version information is |
currently size independent. If that ever changes, this code will |
need to move into elfcode.h. */ |
/* Swap in a Verdef structure. */ |
void |
_bfd_elf_swap_verdef_in (bfd *abfd, |
const Elf_External_Verdef *src, |
Elf_Internal_Verdef *dst) |
{ |
dst->vd_version = H_GET_16 (abfd, src->vd_version); |
dst->vd_flags = H_GET_16 (abfd, src->vd_flags); |
dst->vd_ndx = H_GET_16 (abfd, src->vd_ndx); |
dst->vd_cnt = H_GET_16 (abfd, src->vd_cnt); |
dst->vd_hash = H_GET_32 (abfd, src->vd_hash); |
dst->vd_aux = H_GET_32 (abfd, src->vd_aux); |
dst->vd_next = H_GET_32 (abfd, src->vd_next); |
} |
/* Swap out a Verdef structure. */ |
void |
_bfd_elf_swap_verdef_out (bfd *abfd, |
const Elf_Internal_Verdef *src, |
Elf_External_Verdef *dst) |
{ |
H_PUT_16 (abfd, src->vd_version, dst->vd_version); |
H_PUT_16 (abfd, src->vd_flags, dst->vd_flags); |
H_PUT_16 (abfd, src->vd_ndx, dst->vd_ndx); |
H_PUT_16 (abfd, src->vd_cnt, dst->vd_cnt); |
H_PUT_32 (abfd, src->vd_hash, dst->vd_hash); |
H_PUT_32 (abfd, src->vd_aux, dst->vd_aux); |
H_PUT_32 (abfd, src->vd_next, dst->vd_next); |
} |
/* Swap in a Verdaux structure. */ |
void |
_bfd_elf_swap_verdaux_in (bfd *abfd, |
const Elf_External_Verdaux *src, |
Elf_Internal_Verdaux *dst) |
{ |
dst->vda_name = H_GET_32 (abfd, src->vda_name); |
dst->vda_next = H_GET_32 (abfd, src->vda_next); |
} |
/* Swap out a Verdaux structure. */ |
void |
_bfd_elf_swap_verdaux_out (bfd *abfd, |
const Elf_Internal_Verdaux *src, |
Elf_External_Verdaux *dst) |
{ |
H_PUT_32 (abfd, src->vda_name, dst->vda_name); |
H_PUT_32 (abfd, src->vda_next, dst->vda_next); |
} |
/* Swap in a Verneed structure. */ |
void |
_bfd_elf_swap_verneed_in (bfd *abfd, |
const Elf_External_Verneed *src, |
Elf_Internal_Verneed *dst) |
{ |
dst->vn_version = H_GET_16 (abfd, src->vn_version); |
dst->vn_cnt = H_GET_16 (abfd, src->vn_cnt); |
dst->vn_file = H_GET_32 (abfd, src->vn_file); |
dst->vn_aux = H_GET_32 (abfd, src->vn_aux); |
dst->vn_next = H_GET_32 (abfd, src->vn_next); |
} |
/* Swap out a Verneed structure. */ |
void |
_bfd_elf_swap_verneed_out (bfd *abfd, |
const Elf_Internal_Verneed *src, |
Elf_External_Verneed *dst) |
{ |
H_PUT_16 (abfd, src->vn_version, dst->vn_version); |
H_PUT_16 (abfd, src->vn_cnt, dst->vn_cnt); |
H_PUT_32 (abfd, src->vn_file, dst->vn_file); |
H_PUT_32 (abfd, src->vn_aux, dst->vn_aux); |
H_PUT_32 (abfd, src->vn_next, dst->vn_next); |
} |
/* Swap in a Vernaux structure. */ |
void |
_bfd_elf_swap_vernaux_in (bfd *abfd, |
const Elf_External_Vernaux *src, |
Elf_Internal_Vernaux *dst) |
{ |
dst->vna_hash = H_GET_32 (abfd, src->vna_hash); |
dst->vna_flags = H_GET_16 (abfd, src->vna_flags); |
dst->vna_other = H_GET_16 (abfd, src->vna_other); |
dst->vna_name = H_GET_32 (abfd, src->vna_name); |
dst->vna_next = H_GET_32 (abfd, src->vna_next); |
} |
/* Swap out a Vernaux structure. */ |
void |
_bfd_elf_swap_vernaux_out (bfd *abfd, |
const Elf_Internal_Vernaux *src, |
Elf_External_Vernaux *dst) |
{ |
H_PUT_32 (abfd, src->vna_hash, dst->vna_hash); |
H_PUT_16 (abfd, src->vna_flags, dst->vna_flags); |
H_PUT_16 (abfd, src->vna_other, dst->vna_other); |
H_PUT_32 (abfd, src->vna_name, dst->vna_name); |
H_PUT_32 (abfd, src->vna_next, dst->vna_next); |
} |
/* Swap in a Versym structure. */ |
void |
_bfd_elf_swap_versym_in (bfd *abfd, |
const Elf_External_Versym *src, |
Elf_Internal_Versym *dst) |
{ |
dst->vs_vers = H_GET_16 (abfd, src->vs_vers); |
} |
/* Swap out a Versym structure. */ |
void |
_bfd_elf_swap_versym_out (bfd *abfd, |
const Elf_Internal_Versym *src, |
Elf_External_Versym *dst) |
{ |
H_PUT_16 (abfd, src->vs_vers, dst->vs_vers); |
} |
/* Standard ELF hash function. Do not change this function; you will |
cause invalid hash tables to be generated. */ |
unsigned long |
bfd_elf_hash (const char *namearg) |
{ |
const unsigned char *name = (const unsigned char *) namearg; |
unsigned long h = 0; |
unsigned long g; |
int ch; |
while ((ch = *name++) != '\0') |
{ |
h = (h << 4) + ch; |
if ((g = (h & 0xf0000000)) != 0) |
{ |
h ^= g >> 24; |
/* The ELF ABI says `h &= ~g', but this is equivalent in |
this case and on some machines one insn instead of two. */ |
h ^= g; |
} |
} |
return h & 0xffffffff; |
} |
/* DT_GNU_HASH hash function. Do not change this function; you will |
cause invalid hash tables to be generated. */ |
unsigned long |
bfd_elf_gnu_hash (const char *namearg) |
{ |
const unsigned char *name = (const unsigned char *) namearg; |
unsigned long h = 5381; |
unsigned char ch; |
while ((ch = *name++) != '\0') |
h = (h << 5) + h + ch; |
return h & 0xffffffff; |
} |
/* Create a tdata field OBJECT_SIZE bytes in length, zeroed out and with |
the object_id field of an elf_obj_tdata field set to OBJECT_ID. */ |
bfd_boolean |
bfd_elf_allocate_object (bfd *abfd, |
size_t object_size, |
enum elf_target_id object_id) |
{ |
BFD_ASSERT (object_size >= sizeof (struct elf_obj_tdata)); |
abfd->tdata.any = bfd_zalloc (abfd, object_size); |
if (abfd->tdata.any == NULL) |
return FALSE; |
elf_object_id (abfd) = object_id; |
if (abfd->direction != read_direction) |
{ |
struct output_elf_obj_tdata *o = bfd_zalloc (abfd, sizeof *o); |
if (o == NULL) |
return FALSE; |
elf_tdata (abfd)->o = o; |
elf_program_header_size (abfd) = (bfd_size_type) -1; |
} |
return TRUE; |
} |
bfd_boolean |
bfd_elf_make_object (bfd *abfd) |
{ |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
return bfd_elf_allocate_object (abfd, sizeof (struct elf_obj_tdata), |
bed->target_id); |
} |
bfd_boolean |
bfd_elf_mkcorefile (bfd *abfd) |
{ |
/* I think this can be done just like an object file. */ |
if (!abfd->xvec->_bfd_set_format[(int) bfd_object] (abfd)) |
return FALSE; |
elf_tdata (abfd)->core = bfd_zalloc (abfd, sizeof (*elf_tdata (abfd)->core)); |
return elf_tdata (abfd)->core != NULL; |
} |
static char * |
bfd_elf_get_str_section (bfd *abfd, unsigned int shindex) |
{ |
Elf_Internal_Shdr **i_shdrp; |
bfd_byte *shstrtab = NULL; |
file_ptr offset; |
bfd_size_type shstrtabsize; |
i_shdrp = elf_elfsections (abfd); |
if (i_shdrp == 0 |
|| shindex >= elf_numsections (abfd) |
|| i_shdrp[shindex] == 0) |
return NULL; |
shstrtab = i_shdrp[shindex]->contents; |
if (shstrtab == NULL) |
{ |
/* No cached one, attempt to read, and cache what we read. */ |
offset = i_shdrp[shindex]->sh_offset; |
shstrtabsize = i_shdrp[shindex]->sh_size; |
/* Allocate and clear an extra byte at the end, to prevent crashes |
in case the string table is not terminated. */ |
if (shstrtabsize + 1 <= 1 |
|| (shstrtab = (bfd_byte *) bfd_alloc (abfd, shstrtabsize + 1)) == NULL |
|| bfd_seek (abfd, offset, SEEK_SET) != 0) |
shstrtab = NULL; |
else if (bfd_bread (shstrtab, shstrtabsize, abfd) != shstrtabsize) |
{ |
if (bfd_get_error () != bfd_error_system_call) |
bfd_set_error (bfd_error_file_truncated); |
shstrtab = NULL; |
/* Once we've failed to read it, make sure we don't keep |
trying. Otherwise, we'll keep allocating space for |
the string table over and over. */ |
i_shdrp[shindex]->sh_size = 0; |
} |
else |
shstrtab[shstrtabsize] = '\0'; |
i_shdrp[shindex]->contents = shstrtab; |
} |
return (char *) shstrtab; |
} |
char * |
bfd_elf_string_from_elf_section (bfd *abfd, |
unsigned int shindex, |
unsigned int strindex) |
{ |
Elf_Internal_Shdr *hdr; |
if (strindex == 0) |
return ""; |
if (elf_elfsections (abfd) == NULL || shindex >= elf_numsections (abfd)) |
return NULL; |
hdr = elf_elfsections (abfd)[shindex]; |
if (hdr->contents == NULL |
&& bfd_elf_get_str_section (abfd, shindex) == NULL) |
return NULL; |
if (strindex >= hdr->sh_size) |
{ |
unsigned int shstrndx = elf_elfheader(abfd)->e_shstrndx; |
(*_bfd_error_handler) |
(_("%B: invalid string offset %u >= %lu for section `%s'"), |
abfd, strindex, (unsigned long) hdr->sh_size, |
(shindex == shstrndx && strindex == hdr->sh_name |
? ".shstrtab" |
: bfd_elf_string_from_elf_section (abfd, shstrndx, hdr->sh_name))); |
return NULL; |
} |
return ((char *) hdr->contents) + strindex; |
} |
/* Read and convert symbols to internal format. |
SYMCOUNT specifies the number of symbols to read, starting from |
symbol SYMOFFSET. If any of INTSYM_BUF, EXTSYM_BUF or EXTSHNDX_BUF |
are non-NULL, they are used to store the internal symbols, external |
symbols, and symbol section index extensions, respectively. |
Returns a pointer to the internal symbol buffer (malloced if necessary) |
or NULL if there were no symbols or some kind of problem. */ |
Elf_Internal_Sym * |
bfd_elf_get_elf_syms (bfd *ibfd, |
Elf_Internal_Shdr *symtab_hdr, |
size_t symcount, |
size_t symoffset, |
Elf_Internal_Sym *intsym_buf, |
void *extsym_buf, |
Elf_External_Sym_Shndx *extshndx_buf) |
{ |
Elf_Internal_Shdr *shndx_hdr; |
void *alloc_ext; |
const bfd_byte *esym; |
Elf_External_Sym_Shndx *alloc_extshndx; |
Elf_External_Sym_Shndx *shndx; |
Elf_Internal_Sym *alloc_intsym; |
Elf_Internal_Sym *isym; |
Elf_Internal_Sym *isymend; |
const struct elf_backend_data *bed; |
size_t extsym_size; |
bfd_size_type amt; |
file_ptr pos; |
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) |
abort (); |
if (symcount == 0) |
return intsym_buf; |
/* Normal syms might have section extension entries. */ |
shndx_hdr = NULL; |
if (symtab_hdr == &elf_tdata (ibfd)->symtab_hdr) |
shndx_hdr = &elf_tdata (ibfd)->symtab_shndx_hdr; |
/* Read the symbols. */ |
alloc_ext = NULL; |
alloc_extshndx = NULL; |
alloc_intsym = NULL; |
bed = get_elf_backend_data (ibfd); |
extsym_size = bed->s->sizeof_sym; |
amt = symcount * extsym_size; |
pos = symtab_hdr->sh_offset + symoffset * extsym_size; |
if (extsym_buf == NULL) |
{ |
alloc_ext = bfd_malloc2 (symcount, extsym_size); |
extsym_buf = alloc_ext; |
} |
if (extsym_buf == NULL |
|| bfd_seek (ibfd, pos, SEEK_SET) != 0 |
|| bfd_bread (extsym_buf, amt, ibfd) != amt) |
{ |
intsym_buf = NULL; |
goto out; |
} |
if (shndx_hdr == NULL || shndx_hdr->sh_size == 0) |
extshndx_buf = NULL; |
else |
{ |
amt = symcount * sizeof (Elf_External_Sym_Shndx); |
pos = shndx_hdr->sh_offset + symoffset * sizeof (Elf_External_Sym_Shndx); |
if (extshndx_buf == NULL) |
{ |
alloc_extshndx = (Elf_External_Sym_Shndx *) |
bfd_malloc2 (symcount, sizeof (Elf_External_Sym_Shndx)); |
extshndx_buf = alloc_extshndx; |
} |
if (extshndx_buf == NULL |
|| bfd_seek (ibfd, pos, SEEK_SET) != 0 |
|| bfd_bread (extshndx_buf, amt, ibfd) != amt) |
{ |
intsym_buf = NULL; |
goto out; |
} |
} |
if (intsym_buf == NULL) |
{ |
alloc_intsym = (Elf_Internal_Sym *) |
bfd_malloc2 (symcount, sizeof (Elf_Internal_Sym)); |
intsym_buf = alloc_intsym; |
if (intsym_buf == NULL) |
goto out; |
} |
/* Convert the symbols to internal form. */ |
isymend = intsym_buf + symcount; |
for (esym = (const bfd_byte *) extsym_buf, isym = intsym_buf, |
shndx = extshndx_buf; |
isym < isymend; |
esym += extsym_size, isym++, shndx = shndx != NULL ? shndx + 1 : NULL) |
if (!(*bed->s->swap_symbol_in) (ibfd, esym, shndx, isym)) |
{ |
symoffset += (esym - (bfd_byte *) extsym_buf) / extsym_size; |
(*_bfd_error_handler) (_("%B symbol number %lu references " |
"nonexistent SHT_SYMTAB_SHNDX section"), |
ibfd, (unsigned long) symoffset); |
if (alloc_intsym != NULL) |
free (alloc_intsym); |
intsym_buf = NULL; |
goto out; |
} |
out: |
if (alloc_ext != NULL) |
free (alloc_ext); |
if (alloc_extshndx != NULL) |
free (alloc_extshndx); |
return intsym_buf; |
} |
/* Look up a symbol name. */ |
const char * |
bfd_elf_sym_name (bfd *abfd, |
Elf_Internal_Shdr *symtab_hdr, |
Elf_Internal_Sym *isym, |
asection *sym_sec) |
{ |
const char *name; |
unsigned int iname = isym->st_name; |
unsigned int shindex = symtab_hdr->sh_link; |
if (iname == 0 && ELF_ST_TYPE (isym->st_info) == STT_SECTION |
/* Check for a bogus st_shndx to avoid crashing. */ |
&& isym->st_shndx < elf_numsections (abfd)) |
{ |
iname = elf_elfsections (abfd)[isym->st_shndx]->sh_name; |
shindex = elf_elfheader (abfd)->e_shstrndx; |
} |
name = bfd_elf_string_from_elf_section (abfd, shindex, iname); |
if (name == NULL) |
name = "(null)"; |
else if (sym_sec && *name == '\0') |
name = bfd_section_name (abfd, sym_sec); |
return name; |
} |
/* Elf_Internal_Shdr->contents is an array of these for SHT_GROUP |
sections. The first element is the flags, the rest are section |
pointers. */ |
typedef union elf_internal_group { |
Elf_Internal_Shdr *shdr; |
unsigned int flags; |
} Elf_Internal_Group; |
/* Return the name of the group signature symbol. Why isn't the |
signature just a string? */ |
static const char * |
group_signature (bfd *abfd, Elf_Internal_Shdr *ghdr) |
{ |
Elf_Internal_Shdr *hdr; |
unsigned char esym[sizeof (Elf64_External_Sym)]; |
Elf_External_Sym_Shndx eshndx; |
Elf_Internal_Sym isym; |
/* First we need to ensure the symbol table is available. Make sure |
that it is a symbol table section. */ |
if (ghdr->sh_link >= elf_numsections (abfd)) |
return NULL; |
hdr = elf_elfsections (abfd) [ghdr->sh_link]; |
if (hdr->sh_type != SHT_SYMTAB |
|| ! bfd_section_from_shdr (abfd, ghdr->sh_link)) |
return NULL; |
/* Go read the symbol. */ |
hdr = &elf_tdata (abfd)->symtab_hdr; |
if (bfd_elf_get_elf_syms (abfd, hdr, 1, ghdr->sh_info, |
&isym, esym, &eshndx) == NULL) |
return NULL; |
return bfd_elf_sym_name (abfd, hdr, &isym, NULL); |
} |
/* Set next_in_group list pointer, and group name for NEWSECT. */ |
static bfd_boolean |
setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect) |
{ |
unsigned int num_group = elf_tdata (abfd)->num_group; |
/* If num_group is zero, read in all SHT_GROUP sections. The count |
is set to -1 if there are no SHT_GROUP sections. */ |
if (num_group == 0) |
{ |
unsigned int i, shnum; |
/* First count the number of groups. If we have a SHT_GROUP |
section with just a flag word (ie. sh_size is 4), ignore it. */ |
shnum = elf_numsections (abfd); |
num_group = 0; |
#define IS_VALID_GROUP_SECTION_HEADER(shdr, minsize) \ |
( (shdr)->sh_type == SHT_GROUP \ |
&& (shdr)->sh_size >= minsize \ |
&& (shdr)->sh_entsize == GRP_ENTRY_SIZE \ |
&& ((shdr)->sh_size % GRP_ENTRY_SIZE) == 0) |
for (i = 0; i < shnum; i++) |
{ |
Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i]; |
if (IS_VALID_GROUP_SECTION_HEADER (shdr, 2 * GRP_ENTRY_SIZE)) |
num_group += 1; |
} |
if (num_group == 0) |
{ |
num_group = (unsigned) -1; |
elf_tdata (abfd)->num_group = num_group; |
} |
else |
{ |
/* We keep a list of elf section headers for group sections, |
so we can find them quickly. */ |
bfd_size_type amt; |
elf_tdata (abfd)->num_group = num_group; |
elf_tdata (abfd)->group_sect_ptr = (Elf_Internal_Shdr **) |
bfd_alloc2 (abfd, num_group, sizeof (Elf_Internal_Shdr *)); |
if (elf_tdata (abfd)->group_sect_ptr == NULL) |
return FALSE; |
num_group = 0; |
for (i = 0; i < shnum; i++) |
{ |
Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i]; |
if (IS_VALID_GROUP_SECTION_HEADER (shdr, 2 * GRP_ENTRY_SIZE)) |
{ |
unsigned char *src; |
Elf_Internal_Group *dest; |
/* Add to list of sections. */ |
elf_tdata (abfd)->group_sect_ptr[num_group] = shdr; |
num_group += 1; |
/* Read the raw contents. */ |
BFD_ASSERT (sizeof (*dest) >= 4); |
amt = shdr->sh_size * sizeof (*dest) / 4; |
shdr->contents = (unsigned char *) |
bfd_alloc2 (abfd, shdr->sh_size, sizeof (*dest) / 4); |
/* PR binutils/4110: Handle corrupt group headers. */ |
if (shdr->contents == NULL) |
{ |
_bfd_error_handler |
(_("%B: Corrupt size field in group section header: 0x%lx"), abfd, shdr->sh_size); |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
memset (shdr->contents, 0, amt); |
if (bfd_seek (abfd, shdr->sh_offset, SEEK_SET) != 0 |
|| (bfd_bread (shdr->contents, shdr->sh_size, abfd) |
!= shdr->sh_size)) |
return FALSE; |
/* Translate raw contents, a flag word followed by an |
array of elf section indices all in target byte order, |
to the flag word followed by an array of elf section |
pointers. */ |
src = shdr->contents + shdr->sh_size; |
dest = (Elf_Internal_Group *) (shdr->contents + amt); |
while (1) |
{ |
unsigned int idx; |
src -= 4; |
--dest; |
idx = H_GET_32 (abfd, src); |
if (src == shdr->contents) |
{ |
dest->flags = idx; |
if (shdr->bfd_section != NULL && (idx & GRP_COMDAT)) |
shdr->bfd_section->flags |
|= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; |
break; |
} |
if (idx >= shnum) |
{ |
((*_bfd_error_handler) |
(_("%B: invalid SHT_GROUP entry"), abfd)); |
idx = 0; |
} |
dest->shdr = elf_elfsections (abfd)[idx]; |
} |
} |
} |
} |
} |
if (num_group != (unsigned) -1) |
{ |
unsigned int i; |
for (i = 0; i < num_group; i++) |
{ |
Elf_Internal_Shdr *shdr = elf_tdata (abfd)->group_sect_ptr[i]; |
Elf_Internal_Group *idx = (Elf_Internal_Group *) shdr->contents; |
unsigned int n_elt = shdr->sh_size / 4; |
/* Look through this group's sections to see if current |
section is a member. */ |
while (--n_elt != 0) |
if ((++idx)->shdr == hdr) |
{ |
asection *s = NULL; |
/* We are a member of this group. Go looking through |
other members to see if any others are linked via |
next_in_group. */ |
idx = (Elf_Internal_Group *) shdr->contents; |
n_elt = shdr->sh_size / 4; |
while (--n_elt != 0) |
if ((s = (++idx)->shdr->bfd_section) != NULL |
&& elf_next_in_group (s) != NULL) |
break; |
if (n_elt != 0) |
{ |
/* Snarf the group name from other member, and |
insert current section in circular list. */ |
elf_group_name (newsect) = elf_group_name (s); |
elf_next_in_group (newsect) = elf_next_in_group (s); |
elf_next_in_group (s) = newsect; |
} |
else |
{ |
const char *gname; |
gname = group_signature (abfd, shdr); |
if (gname == NULL) |
return FALSE; |
elf_group_name (newsect) = gname; |
/* Start a circular list with one element. */ |
elf_next_in_group (newsect) = newsect; |
} |
/* If the group section has been created, point to the |
new member. */ |
if (shdr->bfd_section != NULL) |
elf_next_in_group (shdr->bfd_section) = newsect; |
i = num_group - 1; |
break; |
} |
} |
} |
if (elf_group_name (newsect) == NULL) |
{ |
(*_bfd_error_handler) (_("%B: no group info for section %A"), |
abfd, newsect); |
} |
return TRUE; |
} |
bfd_boolean |
_bfd_elf_setup_sections (bfd *abfd) |
{ |
unsigned int i; |
unsigned int num_group = elf_tdata (abfd)->num_group; |
bfd_boolean result = TRUE; |
asection *s; |
/* Process SHF_LINK_ORDER. */ |
for (s = abfd->sections; s != NULL; s = s->next) |
{ |
Elf_Internal_Shdr *this_hdr = &elf_section_data (s)->this_hdr; |
if ((this_hdr->sh_flags & SHF_LINK_ORDER) != 0) |
{ |
unsigned int elfsec = this_hdr->sh_link; |
/* FIXME: The old Intel compiler and old strip/objcopy may |
not set the sh_link or sh_info fields. Hence we could |
get the situation where elfsec is 0. */ |
if (elfsec == 0) |
{ |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
if (bed->link_order_error_handler) |
bed->link_order_error_handler |
(_("%B: warning: sh_link not set for section `%A'"), |
abfd, s); |
} |
else |
{ |
asection *linksec = NULL; |
if (elfsec < elf_numsections (abfd)) |
{ |
this_hdr = elf_elfsections (abfd)[elfsec]; |
linksec = this_hdr->bfd_section; |
} |
/* PR 1991, 2008: |
Some strip/objcopy may leave an incorrect value in |
sh_link. We don't want to proceed. */ |
if (linksec == NULL) |
{ |
(*_bfd_error_handler) |
(_("%B: sh_link [%d] in section `%A' is incorrect"), |
s->owner, s, elfsec); |
result = FALSE; |
} |
elf_linked_to_section (s) = linksec; |
} |
} |
} |
/* Process section groups. */ |
if (num_group == (unsigned) -1) |
return result; |
for (i = 0; i < num_group; i++) |
{ |
Elf_Internal_Shdr *shdr = elf_tdata (abfd)->group_sect_ptr[i]; |
Elf_Internal_Group *idx = (Elf_Internal_Group *) shdr->contents; |
unsigned int n_elt = shdr->sh_size / 4; |
while (--n_elt != 0) |
if ((++idx)->shdr->bfd_section) |
elf_sec_group (idx->shdr->bfd_section) = shdr->bfd_section; |
else if (idx->shdr->sh_type == SHT_RELA |
|| idx->shdr->sh_type == SHT_REL) |
/* We won't include relocation sections in section groups in |
output object files. We adjust the group section size here |
so that relocatable link will work correctly when |
relocation sections are in section group in input object |
files. */ |
shdr->bfd_section->size -= 4; |
else |
{ |
/* There are some unknown sections in the group. */ |
(*_bfd_error_handler) |
(_("%B: unknown [%d] section `%s' in group [%s]"), |
abfd, |
(unsigned int) idx->shdr->sh_type, |
bfd_elf_string_from_elf_section (abfd, |
(elf_elfheader (abfd) |
->e_shstrndx), |
idx->shdr->sh_name), |
shdr->bfd_section->name); |
result = FALSE; |
} |
} |
return result; |
} |
bfd_boolean |
bfd_elf_is_group_section (bfd *abfd ATTRIBUTE_UNUSED, const asection *sec) |
{ |
return elf_next_in_group (sec) != NULL; |
} |
/* Make a BFD section from an ELF section. We store a pointer to the |
BFD section in the bfd_section field of the header. */ |
bfd_boolean |
_bfd_elf_make_section_from_shdr (bfd *abfd, |
Elf_Internal_Shdr *hdr, |
const char *name, |
int shindex) |
{ |
asection *newsect; |
flagword flags; |
const struct elf_backend_data *bed; |
if (hdr->bfd_section != NULL) |
return TRUE; |
newsect = bfd_make_section_anyway (abfd, name); |
if (newsect == NULL) |
return FALSE; |
hdr->bfd_section = newsect; |
elf_section_data (newsect)->this_hdr = *hdr; |
elf_section_data (newsect)->this_idx = shindex; |
/* Always use the real type/flags. */ |
elf_section_type (newsect) = hdr->sh_type; |
elf_section_flags (newsect) = hdr->sh_flags; |
newsect->filepos = hdr->sh_offset; |
if (! bfd_set_section_vma (abfd, newsect, hdr->sh_addr) |
|| ! bfd_set_section_size (abfd, newsect, hdr->sh_size) |
|| ! bfd_set_section_alignment (abfd, newsect, |
bfd_log2 (hdr->sh_addralign))) |
return FALSE; |
flags = SEC_NO_FLAGS; |
if (hdr->sh_type != SHT_NOBITS) |
flags |= SEC_HAS_CONTENTS; |
if (hdr->sh_type == SHT_GROUP) |
flags |= SEC_GROUP | SEC_EXCLUDE; |
if ((hdr->sh_flags & SHF_ALLOC) != 0) |
{ |
flags |= SEC_ALLOC; |
if (hdr->sh_type != SHT_NOBITS) |
flags |= SEC_LOAD; |
} |
if ((hdr->sh_flags & SHF_WRITE) == 0) |
flags |= SEC_READONLY; |
if ((hdr->sh_flags & SHF_EXECINSTR) != 0) |
flags |= SEC_CODE; |
else if ((flags & SEC_LOAD) != 0) |
flags |= SEC_DATA; |
if ((hdr->sh_flags & SHF_MERGE) != 0) |
{ |
flags |= SEC_MERGE; |
newsect->entsize = hdr->sh_entsize; |
if ((hdr->sh_flags & SHF_STRINGS) != 0) |
flags |= SEC_STRINGS; |
} |
if (hdr->sh_flags & SHF_GROUP) |
if (!setup_group (abfd, hdr, newsect)) |
return FALSE; |
if ((hdr->sh_flags & SHF_TLS) != 0) |
flags |= SEC_THREAD_LOCAL; |
if ((hdr->sh_flags & SHF_EXCLUDE) != 0) |
flags |= SEC_EXCLUDE; |
if ((flags & SEC_ALLOC) == 0) |
{ |
/* The debugging sections appear to be recognized only by name, |
not any sort of flag. Their SEC_ALLOC bits are cleared. */ |
if (name [0] == '.') |
{ |
const char *p; |
int n; |
if (name[1] == 'd') |
p = ".debug", n = 6; |
else if (name[1] == 'g' && name[2] == 'n') |
p = ".gnu.linkonce.wi.", n = 17; |
else if (name[1] == 'g' && name[2] == 'd') |
p = ".gdb_index", n = 11; /* yes we really do mean 11. */ |
else if (name[1] == 'l') |
p = ".line", n = 5; |
else if (name[1] == 's') |
p = ".stab", n = 5; |
else if (name[1] == 'z') |
p = ".zdebug", n = 7; |
else |
p = NULL, n = 0; |
if (p != NULL && strncmp (name, p, n) == 0) |
flags |= SEC_DEBUGGING; |
} |
} |
/* As a GNU extension, if the name begins with .gnu.linkonce, we |
only link a single copy of the section. This is used to support |
g++. g++ will emit each template expansion in its own section. |
The symbols will be defined as weak, so that multiple definitions |
are permitted. The GNU linker extension is to actually discard |
all but one of the sections. */ |
if (CONST_STRNEQ (name, ".gnu.linkonce") |
&& elf_next_in_group (newsect) == NULL) |
flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; |
bed = get_elf_backend_data (abfd); |
if (bed->elf_backend_section_flags) |
if (! bed->elf_backend_section_flags (&flags, hdr)) |
return FALSE; |
if (! bfd_set_section_flags (abfd, newsect, flags)) |
return FALSE; |
/* We do not parse the PT_NOTE segments as we are interested even in the |
separate debug info files which may have the segments offsets corrupted. |
PT_NOTEs from the core files are currently not parsed using BFD. */ |
if (hdr->sh_type == SHT_NOTE) |
{ |
bfd_byte *contents; |
if (!bfd_malloc_and_get_section (abfd, newsect, &contents)) |
return FALSE; |
elf_parse_notes (abfd, (char *) contents, hdr->sh_size, -1); |
free (contents); |
} |
if ((flags & SEC_ALLOC) != 0) |
{ |
Elf_Internal_Phdr *phdr; |
unsigned int i, nload; |
/* Some ELF linkers produce binaries with all the program header |
p_paddr fields zero. If we have such a binary with more than |
one PT_LOAD header, then leave the section lma equal to vma |
so that we don't create sections with overlapping lma. */ |
phdr = elf_tdata (abfd)->phdr; |
for (nload = 0, i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++) |
if (phdr->p_paddr != 0) |
break; |
else if (phdr->p_type == PT_LOAD && phdr->p_memsz != 0) |
++nload; |
if (i >= elf_elfheader (abfd)->e_phnum && nload > 1) |
return TRUE; |
phdr = elf_tdata (abfd)->phdr; |
for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++) |
{ |
if (((phdr->p_type == PT_LOAD |
&& (hdr->sh_flags & SHF_TLS) == 0) |
|| phdr->p_type == PT_TLS) |
&& ELF_SECTION_IN_SEGMENT (hdr, phdr)) |
{ |
if ((flags & SEC_LOAD) == 0) |
newsect->lma = (phdr->p_paddr |
+ hdr->sh_addr - phdr->p_vaddr); |
else |
/* We used to use the same adjustment for SEC_LOAD |
sections, but that doesn't work if the segment |
is packed with code from multiple VMAs. |
Instead we calculate the section LMA based on |
the segment LMA. It is assumed that the |
segment will contain sections with contiguous |
LMAs, even if the VMAs are not. */ |
newsect->lma = (phdr->p_paddr |
+ hdr->sh_offset - phdr->p_offset); |
/* With contiguous segments, we can't tell from file |
offsets whether a section with zero size should |
be placed at the end of one segment or the |
beginning of the next. Decide based on vaddr. */ |
if (hdr->sh_addr >= phdr->p_vaddr |
&& (hdr->sh_addr + hdr->sh_size |
<= phdr->p_vaddr + phdr->p_memsz)) |
break; |
} |
} |
} |
/* Compress/decompress DWARF debug sections with names: .debug_* and |
.zdebug_*, after the section flags is set. */ |
if ((flags & SEC_DEBUGGING) |
&& ((name[1] == 'd' && name[6] == '_') |
|| (name[1] == 'z' && name[7] == '_'))) |
{ |
enum { nothing, compress, decompress } action = nothing; |
char *new_name; |
if (bfd_is_section_compressed (abfd, newsect)) |
{ |
/* Compressed section. Check if we should decompress. */ |
if ((abfd->flags & BFD_DECOMPRESS)) |
action = decompress; |
} |
else |
{ |
/* Normal section. Check if we should compress. */ |
if ((abfd->flags & BFD_COMPRESS) && newsect->size != 0) |
action = compress; |
} |
new_name = NULL; |
switch (action) |
{ |
case nothing: |
break; |
case compress: |
if (!bfd_init_section_compress_status (abfd, newsect)) |
{ |
(*_bfd_error_handler) |
(_("%B: unable to initialize compress status for section %s"), |
abfd, name); |
return FALSE; |
} |
if (name[1] != 'z') |
{ |
unsigned int len = strlen (name); |
new_name = bfd_alloc (abfd, len + 2); |
if (new_name == NULL) |
return FALSE; |
new_name[0] = '.'; |
new_name[1] = 'z'; |
memcpy (new_name + 2, name + 1, len); |
} |
break; |
case decompress: |
if (!bfd_init_section_decompress_status (abfd, newsect)) |
{ |
(*_bfd_error_handler) |
(_("%B: unable to initialize decompress status for section %s"), |
abfd, name); |
return FALSE; |
} |
if (name[1] == 'z') |
{ |
unsigned int len = strlen (name); |
new_name = bfd_alloc (abfd, len); |
if (new_name == NULL) |
return FALSE; |
new_name[0] = '.'; |
memcpy (new_name + 1, name + 2, len - 1); |
} |
break; |
} |
if (new_name != NULL) |
bfd_rename_section (abfd, newsect, new_name); |
} |
return TRUE; |
} |
const char *const bfd_elf_section_type_names[] = { |
"SHT_NULL", "SHT_PROGBITS", "SHT_SYMTAB", "SHT_STRTAB", |
"SHT_RELA", "SHT_HASH", "SHT_DYNAMIC", "SHT_NOTE", |
"SHT_NOBITS", "SHT_REL", "SHT_SHLIB", "SHT_DYNSYM", |
}; |
/* ELF relocs are against symbols. If we are producing relocatable |
output, and the reloc is against an external symbol, and nothing |
has given us any additional addend, the resulting reloc will also |
be against the same symbol. In such a case, we don't want to |
change anything about the way the reloc is handled, since it will |
all be done at final link time. Rather than put special case code |
into bfd_perform_relocation, all the reloc types use this howto |
function. It just short circuits the reloc if producing |
relocatable output against an external symbol. */ |
bfd_reloc_status_type |
bfd_elf_generic_reloc (bfd *abfd ATTRIBUTE_UNUSED, |
arelent *reloc_entry, |
asymbol *symbol, |
void *data ATTRIBUTE_UNUSED, |
asection *input_section, |
bfd *output_bfd, |
char **error_message ATTRIBUTE_UNUSED) |
{ |
if (output_bfd != NULL |
&& (symbol->flags & BSF_SECTION_SYM) == 0 |
&& (! reloc_entry->howto->partial_inplace |
|| reloc_entry->addend == 0)) |
{ |
reloc_entry->address += input_section->output_offset; |
return bfd_reloc_ok; |
} |
return bfd_reloc_continue; |
} |
/* Copy the program header and other data from one object module to |
another. */ |
bfd_boolean |
_bfd_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd) |
{ |
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour |
|| bfd_get_flavour (obfd) != bfd_target_elf_flavour) |
return TRUE; |
BFD_ASSERT (!elf_flags_init (obfd) |
|| (elf_elfheader (obfd)->e_flags |
== elf_elfheader (ibfd)->e_flags)); |
elf_gp (obfd) = elf_gp (ibfd); |
elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags; |
elf_flags_init (obfd) = TRUE; |
/* Copy object attributes. */ |
_bfd_elf_copy_obj_attributes (ibfd, obfd); |
return TRUE; |
} |
static const char * |
get_segment_type (unsigned int p_type) |
{ |
const char *pt; |
switch (p_type) |
{ |
case PT_NULL: pt = "NULL"; break; |
case PT_LOAD: pt = "LOAD"; break; |
case PT_DYNAMIC: pt = "DYNAMIC"; break; |
case PT_INTERP: pt = "INTERP"; break; |
case PT_NOTE: pt = "NOTE"; break; |
case PT_SHLIB: pt = "SHLIB"; break; |
case PT_PHDR: pt = "PHDR"; break; |
case PT_TLS: pt = "TLS"; break; |
case PT_GNU_EH_FRAME: pt = "EH_FRAME"; break; |
case PT_GNU_STACK: pt = "STACK"; break; |
case PT_GNU_RELRO: pt = "RELRO"; break; |
default: pt = NULL; break; |
} |
return pt; |
} |
/* Print out the program headers. */ |
bfd_boolean |
_bfd_elf_print_private_bfd_data (bfd *abfd, void *farg) |
{ |
FILE *f = (FILE *) farg; |
Elf_Internal_Phdr *p; |
asection *s; |
bfd_byte *dynbuf = NULL; |
p = elf_tdata (abfd)->phdr; |
if (p != NULL) |
{ |
unsigned int i, c; |
fprintf (f, _("\nProgram Header:\n")); |
c = elf_elfheader (abfd)->e_phnum; |
for (i = 0; i < c; i++, p++) |
{ |
const char *pt = get_segment_type (p->p_type); |
char buf[20]; |
if (pt == NULL) |
{ |
sprintf (buf, "0x%lx", p->p_type); |
pt = buf; |
} |
fprintf (f, "%8s off 0x", pt); |
bfd_fprintf_vma (abfd, f, p->p_offset); |
fprintf (f, " vaddr 0x"); |
bfd_fprintf_vma (abfd, f, p->p_vaddr); |
fprintf (f, " paddr 0x"); |
bfd_fprintf_vma (abfd, f, p->p_paddr); |
fprintf (f, " align 2**%u\n", bfd_log2 (p->p_align)); |
fprintf (f, " filesz 0x"); |
bfd_fprintf_vma (abfd, f, p->p_filesz); |
fprintf (f, " memsz 0x"); |
bfd_fprintf_vma (abfd, f, p->p_memsz); |
fprintf (f, " flags %c%c%c", |
(p->p_flags & PF_R) != 0 ? 'r' : '-', |
(p->p_flags & PF_W) != 0 ? 'w' : '-', |
(p->p_flags & PF_X) != 0 ? 'x' : '-'); |
if ((p->p_flags &~ (unsigned) (PF_R | PF_W | PF_X)) != 0) |
fprintf (f, " %lx", p->p_flags &~ (unsigned) (PF_R | PF_W | PF_X)); |
fprintf (f, "\n"); |
} |
} |
s = bfd_get_section_by_name (abfd, ".dynamic"); |
if (s != NULL) |
{ |
unsigned int elfsec; |
unsigned long shlink; |
bfd_byte *extdyn, *extdynend; |
size_t extdynsize; |
void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *); |
fprintf (f, _("\nDynamic Section:\n")); |
if (!bfd_malloc_and_get_section (abfd, s, &dynbuf)) |
goto error_return; |
elfsec = _bfd_elf_section_from_bfd_section (abfd, s); |
if (elfsec == SHN_BAD) |
goto error_return; |
shlink = elf_elfsections (abfd)[elfsec]->sh_link; |
extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn; |
swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in; |
extdyn = dynbuf; |
extdynend = extdyn + s->size; |
for (; extdyn < extdynend; extdyn += extdynsize) |
{ |
Elf_Internal_Dyn dyn; |
const char *name = ""; |
char ab[20]; |
bfd_boolean stringp; |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
(*swap_dyn_in) (abfd, extdyn, &dyn); |
if (dyn.d_tag == DT_NULL) |
break; |
stringp = FALSE; |
switch (dyn.d_tag) |
{ |
default: |
if (bed->elf_backend_get_target_dtag) |
name = (*bed->elf_backend_get_target_dtag) (dyn.d_tag); |
if (!strcmp (name, "")) |
{ |
sprintf (ab, "0x%lx", (unsigned long) dyn.d_tag); |
name = ab; |
} |
break; |
case DT_NEEDED: name = "NEEDED"; stringp = TRUE; break; |
case DT_PLTRELSZ: name = "PLTRELSZ"; break; |
case DT_PLTGOT: name = "PLTGOT"; break; |
case DT_HASH: name = "HASH"; break; |
case DT_STRTAB: name = "STRTAB"; break; |
case DT_SYMTAB: name = "SYMTAB"; break; |
case DT_RELA: name = "RELA"; break; |
case DT_RELASZ: name = "RELASZ"; break; |
case DT_RELAENT: name = "RELAENT"; break; |
case DT_STRSZ: name = "STRSZ"; break; |
case DT_SYMENT: name = "SYMENT"; break; |
case DT_INIT: name = "INIT"; break; |
case DT_FINI: name = "FINI"; break; |
case DT_SONAME: name = "SONAME"; stringp = TRUE; break; |
case DT_RPATH: name = "RPATH"; stringp = TRUE; break; |
case DT_SYMBOLIC: name = "SYMBOLIC"; break; |
case DT_REL: name = "REL"; break; |
case DT_RELSZ: name = "RELSZ"; break; |
case DT_RELENT: name = "RELENT"; break; |
case DT_PLTREL: name = "PLTREL"; break; |
case DT_DEBUG: name = "DEBUG"; break; |
case DT_TEXTREL: name = "TEXTREL"; break; |
case DT_JMPREL: name = "JMPREL"; break; |
case DT_BIND_NOW: name = "BIND_NOW"; break; |
case DT_INIT_ARRAY: name = "INIT_ARRAY"; break; |
case DT_FINI_ARRAY: name = "FINI_ARRAY"; break; |
case DT_INIT_ARRAYSZ: name = "INIT_ARRAYSZ"; break; |
case DT_FINI_ARRAYSZ: name = "FINI_ARRAYSZ"; break; |
case DT_RUNPATH: name = "RUNPATH"; stringp = TRUE; break; |
case DT_FLAGS: name = "FLAGS"; break; |
case DT_PREINIT_ARRAY: name = "PREINIT_ARRAY"; break; |
case DT_PREINIT_ARRAYSZ: name = "PREINIT_ARRAYSZ"; break; |
case DT_CHECKSUM: name = "CHECKSUM"; break; |
case DT_PLTPADSZ: name = "PLTPADSZ"; break; |
case DT_MOVEENT: name = "MOVEENT"; break; |
case DT_MOVESZ: name = "MOVESZ"; break; |
case DT_FEATURE: name = "FEATURE"; break; |
case DT_POSFLAG_1: name = "POSFLAG_1"; break; |
case DT_SYMINSZ: name = "SYMINSZ"; break; |
case DT_SYMINENT: name = "SYMINENT"; break; |
case DT_CONFIG: name = "CONFIG"; stringp = TRUE; break; |
case DT_DEPAUDIT: name = "DEPAUDIT"; stringp = TRUE; break; |
case DT_AUDIT: name = "AUDIT"; stringp = TRUE; break; |
case DT_PLTPAD: name = "PLTPAD"; break; |
case DT_MOVETAB: name = "MOVETAB"; break; |
case DT_SYMINFO: name = "SYMINFO"; break; |
case DT_RELACOUNT: name = "RELACOUNT"; break; |
case DT_RELCOUNT: name = "RELCOUNT"; break; |
case DT_FLAGS_1: name = "FLAGS_1"; break; |
case DT_VERSYM: name = "VERSYM"; break; |
case DT_VERDEF: name = "VERDEF"; break; |
case DT_VERDEFNUM: name = "VERDEFNUM"; break; |
case DT_VERNEED: name = "VERNEED"; break; |
case DT_VERNEEDNUM: name = "VERNEEDNUM"; break; |
case DT_AUXILIARY: name = "AUXILIARY"; stringp = TRUE; break; |
case DT_USED: name = "USED"; break; |
case DT_FILTER: name = "FILTER"; stringp = TRUE; break; |
case DT_GNU_HASH: name = "GNU_HASH"; break; |
} |
fprintf (f, " %-20s ", name); |
if (! stringp) |
{ |
fprintf (f, "0x"); |
bfd_fprintf_vma (abfd, f, dyn.d_un.d_val); |
} |
else |
{ |
const char *string; |
unsigned int tagv = dyn.d_un.d_val; |
string = bfd_elf_string_from_elf_section (abfd, shlink, tagv); |
if (string == NULL) |
goto error_return; |
fprintf (f, "%s", string); |
} |
fprintf (f, "\n"); |
} |
free (dynbuf); |
dynbuf = NULL; |
} |
if ((elf_dynverdef (abfd) != 0 && elf_tdata (abfd)->verdef == NULL) |
|| (elf_dynverref (abfd) != 0 && elf_tdata (abfd)->verref == NULL)) |
{ |
if (! _bfd_elf_slurp_version_tables (abfd, FALSE)) |
return FALSE; |
} |
if (elf_dynverdef (abfd) != 0) |
{ |
Elf_Internal_Verdef *t; |
fprintf (f, _("\nVersion definitions:\n")); |
for (t = elf_tdata (abfd)->verdef; t != NULL; t = t->vd_nextdef) |
{ |
fprintf (f, "%d 0x%2.2x 0x%8.8lx %s\n", t->vd_ndx, |
t->vd_flags, t->vd_hash, |
t->vd_nodename ? t->vd_nodename : "<corrupt>"); |
if (t->vd_auxptr != NULL && t->vd_auxptr->vda_nextptr != NULL) |
{ |
Elf_Internal_Verdaux *a; |
fprintf (f, "\t"); |
for (a = t->vd_auxptr->vda_nextptr; |
a != NULL; |
a = a->vda_nextptr) |
fprintf (f, "%s ", |
a->vda_nodename ? a->vda_nodename : "<corrupt>"); |
fprintf (f, "\n"); |
} |
} |
} |
if (elf_dynverref (abfd) != 0) |
{ |
Elf_Internal_Verneed *t; |
fprintf (f, _("\nVersion References:\n")); |
for (t = elf_tdata (abfd)->verref; t != NULL; t = t->vn_nextref) |
{ |
Elf_Internal_Vernaux *a; |
fprintf (f, _(" required from %s:\n"), |
t->vn_filename ? t->vn_filename : "<corrupt>"); |
for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr) |
fprintf (f, " 0x%8.8lx 0x%2.2x %2.2d %s\n", a->vna_hash, |
a->vna_flags, a->vna_other, |
a->vna_nodename ? a->vna_nodename : "<corrupt>"); |
} |
} |
return TRUE; |
error_return: |
if (dynbuf != NULL) |
free (dynbuf); |
return FALSE; |
} |
/* Display ELF-specific fields of a symbol. */ |
void |
bfd_elf_print_symbol (bfd *abfd, |
void *filep, |
asymbol *symbol, |
bfd_print_symbol_type how) |
{ |
FILE *file = (FILE *) filep; |
switch (how) |
{ |
case bfd_print_symbol_name: |
fprintf (file, "%s", symbol->name); |
break; |
case bfd_print_symbol_more: |
fprintf (file, "elf "); |
bfd_fprintf_vma (abfd, file, symbol->value); |
fprintf (file, " %lx", (unsigned long) symbol->flags); |
break; |
case bfd_print_symbol_all: |
{ |
const char *section_name; |
const char *name = NULL; |
const struct elf_backend_data *bed; |
unsigned char st_other; |
bfd_vma val; |
section_name = symbol->section ? symbol->section->name : "(*none*)"; |
bed = get_elf_backend_data (abfd); |
if (bed->elf_backend_print_symbol_all) |
name = (*bed->elf_backend_print_symbol_all) (abfd, filep, symbol); |
if (name == NULL) |
{ |
name = symbol->name; |
bfd_print_symbol_vandf (abfd, file, symbol); |
} |
fprintf (file, " %s\t", section_name); |
/* Print the "other" value for a symbol. For common symbols, |
we've already printed the size; now print the alignment. |
For other symbols, we have no specified alignment, and |
we've printed the address; now print the size. */ |
if (symbol->section && bfd_is_com_section (symbol->section)) |
val = ((elf_symbol_type *) symbol)->internal_elf_sym.st_value; |
else |
val = ((elf_symbol_type *) symbol)->internal_elf_sym.st_size; |
bfd_fprintf_vma (abfd, file, val); |
/* If we have version information, print it. */ |
if (elf_dynversym (abfd) != 0 |
&& (elf_dynverdef (abfd) != 0 |
|| elf_dynverref (abfd) != 0)) |
{ |
unsigned int vernum; |
const char *version_string; |
vernum = ((elf_symbol_type *) symbol)->version & VERSYM_VERSION; |
if (vernum == 0) |
version_string = ""; |
else if (vernum == 1) |
version_string = "Base"; |
else if (vernum <= elf_tdata (abfd)->cverdefs) |
version_string = |
elf_tdata (abfd)->verdef[vernum - 1].vd_nodename; |
else |
{ |
Elf_Internal_Verneed *t; |
version_string = ""; |
for (t = elf_tdata (abfd)->verref; |
t != NULL; |
t = t->vn_nextref) |
{ |
Elf_Internal_Vernaux *a; |
for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr) |
{ |
if (a->vna_other == vernum) |
{ |
version_string = a->vna_nodename; |
break; |
} |
} |
} |
} |
if ((((elf_symbol_type *) symbol)->version & VERSYM_HIDDEN) == 0) |
fprintf (file, " %-11s", version_string); |
else |
{ |
int i; |
fprintf (file, " (%s)", version_string); |
for (i = 10 - strlen (version_string); i > 0; --i) |
putc (' ', file); |
} |
} |
/* If the st_other field is not zero, print it. */ |
st_other = ((elf_symbol_type *) symbol)->internal_elf_sym.st_other; |
switch (st_other) |
{ |
case 0: break; |
case STV_INTERNAL: fprintf (file, " .internal"); break; |
case STV_HIDDEN: fprintf (file, " .hidden"); break; |
case STV_PROTECTED: fprintf (file, " .protected"); break; |
default: |
/* Some other non-defined flags are also present, so print |
everything hex. */ |
fprintf (file, " 0x%02x", (unsigned int) st_other); |
} |
fprintf (file, " %s", name); |
} |
break; |
} |
} |
/* Allocate an ELF string table--force the first byte to be zero. */ |
struct bfd_strtab_hash * |
_bfd_elf_stringtab_init (void) |
{ |
struct bfd_strtab_hash *ret; |
ret = _bfd_stringtab_init (); |
if (ret != NULL) |
{ |
bfd_size_type loc; |
loc = _bfd_stringtab_add (ret, "", TRUE, FALSE); |
BFD_ASSERT (loc == 0 || loc == (bfd_size_type) -1); |
if (loc == (bfd_size_type) -1) |
{ |
_bfd_stringtab_free (ret); |
ret = NULL; |
} |
} |
return ret; |
} |
/* ELF .o/exec file reading */ |
/* Create a new bfd section from an ELF section header. */ |
bfd_boolean |
bfd_section_from_shdr (bfd *abfd, unsigned int shindex) |
{ |
Elf_Internal_Shdr *hdr; |
Elf_Internal_Ehdr *ehdr; |
const struct elf_backend_data *bed; |
const char *name; |
if (shindex >= elf_numsections (abfd)) |
return FALSE; |
hdr = elf_elfsections (abfd)[shindex]; |
ehdr = elf_elfheader (abfd); |
name = bfd_elf_string_from_elf_section (abfd, ehdr->e_shstrndx, |
hdr->sh_name); |
if (name == NULL) |
return FALSE; |
bed = get_elf_backend_data (abfd); |
switch (hdr->sh_type) |
{ |
case SHT_NULL: |
/* Inactive section. Throw it away. */ |
return TRUE; |
case SHT_PROGBITS: /* Normal section with contents. */ |
case SHT_NOBITS: /* .bss section. */ |
case SHT_HASH: /* .hash section. */ |
case SHT_NOTE: /* .note section. */ |
case SHT_INIT_ARRAY: /* .init_array section. */ |
case SHT_FINI_ARRAY: /* .fini_array section. */ |
case SHT_PREINIT_ARRAY: /* .preinit_array section. */ |
case SHT_GNU_LIBLIST: /* .gnu.liblist section. */ |
case SHT_GNU_HASH: /* .gnu.hash section. */ |
return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); |
case SHT_DYNAMIC: /* Dynamic linking information. */ |
if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) |
return FALSE; |
if (hdr->sh_link > elf_numsections (abfd)) |
{ |
/* PR 10478: Accept Solaris binaries with a sh_link |
field set to SHN_BEFORE or SHN_AFTER. */ |
switch (bfd_get_arch (abfd)) |
{ |
case bfd_arch_i386: |
case bfd_arch_sparc: |
if (hdr->sh_link == (SHN_LORESERVE & 0xffff) /* SHN_BEFORE */ |
|| hdr->sh_link == ((SHN_LORESERVE + 1) & 0xffff) /* SHN_AFTER */) |
break; |
/* Otherwise fall through. */ |
default: |
return FALSE; |
} |
} |
else if (elf_elfsections (abfd)[hdr->sh_link] == NULL) |
return FALSE; |
else if (elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_STRTAB) |
{ |
Elf_Internal_Shdr *dynsymhdr; |
/* The shared libraries distributed with hpux11 have a bogus |
sh_link field for the ".dynamic" section. Find the |
string table for the ".dynsym" section instead. */ |
if (elf_dynsymtab (abfd) != 0) |
{ |
dynsymhdr = elf_elfsections (abfd)[elf_dynsymtab (abfd)]; |
hdr->sh_link = dynsymhdr->sh_link; |
} |
else |
{ |
unsigned int i, num_sec; |
num_sec = elf_numsections (abfd); |
for (i = 1; i < num_sec; i++) |
{ |
dynsymhdr = elf_elfsections (abfd)[i]; |
if (dynsymhdr->sh_type == SHT_DYNSYM) |
{ |
hdr->sh_link = dynsymhdr->sh_link; |
break; |
} |
} |
} |
} |
break; |
case SHT_SYMTAB: /* A symbol table */ |
if (elf_onesymtab (abfd) == shindex) |
return TRUE; |
if (hdr->sh_entsize != bed->s->sizeof_sym) |
return FALSE; |
if (hdr->sh_info * hdr->sh_entsize > hdr->sh_size) |
{ |
if (hdr->sh_size != 0) |
return FALSE; |
/* Some assemblers erroneously set sh_info to one with a |
zero sh_size. ld sees this as a global symbol count |
of (unsigned) -1. Fix it here. */ |
hdr->sh_info = 0; |
return TRUE; |
} |
BFD_ASSERT (elf_onesymtab (abfd) == 0); |
elf_onesymtab (abfd) = shindex; |
elf_tdata (abfd)->symtab_hdr = *hdr; |
elf_elfsections (abfd)[shindex] = hdr = &elf_tdata (abfd)->symtab_hdr; |
abfd->flags |= HAS_SYMS; |
/* Sometimes a shared object will map in the symbol table. If |
SHF_ALLOC is set, and this is a shared object, then we also |
treat this section as a BFD section. We can not base the |
decision purely on SHF_ALLOC, because that flag is sometimes |
set in a relocatable object file, which would confuse the |
linker. */ |
if ((hdr->sh_flags & SHF_ALLOC) != 0 |
&& (abfd->flags & DYNAMIC) != 0 |
&& ! _bfd_elf_make_section_from_shdr (abfd, hdr, name, |
shindex)) |
return FALSE; |
/* Go looking for SHT_SYMTAB_SHNDX too, since if there is one we |
can't read symbols without that section loaded as well. It |
is most likely specified by the next section header. */ |
if (elf_elfsections (abfd)[elf_symtab_shndx (abfd)]->sh_link != shindex) |
{ |
unsigned int i, num_sec; |
num_sec = elf_numsections (abfd); |
for (i = shindex + 1; i < num_sec; i++) |
{ |
Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i]; |
if (hdr2->sh_type == SHT_SYMTAB_SHNDX |
&& hdr2->sh_link == shindex) |
break; |
} |
if (i == num_sec) |
for (i = 1; i < shindex; i++) |
{ |
Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i]; |
if (hdr2->sh_type == SHT_SYMTAB_SHNDX |
&& hdr2->sh_link == shindex) |
break; |
} |
if (i != shindex) |
return bfd_section_from_shdr (abfd, i); |
} |
return TRUE; |
case SHT_DYNSYM: /* A dynamic symbol table */ |
if (elf_dynsymtab (abfd) == shindex) |
return TRUE; |
if (hdr->sh_entsize != bed->s->sizeof_sym) |
return FALSE; |
if (hdr->sh_info * hdr->sh_entsize > hdr->sh_size) |
{ |
if (hdr->sh_size != 0) |
return FALSE; |
/* Some linkers erroneously set sh_info to one with a |
zero sh_size. ld sees this as a global symbol count |
of (unsigned) -1. Fix it here. */ |
hdr->sh_info = 0; |
return TRUE; |
} |
BFD_ASSERT (elf_dynsymtab (abfd) == 0); |
elf_dynsymtab (abfd) = shindex; |
elf_tdata (abfd)->dynsymtab_hdr = *hdr; |
elf_elfsections (abfd)[shindex] = hdr = &elf_tdata (abfd)->dynsymtab_hdr; |
abfd->flags |= HAS_SYMS; |
/* Besides being a symbol table, we also treat this as a regular |
section, so that objcopy can handle it. */ |
return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); |
case SHT_SYMTAB_SHNDX: /* Symbol section indices when >64k sections */ |
if (elf_symtab_shndx (abfd) == shindex) |
return TRUE; |
BFD_ASSERT (elf_symtab_shndx (abfd) == 0); |
elf_symtab_shndx (abfd) = shindex; |
elf_tdata (abfd)->symtab_shndx_hdr = *hdr; |
elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->symtab_shndx_hdr; |
return TRUE; |
case SHT_STRTAB: /* A string table */ |
if (hdr->bfd_section != NULL) |
return TRUE; |
if (ehdr->e_shstrndx == shindex) |
{ |
elf_tdata (abfd)->shstrtab_hdr = *hdr; |
elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->shstrtab_hdr; |
return TRUE; |
} |
if (elf_elfsections (abfd)[elf_onesymtab (abfd)]->sh_link == shindex) |
{ |
symtab_strtab: |
elf_tdata (abfd)->strtab_hdr = *hdr; |
elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->strtab_hdr; |
return TRUE; |
} |
if (elf_elfsections (abfd)[elf_dynsymtab (abfd)]->sh_link == shindex) |
{ |
dynsymtab_strtab: |
elf_tdata (abfd)->dynstrtab_hdr = *hdr; |
hdr = &elf_tdata (abfd)->dynstrtab_hdr; |
elf_elfsections (abfd)[shindex] = hdr; |
/* We also treat this as a regular section, so that objcopy |
can handle it. */ |
return _bfd_elf_make_section_from_shdr (abfd, hdr, name, |
shindex); |
} |
/* If the string table isn't one of the above, then treat it as a |
regular section. We need to scan all the headers to be sure, |
just in case this strtab section appeared before the above. */ |
if (elf_onesymtab (abfd) == 0 || elf_dynsymtab (abfd) == 0) |
{ |
unsigned int i, num_sec; |
num_sec = elf_numsections (abfd); |
for (i = 1; i < num_sec; i++) |
{ |
Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i]; |
if (hdr2->sh_link == shindex) |
{ |
/* Prevent endless recursion on broken objects. */ |
if (i == shindex) |
return FALSE; |
if (! bfd_section_from_shdr (abfd, i)) |
return FALSE; |
if (elf_onesymtab (abfd) == i) |
goto symtab_strtab; |
if (elf_dynsymtab (abfd) == i) |
goto dynsymtab_strtab; |
} |
} |
} |
return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); |
case SHT_REL: |
case SHT_RELA: |
/* *These* do a lot of work -- but build no sections! */ |
{ |
asection *target_sect; |
Elf_Internal_Shdr *hdr2, **p_hdr; |
unsigned int num_sec = elf_numsections (abfd); |
struct bfd_elf_section_data *esdt; |
bfd_size_type amt; |
if (hdr->sh_entsize |
!= (bfd_size_type) (hdr->sh_type == SHT_REL |
? bed->s->sizeof_rel : bed->s->sizeof_rela)) |
return FALSE; |
/* Check for a bogus link to avoid crashing. */ |
if (hdr->sh_link >= num_sec) |
{ |
((*_bfd_error_handler) |
(_("%B: invalid link %lu for reloc section %s (index %u)"), |
abfd, hdr->sh_link, name, shindex)); |
return _bfd_elf_make_section_from_shdr (abfd, hdr, name, |
shindex); |
} |
/* For some incomprehensible reason Oracle distributes |
libraries for Solaris in which some of the objects have |
bogus sh_link fields. It would be nice if we could just |
reject them, but, unfortunately, some people need to use |
them. We scan through the section headers; if we find only |
one suitable symbol table, we clobber the sh_link to point |
to it. I hope this doesn't break anything. |
Don't do it on executable nor shared library. */ |
if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0 |
&& elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_SYMTAB |
&& elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_DYNSYM) |
{ |
unsigned int scan; |
int found; |
found = 0; |
for (scan = 1; scan < num_sec; scan++) |
{ |
if (elf_elfsections (abfd)[scan]->sh_type == SHT_SYMTAB |
|| elf_elfsections (abfd)[scan]->sh_type == SHT_DYNSYM) |
{ |
if (found != 0) |
{ |
found = 0; |
break; |
} |
found = scan; |
} |
} |
if (found != 0) |
hdr->sh_link = found; |
} |
/* Get the symbol table. */ |
if ((elf_elfsections (abfd)[hdr->sh_link]->sh_type == SHT_SYMTAB |
|| elf_elfsections (abfd)[hdr->sh_link]->sh_type == SHT_DYNSYM) |
&& ! bfd_section_from_shdr (abfd, hdr->sh_link)) |
return FALSE; |
/* If this reloc section does not use the main symbol table we |
don't treat it as a reloc section. BFD can't adequately |
represent such a section, so at least for now, we don't |
try. We just present it as a normal section. We also |
can't use it as a reloc section if it points to the null |
section, an invalid section, another reloc section, or its |
sh_link points to the null section. */ |
if (hdr->sh_link != elf_onesymtab (abfd) |
|| hdr->sh_link == SHN_UNDEF |
|| hdr->sh_info == SHN_UNDEF |
|| hdr->sh_info >= num_sec |
|| elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_REL |
|| elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_RELA) |
return _bfd_elf_make_section_from_shdr (abfd, hdr, name, |
shindex); |
if (! bfd_section_from_shdr (abfd, hdr->sh_info)) |
return FALSE; |
target_sect = bfd_section_from_elf_index (abfd, hdr->sh_info); |
if (target_sect == NULL) |
return FALSE; |
esdt = elf_section_data (target_sect); |
if (hdr->sh_type == SHT_RELA) |
p_hdr = &esdt->rela.hdr; |
else |
p_hdr = &esdt->rel.hdr; |
BFD_ASSERT (*p_hdr == NULL); |
amt = sizeof (*hdr2); |
hdr2 = (Elf_Internal_Shdr *) bfd_alloc (abfd, amt); |
if (hdr2 == NULL) |
return FALSE; |
*hdr2 = *hdr; |
*p_hdr = hdr2; |
elf_elfsections (abfd)[shindex] = hdr2; |
target_sect->reloc_count += NUM_SHDR_ENTRIES (hdr); |
target_sect->flags |= SEC_RELOC; |
target_sect->relocation = NULL; |
target_sect->rel_filepos = hdr->sh_offset; |
/* In the section to which the relocations apply, mark whether |
its relocations are of the REL or RELA variety. */ |
if (hdr->sh_size != 0) |
{ |
if (hdr->sh_type == SHT_RELA) |
target_sect->use_rela_p = 1; |
} |
abfd->flags |= HAS_RELOC; |
return TRUE; |
} |
case SHT_GNU_verdef: |
elf_dynverdef (abfd) = shindex; |
elf_tdata (abfd)->dynverdef_hdr = *hdr; |
return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); |
case SHT_GNU_versym: |
if (hdr->sh_entsize != sizeof (Elf_External_Versym)) |
return FALSE; |
elf_dynversym (abfd) = shindex; |
elf_tdata (abfd)->dynversym_hdr = *hdr; |
return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); |
case SHT_GNU_verneed: |
elf_dynverref (abfd) = shindex; |
elf_tdata (abfd)->dynverref_hdr = *hdr; |
return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); |
case SHT_SHLIB: |
return TRUE; |
case SHT_GROUP: |
if (! IS_VALID_GROUP_SECTION_HEADER (hdr, GRP_ENTRY_SIZE)) |
return FALSE; |
if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) |
return FALSE; |
if (hdr->contents != NULL) |
{ |
Elf_Internal_Group *idx = (Elf_Internal_Group *) hdr->contents; |
unsigned int n_elt = hdr->sh_size / GRP_ENTRY_SIZE; |
asection *s; |
if (idx->flags & GRP_COMDAT) |
hdr->bfd_section->flags |
|= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; |
/* We try to keep the same section order as it comes in. */ |
idx += n_elt; |
while (--n_elt != 0) |
{ |
--idx; |
if (idx->shdr != NULL |
&& (s = idx->shdr->bfd_section) != NULL |
&& elf_next_in_group (s) != NULL) |
{ |
elf_next_in_group (hdr->bfd_section) = s; |
break; |
} |
} |
} |
break; |
default: |
/* Possibly an attributes section. */ |
if (hdr->sh_type == SHT_GNU_ATTRIBUTES |
|| hdr->sh_type == bed->obj_attrs_section_type) |
{ |
if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) |
return FALSE; |
_bfd_elf_parse_attributes (abfd, hdr); |
return TRUE; |
} |
/* Check for any processor-specific section types. */ |
if (bed->elf_backend_section_from_shdr (abfd, hdr, name, shindex)) |
return TRUE; |
if (hdr->sh_type >= SHT_LOUSER && hdr->sh_type <= SHT_HIUSER) |
{ |
if ((hdr->sh_flags & SHF_ALLOC) != 0) |
/* FIXME: How to properly handle allocated section reserved |
for applications? */ |
(*_bfd_error_handler) |
(_("%B: don't know how to handle allocated, application " |
"specific section `%s' [0x%8x]"), |
abfd, name, hdr->sh_type); |
else |
/* Allow sections reserved for applications. */ |
return _bfd_elf_make_section_from_shdr (abfd, hdr, name, |
shindex); |
} |
else if (hdr->sh_type >= SHT_LOPROC |
&& hdr->sh_type <= SHT_HIPROC) |
/* FIXME: We should handle this section. */ |
(*_bfd_error_handler) |
(_("%B: don't know how to handle processor specific section " |
"`%s' [0x%8x]"), |
abfd, name, hdr->sh_type); |
else if (hdr->sh_type >= SHT_LOOS && hdr->sh_type <= SHT_HIOS) |
{ |
/* Unrecognised OS-specific sections. */ |
if ((hdr->sh_flags & SHF_OS_NONCONFORMING) != 0) |
/* SHF_OS_NONCONFORMING indicates that special knowledge is |
required to correctly process the section and the file should |
be rejected with an error message. */ |
(*_bfd_error_handler) |
(_("%B: don't know how to handle OS specific section " |
"`%s' [0x%8x]"), |
abfd, name, hdr->sh_type); |
else |
/* Otherwise it should be processed. */ |
return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); |
} |
else |
/* FIXME: We should handle this section. */ |
(*_bfd_error_handler) |
(_("%B: don't know how to handle section `%s' [0x%8x]"), |
abfd, name, hdr->sh_type); |
return FALSE; |
} |
return TRUE; |
} |
/* Return the local symbol specified by ABFD, R_SYMNDX. */ |
Elf_Internal_Sym * |
bfd_sym_from_r_symndx (struct sym_cache *cache, |
bfd *abfd, |
unsigned long r_symndx) |
{ |
unsigned int ent = r_symndx % LOCAL_SYM_CACHE_SIZE; |
if (cache->abfd != abfd || cache->indx[ent] != r_symndx) |
{ |
Elf_Internal_Shdr *symtab_hdr; |
unsigned char esym[sizeof (Elf64_External_Sym)]; |
Elf_External_Sym_Shndx eshndx; |
symtab_hdr = &elf_tdata (abfd)->symtab_hdr; |
if (bfd_elf_get_elf_syms (abfd, symtab_hdr, 1, r_symndx, |
&cache->sym[ent], esym, &eshndx) == NULL) |
return NULL; |
if (cache->abfd != abfd) |
{ |
memset (cache->indx, -1, sizeof (cache->indx)); |
cache->abfd = abfd; |
} |
cache->indx[ent] = r_symndx; |
} |
return &cache->sym[ent]; |
} |
/* Given an ELF section number, retrieve the corresponding BFD |
section. */ |
asection * |
bfd_section_from_elf_index (bfd *abfd, unsigned int sec_index) |
{ |
if (sec_index >= elf_numsections (abfd)) |
return NULL; |
return elf_elfsections (abfd)[sec_index]->bfd_section; |
} |
static const struct bfd_elf_special_section special_sections_b[] = |
{ |
{ STRING_COMMA_LEN (".bss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, |
{ NULL, 0, 0, 0, 0 } |
}; |
static const struct bfd_elf_special_section special_sections_c[] = |
{ |
{ STRING_COMMA_LEN (".comment"), 0, SHT_PROGBITS, 0 }, |
{ NULL, 0, 0, 0, 0 } |
}; |
static const struct bfd_elf_special_section special_sections_d[] = |
{ |
{ STRING_COMMA_LEN (".data"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, |
{ STRING_COMMA_LEN (".data1"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, |
/* There are more DWARF sections than these, but they needn't be added here |
unless you have to cope with broken compilers that don't emit section |
attributes or you want to help the user writing assembler. */ |
{ STRING_COMMA_LEN (".debug"), 0, SHT_PROGBITS, 0 }, |
{ STRING_COMMA_LEN (".debug_line"), 0, SHT_PROGBITS, 0 }, |
{ STRING_COMMA_LEN (".debug_info"), 0, SHT_PROGBITS, 0 }, |
{ STRING_COMMA_LEN (".debug_abbrev"), 0, SHT_PROGBITS, 0 }, |
{ STRING_COMMA_LEN (".debug_aranges"), 0, SHT_PROGBITS, 0 }, |
{ STRING_COMMA_LEN (".dynamic"), 0, SHT_DYNAMIC, SHF_ALLOC }, |
{ STRING_COMMA_LEN (".dynstr"), 0, SHT_STRTAB, SHF_ALLOC }, |
{ STRING_COMMA_LEN (".dynsym"), 0, SHT_DYNSYM, SHF_ALLOC }, |
{ NULL, 0, 0, 0, 0 } |
}; |
static const struct bfd_elf_special_section special_sections_f[] = |
{ |
{ STRING_COMMA_LEN (".fini"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, |
{ STRING_COMMA_LEN (".fini_array"), 0, SHT_FINI_ARRAY, SHF_ALLOC + SHF_WRITE }, |
{ NULL, 0, 0, 0, 0 } |
}; |
static const struct bfd_elf_special_section special_sections_g[] = |
{ |
{ STRING_COMMA_LEN (".gnu.linkonce.b"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, |
{ STRING_COMMA_LEN (".gnu.lto_"), -1, SHT_PROGBITS, SHF_EXCLUDE }, |
{ STRING_COMMA_LEN (".got"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, |
{ STRING_COMMA_LEN (".gnu.version"), 0, SHT_GNU_versym, 0 }, |
{ STRING_COMMA_LEN (".gnu.version_d"), 0, SHT_GNU_verdef, 0 }, |
{ STRING_COMMA_LEN (".gnu.version_r"), 0, SHT_GNU_verneed, 0 }, |
{ STRING_COMMA_LEN (".gnu.liblist"), 0, SHT_GNU_LIBLIST, SHF_ALLOC }, |
{ STRING_COMMA_LEN (".gnu.conflict"), 0, SHT_RELA, SHF_ALLOC }, |
{ STRING_COMMA_LEN (".gnu.hash"), 0, SHT_GNU_HASH, SHF_ALLOC }, |
{ NULL, 0, 0, 0, 0 } |
}; |
static const struct bfd_elf_special_section special_sections_h[] = |
{ |
{ STRING_COMMA_LEN (".hash"), 0, SHT_HASH, SHF_ALLOC }, |
{ NULL, 0, 0, 0, 0 } |
}; |
static const struct bfd_elf_special_section special_sections_i[] = |
{ |
{ STRING_COMMA_LEN (".init"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, |
{ STRING_COMMA_LEN (".init_array"), 0, SHT_INIT_ARRAY, SHF_ALLOC + SHF_WRITE }, |
{ STRING_COMMA_LEN (".interp"), 0, SHT_PROGBITS, 0 }, |
{ NULL, 0, 0, 0, 0 } |
}; |
static const struct bfd_elf_special_section special_sections_l[] = |
{ |
{ STRING_COMMA_LEN (".line"), 0, SHT_PROGBITS, 0 }, |
{ NULL, 0, 0, 0, 0 } |
}; |
static const struct bfd_elf_special_section special_sections_n[] = |
{ |
{ STRING_COMMA_LEN (".note.GNU-stack"), 0, SHT_PROGBITS, 0 }, |
{ STRING_COMMA_LEN (".note"), -1, SHT_NOTE, 0 }, |
{ NULL, 0, 0, 0, 0 } |
}; |
static const struct bfd_elf_special_section special_sections_p[] = |
{ |
{ STRING_COMMA_LEN (".preinit_array"), 0, SHT_PREINIT_ARRAY, SHF_ALLOC + SHF_WRITE }, |
{ STRING_COMMA_LEN (".plt"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, |
{ NULL, 0, 0, 0, 0 } |
}; |
static const struct bfd_elf_special_section special_sections_r[] = |
{ |
{ STRING_COMMA_LEN (".rodata"), -2, SHT_PROGBITS, SHF_ALLOC }, |
{ STRING_COMMA_LEN (".rodata1"), 0, SHT_PROGBITS, SHF_ALLOC }, |
{ STRING_COMMA_LEN (".rela"), -1, SHT_RELA, 0 }, |
{ STRING_COMMA_LEN (".rel"), -1, SHT_REL, 0 }, |
{ NULL, 0, 0, 0, 0 } |
}; |
static const struct bfd_elf_special_section special_sections_s[] = |
{ |
{ STRING_COMMA_LEN (".shstrtab"), 0, SHT_STRTAB, 0 }, |
{ STRING_COMMA_LEN (".strtab"), 0, SHT_STRTAB, 0 }, |
{ STRING_COMMA_LEN (".symtab"), 0, SHT_SYMTAB, 0 }, |
/* See struct bfd_elf_special_section declaration for the semantics of |
this special case where .prefix_length != strlen (.prefix). */ |
{ ".stabstr", 5, 3, SHT_STRTAB, 0 }, |
{ NULL, 0, 0, 0, 0 } |
}; |
static const struct bfd_elf_special_section special_sections_t[] = |
{ |
{ STRING_COMMA_LEN (".text"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, |
{ STRING_COMMA_LEN (".tbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_TLS }, |
{ STRING_COMMA_LEN (".tdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_TLS }, |
{ NULL, 0, 0, 0, 0 } |
}; |
static const struct bfd_elf_special_section special_sections_z[] = |
{ |
{ STRING_COMMA_LEN (".zdebug_line"), 0, SHT_PROGBITS, 0 }, |
{ STRING_COMMA_LEN (".zdebug_info"), 0, SHT_PROGBITS, 0 }, |
{ STRING_COMMA_LEN (".zdebug_abbrev"), 0, SHT_PROGBITS, 0 }, |
{ STRING_COMMA_LEN (".zdebug_aranges"), 0, SHT_PROGBITS, 0 }, |
{ NULL, 0, 0, 0, 0 } |
}; |
static const struct bfd_elf_special_section * const special_sections[] = |
{ |
special_sections_b, /* 'b' */ |
special_sections_c, /* 'c' */ |
special_sections_d, /* 'd' */ |
NULL, /* 'e' */ |
special_sections_f, /* 'f' */ |
special_sections_g, /* 'g' */ |
special_sections_h, /* 'h' */ |
special_sections_i, /* 'i' */ |
NULL, /* 'j' */ |
NULL, /* 'k' */ |
special_sections_l, /* 'l' */ |
NULL, /* 'm' */ |
special_sections_n, /* 'n' */ |
NULL, /* 'o' */ |
special_sections_p, /* 'p' */ |
NULL, /* 'q' */ |
special_sections_r, /* 'r' */ |
special_sections_s, /* 's' */ |
special_sections_t, /* 't' */ |
NULL, /* 'u' */ |
NULL, /* 'v' */ |
NULL, /* 'w' */ |
NULL, /* 'x' */ |
NULL, /* 'y' */ |
special_sections_z /* 'z' */ |
}; |
const struct bfd_elf_special_section * |
_bfd_elf_get_special_section (const char *name, |
const struct bfd_elf_special_section *spec, |
unsigned int rela) |
{ |
int i; |
int len; |
len = strlen (name); |
for (i = 0; spec[i].prefix != NULL; i++) |
{ |
int suffix_len; |
int prefix_len = spec[i].prefix_length; |
if (len < prefix_len) |
continue; |
if (memcmp (name, spec[i].prefix, prefix_len) != 0) |
continue; |
suffix_len = spec[i].suffix_length; |
if (suffix_len <= 0) |
{ |
if (name[prefix_len] != 0) |
{ |
if (suffix_len == 0) |
continue; |
if (name[prefix_len] != '.' |
&& (suffix_len == -2 |
|| (rela && spec[i].type == SHT_REL))) |
continue; |
} |
} |
else |
{ |
if (len < prefix_len + suffix_len) |
continue; |
if (memcmp (name + len - suffix_len, |
spec[i].prefix + prefix_len, |
suffix_len) != 0) |
continue; |
} |
return &spec[i]; |
} |
return NULL; |
} |
const struct bfd_elf_special_section * |
_bfd_elf_get_sec_type_attr (bfd *abfd, asection *sec) |
{ |
int i; |
const struct bfd_elf_special_section *spec; |
const struct elf_backend_data *bed; |
/* See if this is one of the special sections. */ |
if (sec->name == NULL) |
return NULL; |
bed = get_elf_backend_data (abfd); |
spec = bed->special_sections; |
if (spec) |
{ |
spec = _bfd_elf_get_special_section (sec->name, |
bed->special_sections, |
sec->use_rela_p); |
if (spec != NULL) |
return spec; |
} |
if (sec->name[0] != '.') |
return NULL; |
i = sec->name[1] - 'b'; |
if (i < 0 || i > 'z' - 'b') |
return NULL; |
spec = special_sections[i]; |
if (spec == NULL) |
return NULL; |
return _bfd_elf_get_special_section (sec->name, spec, sec->use_rela_p); |
} |
bfd_boolean |
_bfd_elf_new_section_hook (bfd *abfd, asection *sec) |
{ |
struct bfd_elf_section_data *sdata; |
const struct elf_backend_data *bed; |
const struct bfd_elf_special_section *ssect; |
sdata = (struct bfd_elf_section_data *) sec->used_by_bfd; |
if (sdata == NULL) |
{ |
sdata = (struct bfd_elf_section_data *) bfd_zalloc (abfd, |
sizeof (*sdata)); |
if (sdata == NULL) |
return FALSE; |
sec->used_by_bfd = sdata; |
} |
/* Indicate whether or not this section should use RELA relocations. */ |
bed = get_elf_backend_data (abfd); |
sec->use_rela_p = bed->default_use_rela_p; |
/* When we read a file, we don't need to set ELF section type and |
flags. They will be overridden in _bfd_elf_make_section_from_shdr |
anyway. We will set ELF section type and flags for all linker |
created sections. If user specifies BFD section flags, we will |
set ELF section type and flags based on BFD section flags in |
elf_fake_sections. Special handling for .init_array/.fini_array |
output sections since they may contain .ctors/.dtors input |
sections. We don't want _bfd_elf_init_private_section_data to |
copy ELF section type from .ctors/.dtors input sections. */ |
if (abfd->direction != read_direction |
|| (sec->flags & SEC_LINKER_CREATED) != 0) |
{ |
ssect = (*bed->get_sec_type_attr) (abfd, sec); |
if (ssect != NULL |
&& (!sec->flags |
|| (sec->flags & SEC_LINKER_CREATED) != 0 |
|| ssect->type == SHT_INIT_ARRAY |
|| ssect->type == SHT_FINI_ARRAY)) |
{ |
elf_section_type (sec) = ssect->type; |
elf_section_flags (sec) = ssect->attr; |
} |
} |
return _bfd_generic_new_section_hook (abfd, sec); |
} |
/* Create a new bfd section from an ELF program header. |
Since program segments have no names, we generate a synthetic name |
of the form segment<NUM>, where NUM is generally the index in the |
program header table. For segments that are split (see below) we |
generate the names segment<NUM>a and segment<NUM>b. |
Note that some program segments may have a file size that is different than |
(less than) the memory size. All this means is that at execution the |
system must allocate the amount of memory specified by the memory size, |
but only initialize it with the first "file size" bytes read from the |
file. This would occur for example, with program segments consisting |
of combined data+bss. |
To handle the above situation, this routine generates TWO bfd sections |
for the single program segment. The first has the length specified by |
the file size of the segment, and the second has the length specified |
by the difference between the two sizes. In effect, the segment is split |
into its initialized and uninitialized parts. |
*/ |
bfd_boolean |
_bfd_elf_make_section_from_phdr (bfd *abfd, |
Elf_Internal_Phdr *hdr, |
int hdr_index, |
const char *type_name) |
{ |
asection *newsect; |
char *name; |
char namebuf[64]; |
size_t len; |
int split; |
split = ((hdr->p_memsz > 0) |
&& (hdr->p_filesz > 0) |
&& (hdr->p_memsz > hdr->p_filesz)); |
if (hdr->p_filesz > 0) |
{ |
sprintf (namebuf, "%s%d%s", type_name, hdr_index, split ? "a" : ""); |
len = strlen (namebuf) + 1; |
name = (char *) bfd_alloc (abfd, len); |
if (!name) |
return FALSE; |
memcpy (name, namebuf, len); |
newsect = bfd_make_section (abfd, name); |
if (newsect == NULL) |
return FALSE; |
newsect->vma = hdr->p_vaddr; |
newsect->lma = hdr->p_paddr; |
newsect->size = hdr->p_filesz; |
newsect->filepos = hdr->p_offset; |
newsect->flags |= SEC_HAS_CONTENTS; |
newsect->alignment_power = bfd_log2 (hdr->p_align); |
if (hdr->p_type == PT_LOAD) |
{ |
newsect->flags |= SEC_ALLOC; |
newsect->flags |= SEC_LOAD; |
if (hdr->p_flags & PF_X) |
{ |
/* FIXME: all we known is that it has execute PERMISSION, |
may be data. */ |
newsect->flags |= SEC_CODE; |
} |
} |
if (!(hdr->p_flags & PF_W)) |
{ |
newsect->flags |= SEC_READONLY; |
} |
} |
if (hdr->p_memsz > hdr->p_filesz) |
{ |
bfd_vma align; |
sprintf (namebuf, "%s%d%s", type_name, hdr_index, split ? "b" : ""); |
len = strlen (namebuf) + 1; |
name = (char *) bfd_alloc (abfd, len); |
if (!name) |
return FALSE; |
memcpy (name, namebuf, len); |
newsect = bfd_make_section (abfd, name); |
if (newsect == NULL) |
return FALSE; |
newsect->vma = hdr->p_vaddr + hdr->p_filesz; |
newsect->lma = hdr->p_paddr + hdr->p_filesz; |
newsect->size = hdr->p_memsz - hdr->p_filesz; |
newsect->filepos = hdr->p_offset + hdr->p_filesz; |
align = newsect->vma & -newsect->vma; |
if (align == 0 || align > hdr->p_align) |
align = hdr->p_align; |
newsect->alignment_power = bfd_log2 (align); |
if (hdr->p_type == PT_LOAD) |
{ |
/* Hack for gdb. Segments that have not been modified do |
not have their contents written to a core file, on the |
assumption that a debugger can find the contents in the |
executable. We flag this case by setting the fake |
section size to zero. Note that "real" bss sections will |
always have their contents dumped to the core file. */ |
if (bfd_get_format (abfd) == bfd_core) |
newsect->size = 0; |
newsect->flags |= SEC_ALLOC; |
if (hdr->p_flags & PF_X) |
newsect->flags |= SEC_CODE; |
} |
if (!(hdr->p_flags & PF_W)) |
newsect->flags |= SEC_READONLY; |
} |
return TRUE; |
} |
bfd_boolean |
bfd_section_from_phdr (bfd *abfd, Elf_Internal_Phdr *hdr, int hdr_index) |
{ |
const struct elf_backend_data *bed; |
switch (hdr->p_type) |
{ |
case PT_NULL: |
return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "null"); |
case PT_LOAD: |
return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "load"); |
case PT_DYNAMIC: |
return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "dynamic"); |
case PT_INTERP: |
return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "interp"); |
case PT_NOTE: |
if (! _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "note")) |
return FALSE; |
if (! elf_read_notes (abfd, hdr->p_offset, hdr->p_filesz)) |
return FALSE; |
return TRUE; |
case PT_SHLIB: |
return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "shlib"); |
case PT_PHDR: |
return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "phdr"); |
case PT_GNU_EH_FRAME: |
return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, |
"eh_frame_hdr"); |
case PT_GNU_STACK: |
return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "stack"); |
case PT_GNU_RELRO: |
return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "relro"); |
default: |
/* Check for any processor-specific program segment types. */ |
bed = get_elf_backend_data (abfd); |
return bed->elf_backend_section_from_phdr (abfd, hdr, hdr_index, "proc"); |
} |
} |
/* Return the REL_HDR for SEC, assuming there is only a single one, either |
REL or RELA. */ |
Elf_Internal_Shdr * |
_bfd_elf_single_rel_hdr (asection *sec) |
{ |
if (elf_section_data (sec)->rel.hdr) |
{ |
BFD_ASSERT (elf_section_data (sec)->rela.hdr == NULL); |
return elf_section_data (sec)->rel.hdr; |
} |
else |
return elf_section_data (sec)->rela.hdr; |
} |
/* Allocate and initialize a section-header for a new reloc section, |
containing relocations against ASECT. It is stored in RELDATA. If |
USE_RELA_P is TRUE, we use RELA relocations; otherwise, we use REL |
relocations. */ |
static bfd_boolean |
_bfd_elf_init_reloc_shdr (bfd *abfd, |
struct bfd_elf_section_reloc_data *reldata, |
asection *asect, |
bfd_boolean use_rela_p) |
{ |
Elf_Internal_Shdr *rel_hdr; |
char *name; |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
bfd_size_type amt; |
amt = sizeof (Elf_Internal_Shdr); |
BFD_ASSERT (reldata->hdr == NULL); |
rel_hdr = bfd_zalloc (abfd, amt); |
reldata->hdr = rel_hdr; |
amt = sizeof ".rela" + strlen (asect->name); |
name = (char *) bfd_alloc (abfd, amt); |
if (name == NULL) |
return FALSE; |
sprintf (name, "%s%s", use_rela_p ? ".rela" : ".rel", asect->name); |
rel_hdr->sh_name = |
(unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd), name, |
FALSE); |
if (rel_hdr->sh_name == (unsigned int) -1) |
return FALSE; |
rel_hdr->sh_type = use_rela_p ? SHT_RELA : SHT_REL; |
rel_hdr->sh_entsize = (use_rela_p |
? bed->s->sizeof_rela |
: bed->s->sizeof_rel); |
rel_hdr->sh_addralign = (bfd_vma) 1 << bed->s->log_file_align; |
rel_hdr->sh_flags = 0; |
rel_hdr->sh_addr = 0; |
rel_hdr->sh_size = 0; |
rel_hdr->sh_offset = 0; |
return TRUE; |
} |
/* Return the default section type based on the passed in section flags. */ |
int |
bfd_elf_get_default_section_type (flagword flags) |
{ |
if ((flags & SEC_ALLOC) != 0 |
&& (flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0) |
return SHT_NOBITS; |
return SHT_PROGBITS; |
} |
struct fake_section_arg |
{ |
struct bfd_link_info *link_info; |
bfd_boolean failed; |
}; |
/* Set up an ELF internal section header for a section. */ |
static void |
elf_fake_sections (bfd *abfd, asection *asect, void *fsarg) |
{ |
struct fake_section_arg *arg = (struct fake_section_arg *)fsarg; |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
struct bfd_elf_section_data *esd = elf_section_data (asect); |
Elf_Internal_Shdr *this_hdr; |
unsigned int sh_type; |
if (arg->failed) |
{ |
/* We already failed; just get out of the bfd_map_over_sections |
loop. */ |
return; |
} |
this_hdr = &esd->this_hdr; |
this_hdr->sh_name = (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd), |
asect->name, FALSE); |
if (this_hdr->sh_name == (unsigned int) -1) |
{ |
arg->failed = TRUE; |
return; |
} |
/* Don't clear sh_flags. Assembler may set additional bits. */ |
if ((asect->flags & SEC_ALLOC) != 0 |
|| asect->user_set_vma) |
this_hdr->sh_addr = asect->vma; |
else |
this_hdr->sh_addr = 0; |
this_hdr->sh_offset = 0; |
this_hdr->sh_size = asect->size; |
this_hdr->sh_link = 0; |
this_hdr->sh_addralign = (bfd_vma) 1 << asect->alignment_power; |
/* The sh_entsize and sh_info fields may have been set already by |
copy_private_section_data. */ |
this_hdr->bfd_section = asect; |
this_hdr->contents = NULL; |
/* If the section type is unspecified, we set it based on |
asect->flags. */ |
if ((asect->flags & SEC_GROUP) != 0) |
sh_type = SHT_GROUP; |
else |
sh_type = bfd_elf_get_default_section_type (asect->flags); |
if (this_hdr->sh_type == SHT_NULL) |
this_hdr->sh_type = sh_type; |
else if (this_hdr->sh_type == SHT_NOBITS |
&& sh_type == SHT_PROGBITS |
&& (asect->flags & SEC_ALLOC) != 0) |
{ |
/* Warn if we are changing a NOBITS section to PROGBITS, but |
allow the link to proceed. This can happen when users link |
non-bss input sections to bss output sections, or emit data |
to a bss output section via a linker script. */ |
(*_bfd_error_handler) |
(_("warning: section `%A' type changed to PROGBITS"), asect); |
this_hdr->sh_type = sh_type; |
} |
switch (this_hdr->sh_type) |
{ |
default: |
break; |
case SHT_STRTAB: |
case SHT_INIT_ARRAY: |
case SHT_FINI_ARRAY: |
case SHT_PREINIT_ARRAY: |
case SHT_NOTE: |
case SHT_NOBITS: |
case SHT_PROGBITS: |
break; |
case SHT_HASH: |
this_hdr->sh_entsize = bed->s->sizeof_hash_entry; |
break; |
case SHT_DYNSYM: |
this_hdr->sh_entsize = bed->s->sizeof_sym; |
break; |
case SHT_DYNAMIC: |
this_hdr->sh_entsize = bed->s->sizeof_dyn; |
break; |
case SHT_RELA: |
if (get_elf_backend_data (abfd)->may_use_rela_p) |
this_hdr->sh_entsize = bed->s->sizeof_rela; |
break; |
case SHT_REL: |
if (get_elf_backend_data (abfd)->may_use_rel_p) |
this_hdr->sh_entsize = bed->s->sizeof_rel; |
break; |
case SHT_GNU_versym: |
this_hdr->sh_entsize = sizeof (Elf_External_Versym); |
break; |
case SHT_GNU_verdef: |
this_hdr->sh_entsize = 0; |
/* objcopy or strip will copy over sh_info, but may not set |
cverdefs. The linker will set cverdefs, but sh_info will be |
zero. */ |
if (this_hdr->sh_info == 0) |
this_hdr->sh_info = elf_tdata (abfd)->cverdefs; |
else |
BFD_ASSERT (elf_tdata (abfd)->cverdefs == 0 |
|| this_hdr->sh_info == elf_tdata (abfd)->cverdefs); |
break; |
case SHT_GNU_verneed: |
this_hdr->sh_entsize = 0; |
/* objcopy or strip will copy over sh_info, but may not set |
cverrefs. The linker will set cverrefs, but sh_info will be |
zero. */ |
if (this_hdr->sh_info == 0) |
this_hdr->sh_info = elf_tdata (abfd)->cverrefs; |
else |
BFD_ASSERT (elf_tdata (abfd)->cverrefs == 0 |
|| this_hdr->sh_info == elf_tdata (abfd)->cverrefs); |
break; |
case SHT_GROUP: |
this_hdr->sh_entsize = GRP_ENTRY_SIZE; |
break; |
case SHT_GNU_HASH: |
this_hdr->sh_entsize = bed->s->arch_size == 64 ? 0 : 4; |
break; |
} |
if ((asect->flags & SEC_ALLOC) != 0) |
this_hdr->sh_flags |= SHF_ALLOC; |
if ((asect->flags & SEC_READONLY) == 0) |
this_hdr->sh_flags |= SHF_WRITE; |
if ((asect->flags & SEC_CODE) != 0) |
this_hdr->sh_flags |= SHF_EXECINSTR; |
if ((asect->flags & SEC_MERGE) != 0) |
{ |
this_hdr->sh_flags |= SHF_MERGE; |
this_hdr->sh_entsize = asect->entsize; |
if ((asect->flags & SEC_STRINGS) != 0) |
this_hdr->sh_flags |= SHF_STRINGS; |
} |
if ((asect->flags & SEC_GROUP) == 0 && elf_group_name (asect) != NULL) |
this_hdr->sh_flags |= SHF_GROUP; |
if ((asect->flags & SEC_THREAD_LOCAL) != 0) |
{ |
this_hdr->sh_flags |= SHF_TLS; |
if (asect->size == 0 |
&& (asect->flags & SEC_HAS_CONTENTS) == 0) |
{ |
struct bfd_link_order *o = asect->map_tail.link_order; |
this_hdr->sh_size = 0; |
if (o != NULL) |
{ |
this_hdr->sh_size = o->offset + o->size; |
if (this_hdr->sh_size != 0) |
this_hdr->sh_type = SHT_NOBITS; |
} |
} |
} |
if ((asect->flags & (SEC_GROUP | SEC_EXCLUDE)) == SEC_EXCLUDE) |
this_hdr->sh_flags |= SHF_EXCLUDE; |
/* If the section has relocs, set up a section header for the |
SHT_REL[A] section. If two relocation sections are required for |
this section, it is up to the processor-specific back-end to |
create the other. */ |
if ((asect->flags & SEC_RELOC) != 0) |
{ |
/* When doing a relocatable link, create both REL and RELA sections if |
needed. */ |
if (arg->link_info |
/* Do the normal setup if we wouldn't create any sections here. */ |
&& esd->rel.count + esd->rela.count > 0 |
&& (arg->link_info->relocatable || arg->link_info->emitrelocations)) |
{ |
if (esd->rel.count && esd->rel.hdr == NULL |
&& !_bfd_elf_init_reloc_shdr (abfd, &esd->rel, asect, FALSE)) |
{ |
arg->failed = TRUE; |
return; |
} |
if (esd->rela.count && esd->rela.hdr == NULL |
&& !_bfd_elf_init_reloc_shdr (abfd, &esd->rela, asect, TRUE)) |
{ |
arg->failed = TRUE; |
return; |
} |
} |
else if (!_bfd_elf_init_reloc_shdr (abfd, |
(asect->use_rela_p |
? &esd->rela : &esd->rel), |
asect, |
asect->use_rela_p)) |
arg->failed = TRUE; |
} |
/* Check for processor-specific section types. */ |
sh_type = this_hdr->sh_type; |
if (bed->elf_backend_fake_sections |
&& !(*bed->elf_backend_fake_sections) (abfd, this_hdr, asect)) |
arg->failed = TRUE; |
if (sh_type == SHT_NOBITS && asect->size != 0) |
{ |
/* Don't change the header type from NOBITS if we are being |
called for objcopy --only-keep-debug. */ |
this_hdr->sh_type = sh_type; |
} |
} |
/* Fill in the contents of a SHT_GROUP section. Called from |
_bfd_elf_compute_section_file_positions for gas, objcopy, and |
when ELF targets use the generic linker, ld. Called for ld -r |
from bfd_elf_final_link. */ |
void |
bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg) |
{ |
bfd_boolean *failedptr = (bfd_boolean *) failedptrarg; |
asection *elt, *first; |
unsigned char *loc; |
bfd_boolean gas; |
/* Ignore linker created group section. See elfNN_ia64_object_p in |
elfxx-ia64.c. */ |
if (((sec->flags & (SEC_GROUP | SEC_LINKER_CREATED)) != SEC_GROUP) |
|| *failedptr) |
return; |
if (elf_section_data (sec)->this_hdr.sh_info == 0) |
{ |
unsigned long symindx = 0; |
/* elf_group_id will have been set up by objcopy and the |
generic linker. */ |
if (elf_group_id (sec) != NULL) |
symindx = elf_group_id (sec)->udata.i; |
if (symindx == 0) |
{ |
/* If called from the assembler, swap_out_syms will have set up |
elf_section_syms. */ |
BFD_ASSERT (elf_section_syms (abfd) != NULL); |
symindx = elf_section_syms (abfd)[sec->index]->udata.i; |
} |
elf_section_data (sec)->this_hdr.sh_info = symindx; |
} |
else if (elf_section_data (sec)->this_hdr.sh_info == (unsigned int) -2) |
{ |
/* The ELF backend linker sets sh_info to -2 when the group |
signature symbol is global, and thus the index can't be |
set until all local symbols are output. */ |
asection *igroup = elf_sec_group (elf_next_in_group (sec)); |
struct bfd_elf_section_data *sec_data = elf_section_data (igroup); |
unsigned long symndx = sec_data->this_hdr.sh_info; |
unsigned long extsymoff = 0; |
struct elf_link_hash_entry *h; |
if (!elf_bad_symtab (igroup->owner)) |
{ |
Elf_Internal_Shdr *symtab_hdr; |
symtab_hdr = &elf_tdata (igroup->owner)->symtab_hdr; |
extsymoff = symtab_hdr->sh_info; |
} |
h = elf_sym_hashes (igroup->owner)[symndx - extsymoff]; |
while (h->root.type == bfd_link_hash_indirect |
|| h->root.type == bfd_link_hash_warning) |
h = (struct elf_link_hash_entry *) h->root.u.i.link; |
elf_section_data (sec)->this_hdr.sh_info = h->indx; |
} |
/* The contents won't be allocated for "ld -r" or objcopy. */ |
gas = TRUE; |
if (sec->contents == NULL) |
{ |
gas = FALSE; |
sec->contents = (unsigned char *) bfd_alloc (abfd, sec->size); |
/* Arrange for the section to be written out. */ |
elf_section_data (sec)->this_hdr.contents = sec->contents; |
if (sec->contents == NULL) |
{ |
*failedptr = TRUE; |
return; |
} |
} |
loc = sec->contents + sec->size; |
/* Get the pointer to the first section in the group that gas |
squirreled away here. objcopy arranges for this to be set to the |
start of the input section group. */ |
first = elt = elf_next_in_group (sec); |
/* First element is a flag word. Rest of section is elf section |
indices for all the sections of the group. Write them backwards |
just to keep the group in the same order as given in .section |
directives, not that it matters. */ |
while (elt != NULL) |
{ |
asection *s; |
s = elt; |
if (!gas) |
s = s->output_section; |
if (s != NULL |
&& !bfd_is_abs_section (s)) |
{ |
unsigned int idx = elf_section_data (s)->this_idx; |
loc -= 4; |
H_PUT_32 (abfd, idx, loc); |
} |
elt = elf_next_in_group (elt); |
if (elt == first) |
break; |
} |
if ((loc -= 4) != sec->contents) |
abort (); |
H_PUT_32 (abfd, sec->flags & SEC_LINK_ONCE ? GRP_COMDAT : 0, loc); |
} |
/* Assign all ELF section numbers. The dummy first section is handled here |
too. The link/info pointers for the standard section types are filled |
in here too, while we're at it. */ |
static bfd_boolean |
assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) |
{ |
struct elf_obj_tdata *t = elf_tdata (abfd); |
asection *sec; |
unsigned int section_number, secn; |
Elf_Internal_Shdr **i_shdrp; |
struct bfd_elf_section_data *d; |
bfd_boolean need_symtab; |
section_number = 1; |
_bfd_elf_strtab_clear_all_refs (elf_shstrtab (abfd)); |
/* SHT_GROUP sections are in relocatable files only. */ |
if (link_info == NULL || link_info->relocatable) |
{ |
/* Put SHT_GROUP sections first. */ |
for (sec = abfd->sections; sec != NULL; sec = sec->next) |
{ |
d = elf_section_data (sec); |
if (d->this_hdr.sh_type == SHT_GROUP) |
{ |
if (sec->flags & SEC_LINKER_CREATED) |
{ |
/* Remove the linker created SHT_GROUP sections. */ |
bfd_section_list_remove (abfd, sec); |
abfd->section_count--; |
} |
else |
d->this_idx = section_number++; |
} |
} |
} |
for (sec = abfd->sections; sec; sec = sec->next) |
{ |
d = elf_section_data (sec); |
if (d->this_hdr.sh_type != SHT_GROUP) |
d->this_idx = section_number++; |
_bfd_elf_strtab_addref (elf_shstrtab (abfd), d->this_hdr.sh_name); |
if (d->rel.hdr) |
{ |
d->rel.idx = section_number++; |
_bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rel.hdr->sh_name); |
} |
else |
d->rel.idx = 0; |
if (d->rela.hdr) |
{ |
d->rela.idx = section_number++; |
_bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rela.hdr->sh_name); |
} |
else |
d->rela.idx = 0; |
} |
elf_shstrtab_sec (abfd) = section_number++; |
_bfd_elf_strtab_addref (elf_shstrtab (abfd), t->shstrtab_hdr.sh_name); |
elf_elfheader (abfd)->e_shstrndx = elf_shstrtab_sec (abfd); |
need_symtab = (bfd_get_symcount (abfd) > 0 |
|| (link_info == NULL |
&& ((abfd->flags & (EXEC_P | DYNAMIC | HAS_RELOC)) |
== HAS_RELOC))); |
if (need_symtab) |
{ |
elf_onesymtab (abfd) = section_number++; |
_bfd_elf_strtab_addref (elf_shstrtab (abfd), t->symtab_hdr.sh_name); |
if (section_number > ((SHN_LORESERVE - 2) & 0xFFFF)) |
{ |
elf_symtab_shndx (abfd) = section_number++; |
t->symtab_shndx_hdr.sh_name |
= (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd), |
".symtab_shndx", FALSE); |
if (t->symtab_shndx_hdr.sh_name == (unsigned int) -1) |
return FALSE; |
} |
elf_strtab_sec (abfd) = section_number++; |
_bfd_elf_strtab_addref (elf_shstrtab (abfd), t->strtab_hdr.sh_name); |
} |
if (section_number >= SHN_LORESERVE) |
{ |
_bfd_error_handler (_("%B: too many sections: %u"), |
abfd, section_number); |
return FALSE; |
} |
_bfd_elf_strtab_finalize (elf_shstrtab (abfd)); |
t->shstrtab_hdr.sh_size = _bfd_elf_strtab_size (elf_shstrtab (abfd)); |
elf_numsections (abfd) = section_number; |
elf_elfheader (abfd)->e_shnum = section_number; |
/* Set up the list of section header pointers, in agreement with the |
indices. */ |
i_shdrp = (Elf_Internal_Shdr **) bfd_zalloc2 (abfd, section_number, |
sizeof (Elf_Internal_Shdr *)); |
if (i_shdrp == NULL) |
return FALSE; |
i_shdrp[0] = (Elf_Internal_Shdr *) bfd_zalloc (abfd, |
sizeof (Elf_Internal_Shdr)); |
if (i_shdrp[0] == NULL) |
{ |
bfd_release (abfd, i_shdrp); |
return FALSE; |
} |
elf_elfsections (abfd) = i_shdrp; |
i_shdrp[elf_shstrtab_sec (abfd)] = &t->shstrtab_hdr; |
if (need_symtab) |
{ |
i_shdrp[elf_onesymtab (abfd)] = &t->symtab_hdr; |
if (elf_numsections (abfd) > (SHN_LORESERVE & 0xFFFF)) |
{ |
i_shdrp[elf_symtab_shndx (abfd)] = &t->symtab_shndx_hdr; |
t->symtab_shndx_hdr.sh_link = elf_onesymtab (abfd); |
} |
i_shdrp[elf_strtab_sec (abfd)] = &t->strtab_hdr; |
t->symtab_hdr.sh_link = elf_strtab_sec (abfd); |
} |
for (sec = abfd->sections; sec; sec = sec->next) |
{ |
asection *s; |
const char *name; |
d = elf_section_data (sec); |
i_shdrp[d->this_idx] = &d->this_hdr; |
if (d->rel.idx != 0) |
i_shdrp[d->rel.idx] = d->rel.hdr; |
if (d->rela.idx != 0) |
i_shdrp[d->rela.idx] = d->rela.hdr; |
/* Fill in the sh_link and sh_info fields while we're at it. */ |
/* sh_link of a reloc section is the section index of the symbol |
table. sh_info is the section index of the section to which |
the relocation entries apply. */ |
if (d->rel.idx != 0) |
{ |
d->rel.hdr->sh_link = elf_onesymtab (abfd); |
d->rel.hdr->sh_info = d->this_idx; |
} |
if (d->rela.idx != 0) |
{ |
d->rela.hdr->sh_link = elf_onesymtab (abfd); |
d->rela.hdr->sh_info = d->this_idx; |
} |
/* We need to set up sh_link for SHF_LINK_ORDER. */ |
if ((d->this_hdr.sh_flags & SHF_LINK_ORDER) != 0) |
{ |
s = elf_linked_to_section (sec); |
if (s) |
{ |
/* elf_linked_to_section points to the input section. */ |
if (link_info != NULL) |
{ |
/* Check discarded linkonce section. */ |
if (discarded_section (s)) |
{ |
asection *kept; |
(*_bfd_error_handler) |
(_("%B: sh_link of section `%A' points to discarded section `%A' of `%B'"), |
abfd, d->this_hdr.bfd_section, |
s, s->owner); |
/* Point to the kept section if it has the same |
size as the discarded one. */ |
kept = _bfd_elf_check_kept_section (s, link_info); |
if (kept == NULL) |
{ |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
s = kept; |
} |
s = s->output_section; |
BFD_ASSERT (s != NULL); |
} |
else |
{ |
/* Handle objcopy. */ |
if (s->output_section == NULL) |
{ |
(*_bfd_error_handler) |
(_("%B: sh_link of section `%A' points to removed section `%A' of `%B'"), |
abfd, d->this_hdr.bfd_section, s, s->owner); |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
s = s->output_section; |
} |
d->this_hdr.sh_link = elf_section_data (s)->this_idx; |
} |
else |
{ |
/* PR 290: |
The Intel C compiler generates SHT_IA_64_UNWIND with |
SHF_LINK_ORDER. But it doesn't set the sh_link or |
sh_info fields. Hence we could get the situation |
where s is NULL. */ |
const struct elf_backend_data *bed |
= get_elf_backend_data (abfd); |
if (bed->link_order_error_handler) |
bed->link_order_error_handler |
(_("%B: warning: sh_link not set for section `%A'"), |
abfd, sec); |
} |
} |
switch (d->this_hdr.sh_type) |
{ |
case SHT_REL: |
case SHT_RELA: |
/* A reloc section which we are treating as a normal BFD |
section. sh_link is the section index of the symbol |
table. sh_info is the section index of the section to |
which the relocation entries apply. We assume that an |
allocated reloc section uses the dynamic symbol table. |
FIXME: How can we be sure? */ |
s = bfd_get_section_by_name (abfd, ".dynsym"); |
if (s != NULL) |
d->this_hdr.sh_link = elf_section_data (s)->this_idx; |
/* We look up the section the relocs apply to by name. */ |
name = sec->name; |
if (d->this_hdr.sh_type == SHT_REL) |
name += 4; |
else |
name += 5; |
s = bfd_get_section_by_name (abfd, name); |
if (s != NULL) |
d->this_hdr.sh_info = elf_section_data (s)->this_idx; |
break; |
case SHT_STRTAB: |
/* We assume that a section named .stab*str is a stabs |
string section. We look for a section with the same name |
but without the trailing ``str'', and set its sh_link |
field to point to this section. */ |
if (CONST_STRNEQ (sec->name, ".stab") |
&& strcmp (sec->name + strlen (sec->name) - 3, "str") == 0) |
{ |
size_t len; |
char *alc; |
len = strlen (sec->name); |
alc = (char *) bfd_malloc (len - 2); |
if (alc == NULL) |
return FALSE; |
memcpy (alc, sec->name, len - 3); |
alc[len - 3] = '\0'; |
s = bfd_get_section_by_name (abfd, alc); |
free (alc); |
if (s != NULL) |
{ |
elf_section_data (s)->this_hdr.sh_link = d->this_idx; |
/* This is a .stab section. */ |
if (elf_section_data (s)->this_hdr.sh_entsize == 0) |
elf_section_data (s)->this_hdr.sh_entsize |
= 4 + 2 * bfd_get_arch_size (abfd) / 8; |
} |
} |
break; |
case SHT_DYNAMIC: |
case SHT_DYNSYM: |
case SHT_GNU_verneed: |
case SHT_GNU_verdef: |
/* sh_link is the section header index of the string table |
used for the dynamic entries, or the symbol table, or the |
version strings. */ |
s = bfd_get_section_by_name (abfd, ".dynstr"); |
if (s != NULL) |
d->this_hdr.sh_link = elf_section_data (s)->this_idx; |
break; |
case SHT_GNU_LIBLIST: |
/* sh_link is the section header index of the prelink library |
list used for the dynamic entries, or the symbol table, or |
the version strings. */ |
s = bfd_get_section_by_name (abfd, (sec->flags & SEC_ALLOC) |
? ".dynstr" : ".gnu.libstr"); |
if (s != NULL) |
d->this_hdr.sh_link = elf_section_data (s)->this_idx; |
break; |
case SHT_HASH: |
case SHT_GNU_HASH: |
case SHT_GNU_versym: |
/* sh_link is the section header index of the symbol table |
this hash table or version table is for. */ |
s = bfd_get_section_by_name (abfd, ".dynsym"); |
if (s != NULL) |
d->this_hdr.sh_link = elf_section_data (s)->this_idx; |
break; |
case SHT_GROUP: |
d->this_hdr.sh_link = elf_onesymtab (abfd); |
} |
} |
for (secn = 1; secn < section_number; ++secn) |
if (i_shdrp[secn] == NULL) |
i_shdrp[secn] = i_shdrp[0]; |
else |
i_shdrp[secn]->sh_name = _bfd_elf_strtab_offset (elf_shstrtab (abfd), |
i_shdrp[secn]->sh_name); |
return TRUE; |
} |
static bfd_boolean |
sym_is_global (bfd *abfd, asymbol *sym) |
{ |
/* If the backend has a special mapping, use it. */ |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
if (bed->elf_backend_sym_is_global) |
return (*bed->elf_backend_sym_is_global) (abfd, sym); |
return ((sym->flags & (BSF_GLOBAL | BSF_WEAK | BSF_GNU_UNIQUE)) != 0 |
|| bfd_is_und_section (bfd_get_section (sym)) |
|| bfd_is_com_section (bfd_get_section (sym))); |
} |
/* Don't output section symbols for sections that are not going to be |
output, that are duplicates or there is no BFD section. */ |
static bfd_boolean |
ignore_section_sym (bfd *abfd, asymbol *sym) |
{ |
elf_symbol_type *type_ptr; |
if ((sym->flags & BSF_SECTION_SYM) == 0) |
return FALSE; |
type_ptr = elf_symbol_from (abfd, sym); |
return ((type_ptr != NULL |
&& type_ptr->internal_elf_sym.st_shndx != 0 |
&& bfd_is_abs_section (sym->section)) |
|| !(sym->section->owner == abfd |
|| (sym->section->output_section->owner == abfd |
&& sym->section->output_offset == 0) |
|| bfd_is_abs_section (sym->section))); |
} |
/* Map symbol from it's internal number to the external number, moving |
all local symbols to be at the head of the list. */ |
static bfd_boolean |
elf_map_symbols (bfd *abfd, unsigned int *pnum_locals) |
{ |
unsigned int symcount = bfd_get_symcount (abfd); |
asymbol **syms = bfd_get_outsymbols (abfd); |
asymbol **sect_syms; |
unsigned int num_locals = 0; |
unsigned int num_globals = 0; |
unsigned int num_locals2 = 0; |
unsigned int num_globals2 = 0; |
int max_index = 0; |
unsigned int idx; |
asection *asect; |
asymbol **new_syms; |
#ifdef DEBUG |
fprintf (stderr, "elf_map_symbols\n"); |
fflush (stderr); |
#endif |
for (asect = abfd->sections; asect; asect = asect->next) |
{ |
if (max_index < asect->index) |
max_index = asect->index; |
} |
max_index++; |
sect_syms = (asymbol **) bfd_zalloc2 (abfd, max_index, sizeof (asymbol *)); |
if (sect_syms == NULL) |
return FALSE; |
elf_section_syms (abfd) = sect_syms; |
elf_num_section_syms (abfd) = max_index; |
/* Init sect_syms entries for any section symbols we have already |
decided to output. */ |
for (idx = 0; idx < symcount; idx++) |
{ |
asymbol *sym = syms[idx]; |
if ((sym->flags & BSF_SECTION_SYM) != 0 |
&& sym->value == 0 |
&& !ignore_section_sym (abfd, sym) |
&& !bfd_is_abs_section (sym->section)) |
{ |
asection *sec = sym->section; |
if (sec->owner != abfd) |
sec = sec->output_section; |
sect_syms[sec->index] = syms[idx]; |
} |
} |
/* Classify all of the symbols. */ |
for (idx = 0; idx < symcount; idx++) |
{ |
if (sym_is_global (abfd, syms[idx])) |
num_globals++; |
else if (!ignore_section_sym (abfd, syms[idx])) |
num_locals++; |
} |
/* We will be adding a section symbol for each normal BFD section. Most |
sections will already have a section symbol in outsymbols, but |
eg. SHT_GROUP sections will not, and we need the section symbol mapped |
at least in that case. */ |
for (asect = abfd->sections; asect; asect = asect->next) |
{ |
if (sect_syms[asect->index] == NULL) |
{ |
if (!sym_is_global (abfd, asect->symbol)) |
num_locals++; |
else |
num_globals++; |
} |
} |
/* Now sort the symbols so the local symbols are first. */ |
new_syms = (asymbol **) bfd_alloc2 (abfd, num_locals + num_globals, |
sizeof (asymbol *)); |
if (new_syms == NULL) |
return FALSE; |
for (idx = 0; idx < symcount; idx++) |
{ |
asymbol *sym = syms[idx]; |
unsigned int i; |
if (sym_is_global (abfd, sym)) |
i = num_locals + num_globals2++; |
else if (!ignore_section_sym (abfd, sym)) |
i = num_locals2++; |
else |
continue; |
new_syms[i] = sym; |
sym->udata.i = i + 1; |
} |
for (asect = abfd->sections; asect; asect = asect->next) |
{ |
if (sect_syms[asect->index] == NULL) |
{ |
asymbol *sym = asect->symbol; |
unsigned int i; |
sect_syms[asect->index] = sym; |
if (!sym_is_global (abfd, sym)) |
i = num_locals2++; |
else |
i = num_locals + num_globals2++; |
new_syms[i] = sym; |
sym->udata.i = i + 1; |
} |
} |
bfd_set_symtab (abfd, new_syms, num_locals + num_globals); |
*pnum_locals = num_locals; |
return TRUE; |
} |
/* Align to the maximum file alignment that could be required for any |
ELF data structure. */ |
static inline file_ptr |
align_file_position (file_ptr off, int align) |
{ |
return (off + align - 1) & ~(align - 1); |
} |
/* Assign a file position to a section, optionally aligning to the |
required section alignment. */ |
file_ptr |
_bfd_elf_assign_file_position_for_section (Elf_Internal_Shdr *i_shdrp, |
file_ptr offset, |
bfd_boolean align) |
{ |
if (align && i_shdrp->sh_addralign > 1) |
offset = BFD_ALIGN (offset, i_shdrp->sh_addralign); |
i_shdrp->sh_offset = offset; |
if (i_shdrp->bfd_section != NULL) |
i_shdrp->bfd_section->filepos = offset; |
if (i_shdrp->sh_type != SHT_NOBITS) |
offset += i_shdrp->sh_size; |
return offset; |
} |
/* Compute the file positions we are going to put the sections at, and |
otherwise prepare to begin writing out the ELF file. If LINK_INFO |
is not NULL, this is being called by the ELF backend linker. */ |
bfd_boolean |
_bfd_elf_compute_section_file_positions (bfd *abfd, |
struct bfd_link_info *link_info) |
{ |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
struct fake_section_arg fsargs; |
bfd_boolean failed; |
struct bfd_strtab_hash *strtab = NULL; |
Elf_Internal_Shdr *shstrtab_hdr; |
bfd_boolean need_symtab; |
if (abfd->output_has_begun) |
return TRUE; |
/* Do any elf backend specific processing first. */ |
if (bed->elf_backend_begin_write_processing) |
(*bed->elf_backend_begin_write_processing) (abfd, link_info); |
if (! prep_headers (abfd)) |
return FALSE; |
/* Post process the headers if necessary. */ |
if (bed->elf_backend_post_process_headers) |
(*bed->elf_backend_post_process_headers) (abfd, link_info); |
fsargs.failed = FALSE; |
fsargs.link_info = link_info; |
bfd_map_over_sections (abfd, elf_fake_sections, &fsargs); |
if (fsargs.failed) |
return FALSE; |
if (!assign_section_numbers (abfd, link_info)) |
return FALSE; |
/* The backend linker builds symbol table information itself. */ |
need_symtab = (link_info == NULL |
&& (bfd_get_symcount (abfd) > 0 |
|| ((abfd->flags & (EXEC_P | DYNAMIC | HAS_RELOC)) |
== HAS_RELOC))); |
if (need_symtab) |
{ |
/* Non-zero if doing a relocatable link. */ |
int relocatable_p = ! (abfd->flags & (EXEC_P | DYNAMIC)); |
if (! swap_out_syms (abfd, &strtab, relocatable_p)) |
return FALSE; |
} |
failed = FALSE; |
if (link_info == NULL) |
{ |
bfd_map_over_sections (abfd, bfd_elf_set_group_contents, &failed); |
if (failed) |
return FALSE; |
} |
shstrtab_hdr = &elf_tdata (abfd)->shstrtab_hdr; |
/* sh_name was set in prep_headers. */ |
shstrtab_hdr->sh_type = SHT_STRTAB; |
shstrtab_hdr->sh_flags = 0; |
shstrtab_hdr->sh_addr = 0; |
shstrtab_hdr->sh_size = _bfd_elf_strtab_size (elf_shstrtab (abfd)); |
shstrtab_hdr->sh_entsize = 0; |
shstrtab_hdr->sh_link = 0; |
shstrtab_hdr->sh_info = 0; |
/* sh_offset is set in assign_file_positions_except_relocs. */ |
shstrtab_hdr->sh_addralign = 1; |
if (!assign_file_positions_except_relocs (abfd, link_info)) |
return FALSE; |
if (need_symtab) |
{ |
file_ptr off; |
Elf_Internal_Shdr *hdr; |
off = elf_next_file_pos (abfd); |
hdr = &elf_tdata (abfd)->symtab_hdr; |
off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE); |
hdr = &elf_tdata (abfd)->symtab_shndx_hdr; |
if (hdr->sh_size != 0) |
off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE); |
hdr = &elf_tdata (abfd)->strtab_hdr; |
off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE); |
elf_next_file_pos (abfd) = off; |
/* Now that we know where the .strtab section goes, write it |
out. */ |
if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0 |
|| ! _bfd_stringtab_emit (abfd, strtab)) |
return FALSE; |
_bfd_stringtab_free (strtab); |
} |
abfd->output_has_begun = TRUE; |
return TRUE; |
} |
/* Make an initial estimate of the size of the program header. If we |
get the number wrong here, we'll redo section placement. */ |
static bfd_size_type |
get_program_header_size (bfd *abfd, struct bfd_link_info *info) |
{ |
size_t segs; |
asection *s; |
const struct elf_backend_data *bed; |
/* Assume we will need exactly two PT_LOAD segments: one for text |
and one for data. */ |
segs = 2; |
s = bfd_get_section_by_name (abfd, ".interp"); |
if (s != NULL && (s->flags & SEC_LOAD) != 0) |
{ |
/* If we have a loadable interpreter section, we need a |
PT_INTERP segment. In this case, assume we also need a |
PT_PHDR segment, although that may not be true for all |
targets. */ |
segs += 2; |
} |
if (bfd_get_section_by_name (abfd, ".dynamic") != NULL) |
{ |
/* We need a PT_DYNAMIC segment. */ |
++segs; |
} |
if (info != NULL && info->relro) |
{ |
/* We need a PT_GNU_RELRO segment. */ |
++segs; |
} |
if (elf_eh_frame_hdr (abfd)) |
{ |
/* We need a PT_GNU_EH_FRAME segment. */ |
++segs; |
} |
if (elf_stack_flags (abfd)) |
{ |
/* We need a PT_GNU_STACK segment. */ |
++segs; |
} |
for (s = abfd->sections; s != NULL; s = s->next) |
{ |
if ((s->flags & SEC_LOAD) != 0 |
&& CONST_STRNEQ (s->name, ".note")) |
{ |
/* We need a PT_NOTE segment. */ |
++segs; |
/* Try to create just one PT_NOTE segment |
for all adjacent loadable .note* sections. |
gABI requires that within a PT_NOTE segment |
(and also inside of each SHT_NOTE section) |
each note is padded to a multiple of 4 size, |
so we check whether the sections are correctly |
aligned. */ |
if (s->alignment_power == 2) |
while (s->next != NULL |
&& s->next->alignment_power == 2 |
&& (s->next->flags & SEC_LOAD) != 0 |
&& CONST_STRNEQ (s->next->name, ".note")) |
s = s->next; |
} |
} |
for (s = abfd->sections; s != NULL; s = s->next) |
{ |
if (s->flags & SEC_THREAD_LOCAL) |
{ |
/* We need a PT_TLS segment. */ |
++segs; |
break; |
} |
} |
/* Let the backend count up any program headers it might need. */ |
bed = get_elf_backend_data (abfd); |
if (bed->elf_backend_additional_program_headers) |
{ |
int a; |
a = (*bed->elf_backend_additional_program_headers) (abfd, info); |
if (a == -1) |
abort (); |
segs += a; |
} |
return segs * bed->s->sizeof_phdr; |
} |
/* Find the segment that contains the output_section of section. */ |
Elf_Internal_Phdr * |
_bfd_elf_find_segment_containing_section (bfd * abfd, asection * section) |
{ |
struct elf_segment_map *m; |
Elf_Internal_Phdr *p; |
for (m = elf_seg_map (abfd), p = elf_tdata (abfd)->phdr; |
m != NULL; |
m = m->next, p++) |
{ |
int i; |
for (i = m->count - 1; i >= 0; i--) |
if (m->sections[i] == section) |
return p; |
} |
return NULL; |
} |
/* Create a mapping from a set of sections to a program segment. */ |
static struct elf_segment_map * |
make_mapping (bfd *abfd, |
asection **sections, |
unsigned int from, |
unsigned int to, |
bfd_boolean phdr) |
{ |
struct elf_segment_map *m; |
unsigned int i; |
asection **hdrpp; |
bfd_size_type amt; |
amt = sizeof (struct elf_segment_map); |
amt += (to - from - 1) * sizeof (asection *); |
m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); |
if (m == NULL) |
return NULL; |
m->next = NULL; |
m->p_type = PT_LOAD; |
for (i = from, hdrpp = sections + from; i < to; i++, hdrpp++) |
m->sections[i - from] = *hdrpp; |
m->count = to - from; |
if (from == 0 && phdr) |
{ |
/* Include the headers in the first PT_LOAD segment. */ |
m->includes_filehdr = 1; |
m->includes_phdrs = 1; |
} |
return m; |
} |
/* Create the PT_DYNAMIC segment, which includes DYNSEC. Returns NULL |
on failure. */ |
struct elf_segment_map * |
_bfd_elf_make_dynamic_segment (bfd *abfd, asection *dynsec) |
{ |
struct elf_segment_map *m; |
m = (struct elf_segment_map *) bfd_zalloc (abfd, |
sizeof (struct elf_segment_map)); |
if (m == NULL) |
return NULL; |
m->next = NULL; |
m->p_type = PT_DYNAMIC; |
m->count = 1; |
m->sections[0] = dynsec; |
return m; |
} |
/* Possibly add or remove segments from the segment map. */ |
static bfd_boolean |
elf_modify_segment_map (bfd *abfd, |
struct bfd_link_info *info, |
bfd_boolean remove_empty_load) |
{ |
struct elf_segment_map **m; |
const struct elf_backend_data *bed; |
/* The placement algorithm assumes that non allocated sections are |
not in PT_LOAD segments. We ensure this here by removing such |
sections from the segment map. We also remove excluded |
sections. Finally, any PT_LOAD segment without sections is |
removed. */ |
m = &elf_seg_map (abfd); |
while (*m) |
{ |
unsigned int i, new_count; |
for (new_count = 0, i = 0; i < (*m)->count; i++) |
{ |
if (((*m)->sections[i]->flags & SEC_EXCLUDE) == 0 |
&& (((*m)->sections[i]->flags & SEC_ALLOC) != 0 |
|| (*m)->p_type != PT_LOAD)) |
{ |
(*m)->sections[new_count] = (*m)->sections[i]; |
new_count++; |
} |
} |
(*m)->count = new_count; |
if (remove_empty_load && (*m)->p_type == PT_LOAD && (*m)->count == 0) |
*m = (*m)->next; |
else |
m = &(*m)->next; |
} |
bed = get_elf_backend_data (abfd); |
if (bed->elf_backend_modify_segment_map != NULL) |
{ |
if (!(*bed->elf_backend_modify_segment_map) (abfd, info)) |
return FALSE; |
} |
return TRUE; |
} |
/* Set up a mapping from BFD sections to program segments. */ |
bfd_boolean |
_bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) |
{ |
unsigned int count; |
struct elf_segment_map *m; |
asection **sections = NULL; |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
bfd_boolean no_user_phdrs; |
no_user_phdrs = elf_seg_map (abfd) == NULL; |
if (info != NULL) |
info->user_phdrs = !no_user_phdrs; |
if (no_user_phdrs && bfd_count_sections (abfd) != 0) |
{ |
asection *s; |
unsigned int i; |
struct elf_segment_map *mfirst; |
struct elf_segment_map **pm; |
asection *last_hdr; |
bfd_vma last_size; |
unsigned int phdr_index; |
bfd_vma maxpagesize; |
asection **hdrpp; |
bfd_boolean phdr_in_segment = TRUE; |
bfd_boolean writable; |
int tls_count = 0; |
asection *first_tls = NULL; |
asection *dynsec, *eh_frame_hdr; |
bfd_size_type amt; |
bfd_vma addr_mask, wrap_to = 0; |
/* Select the allocated sections, and sort them. */ |
sections = (asection **) bfd_malloc2 (bfd_count_sections (abfd), |
sizeof (asection *)); |
if (sections == NULL) |
goto error_return; |
/* Calculate top address, avoiding undefined behaviour of shift |
left operator when shift count is equal to size of type |
being shifted. */ |
addr_mask = ((bfd_vma) 1 << (bfd_arch_bits_per_address (abfd) - 1)) - 1; |
addr_mask = (addr_mask << 1) + 1; |
i = 0; |
for (s = abfd->sections; s != NULL; s = s->next) |
{ |
if ((s->flags & SEC_ALLOC) != 0) |
{ |
sections[i] = s; |
++i; |
/* A wrapping section potentially clashes with header. */ |
if (((s->lma + s->size) & addr_mask) < (s->lma & addr_mask)) |
wrap_to = (s->lma + s->size) & addr_mask; |
} |
} |
BFD_ASSERT (i <= bfd_count_sections (abfd)); |
count = i; |
qsort (sections, (size_t) count, sizeof (asection *), elf_sort_sections); |
/* Build the mapping. */ |
mfirst = NULL; |
pm = &mfirst; |
/* If we have a .interp section, then create a PT_PHDR segment for |
the program headers and a PT_INTERP segment for the .interp |
section. */ |
s = bfd_get_section_by_name (abfd, ".interp"); |
if (s != NULL && (s->flags & SEC_LOAD) != 0) |
{ |
amt = sizeof (struct elf_segment_map); |
m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); |
if (m == NULL) |
goto error_return; |
m->next = NULL; |
m->p_type = PT_PHDR; |
/* FIXME: UnixWare and Solaris set PF_X, Irix 5 does not. */ |
m->p_flags = PF_R | PF_X; |
m->p_flags_valid = 1; |
m->includes_phdrs = 1; |
*pm = m; |
pm = &m->next; |
amt = sizeof (struct elf_segment_map); |
m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); |
if (m == NULL) |
goto error_return; |
m->next = NULL; |
m->p_type = PT_INTERP; |
m->count = 1; |
m->sections[0] = s; |
*pm = m; |
pm = &m->next; |
} |
/* Look through the sections. We put sections in the same program |
segment when the start of the second section can be placed within |
a few bytes of the end of the first section. */ |
last_hdr = NULL; |
last_size = 0; |
phdr_index = 0; |
maxpagesize = bed->maxpagesize; |
writable = FALSE; |
dynsec = bfd_get_section_by_name (abfd, ".dynamic"); |
if (dynsec != NULL |
&& (dynsec->flags & SEC_LOAD) == 0) |
dynsec = NULL; |
/* Deal with -Ttext or something similar such that the first section |
is not adjacent to the program headers. This is an |
approximation, since at this point we don't know exactly how many |
program headers we will need. */ |
if (count > 0) |
{ |
bfd_size_type phdr_size = elf_program_header_size (abfd); |
if (phdr_size == (bfd_size_type) -1) |
phdr_size = get_program_header_size (abfd, info); |
phdr_size += bed->s->sizeof_ehdr; |
if ((abfd->flags & D_PAGED) == 0 |
|| (sections[0]->lma & addr_mask) < phdr_size |
|| ((sections[0]->lma & addr_mask) % maxpagesize |
< phdr_size % maxpagesize) |
|| (sections[0]->lma & addr_mask & -maxpagesize) < wrap_to) |
phdr_in_segment = FALSE; |
} |
for (i = 0, hdrpp = sections; i < count; i++, hdrpp++) |
{ |
asection *hdr; |
bfd_boolean new_segment; |
hdr = *hdrpp; |
/* See if this section and the last one will fit in the same |
segment. */ |
if (last_hdr == NULL) |
{ |
/* If we don't have a segment yet, then we don't need a new |
one (we build the last one after this loop). */ |
new_segment = FALSE; |
} |
else if (last_hdr->lma - last_hdr->vma != hdr->lma - hdr->vma) |
{ |
/* If this section has a different relation between the |
virtual address and the load address, then we need a new |
segment. */ |
new_segment = TRUE; |
} |
else if (hdr->lma < last_hdr->lma + last_size |
|| last_hdr->lma + last_size < last_hdr->lma) |
{ |
/* If this section has a load address that makes it overlap |
the previous section, then we need a new segment. */ |
new_segment = TRUE; |
} |
/* In the next test we have to be careful when last_hdr->lma is close |
to the end of the address space. If the aligned address wraps |
around to the start of the address space, then there are no more |
pages left in memory and it is OK to assume that the current |
section can be included in the current segment. */ |
else if ((BFD_ALIGN (last_hdr->lma + last_size, maxpagesize) + maxpagesize |
> last_hdr->lma) |
&& (BFD_ALIGN (last_hdr->lma + last_size, maxpagesize) + maxpagesize |
<= hdr->lma)) |
{ |
/* If putting this section in this segment would force us to |
skip a page in the segment, then we need a new segment. */ |
new_segment = TRUE; |
} |
else if ((last_hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) == 0 |
&& (hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) != 0) |
{ |
/* We don't want to put a loadable section after a |
nonloadable section in the same segment. |
Consider .tbss sections as loadable for this purpose. */ |
new_segment = TRUE; |
} |
else if ((abfd->flags & D_PAGED) == 0) |
{ |
/* If the file is not demand paged, which means that we |
don't require the sections to be correctly aligned in the |
file, then there is no other reason for a new segment. */ |
new_segment = FALSE; |
} |
else if (! writable |
&& (hdr->flags & SEC_READONLY) == 0 |
&& (((last_hdr->lma + last_size - 1) & -maxpagesize) |
!= (hdr->lma & -maxpagesize))) |
{ |
/* We don't want to put a writable section in a read only |
segment, unless they are on the same page in memory |
anyhow. We already know that the last section does not |
bring us past the current section on the page, so the |
only case in which the new section is not on the same |
page as the previous section is when the previous section |
ends precisely on a page boundary. */ |
new_segment = TRUE; |
} |
else |
{ |
/* Otherwise, we can use the same segment. */ |
new_segment = FALSE; |
} |
/* Allow interested parties a chance to override our decision. */ |
if (last_hdr != NULL |
&& info != NULL |
&& info->callbacks->override_segment_assignment != NULL) |
new_segment |
= info->callbacks->override_segment_assignment (info, abfd, hdr, |
last_hdr, |
new_segment); |
if (! new_segment) |
{ |
if ((hdr->flags & SEC_READONLY) == 0) |
writable = TRUE; |
last_hdr = hdr; |
/* .tbss sections effectively have zero size. */ |
if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) |
!= SEC_THREAD_LOCAL) |
last_size = hdr->size; |
else |
last_size = 0; |
continue; |
} |
/* We need a new program segment. We must create a new program |
header holding all the sections from phdr_index until hdr. */ |
m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment); |
if (m == NULL) |
goto error_return; |
*pm = m; |
pm = &m->next; |
if ((hdr->flags & SEC_READONLY) == 0) |
writable = TRUE; |
else |
writable = FALSE; |
last_hdr = hdr; |
/* .tbss sections effectively have zero size. */ |
if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) != SEC_THREAD_LOCAL) |
last_size = hdr->size; |
else |
last_size = 0; |
phdr_index = i; |
phdr_in_segment = FALSE; |
} |
/* Create a final PT_LOAD program segment, but not if it's just |
for .tbss. */ |
if (last_hdr != NULL |
&& (i - phdr_index != 1 |
|| ((last_hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) |
!= SEC_THREAD_LOCAL))) |
{ |
m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment); |
if (m == NULL) |
goto error_return; |
*pm = m; |
pm = &m->next; |
} |
/* If there is a .dynamic section, throw in a PT_DYNAMIC segment. */ |
if (dynsec != NULL) |
{ |
m = _bfd_elf_make_dynamic_segment (abfd, dynsec); |
if (m == NULL) |
goto error_return; |
*pm = m; |
pm = &m->next; |
} |
/* For each batch of consecutive loadable .note sections, |
add a PT_NOTE segment. We don't use bfd_get_section_by_name, |
because if we link together nonloadable .note sections and |
loadable .note sections, we will generate two .note sections |
in the output file. FIXME: Using names for section types is |
bogus anyhow. */ |
for (s = abfd->sections; s != NULL; s = s->next) |
{ |
if ((s->flags & SEC_LOAD) != 0 |
&& CONST_STRNEQ (s->name, ".note")) |
{ |
asection *s2; |
count = 1; |
amt = sizeof (struct elf_segment_map); |
if (s->alignment_power == 2) |
for (s2 = s; s2->next != NULL; s2 = s2->next) |
{ |
if (s2->next->alignment_power == 2 |
&& (s2->next->flags & SEC_LOAD) != 0 |
&& CONST_STRNEQ (s2->next->name, ".note") |
&& align_power (s2->lma + s2->size, 2) |
== s2->next->lma) |
count++; |
else |
break; |
} |
amt += (count - 1) * sizeof (asection *); |
m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); |
if (m == NULL) |
goto error_return; |
m->next = NULL; |
m->p_type = PT_NOTE; |
m->count = count; |
while (count > 1) |
{ |
m->sections[m->count - count--] = s; |
BFD_ASSERT ((s->flags & SEC_THREAD_LOCAL) == 0); |
s = s->next; |
} |
m->sections[m->count - 1] = s; |
BFD_ASSERT ((s->flags & SEC_THREAD_LOCAL) == 0); |
*pm = m; |
pm = &m->next; |
} |
if (s->flags & SEC_THREAD_LOCAL) |
{ |
if (! tls_count) |
first_tls = s; |
tls_count++; |
} |
} |
/* If there are any SHF_TLS output sections, add PT_TLS segment. */ |
if (tls_count > 0) |
{ |
amt = sizeof (struct elf_segment_map); |
amt += (tls_count - 1) * sizeof (asection *); |
m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); |
if (m == NULL) |
goto error_return; |
m->next = NULL; |
m->p_type = PT_TLS; |
m->count = tls_count; |
/* Mandated PF_R. */ |
m->p_flags = PF_R; |
m->p_flags_valid = 1; |
for (i = 0; i < (unsigned int) tls_count; ++i) |
{ |
BFD_ASSERT (first_tls->flags & SEC_THREAD_LOCAL); |
m->sections[i] = first_tls; |
first_tls = first_tls->next; |
} |
*pm = m; |
pm = &m->next; |
} |
/* If there is a .eh_frame_hdr section, throw in a PT_GNU_EH_FRAME |
segment. */ |
eh_frame_hdr = elf_eh_frame_hdr (abfd); |
if (eh_frame_hdr != NULL |
&& (eh_frame_hdr->output_section->flags & SEC_LOAD) != 0) |
{ |
amt = sizeof (struct elf_segment_map); |
m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); |
if (m == NULL) |
goto error_return; |
m->next = NULL; |
m->p_type = PT_GNU_EH_FRAME; |
m->count = 1; |
m->sections[0] = eh_frame_hdr->output_section; |
*pm = m; |
pm = &m->next; |
} |
if (elf_stack_flags (abfd)) |
{ |
amt = sizeof (struct elf_segment_map); |
m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); |
if (m == NULL) |
goto error_return; |
m->next = NULL; |
m->p_type = PT_GNU_STACK; |
m->p_flags = elf_stack_flags (abfd); |
m->p_align = bed->stack_align; |
m->p_flags_valid = 1; |
m->p_align_valid = m->p_align != 0; |
if (info->stacksize > 0) |
{ |
m->p_size = info->stacksize; |
m->p_size_valid = 1; |
} |
*pm = m; |
pm = &m->next; |
} |
if (info != NULL && info->relro) |
{ |
for (m = mfirst; m != NULL; m = m->next) |
{ |
if (m->p_type == PT_LOAD |
&& m->count != 0 |
&& m->sections[0]->vma >= info->relro_start |
&& m->sections[0]->vma < info->relro_end) |
{ |
i = m->count; |
while (--i != (unsigned) -1) |
if ((m->sections[i]->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) |
== (SEC_LOAD | SEC_HAS_CONTENTS)) |
break; |
if (i == (unsigned) -1) |
continue; |
if (m->sections[i]->vma + m->sections[i]->size |
>= info->relro_end) |
break; |
} |
} |
/* Make a PT_GNU_RELRO segment only when it isn't empty. */ |
if (m != NULL) |
{ |
amt = sizeof (struct elf_segment_map); |
m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); |
if (m == NULL) |
goto error_return; |
m->next = NULL; |
m->p_type = PT_GNU_RELRO; |
m->p_flags = PF_R; |
m->p_flags_valid = 1; |
*pm = m; |
pm = &m->next; |
} |
} |
free (sections); |
elf_seg_map (abfd) = mfirst; |
} |
if (!elf_modify_segment_map (abfd, info, no_user_phdrs)) |
return FALSE; |
for (count = 0, m = elf_seg_map (abfd); m != NULL; m = m->next) |
++count; |
elf_program_header_size (abfd) = count * bed->s->sizeof_phdr; |
return TRUE; |
error_return: |
if (sections != NULL) |
free (sections); |
return FALSE; |
} |
/* Sort sections by address. */ |
static int |
elf_sort_sections (const void *arg1, const void *arg2) |
{ |
const asection *sec1 = *(const asection **) arg1; |
const asection *sec2 = *(const asection **) arg2; |
bfd_size_type size1, size2; |
/* Sort by LMA first, since this is the address used to |
place the section into a segment. */ |
if (sec1->lma < sec2->lma) |
return -1; |
else if (sec1->lma > sec2->lma) |
return 1; |
/* Then sort by VMA. Normally the LMA and the VMA will be |
the same, and this will do nothing. */ |
if (sec1->vma < sec2->vma) |
return -1; |
else if (sec1->vma > sec2->vma) |
return 1; |
/* Put !SEC_LOAD sections after SEC_LOAD ones. */ |
#define TOEND(x) (((x)->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) == 0) |
if (TOEND (sec1)) |
{ |
if (TOEND (sec2)) |
{ |
/* If the indicies are the same, do not return 0 |
here, but continue to try the next comparison. */ |
if (sec1->target_index - sec2->target_index != 0) |
return sec1->target_index - sec2->target_index; |
} |
else |
return 1; |
} |
else if (TOEND (sec2)) |
return -1; |
#undef TOEND |
/* Sort by size, to put zero sized sections |
before others at the same address. */ |
size1 = (sec1->flags & SEC_LOAD) ? sec1->size : 0; |
size2 = (sec2->flags & SEC_LOAD) ? sec2->size : 0; |
if (size1 < size2) |
return -1; |
if (size1 > size2) |
return 1; |
return sec1->target_index - sec2->target_index; |
} |
/* Ian Lance Taylor writes: |
We shouldn't be using % with a negative signed number. That's just |
not good. We have to make sure either that the number is not |
negative, or that the number has an unsigned type. When the types |
are all the same size they wind up as unsigned. When file_ptr is a |
larger signed type, the arithmetic winds up as signed long long, |
which is wrong. |
What we're trying to say here is something like ``increase OFF by |
the least amount that will cause it to be equal to the VMA modulo |
the page size.'' */ |
/* In other words, something like: |
vma_offset = m->sections[0]->vma % bed->maxpagesize; |
off_offset = off % bed->maxpagesize; |
if (vma_offset < off_offset) |
adjustment = vma_offset + bed->maxpagesize - off_offset; |
else |
adjustment = vma_offset - off_offset; |
which can can be collapsed into the expression below. */ |
static file_ptr |
vma_page_aligned_bias (bfd_vma vma, ufile_ptr off, bfd_vma maxpagesize) |
{ |
return ((vma - off) % maxpagesize); |
} |
static void |
print_segment_map (const struct elf_segment_map *m) |
{ |
unsigned int j; |
const char *pt = get_segment_type (m->p_type); |
char buf[32]; |
if (pt == NULL) |
{ |
if (m->p_type >= PT_LOPROC && m->p_type <= PT_HIPROC) |
sprintf (buf, "LOPROC+%7.7x", |
(unsigned int) (m->p_type - PT_LOPROC)); |
else if (m->p_type >= PT_LOOS && m->p_type <= PT_HIOS) |
sprintf (buf, "LOOS+%7.7x", |
(unsigned int) (m->p_type - PT_LOOS)); |
else |
snprintf (buf, sizeof (buf), "%8.8x", |
(unsigned int) m->p_type); |
pt = buf; |
} |
fflush (stdout); |
fprintf (stderr, "%s:", pt); |
for (j = 0; j < m->count; j++) |
fprintf (stderr, " %s", m->sections [j]->name); |
putc ('\n',stderr); |
fflush (stderr); |
} |
static bfd_boolean |
write_zeros (bfd *abfd, file_ptr pos, bfd_size_type len) |
{ |
void *buf; |
bfd_boolean ret; |
if (bfd_seek (abfd, pos, SEEK_SET) != 0) |
return FALSE; |
buf = bfd_zmalloc (len); |
if (buf == NULL) |
return FALSE; |
ret = bfd_bwrite (buf, len, abfd) == len; |
free (buf); |
return ret; |
} |
/* Assign file positions to the sections based on the mapping from |
sections to segments. This function also sets up some fields in |
the file header. */ |
static bfd_boolean |
assign_file_positions_for_load_sections (bfd *abfd, |
struct bfd_link_info *link_info) |
{ |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
struct elf_segment_map *m; |
Elf_Internal_Phdr *phdrs; |
Elf_Internal_Phdr *p; |
file_ptr off; |
bfd_size_type maxpagesize; |
unsigned int alloc; |
unsigned int i, j; |
bfd_vma header_pad = 0; |
if (link_info == NULL |
&& !_bfd_elf_map_sections_to_segments (abfd, link_info)) |
return FALSE; |
alloc = 0; |
for (m = elf_seg_map (abfd); m != NULL; m = m->next) |
{ |
++alloc; |
if (m->header_size) |
header_pad = m->header_size; |
} |
if (alloc) |
{ |
elf_elfheader (abfd)->e_phoff = bed->s->sizeof_ehdr; |
elf_elfheader (abfd)->e_phentsize = bed->s->sizeof_phdr; |
} |
else |
{ |
/* PR binutils/12467. */ |
elf_elfheader (abfd)->e_phoff = 0; |
elf_elfheader (abfd)->e_phentsize = 0; |
} |
elf_elfheader (abfd)->e_phnum = alloc; |
if (elf_program_header_size (abfd) == (bfd_size_type) -1) |
elf_program_header_size (abfd) = alloc * bed->s->sizeof_phdr; |
else |
BFD_ASSERT (elf_program_header_size (abfd) |
>= alloc * bed->s->sizeof_phdr); |
if (alloc == 0) |
{ |
elf_next_file_pos (abfd) = bed->s->sizeof_ehdr; |
return TRUE; |
} |
/* We're writing the size in elf_program_header_size (abfd), |
see assign_file_positions_except_relocs, so make sure we have |
that amount allocated, with trailing space cleared. |
The variable alloc contains the computed need, while |
elf_program_header_size (abfd) contains the size used for the |
layout. |
See ld/emultempl/elf-generic.em:gld${EMULATION_NAME}_map_segments |
where the layout is forced to according to a larger size in the |
last iterations for the testcase ld-elf/header. */ |
BFD_ASSERT (elf_program_header_size (abfd) % bed->s->sizeof_phdr |
== 0); |
phdrs = (Elf_Internal_Phdr *) |
bfd_zalloc2 (abfd, |
(elf_program_header_size (abfd) / bed->s->sizeof_phdr), |
sizeof (Elf_Internal_Phdr)); |
elf_tdata (abfd)->phdr = phdrs; |
if (phdrs == NULL) |
return FALSE; |
maxpagesize = 1; |
if ((abfd->flags & D_PAGED) != 0) |
maxpagesize = bed->maxpagesize; |
off = bed->s->sizeof_ehdr; |
off += alloc * bed->s->sizeof_phdr; |
if (header_pad < (bfd_vma) off) |
header_pad = 0; |
else |
header_pad -= off; |
off += header_pad; |
for (m = elf_seg_map (abfd), p = phdrs, j = 0; |
m != NULL; |
m = m->next, p++, j++) |
{ |
asection **secpp; |
bfd_vma off_adjust; |
bfd_boolean no_contents; |
/* If elf_segment_map is not from map_sections_to_segments, the |
sections may not be correctly ordered. NOTE: sorting should |
not be done to the PT_NOTE section of a corefile, which may |
contain several pseudo-sections artificially created by bfd. |
Sorting these pseudo-sections breaks things badly. */ |
if (m->count > 1 |
&& !(elf_elfheader (abfd)->e_type == ET_CORE |
&& m->p_type == PT_NOTE)) |
qsort (m->sections, (size_t) m->count, sizeof (asection *), |
elf_sort_sections); |
/* An ELF segment (described by Elf_Internal_Phdr) may contain a |
number of sections with contents contributing to both p_filesz |
and p_memsz, followed by a number of sections with no contents |
that just contribute to p_memsz. In this loop, OFF tracks next |
available file offset for PT_LOAD and PT_NOTE segments. */ |
p->p_type = m->p_type; |
p->p_flags = m->p_flags; |
if (m->count == 0) |
p->p_vaddr = 0; |
else |
p->p_vaddr = m->sections[0]->vma - m->p_vaddr_offset; |
if (m->p_paddr_valid) |
p->p_paddr = m->p_paddr; |
else if (m->count == 0) |
p->p_paddr = 0; |
else |
p->p_paddr = m->sections[0]->lma - m->p_vaddr_offset; |
if (p->p_type == PT_LOAD |
&& (abfd->flags & D_PAGED) != 0) |
{ |
/* p_align in demand paged PT_LOAD segments effectively stores |
the maximum page size. When copying an executable with |
objcopy, we set m->p_align from the input file. Use this |
value for maxpagesize rather than bed->maxpagesize, which |
may be different. Note that we use maxpagesize for PT_TLS |
segment alignment later in this function, so we are relying |
on at least one PT_LOAD segment appearing before a PT_TLS |
segment. */ |
if (m->p_align_valid) |
maxpagesize = m->p_align; |
p->p_align = maxpagesize; |
} |
else if (m->p_align_valid) |
p->p_align = m->p_align; |
else if (m->count == 0) |
p->p_align = 1 << bed->s->log_file_align; |
else |
p->p_align = 0; |
no_contents = FALSE; |
off_adjust = 0; |
if (p->p_type == PT_LOAD |
&& m->count > 0) |
{ |
bfd_size_type align; |
unsigned int align_power = 0; |
if (m->p_align_valid) |
align = p->p_align; |
else |
{ |
for (i = 0, secpp = m->sections; i < m->count; i++, secpp++) |
{ |
unsigned int secalign; |
secalign = bfd_get_section_alignment (abfd, *secpp); |
if (secalign > align_power) |
align_power = secalign; |
} |
align = (bfd_size_type) 1 << align_power; |
if (align < maxpagesize) |
align = maxpagesize; |
} |
for (i = 0; i < m->count; i++) |
if ((m->sections[i]->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0) |
/* If we aren't making room for this section, then |
it must be SHT_NOBITS regardless of what we've |
set via struct bfd_elf_special_section. */ |
elf_section_type (m->sections[i]) = SHT_NOBITS; |
/* Find out whether this segment contains any loadable |
sections. */ |
no_contents = TRUE; |
for (i = 0; i < m->count; i++) |
if (elf_section_type (m->sections[i]) != SHT_NOBITS) |
{ |
no_contents = FALSE; |
break; |
} |
off_adjust = vma_page_aligned_bias (p->p_vaddr, off, align); |
off += off_adjust; |
if (no_contents) |
{ |
/* We shouldn't need to align the segment on disk since |
the segment doesn't need file space, but the gABI |
arguably requires the alignment and glibc ld.so |
checks it. So to comply with the alignment |
requirement but not waste file space, we adjust |
p_offset for just this segment. (OFF_ADJUST is |
subtracted from OFF later.) This may put p_offset |
past the end of file, but that shouldn't matter. */ |
} |
else |
off_adjust = 0; |
} |
/* Make sure the .dynamic section is the first section in the |
PT_DYNAMIC segment. */ |
else if (p->p_type == PT_DYNAMIC |
&& m->count > 1 |
&& strcmp (m->sections[0]->name, ".dynamic") != 0) |
{ |
_bfd_error_handler |
(_("%B: The first section in the PT_DYNAMIC segment is not the .dynamic section"), |
abfd); |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
/* Set the note section type to SHT_NOTE. */ |
else if (p->p_type == PT_NOTE) |
for (i = 0; i < m->count; i++) |
elf_section_type (m->sections[i]) = SHT_NOTE; |
p->p_offset = 0; |
p->p_filesz = 0; |
p->p_memsz = 0; |
if (m->includes_filehdr) |
{ |
if (!m->p_flags_valid) |
p->p_flags |= PF_R; |
p->p_filesz = bed->s->sizeof_ehdr; |
p->p_memsz = bed->s->sizeof_ehdr; |
if (m->count > 0) |
{ |
if (p->p_vaddr < (bfd_vma) off) |
{ |
(*_bfd_error_handler) |
(_("%B: Not enough room for program headers, try linking with -N"), |
abfd); |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
p->p_vaddr -= off; |
if (!m->p_paddr_valid) |
p->p_paddr -= off; |
} |
} |
if (m->includes_phdrs) |
{ |
if (!m->p_flags_valid) |
p->p_flags |= PF_R; |
if (!m->includes_filehdr) |
{ |
p->p_offset = bed->s->sizeof_ehdr; |
if (m->count > 0) |
{ |
p->p_vaddr -= off - p->p_offset; |
if (!m->p_paddr_valid) |
p->p_paddr -= off - p->p_offset; |
} |
} |
p->p_filesz += alloc * bed->s->sizeof_phdr; |
p->p_memsz += alloc * bed->s->sizeof_phdr; |
if (m->count) |
{ |
p->p_filesz += header_pad; |
p->p_memsz += header_pad; |
} |
} |
if (p->p_type == PT_LOAD |
|| (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core)) |
{ |
if (!m->includes_filehdr && !m->includes_phdrs) |
p->p_offset = off; |
else |
{ |
file_ptr adjust; |
adjust = off - (p->p_offset + p->p_filesz); |
if (!no_contents) |
p->p_filesz += adjust; |
p->p_memsz += adjust; |
} |
} |
/* Set up p_filesz, p_memsz, p_align and p_flags from the section |
maps. Set filepos for sections in PT_LOAD segments, and in |
core files, for sections in PT_NOTE segments. |
assign_file_positions_for_non_load_sections will set filepos |
for other sections and update p_filesz for other segments. */ |
for (i = 0, secpp = m->sections; i < m->count; i++, secpp++) |
{ |
asection *sec; |
bfd_size_type align; |
Elf_Internal_Shdr *this_hdr; |
sec = *secpp; |
this_hdr = &elf_section_data (sec)->this_hdr; |
align = (bfd_size_type) 1 << bfd_get_section_alignment (abfd, sec); |
if ((p->p_type == PT_LOAD |
|| p->p_type == PT_TLS) |
&& (this_hdr->sh_type != SHT_NOBITS |
|| ((this_hdr->sh_flags & SHF_ALLOC) != 0 |
&& ((this_hdr->sh_flags & SHF_TLS) == 0 |
|| p->p_type == PT_TLS)))) |
{ |
bfd_vma p_start = p->p_paddr; |
bfd_vma p_end = p_start + p->p_memsz; |
bfd_vma s_start = sec->lma; |
bfd_vma adjust = s_start - p_end; |
if (adjust != 0 |
&& (s_start < p_end |
|| p_end < p_start)) |
{ |
(*_bfd_error_handler) |
(_("%B: section %A lma %#lx adjusted to %#lx"), abfd, sec, |
(unsigned long) s_start, (unsigned long) p_end); |
adjust = 0; |
sec->lma = p_end; |
} |
p->p_memsz += adjust; |
if (this_hdr->sh_type != SHT_NOBITS) |
{ |
if (p->p_filesz + adjust < p->p_memsz) |
{ |
/* We have a PROGBITS section following NOBITS ones. |
Allocate file space for the NOBITS section(s) and |
zero it. */ |
adjust = p->p_memsz - p->p_filesz; |
if (!write_zeros (abfd, off, adjust)) |
return FALSE; |
} |
off += adjust; |
p->p_filesz += adjust; |
} |
} |
if (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core) |
{ |
/* The section at i == 0 is the one that actually contains |
everything. */ |
if (i == 0) |
{ |
this_hdr->sh_offset = sec->filepos = off; |
off += this_hdr->sh_size; |
p->p_filesz = this_hdr->sh_size; |
p->p_memsz = 0; |
p->p_align = 1; |
} |
else |
{ |
/* The rest are fake sections that shouldn't be written. */ |
sec->filepos = 0; |
sec->size = 0; |
sec->flags = 0; |
continue; |
} |
} |
else |
{ |
if (p->p_type == PT_LOAD) |
{ |
this_hdr->sh_offset = sec->filepos = off; |
if (this_hdr->sh_type != SHT_NOBITS) |
off += this_hdr->sh_size; |
} |
else if (this_hdr->sh_type == SHT_NOBITS |
&& (this_hdr->sh_flags & SHF_TLS) != 0 |
&& this_hdr->sh_offset == 0) |
{ |
/* This is a .tbss section that didn't get a PT_LOAD. |
(See _bfd_elf_map_sections_to_segments "Create a |
final PT_LOAD".) Set sh_offset to the value it |
would have if we had created a zero p_filesz and |
p_memsz PT_LOAD header for the section. This |
also makes the PT_TLS header have the same |
p_offset value. */ |
bfd_vma adjust = vma_page_aligned_bias (this_hdr->sh_addr, |
off, align); |
this_hdr->sh_offset = sec->filepos = off + adjust; |
} |
if (this_hdr->sh_type != SHT_NOBITS) |
{ |
p->p_filesz += this_hdr->sh_size; |
/* A load section without SHF_ALLOC is something like |
a note section in a PT_NOTE segment. These take |
file space but are not loaded into memory. */ |
if ((this_hdr->sh_flags & SHF_ALLOC) != 0) |
p->p_memsz += this_hdr->sh_size; |
} |
else if ((this_hdr->sh_flags & SHF_ALLOC) != 0) |
{ |
if (p->p_type == PT_TLS) |
p->p_memsz += this_hdr->sh_size; |
/* .tbss is special. It doesn't contribute to p_memsz of |
normal segments. */ |
else if ((this_hdr->sh_flags & SHF_TLS) == 0) |
p->p_memsz += this_hdr->sh_size; |
} |
if (align > p->p_align |
&& !m->p_align_valid |
&& (p->p_type != PT_LOAD |
|| (abfd->flags & D_PAGED) == 0)) |
p->p_align = align; |
} |
if (!m->p_flags_valid) |
{ |
p->p_flags |= PF_R; |
if ((this_hdr->sh_flags & SHF_EXECINSTR) != 0) |
p->p_flags |= PF_X; |
if ((this_hdr->sh_flags & SHF_WRITE) != 0) |
p->p_flags |= PF_W; |
} |
} |
off -= off_adjust; |
/* Check that all sections are in a PT_LOAD segment. |
Don't check funky gdb generated core files. */ |
if (p->p_type == PT_LOAD && bfd_get_format (abfd) != bfd_core) |
{ |
bfd_boolean check_vma = TRUE; |
for (i = 1; i < m->count; i++) |
if (m->sections[i]->vma == m->sections[i - 1]->vma |
&& ELF_SECTION_SIZE (&(elf_section_data (m->sections[i]) |
->this_hdr), p) != 0 |
&& ELF_SECTION_SIZE (&(elf_section_data (m->sections[i - 1]) |
->this_hdr), p) != 0) |
{ |
/* Looks like we have overlays packed into the segment. */ |
check_vma = FALSE; |
break; |
} |
for (i = 0; i < m->count; i++) |
{ |
Elf_Internal_Shdr *this_hdr; |
asection *sec; |
sec = m->sections[i]; |
this_hdr = &(elf_section_data(sec)->this_hdr); |
if (!ELF_SECTION_IN_SEGMENT_1 (this_hdr, p, check_vma, 0) |
&& !ELF_TBSS_SPECIAL (this_hdr, p)) |
{ |
(*_bfd_error_handler) |
(_("%B: section `%A' can't be allocated in segment %d"), |
abfd, sec, j); |
print_segment_map (m); |
} |
} |
} |
} |
elf_next_file_pos (abfd) = off; |
return TRUE; |
} |
/* Assign file positions for the other sections. */ |
static bfd_boolean |
assign_file_positions_for_non_load_sections (bfd *abfd, |
struct bfd_link_info *link_info) |
{ |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
Elf_Internal_Shdr **i_shdrpp; |
Elf_Internal_Shdr **hdrpp; |
Elf_Internal_Phdr *phdrs; |
Elf_Internal_Phdr *p; |
struct elf_segment_map *m; |
struct elf_segment_map *hdrs_segment; |
bfd_vma filehdr_vaddr, filehdr_paddr; |
bfd_vma phdrs_vaddr, phdrs_paddr; |
file_ptr off; |
unsigned int num_sec; |
unsigned int i; |
unsigned int count; |
i_shdrpp = elf_elfsections (abfd); |
num_sec = elf_numsections (abfd); |
off = elf_next_file_pos (abfd); |
for (i = 1, hdrpp = i_shdrpp + 1; i < num_sec; i++, hdrpp++) |
{ |
Elf_Internal_Shdr *hdr; |
hdr = *hdrpp; |
if (hdr->bfd_section != NULL |
&& (hdr->bfd_section->filepos != 0 |
|| (hdr->sh_type == SHT_NOBITS |
&& hdr->contents == NULL))) |
BFD_ASSERT (hdr->sh_offset == hdr->bfd_section->filepos); |
else if ((hdr->sh_flags & SHF_ALLOC) != 0) |
{ |
if (hdr->sh_size != 0) |
(*_bfd_error_handler) |
(_("%B: warning: allocated section `%s' not in segment"), |
abfd, |
(hdr->bfd_section == NULL |
? "*unknown*" |
: hdr->bfd_section->name)); |
/* We don't need to page align empty sections. */ |
if ((abfd->flags & D_PAGED) != 0 && hdr->sh_size != 0) |
off += vma_page_aligned_bias (hdr->sh_addr, off, |
bed->maxpagesize); |
else |
off += vma_page_aligned_bias (hdr->sh_addr, off, |
hdr->sh_addralign); |
off = _bfd_elf_assign_file_position_for_section (hdr, off, |
FALSE); |
} |
else if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA) |
&& hdr->bfd_section == NULL) |
|| hdr == i_shdrpp[elf_onesymtab (abfd)] |
|| hdr == i_shdrpp[elf_symtab_shndx (abfd)] |
|| hdr == i_shdrpp[elf_strtab_sec (abfd)]) |
hdr->sh_offset = -1; |
else |
off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE); |
} |
/* Now that we have set the section file positions, we can set up |
the file positions for the non PT_LOAD segments. */ |
count = 0; |
filehdr_vaddr = 0; |
filehdr_paddr = 0; |
phdrs_vaddr = bed->maxpagesize + bed->s->sizeof_ehdr; |
phdrs_paddr = 0; |
hdrs_segment = NULL; |
phdrs = elf_tdata (abfd)->phdr; |
for (m = elf_seg_map (abfd), p = phdrs; m != NULL; m = m->next, p++) |
{ |
++count; |
if (p->p_type != PT_LOAD) |
continue; |
if (m->includes_filehdr) |
{ |
filehdr_vaddr = p->p_vaddr; |
filehdr_paddr = p->p_paddr; |
} |
if (m->includes_phdrs) |
{ |
phdrs_vaddr = p->p_vaddr; |
phdrs_paddr = p->p_paddr; |
if (m->includes_filehdr) |
{ |
hdrs_segment = m; |
phdrs_vaddr += bed->s->sizeof_ehdr; |
phdrs_paddr += bed->s->sizeof_ehdr; |
} |
} |
} |
if (hdrs_segment != NULL && link_info != NULL) |
{ |
/* There is a segment that contains both the file headers and the |
program headers, so provide a symbol __ehdr_start pointing there. |
A program can use this to examine itself robustly. */ |
struct elf_link_hash_entry *hash |
= elf_link_hash_lookup (elf_hash_table (link_info), "__ehdr_start", |
FALSE, FALSE, TRUE); |
/* If the symbol was referenced and not defined, define it. */ |
if (hash != NULL |
&& (hash->root.type == bfd_link_hash_new |
|| hash->root.type == bfd_link_hash_undefined |
|| hash->root.type == bfd_link_hash_undefweak |
|| hash->root.type == bfd_link_hash_common)) |
{ |
asection *s = NULL; |
if (hdrs_segment->count != 0) |
/* The segment contains sections, so use the first one. */ |
s = hdrs_segment->sections[0]; |
else |
/* Use the first (i.e. lowest-addressed) section in any segment. */ |
for (m = elf_seg_map (abfd); m != NULL; m = m->next) |
if (m->count != 0) |
{ |
s = m->sections[0]; |
break; |
} |
if (s != NULL) |
{ |
hash->root.u.def.value = filehdr_vaddr - s->vma; |
hash->root.u.def.section = s; |
} |
else |
{ |
hash->root.u.def.value = filehdr_vaddr; |
hash->root.u.def.section = bfd_abs_section_ptr; |
} |
hash->root.type = bfd_link_hash_defined; |
hash->def_regular = 1; |
hash->non_elf = 0; |
} |
} |
for (m = elf_seg_map (abfd), p = phdrs; m != NULL; m = m->next, p++) |
{ |
if (p->p_type == PT_GNU_RELRO) |
{ |
const Elf_Internal_Phdr *lp; |
struct elf_segment_map *lm; |
if (link_info != NULL) |
{ |
/* During linking the range of the RELRO segment is passed |
in link_info. */ |
for (lm = elf_seg_map (abfd), lp = phdrs; |
lm != NULL; |
lm = lm->next, lp++) |
{ |
if (lp->p_type == PT_LOAD |
&& lp->p_vaddr < link_info->relro_end |
&& lp->p_vaddr + lp->p_filesz >= link_info->relro_end |
&& lm->count != 0 |
&& lm->sections[0]->vma >= link_info->relro_start) |
break; |
} |
/* PR ld/14207. If the RELRO segment doesn't fit in the |
LOAD segment, it should be removed. */ |
BFD_ASSERT (lm != NULL); |
} |
else |
{ |
/* Otherwise we are copying an executable or shared |
library, but we need to use the same linker logic. */ |
for (lp = phdrs; lp < phdrs + count; ++lp) |
{ |
if (lp->p_type == PT_LOAD |
&& lp->p_paddr == p->p_paddr) |
break; |
} |
} |
if (lp < phdrs + count) |
{ |
p->p_vaddr = lp->p_vaddr; |
p->p_paddr = lp->p_paddr; |
p->p_offset = lp->p_offset; |
if (link_info != NULL) |
p->p_filesz = link_info->relro_end - lp->p_vaddr; |
else if (m->p_size_valid) |
p->p_filesz = m->p_size; |
else |
abort (); |
p->p_memsz = p->p_filesz; |
/* Preserve the alignment and flags if they are valid. The |
gold linker generates RW/4 for the PT_GNU_RELRO section. |
It is better for objcopy/strip to honor these attributes |
otherwise gdb will choke when using separate debug files. |
*/ |
if (!m->p_align_valid) |
p->p_align = 1; |
if (!m->p_flags_valid) |
p->p_flags = (lp->p_flags & ~PF_W); |
} |
else |
{ |
memset (p, 0, sizeof *p); |
p->p_type = PT_NULL; |
} |
} |
else if (p->p_type == PT_GNU_STACK) |
{ |
if (m->p_size_valid) |
p->p_memsz = m->p_size; |
} |
else if (m->count != 0) |
{ |
if (p->p_type != PT_LOAD |
&& (p->p_type != PT_NOTE |
|| bfd_get_format (abfd) != bfd_core)) |
{ |
BFD_ASSERT (!m->includes_filehdr && !m->includes_phdrs); |
p->p_filesz = 0; |
p->p_offset = m->sections[0]->filepos; |
for (i = m->count; i-- != 0;) |
{ |
asection *sect = m->sections[i]; |
Elf_Internal_Shdr *hdr = &elf_section_data (sect)->this_hdr; |
if (hdr->sh_type != SHT_NOBITS) |
{ |
p->p_filesz = (sect->filepos - m->sections[0]->filepos |
+ hdr->sh_size); |
break; |
} |
} |
} |
} |
else if (m->includes_filehdr) |
{ |
p->p_vaddr = filehdr_vaddr; |
if (! m->p_paddr_valid) |
p->p_paddr = filehdr_paddr; |
} |
else if (m->includes_phdrs) |
{ |
p->p_vaddr = phdrs_vaddr; |
if (! m->p_paddr_valid) |
p->p_paddr = phdrs_paddr; |
} |
} |
elf_next_file_pos (abfd) = off; |
return TRUE; |
} |
/* Work out the file positions of all the sections. This is called by |
_bfd_elf_compute_section_file_positions. All the section sizes and |
VMAs must be known before this is called. |
Reloc sections come in two flavours: Those processed specially as |
"side-channel" data attached to a section to which they apply, and |
those that bfd doesn't process as relocations. The latter sort are |
stored in a normal bfd section by bfd_section_from_shdr. We don't |
consider the former sort here, unless they form part of the loadable |
image. Reloc sections not assigned here will be handled later by |
assign_file_positions_for_relocs. |
We also don't set the positions of the .symtab and .strtab here. */ |
static bfd_boolean |
assign_file_positions_except_relocs (bfd *abfd, |
struct bfd_link_info *link_info) |
{ |
struct elf_obj_tdata *tdata = elf_tdata (abfd); |
Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd); |
file_ptr off; |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0 |
&& bfd_get_format (abfd) != bfd_core) |
{ |
Elf_Internal_Shdr ** const i_shdrpp = elf_elfsections (abfd); |
unsigned int num_sec = elf_numsections (abfd); |
Elf_Internal_Shdr **hdrpp; |
unsigned int i; |
/* Start after the ELF header. */ |
off = i_ehdrp->e_ehsize; |
/* We are not creating an executable, which means that we are |
not creating a program header, and that the actual order of |
the sections in the file is unimportant. */ |
for (i = 1, hdrpp = i_shdrpp + 1; i < num_sec; i++, hdrpp++) |
{ |
Elf_Internal_Shdr *hdr; |
hdr = *hdrpp; |
if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA) |
&& hdr->bfd_section == NULL) |
|| i == elf_onesymtab (abfd) |
|| i == elf_symtab_shndx (abfd) |
|| i == elf_strtab_sec (abfd)) |
{ |
hdr->sh_offset = -1; |
} |
else |
off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE); |
} |
} |
else |
{ |
unsigned int alloc; |
/* Assign file positions for the loaded sections based on the |
assignment of sections to segments. */ |
if (!assign_file_positions_for_load_sections (abfd, link_info)) |
return FALSE; |
/* And for non-load sections. */ |
if (!assign_file_positions_for_non_load_sections (abfd, link_info)) |
return FALSE; |
if (bed->elf_backend_modify_program_headers != NULL) |
{ |
if (!(*bed->elf_backend_modify_program_headers) (abfd, link_info)) |
return FALSE; |
} |
/* Write out the program headers. */ |
alloc = elf_program_header_size (abfd) / bed->s->sizeof_phdr; |
if (bfd_seek (abfd, (bfd_signed_vma) bed->s->sizeof_ehdr, SEEK_SET) != 0 |
|| bed->s->write_out_phdrs (abfd, tdata->phdr, alloc) != 0) |
return FALSE; |
off = elf_next_file_pos (abfd); |
} |
/* Place the section headers. */ |
off = align_file_position (off, 1 << bed->s->log_file_align); |
i_ehdrp->e_shoff = off; |
off += i_ehdrp->e_shnum * i_ehdrp->e_shentsize; |
elf_next_file_pos (abfd) = off; |
return TRUE; |
} |
static bfd_boolean |
prep_headers (bfd *abfd) |
{ |
Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form. */ |
struct elf_strtab_hash *shstrtab; |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
i_ehdrp = elf_elfheader (abfd); |
shstrtab = _bfd_elf_strtab_init (); |
if (shstrtab == NULL) |
return FALSE; |
elf_shstrtab (abfd) = shstrtab; |
i_ehdrp->e_ident[EI_MAG0] = ELFMAG0; |
i_ehdrp->e_ident[EI_MAG1] = ELFMAG1; |
i_ehdrp->e_ident[EI_MAG2] = ELFMAG2; |
i_ehdrp->e_ident[EI_MAG3] = ELFMAG3; |
i_ehdrp->e_ident[EI_CLASS] = bed->s->elfclass; |
i_ehdrp->e_ident[EI_DATA] = |
bfd_big_endian (abfd) ? ELFDATA2MSB : ELFDATA2LSB; |
i_ehdrp->e_ident[EI_VERSION] = bed->s->ev_current; |
if ((abfd->flags & DYNAMIC) != 0) |
i_ehdrp->e_type = ET_DYN; |
else if ((abfd->flags & EXEC_P) != 0) |
i_ehdrp->e_type = ET_EXEC; |
else if (bfd_get_format (abfd) == bfd_core) |
i_ehdrp->e_type = ET_CORE; |
else |
i_ehdrp->e_type = ET_REL; |
switch (bfd_get_arch (abfd)) |
{ |
case bfd_arch_unknown: |
i_ehdrp->e_machine = EM_NONE; |
break; |
/* There used to be a long list of cases here, each one setting |
e_machine to the same EM_* macro #defined as ELF_MACHINE_CODE |
in the corresponding bfd definition. To avoid duplication, |
the switch was removed. Machines that need special handling |
can generally do it in elf_backend_final_write_processing(), |
unless they need the information earlier than the final write. |
Such need can generally be supplied by replacing the tests for |
e_machine with the conditions used to determine it. */ |
default: |
i_ehdrp->e_machine = bed->elf_machine_code; |
} |
i_ehdrp->e_version = bed->s->ev_current; |
i_ehdrp->e_ehsize = bed->s->sizeof_ehdr; |
/* No program header, for now. */ |
i_ehdrp->e_phoff = 0; |
i_ehdrp->e_phentsize = 0; |
i_ehdrp->e_phnum = 0; |
/* Each bfd section is section header entry. */ |
i_ehdrp->e_entry = bfd_get_start_address (abfd); |
i_ehdrp->e_shentsize = bed->s->sizeof_shdr; |
/* If we're building an executable, we'll need a program header table. */ |
if (abfd->flags & EXEC_P) |
/* It all happens later. */ |
; |
else |
{ |
i_ehdrp->e_phentsize = 0; |
i_ehdrp->e_phoff = 0; |
} |
elf_tdata (abfd)->symtab_hdr.sh_name = |
(unsigned int) _bfd_elf_strtab_add (shstrtab, ".symtab", FALSE); |
elf_tdata (abfd)->strtab_hdr.sh_name = |
(unsigned int) _bfd_elf_strtab_add (shstrtab, ".strtab", FALSE); |
elf_tdata (abfd)->shstrtab_hdr.sh_name = |
(unsigned int) _bfd_elf_strtab_add (shstrtab, ".shstrtab", FALSE); |
if (elf_tdata (abfd)->symtab_hdr.sh_name == (unsigned int) -1 |
|| elf_tdata (abfd)->symtab_hdr.sh_name == (unsigned int) -1 |
|| elf_tdata (abfd)->shstrtab_hdr.sh_name == (unsigned int) -1) |
return FALSE; |
return TRUE; |
} |
/* Assign file positions for all the reloc sections which are not part |
of the loadable file image. */ |
void |
_bfd_elf_assign_file_positions_for_relocs (bfd *abfd) |
{ |
file_ptr off; |
unsigned int i, num_sec; |
Elf_Internal_Shdr **shdrpp; |
off = elf_next_file_pos (abfd); |
num_sec = elf_numsections (abfd); |
for (i = 1, shdrpp = elf_elfsections (abfd) + 1; i < num_sec; i++, shdrpp++) |
{ |
Elf_Internal_Shdr *shdrp; |
shdrp = *shdrpp; |
if ((shdrp->sh_type == SHT_REL || shdrp->sh_type == SHT_RELA) |
&& shdrp->sh_offset == -1) |
off = _bfd_elf_assign_file_position_for_section (shdrp, off, TRUE); |
} |
elf_next_file_pos (abfd) = off; |
} |
bfd_boolean |
_bfd_elf_write_object_contents (bfd *abfd) |
{ |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
Elf_Internal_Shdr **i_shdrp; |
bfd_boolean failed; |
unsigned int count, num_sec; |
struct elf_obj_tdata *t; |
if (! abfd->output_has_begun |
&& ! _bfd_elf_compute_section_file_positions (abfd, NULL)) |
return FALSE; |
i_shdrp = elf_elfsections (abfd); |
failed = FALSE; |
bfd_map_over_sections (abfd, bed->s->write_relocs, &failed); |
if (failed) |
return FALSE; |
_bfd_elf_assign_file_positions_for_relocs (abfd); |
/* After writing the headers, we need to write the sections too... */ |
num_sec = elf_numsections (abfd); |
for (count = 1; count < num_sec; count++) |
{ |
if (bed->elf_backend_section_processing) |
(*bed->elf_backend_section_processing) (abfd, i_shdrp[count]); |
if (i_shdrp[count]->contents) |
{ |
bfd_size_type amt = i_shdrp[count]->sh_size; |
if (bfd_seek (abfd, i_shdrp[count]->sh_offset, SEEK_SET) != 0 |
|| bfd_bwrite (i_shdrp[count]->contents, amt, abfd) != amt) |
return FALSE; |
} |
} |
/* Write out the section header names. */ |
t = elf_tdata (abfd); |
if (elf_shstrtab (abfd) != NULL |
&& (bfd_seek (abfd, t->shstrtab_hdr.sh_offset, SEEK_SET) != 0 |
|| !_bfd_elf_strtab_emit (abfd, elf_shstrtab (abfd)))) |
return FALSE; |
if (bed->elf_backend_final_write_processing) |
(*bed->elf_backend_final_write_processing) (abfd, elf_linker (abfd)); |
if (!bed->s->write_shdrs_and_ehdr (abfd)) |
return FALSE; |
/* This is last since write_shdrs_and_ehdr can touch i_shdrp[0]. */ |
if (t->o->build_id.after_write_object_contents != NULL) |
return (*t->o->build_id.after_write_object_contents) (abfd); |
return TRUE; |
} |
bfd_boolean |
_bfd_elf_write_corefile_contents (bfd *abfd) |
{ |
/* Hopefully this can be done just like an object file. */ |
return _bfd_elf_write_object_contents (abfd); |
} |
/* Given a section, search the header to find them. */ |
unsigned int |
_bfd_elf_section_from_bfd_section (bfd *abfd, struct bfd_section *asect) |
{ |
const struct elf_backend_data *bed; |
unsigned int sec_index; |
if (elf_section_data (asect) != NULL |
&& elf_section_data (asect)->this_idx != 0) |
return elf_section_data (asect)->this_idx; |
if (bfd_is_abs_section (asect)) |
sec_index = SHN_ABS; |
else if (bfd_is_com_section (asect)) |
sec_index = SHN_COMMON; |
else if (bfd_is_und_section (asect)) |
sec_index = SHN_UNDEF; |
else |
sec_index = SHN_BAD; |
bed = get_elf_backend_data (abfd); |
if (bed->elf_backend_section_from_bfd_section) |
{ |
int retval = sec_index; |
if ((*bed->elf_backend_section_from_bfd_section) (abfd, asect, &retval)) |
return retval; |
} |
if (sec_index == SHN_BAD) |
bfd_set_error (bfd_error_nonrepresentable_section); |
return sec_index; |
} |
/* Given a BFD symbol, return the index in the ELF symbol table, or -1 |
on error. */ |
int |
_bfd_elf_symbol_from_bfd_symbol (bfd *abfd, asymbol **asym_ptr_ptr) |
{ |
asymbol *asym_ptr = *asym_ptr_ptr; |
int idx; |
flagword flags = asym_ptr->flags; |
/* When gas creates relocations against local labels, it creates its |
own symbol for the section, but does put the symbol into the |
symbol chain, so udata is 0. When the linker is generating |
relocatable output, this section symbol may be for one of the |
input sections rather than the output section. */ |
if (asym_ptr->udata.i == 0 |
&& (flags & BSF_SECTION_SYM) |
&& asym_ptr->section) |
{ |
asection *sec; |
int indx; |
sec = asym_ptr->section; |
if (sec->owner != abfd && sec->output_section != NULL) |
sec = sec->output_section; |
if (sec->owner == abfd |
&& (indx = sec->index) < elf_num_section_syms (abfd) |
&& elf_section_syms (abfd)[indx] != NULL) |
asym_ptr->udata.i = elf_section_syms (abfd)[indx]->udata.i; |
} |
idx = asym_ptr->udata.i; |
if (idx == 0) |
{ |
/* This case can occur when using --strip-symbol on a symbol |
which is used in a relocation entry. */ |
(*_bfd_error_handler) |
(_("%B: symbol `%s' required but not present"), |
abfd, bfd_asymbol_name (asym_ptr)); |
bfd_set_error (bfd_error_no_symbols); |
return -1; |
} |
#if DEBUG & 4 |
{ |
fprintf (stderr, |
"elf_symbol_from_bfd_symbol 0x%.8lx, name = %s, sym num = %d, flags = 0x%.8lx\n", |
(long) asym_ptr, asym_ptr->name, idx, (long) flags); |
fflush (stderr); |
} |
#endif |
return idx; |
} |
/* Rewrite program header information. */ |
static bfd_boolean |
rewrite_elf_program_header (bfd *ibfd, bfd *obfd) |
{ |
Elf_Internal_Ehdr *iehdr; |
struct elf_segment_map *map; |
struct elf_segment_map *map_first; |
struct elf_segment_map **pointer_to_map; |
Elf_Internal_Phdr *segment; |
asection *section; |
unsigned int i; |
unsigned int num_segments; |
bfd_boolean phdr_included = FALSE; |
bfd_boolean p_paddr_valid; |
bfd_vma maxpagesize; |
struct elf_segment_map *phdr_adjust_seg = NULL; |
unsigned int phdr_adjust_num = 0; |
const struct elf_backend_data *bed; |
bed = get_elf_backend_data (ibfd); |
iehdr = elf_elfheader (ibfd); |
map_first = NULL; |
pointer_to_map = &map_first; |
num_segments = elf_elfheader (ibfd)->e_phnum; |
maxpagesize = get_elf_backend_data (obfd)->maxpagesize; |
/* Returns the end address of the segment + 1. */ |
#define SEGMENT_END(segment, start) \ |
(start + (segment->p_memsz > segment->p_filesz \ |
? segment->p_memsz : segment->p_filesz)) |
#define SECTION_SIZE(section, segment) \ |
(((section->flags & (SEC_HAS_CONTENTS | SEC_THREAD_LOCAL)) \ |
!= SEC_THREAD_LOCAL || segment->p_type == PT_TLS) \ |
? section->size : 0) |
/* Returns TRUE if the given section is contained within |
the given segment. VMA addresses are compared. */ |
#define IS_CONTAINED_BY_VMA(section, segment) \ |
(section->vma >= segment->p_vaddr \ |
&& (section->vma + SECTION_SIZE (section, segment) \ |
<= (SEGMENT_END (segment, segment->p_vaddr)))) |
/* Returns TRUE if the given section is contained within |
the given segment. LMA addresses are compared. */ |
#define IS_CONTAINED_BY_LMA(section, segment, base) \ |
(section->lma >= base \ |
&& (section->lma + SECTION_SIZE (section, segment) \ |
<= SEGMENT_END (segment, base))) |
/* Handle PT_NOTE segment. */ |
#define IS_NOTE(p, s) \ |
(p->p_type == PT_NOTE \ |
&& elf_section_type (s) == SHT_NOTE \ |
&& (bfd_vma) s->filepos >= p->p_offset \ |
&& ((bfd_vma) s->filepos + s->size \ |
<= p->p_offset + p->p_filesz)) |
/* Special case: corefile "NOTE" section containing regs, prpsinfo |
etc. */ |
#define IS_COREFILE_NOTE(p, s) \ |
(IS_NOTE (p, s) \ |
&& bfd_get_format (ibfd) == bfd_core \ |
&& s->vma == 0 \ |
&& s->lma == 0) |
/* The complicated case when p_vaddr is 0 is to handle the Solaris |
linker, which generates a PT_INTERP section with p_vaddr and |
p_memsz set to 0. */ |
#define IS_SOLARIS_PT_INTERP(p, s) \ |
(p->p_vaddr == 0 \ |
&& p->p_paddr == 0 \ |
&& p->p_memsz == 0 \ |
&& p->p_filesz > 0 \ |
&& (s->flags & SEC_HAS_CONTENTS) != 0 \ |
&& s->size > 0 \ |
&& (bfd_vma) s->filepos >= p->p_offset \ |
&& ((bfd_vma) s->filepos + s->size \ |
<= p->p_offset + p->p_filesz)) |
/* Decide if the given section should be included in the given segment. |
A section will be included if: |
1. It is within the address space of the segment -- we use the LMA |
if that is set for the segment and the VMA otherwise, |
2. It is an allocated section or a NOTE section in a PT_NOTE |
segment. |
3. There is an output section associated with it, |
4. The section has not already been allocated to a previous segment. |
5. PT_GNU_STACK segments do not include any sections. |
6. PT_TLS segment includes only SHF_TLS sections. |
7. SHF_TLS sections are only in PT_TLS or PT_LOAD segments. |
8. PT_DYNAMIC should not contain empty sections at the beginning |
(with the possible exception of .dynamic). */ |
#define IS_SECTION_IN_INPUT_SEGMENT(section, segment, bed) \ |
((((segment->p_paddr \ |
? IS_CONTAINED_BY_LMA (section, segment, segment->p_paddr) \ |
: IS_CONTAINED_BY_VMA (section, segment)) \ |
&& (section->flags & SEC_ALLOC) != 0) \ |
|| IS_NOTE (segment, section)) \ |
&& segment->p_type != PT_GNU_STACK \ |
&& (segment->p_type != PT_TLS \ |
|| (section->flags & SEC_THREAD_LOCAL)) \ |
&& (segment->p_type == PT_LOAD \ |
|| segment->p_type == PT_TLS \ |
|| (section->flags & SEC_THREAD_LOCAL) == 0) \ |
&& (segment->p_type != PT_DYNAMIC \ |
|| SECTION_SIZE (section, segment) > 0 \ |
|| (segment->p_paddr \ |
? segment->p_paddr != section->lma \ |
: segment->p_vaddr != section->vma) \ |
|| (strcmp (bfd_get_section_name (ibfd, section), ".dynamic") \ |
== 0)) \ |
&& !section->segment_mark) |
/* If the output section of a section in the input segment is NULL, |
it is removed from the corresponding output segment. */ |
#define INCLUDE_SECTION_IN_SEGMENT(section, segment, bed) \ |
(IS_SECTION_IN_INPUT_SEGMENT (section, segment, bed) \ |
&& section->output_section != NULL) |
/* Returns TRUE iff seg1 starts after the end of seg2. */ |
#define SEGMENT_AFTER_SEGMENT(seg1, seg2, field) \ |
(seg1->field >= SEGMENT_END (seg2, seg2->field)) |
/* Returns TRUE iff seg1 and seg2 overlap. Segments overlap iff both |
their VMA address ranges and their LMA address ranges overlap. |
It is possible to have overlapping VMA ranges without overlapping LMA |
ranges. RedBoot images for example can have both .data and .bss mapped |
to the same VMA range, but with the .data section mapped to a different |
LMA. */ |
#define SEGMENT_OVERLAPS(seg1, seg2) \ |
( !(SEGMENT_AFTER_SEGMENT (seg1, seg2, p_vaddr) \ |
|| SEGMENT_AFTER_SEGMENT (seg2, seg1, p_vaddr)) \ |
&& !(SEGMENT_AFTER_SEGMENT (seg1, seg2, p_paddr) \ |
|| SEGMENT_AFTER_SEGMENT (seg2, seg1, p_paddr))) |
/* Initialise the segment mark field. */ |
for (section = ibfd->sections; section != NULL; section = section->next) |
section->segment_mark = FALSE; |
/* The Solaris linker creates program headers in which all the |
p_paddr fields are zero. When we try to objcopy or strip such a |
file, we get confused. Check for this case, and if we find it |
don't set the p_paddr_valid fields. */ |
p_paddr_valid = FALSE; |
for (i = 0, segment = elf_tdata (ibfd)->phdr; |
i < num_segments; |
i++, segment++) |
if (segment->p_paddr != 0) |
{ |
p_paddr_valid = TRUE; |
break; |
} |
/* Scan through the segments specified in the program header |
of the input BFD. For this first scan we look for overlaps |
in the loadable segments. These can be created by weird |
parameters to objcopy. Also, fix some solaris weirdness. */ |
for (i = 0, segment = elf_tdata (ibfd)->phdr; |
i < num_segments; |
i++, segment++) |
{ |
unsigned int j; |
Elf_Internal_Phdr *segment2; |
if (segment->p_type == PT_INTERP) |
for (section = ibfd->sections; section; section = section->next) |
if (IS_SOLARIS_PT_INTERP (segment, section)) |
{ |
/* Mininal change so that the normal section to segment |
assignment code will work. */ |
segment->p_vaddr = section->vma; |
break; |
} |
if (segment->p_type != PT_LOAD) |
{ |
/* Remove PT_GNU_RELRO segment. */ |
if (segment->p_type == PT_GNU_RELRO) |
segment->p_type = PT_NULL; |
continue; |
} |
/* Determine if this segment overlaps any previous segments. */ |
for (j = 0, segment2 = elf_tdata (ibfd)->phdr; j < i; j++, segment2++) |
{ |
bfd_signed_vma extra_length; |
if (segment2->p_type != PT_LOAD |
|| !SEGMENT_OVERLAPS (segment, segment2)) |
continue; |
/* Merge the two segments together. */ |
if (segment2->p_vaddr < segment->p_vaddr) |
{ |
/* Extend SEGMENT2 to include SEGMENT and then delete |
SEGMENT. */ |
extra_length = (SEGMENT_END (segment, segment->p_vaddr) |
- SEGMENT_END (segment2, segment2->p_vaddr)); |
if (extra_length > 0) |
{ |
segment2->p_memsz += extra_length; |
segment2->p_filesz += extra_length; |
} |
segment->p_type = PT_NULL; |
/* Since we have deleted P we must restart the outer loop. */ |
i = 0; |
segment = elf_tdata (ibfd)->phdr; |
break; |
} |
else |
{ |
/* Extend SEGMENT to include SEGMENT2 and then delete |
SEGMENT2. */ |
extra_length = (SEGMENT_END (segment2, segment2->p_vaddr) |
- SEGMENT_END (segment, segment->p_vaddr)); |
if (extra_length > 0) |
{ |
segment->p_memsz += extra_length; |
segment->p_filesz += extra_length; |
} |
segment2->p_type = PT_NULL; |
} |
} |
} |
/* The second scan attempts to assign sections to segments. */ |
for (i = 0, segment = elf_tdata (ibfd)->phdr; |
i < num_segments; |
i++, segment++) |
{ |
unsigned int section_count; |
asection **sections; |
asection *output_section; |
unsigned int isec; |
bfd_vma matching_lma; |
bfd_vma suggested_lma; |
unsigned int j; |
bfd_size_type amt; |
asection *first_section; |
bfd_boolean first_matching_lma; |
bfd_boolean first_suggested_lma; |
if (segment->p_type == PT_NULL) |
continue; |
first_section = NULL; |
/* Compute how many sections might be placed into this segment. */ |
for (section = ibfd->sections, section_count = 0; |
section != NULL; |
section = section->next) |
{ |
/* Find the first section in the input segment, which may be |
removed from the corresponding output segment. */ |
if (IS_SECTION_IN_INPUT_SEGMENT (section, segment, bed)) |
{ |
if (first_section == NULL) |
first_section = section; |
if (section->output_section != NULL) |
++section_count; |
} |
} |
/* Allocate a segment map big enough to contain |
all of the sections we have selected. */ |
amt = sizeof (struct elf_segment_map); |
amt += ((bfd_size_type) section_count - 1) * sizeof (asection *); |
map = (struct elf_segment_map *) bfd_zalloc (obfd, amt); |
if (map == NULL) |
return FALSE; |
/* Initialise the fields of the segment map. Default to |
using the physical address of the segment in the input BFD. */ |
map->next = NULL; |
map->p_type = segment->p_type; |
map->p_flags = segment->p_flags; |
map->p_flags_valid = 1; |
/* If the first section in the input segment is removed, there is |
no need to preserve segment physical address in the corresponding |
output segment. */ |
if (!first_section || first_section->output_section != NULL) |
{ |
map->p_paddr = segment->p_paddr; |
map->p_paddr_valid = p_paddr_valid; |
} |
/* Determine if this segment contains the ELF file header |
and if it contains the program headers themselves. */ |
map->includes_filehdr = (segment->p_offset == 0 |
&& segment->p_filesz >= iehdr->e_ehsize); |
map->includes_phdrs = 0; |
if (!phdr_included || segment->p_type != PT_LOAD) |
{ |
map->includes_phdrs = |
(segment->p_offset <= (bfd_vma) iehdr->e_phoff |
&& (segment->p_offset + segment->p_filesz |
>= ((bfd_vma) iehdr->e_phoff |
+ iehdr->e_phnum * iehdr->e_phentsize))); |
if (segment->p_type == PT_LOAD && map->includes_phdrs) |
phdr_included = TRUE; |
} |
if (section_count == 0) |
{ |
/* Special segments, such as the PT_PHDR segment, may contain |
no sections, but ordinary, loadable segments should contain |
something. They are allowed by the ELF spec however, so only |
a warning is produced. */ |
if (segment->p_type == PT_LOAD) |
(*_bfd_error_handler) (_("%B: warning: Empty loadable segment" |
" detected, is this intentional ?\n"), |
ibfd); |
map->count = 0; |
*pointer_to_map = map; |
pointer_to_map = &map->next; |
continue; |
} |
/* Now scan the sections in the input BFD again and attempt |
to add their corresponding output sections to the segment map. |
The problem here is how to handle an output section which has |
been moved (ie had its LMA changed). There are four possibilities: |
1. None of the sections have been moved. |
In this case we can continue to use the segment LMA from the |
input BFD. |
2. All of the sections have been moved by the same amount. |
In this case we can change the segment's LMA to match the LMA |
of the first section. |
3. Some of the sections have been moved, others have not. |
In this case those sections which have not been moved can be |
placed in the current segment which will have to have its size, |
and possibly its LMA changed, and a new segment or segments will |
have to be created to contain the other sections. |
4. The sections have been moved, but not by the same amount. |
In this case we can change the segment's LMA to match the LMA |
of the first section and we will have to create a new segment |
or segments to contain the other sections. |
In order to save time, we allocate an array to hold the section |
pointers that we are interested in. As these sections get assigned |
to a segment, they are removed from this array. */ |
sections = (asection **) bfd_malloc2 (section_count, sizeof (asection *)); |
if (sections == NULL) |
return FALSE; |
/* Step One: Scan for segment vs section LMA conflicts. |
Also add the sections to the section array allocated above. |
Also add the sections to the current segment. In the common |
case, where the sections have not been moved, this means that |
we have completely filled the segment, and there is nothing |
more to do. */ |
isec = 0; |
matching_lma = 0; |
suggested_lma = 0; |
first_matching_lma = TRUE; |
first_suggested_lma = TRUE; |
for (section = ibfd->sections; |
section != NULL; |
section = section->next) |
if (section == first_section) |
break; |
for (j = 0; section != NULL; section = section->next) |
{ |
if (INCLUDE_SECTION_IN_SEGMENT (section, segment, bed)) |
{ |
output_section = section->output_section; |
sections[j++] = section; |
/* The Solaris native linker always sets p_paddr to 0. |
We try to catch that case here, and set it to the |
correct value. Note - some backends require that |
p_paddr be left as zero. */ |
if (!p_paddr_valid |
&& segment->p_vaddr != 0 |
&& !bed->want_p_paddr_set_to_zero |
&& isec == 0 |
&& output_section->lma != 0 |
&& output_section->vma == (segment->p_vaddr |
+ (map->includes_filehdr |
? iehdr->e_ehsize |
: 0) |
+ (map->includes_phdrs |
? (iehdr->e_phnum |
* iehdr->e_phentsize) |
: 0))) |
map->p_paddr = segment->p_vaddr; |
/* Match up the physical address of the segment with the |
LMA address of the output section. */ |
if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr) |
|| IS_COREFILE_NOTE (segment, section) |
|| (bed->want_p_paddr_set_to_zero |
&& IS_CONTAINED_BY_VMA (output_section, segment))) |
{ |
if (first_matching_lma || output_section->lma < matching_lma) |
{ |
matching_lma = output_section->lma; |
first_matching_lma = FALSE; |
} |
/* We assume that if the section fits within the segment |
then it does not overlap any other section within that |
segment. */ |
map->sections[isec++] = output_section; |
} |
else if (first_suggested_lma) |
{ |
suggested_lma = output_section->lma; |
first_suggested_lma = FALSE; |
} |
if (j == section_count) |
break; |
} |
} |
BFD_ASSERT (j == section_count); |
/* Step Two: Adjust the physical address of the current segment, |
if necessary. */ |
if (isec == section_count) |
{ |
/* All of the sections fitted within the segment as currently |
specified. This is the default case. Add the segment to |
the list of built segments and carry on to process the next |
program header in the input BFD. */ |
map->count = section_count; |
*pointer_to_map = map; |
pointer_to_map = &map->next; |
if (p_paddr_valid |
&& !bed->want_p_paddr_set_to_zero |
&& matching_lma != map->p_paddr |
&& !map->includes_filehdr |
&& !map->includes_phdrs) |
/* There is some padding before the first section in the |
segment. So, we must account for that in the output |
segment's vma. */ |
map->p_vaddr_offset = matching_lma - map->p_paddr; |
free (sections); |
continue; |
} |
else |
{ |
if (!first_matching_lma) |
{ |
/* At least one section fits inside the current segment. |
Keep it, but modify its physical address to match the |
LMA of the first section that fitted. */ |
map->p_paddr = matching_lma; |
} |
else |
{ |
/* None of the sections fitted inside the current segment. |
Change the current segment's physical address to match |
the LMA of the first section. */ |
map->p_paddr = suggested_lma; |
} |
/* Offset the segment physical address from the lma |
to allow for space taken up by elf headers. */ |
if (map->includes_filehdr) |
{ |
if (map->p_paddr >= iehdr->e_ehsize) |
map->p_paddr -= iehdr->e_ehsize; |
else |
{ |
map->includes_filehdr = FALSE; |
map->includes_phdrs = FALSE; |
} |
} |
if (map->includes_phdrs) |
{ |
if (map->p_paddr >= iehdr->e_phnum * iehdr->e_phentsize) |
{ |
map->p_paddr -= iehdr->e_phnum * iehdr->e_phentsize; |
/* iehdr->e_phnum is just an estimate of the number |
of program headers that we will need. Make a note |
here of the number we used and the segment we chose |
to hold these headers, so that we can adjust the |
offset when we know the correct value. */ |
phdr_adjust_num = iehdr->e_phnum; |
phdr_adjust_seg = map; |
} |
else |
map->includes_phdrs = FALSE; |
} |
} |
/* Step Three: Loop over the sections again, this time assigning |
those that fit to the current segment and removing them from the |
sections array; but making sure not to leave large gaps. Once all |
possible sections have been assigned to the current segment it is |
added to the list of built segments and if sections still remain |
to be assigned, a new segment is constructed before repeating |
the loop. */ |
isec = 0; |
do |
{ |
map->count = 0; |
suggested_lma = 0; |
first_suggested_lma = TRUE; |
/* Fill the current segment with sections that fit. */ |
for (j = 0; j < section_count; j++) |
{ |
section = sections[j]; |
if (section == NULL) |
continue; |
output_section = section->output_section; |
BFD_ASSERT (output_section != NULL); |
if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr) |
|| IS_COREFILE_NOTE (segment, section)) |
{ |
if (map->count == 0) |
{ |
/* If the first section in a segment does not start at |
the beginning of the segment, then something is |
wrong. */ |
if (output_section->lma |
!= (map->p_paddr |
+ (map->includes_filehdr ? iehdr->e_ehsize : 0) |
+ (map->includes_phdrs |
? iehdr->e_phnum * iehdr->e_phentsize |
: 0))) |
abort (); |
} |
else |
{ |
asection *prev_sec; |
prev_sec = map->sections[map->count - 1]; |
/* If the gap between the end of the previous section |
and the start of this section is more than |
maxpagesize then we need to start a new segment. */ |
if ((BFD_ALIGN (prev_sec->lma + prev_sec->size, |
maxpagesize) |
< BFD_ALIGN (output_section->lma, maxpagesize)) |
|| (prev_sec->lma + prev_sec->size |
> output_section->lma)) |
{ |
if (first_suggested_lma) |
{ |
suggested_lma = output_section->lma; |
first_suggested_lma = FALSE; |
} |
continue; |
} |
} |
map->sections[map->count++] = output_section; |
++isec; |
sections[j] = NULL; |
section->segment_mark = TRUE; |
} |
else if (first_suggested_lma) |
{ |
suggested_lma = output_section->lma; |
first_suggested_lma = FALSE; |
} |
} |
BFD_ASSERT (map->count > 0); |
/* Add the current segment to the list of built segments. */ |
*pointer_to_map = map; |
pointer_to_map = &map->next; |
if (isec < section_count) |
{ |
/* We still have not allocated all of the sections to |
segments. Create a new segment here, initialise it |
and carry on looping. */ |
amt = sizeof (struct elf_segment_map); |
amt += ((bfd_size_type) section_count - 1) * sizeof (asection *); |
map = (struct elf_segment_map *) bfd_zalloc (obfd, amt); |
if (map == NULL) |
{ |
free (sections); |
return FALSE; |
} |
/* Initialise the fields of the segment map. Set the physical |
physical address to the LMA of the first section that has |
not yet been assigned. */ |
map->next = NULL; |
map->p_type = segment->p_type; |
map->p_flags = segment->p_flags; |
map->p_flags_valid = 1; |
map->p_paddr = suggested_lma; |
map->p_paddr_valid = p_paddr_valid; |
map->includes_filehdr = 0; |
map->includes_phdrs = 0; |
} |
} |
while (isec < section_count); |
free (sections); |
} |
elf_seg_map (obfd) = map_first; |
/* If we had to estimate the number of program headers that were |
going to be needed, then check our estimate now and adjust |
the offset if necessary. */ |
if (phdr_adjust_seg != NULL) |
{ |
unsigned int count; |
for (count = 0, map = map_first; map != NULL; map = map->next) |
count++; |
if (count > phdr_adjust_num) |
phdr_adjust_seg->p_paddr |
-= (count - phdr_adjust_num) * iehdr->e_phentsize; |
} |
#undef SEGMENT_END |
#undef SECTION_SIZE |
#undef IS_CONTAINED_BY_VMA |
#undef IS_CONTAINED_BY_LMA |
#undef IS_NOTE |
#undef IS_COREFILE_NOTE |
#undef IS_SOLARIS_PT_INTERP |
#undef IS_SECTION_IN_INPUT_SEGMENT |
#undef INCLUDE_SECTION_IN_SEGMENT |
#undef SEGMENT_AFTER_SEGMENT |
#undef SEGMENT_OVERLAPS |
return TRUE; |
} |
/* Copy ELF program header information. */ |
static bfd_boolean |
copy_elf_program_header (bfd *ibfd, bfd *obfd) |
{ |
Elf_Internal_Ehdr *iehdr; |
struct elf_segment_map *map; |
struct elf_segment_map *map_first; |
struct elf_segment_map **pointer_to_map; |
Elf_Internal_Phdr *segment; |
unsigned int i; |
unsigned int num_segments; |
bfd_boolean phdr_included = FALSE; |
bfd_boolean p_paddr_valid; |
iehdr = elf_elfheader (ibfd); |
map_first = NULL; |
pointer_to_map = &map_first; |
/* If all the segment p_paddr fields are zero, don't set |
map->p_paddr_valid. */ |
p_paddr_valid = FALSE; |
num_segments = elf_elfheader (ibfd)->e_phnum; |
for (i = 0, segment = elf_tdata (ibfd)->phdr; |
i < num_segments; |
i++, segment++) |
if (segment->p_paddr != 0) |
{ |
p_paddr_valid = TRUE; |
break; |
} |
for (i = 0, segment = elf_tdata (ibfd)->phdr; |
i < num_segments; |
i++, segment++) |
{ |
asection *section; |
unsigned int section_count; |
bfd_size_type amt; |
Elf_Internal_Shdr *this_hdr; |
asection *first_section = NULL; |
asection *lowest_section; |
/* Compute how many sections are in this segment. */ |
for (section = ibfd->sections, section_count = 0; |
section != NULL; |
section = section->next) |
{ |
this_hdr = &(elf_section_data(section)->this_hdr); |
if (ELF_SECTION_IN_SEGMENT (this_hdr, segment)) |
{ |
if (first_section == NULL) |
first_section = section; |
section_count++; |
} |
} |
/* Allocate a segment map big enough to contain |
all of the sections we have selected. */ |
amt = sizeof (struct elf_segment_map); |
if (section_count != 0) |
amt += ((bfd_size_type) section_count - 1) * sizeof (asection *); |
map = (struct elf_segment_map *) bfd_zalloc (obfd, amt); |
if (map == NULL) |
return FALSE; |
/* Initialize the fields of the output segment map with the |
input segment. */ |
map->next = NULL; |
map->p_type = segment->p_type; |
map->p_flags = segment->p_flags; |
map->p_flags_valid = 1; |
map->p_paddr = segment->p_paddr; |
map->p_paddr_valid = p_paddr_valid; |
map->p_align = segment->p_align; |
map->p_align_valid = 1; |
map->p_vaddr_offset = 0; |
if (map->p_type == PT_GNU_RELRO |
|| map->p_type == PT_GNU_STACK) |
{ |
/* The PT_GNU_RELRO segment may contain the first a few |
bytes in the .got.plt section even if the whole .got.plt |
section isn't in the PT_GNU_RELRO segment. We won't |
change the size of the PT_GNU_RELRO segment. |
Similarly, PT_GNU_STACK size is significant on uclinux |
systems. */ |
map->p_size = segment->p_memsz; |
map->p_size_valid = 1; |
} |
/* Determine if this segment contains the ELF file header |
and if it contains the program headers themselves. */ |
map->includes_filehdr = (segment->p_offset == 0 |
&& segment->p_filesz >= iehdr->e_ehsize); |
map->includes_phdrs = 0; |
if (! phdr_included || segment->p_type != PT_LOAD) |
{ |
map->includes_phdrs = |
(segment->p_offset <= (bfd_vma) iehdr->e_phoff |
&& (segment->p_offset + segment->p_filesz |
>= ((bfd_vma) iehdr->e_phoff |
+ iehdr->e_phnum * iehdr->e_phentsize))); |
if (segment->p_type == PT_LOAD && map->includes_phdrs) |
phdr_included = TRUE; |
} |
lowest_section = first_section; |
if (section_count != 0) |
{ |
unsigned int isec = 0; |
for (section = first_section; |
section != NULL; |
section = section->next) |
{ |
this_hdr = &(elf_section_data(section)->this_hdr); |
if (ELF_SECTION_IN_SEGMENT (this_hdr, segment)) |
{ |
map->sections[isec++] = section->output_section; |
if ((section->flags & SEC_ALLOC) != 0) |
{ |
bfd_vma seg_off; |
if (section->lma < lowest_section->lma) |
lowest_section = section; |
/* Section lmas are set up from PT_LOAD header |
p_paddr in _bfd_elf_make_section_from_shdr. |
If this header has a p_paddr that disagrees |
with the section lma, flag the p_paddr as |
invalid. */ |
if ((section->flags & SEC_LOAD) != 0) |
seg_off = this_hdr->sh_offset - segment->p_offset; |
else |
seg_off = this_hdr->sh_addr - segment->p_vaddr; |
if (section->lma - segment->p_paddr != seg_off) |
map->p_paddr_valid = FALSE; |
} |
if (isec == section_count) |
break; |
} |
} |
} |
if (map->includes_filehdr && lowest_section != NULL) |
/* We need to keep the space used by the headers fixed. */ |
map->header_size = lowest_section->vma - segment->p_vaddr; |
if (!map->includes_phdrs |
&& !map->includes_filehdr |
&& map->p_paddr_valid) |
/* There is some other padding before the first section. */ |
map->p_vaddr_offset = ((lowest_section ? lowest_section->lma : 0) |
- segment->p_paddr); |
map->count = section_count; |
*pointer_to_map = map; |
pointer_to_map = &map->next; |
} |
elf_seg_map (obfd) = map_first; |
return TRUE; |
} |
/* Copy private BFD data. This copies or rewrites ELF program header |
information. */ |
static bfd_boolean |
copy_private_bfd_data (bfd *ibfd, bfd *obfd) |
{ |
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour |
|| bfd_get_flavour (obfd) != bfd_target_elf_flavour) |
return TRUE; |
if (elf_tdata (ibfd)->phdr == NULL) |
return TRUE; |
if (ibfd->xvec == obfd->xvec) |
{ |
/* Check to see if any sections in the input BFD |
covered by ELF program header have changed. */ |
Elf_Internal_Phdr *segment; |
asection *section, *osec; |
unsigned int i, num_segments; |
Elf_Internal_Shdr *this_hdr; |
const struct elf_backend_data *bed; |
bed = get_elf_backend_data (ibfd); |
/* Regenerate the segment map if p_paddr is set to 0. */ |
if (bed->want_p_paddr_set_to_zero) |
goto rewrite; |
/* Initialize the segment mark field. */ |
for (section = obfd->sections; section != NULL; |
section = section->next) |
section->segment_mark = FALSE; |
num_segments = elf_elfheader (ibfd)->e_phnum; |
for (i = 0, segment = elf_tdata (ibfd)->phdr; |
i < num_segments; |
i++, segment++) |
{ |
/* PR binutils/3535. The Solaris linker always sets the p_paddr |
and p_memsz fields of special segments (DYNAMIC, INTERP) to 0 |
which severly confuses things, so always regenerate the segment |
map in this case. */ |
if (segment->p_paddr == 0 |
&& segment->p_memsz == 0 |
&& (segment->p_type == PT_INTERP || segment->p_type == PT_DYNAMIC)) |
goto rewrite; |
for (section = ibfd->sections; |
section != NULL; section = section->next) |
{ |
/* We mark the output section so that we know it comes |
from the input BFD. */ |
osec = section->output_section; |
if (osec) |
osec->segment_mark = TRUE; |
/* Check if this section is covered by the segment. */ |
this_hdr = &(elf_section_data(section)->this_hdr); |
if (ELF_SECTION_IN_SEGMENT (this_hdr, segment)) |
{ |
/* FIXME: Check if its output section is changed or |
removed. What else do we need to check? */ |
if (osec == NULL |
|| section->flags != osec->flags |
|| section->lma != osec->lma |
|| section->vma != osec->vma |
|| section->size != osec->size |
|| section->rawsize != osec->rawsize |
|| section->alignment_power != osec->alignment_power) |
goto rewrite; |
} |
} |
} |
/* Check to see if any output section do not come from the |
input BFD. */ |
for (section = obfd->sections; section != NULL; |
section = section->next) |
{ |
if (section->segment_mark == FALSE) |
goto rewrite; |
else |
section->segment_mark = FALSE; |
} |
return copy_elf_program_header (ibfd, obfd); |
} |
rewrite: |
if (ibfd->xvec == obfd->xvec) |
{ |
/* When rewriting program header, set the output maxpagesize to |
the maximum alignment of input PT_LOAD segments. */ |
Elf_Internal_Phdr *segment; |
unsigned int i; |
unsigned int num_segments = elf_elfheader (ibfd)->e_phnum; |
bfd_vma maxpagesize = 0; |
for (i = 0, segment = elf_tdata (ibfd)->phdr; |
i < num_segments; |
i++, segment++) |
if (segment->p_type == PT_LOAD |
&& maxpagesize < segment->p_align) |
maxpagesize = segment->p_align; |
if (maxpagesize != get_elf_backend_data (obfd)->maxpagesize) |
bfd_emul_set_maxpagesize (bfd_get_target (obfd), maxpagesize); |
} |
return rewrite_elf_program_header (ibfd, obfd); |
} |
/* Initialize private output section information from input section. */ |
bfd_boolean |
_bfd_elf_init_private_section_data (bfd *ibfd, |
asection *isec, |
bfd *obfd, |
asection *osec, |
struct bfd_link_info *link_info) |
{ |
Elf_Internal_Shdr *ihdr, *ohdr; |
bfd_boolean final_link = link_info != NULL && !link_info->relocatable; |
if (ibfd->xvec->flavour != bfd_target_elf_flavour |
|| obfd->xvec->flavour != bfd_target_elf_flavour) |
return TRUE; |
BFD_ASSERT (elf_section_data (osec) != NULL); |
/* For objcopy and relocatable link, don't copy the output ELF |
section type from input if the output BFD section flags have been |
set to something different. For a final link allow some flags |
that the linker clears to differ. */ |
if (elf_section_type (osec) == SHT_NULL |
&& (osec->flags == isec->flags |
|| (final_link |
&& ((osec->flags ^ isec->flags) |
& ~(SEC_LINK_ONCE | SEC_LINK_DUPLICATES | SEC_RELOC)) == 0))) |
elf_section_type (osec) = elf_section_type (isec); |
/* FIXME: Is this correct for all OS/PROC specific flags? */ |
elf_section_flags (osec) |= (elf_section_flags (isec) |
& (SHF_MASKOS | SHF_MASKPROC)); |
/* Set things up for objcopy and relocatable link. The output |
SHT_GROUP section will have its elf_next_in_group pointing back |
to the input group members. Ignore linker created group section. |
See elfNN_ia64_object_p in elfxx-ia64.c. */ |
if (!final_link) |
{ |
if (elf_sec_group (isec) == NULL |
|| (elf_sec_group (isec)->flags & SEC_LINKER_CREATED) == 0) |
{ |
if (elf_section_flags (isec) & SHF_GROUP) |
elf_section_flags (osec) |= SHF_GROUP; |
elf_next_in_group (osec) = elf_next_in_group (isec); |
elf_section_data (osec)->group = elf_section_data (isec)->group; |
} |
} |
ihdr = &elf_section_data (isec)->this_hdr; |
/* We need to handle elf_linked_to_section for SHF_LINK_ORDER. We |
don't use the output section of the linked-to section since it |
may be NULL at this point. */ |
if ((ihdr->sh_flags & SHF_LINK_ORDER) != 0) |
{ |
ohdr = &elf_section_data (osec)->this_hdr; |
ohdr->sh_flags |= SHF_LINK_ORDER; |
elf_linked_to_section (osec) = elf_linked_to_section (isec); |
} |
osec->use_rela_p = isec->use_rela_p; |
return TRUE; |
} |
/* Copy private section information. This copies over the entsize |
field, and sometimes the info field. */ |
bfd_boolean |
_bfd_elf_copy_private_section_data (bfd *ibfd, |
asection *isec, |
bfd *obfd, |
asection *osec) |
{ |
Elf_Internal_Shdr *ihdr, *ohdr; |
if (ibfd->xvec->flavour != bfd_target_elf_flavour |
|| obfd->xvec->flavour != bfd_target_elf_flavour) |
return TRUE; |
ihdr = &elf_section_data (isec)->this_hdr; |
ohdr = &elf_section_data (osec)->this_hdr; |
ohdr->sh_entsize = ihdr->sh_entsize; |
if (ihdr->sh_type == SHT_SYMTAB |
|| ihdr->sh_type == SHT_DYNSYM |
|| ihdr->sh_type == SHT_GNU_verneed |
|| ihdr->sh_type == SHT_GNU_verdef) |
ohdr->sh_info = ihdr->sh_info; |
return _bfd_elf_init_private_section_data (ibfd, isec, obfd, osec, |
NULL); |
} |
/* Look at all the SHT_GROUP sections in IBFD, making any adjustments |
necessary if we are removing either the SHT_GROUP section or any of |
the group member sections. DISCARDED is the value that a section's |
output_section has if the section will be discarded, NULL when this |
function is called from objcopy, bfd_abs_section_ptr when called |
from the linker. */ |
bfd_boolean |
_bfd_elf_fixup_group_sections (bfd *ibfd, asection *discarded) |
{ |
asection *isec; |
for (isec = ibfd->sections; isec != NULL; isec = isec->next) |
if (elf_section_type (isec) == SHT_GROUP) |
{ |
asection *first = elf_next_in_group (isec); |
asection *s = first; |
bfd_size_type removed = 0; |
while (s != NULL) |
{ |
/* If this member section is being output but the |
SHT_GROUP section is not, then clear the group info |
set up by _bfd_elf_copy_private_section_data. */ |
if (s->output_section != discarded |
&& isec->output_section == discarded) |
{ |
elf_section_flags (s->output_section) &= ~SHF_GROUP; |
elf_group_name (s->output_section) = NULL; |
} |
/* Conversely, if the member section is not being output |
but the SHT_GROUP section is, then adjust its size. */ |
else if (s->output_section == discarded |
&& isec->output_section != discarded) |
removed += 4; |
s = elf_next_in_group (s); |
if (s == first) |
break; |
} |
if (removed != 0) |
{ |
if (discarded != NULL) |
{ |
/* If we've been called for ld -r, then we need to |
adjust the input section size. This function may |
be called multiple times, so save the original |
size. */ |
if (isec->rawsize == 0) |
isec->rawsize = isec->size; |
isec->size = isec->rawsize - removed; |
} |
else |
{ |
/* Adjust the output section size when called from |
objcopy. */ |
isec->output_section->size -= removed; |
} |
} |
} |
return TRUE; |
} |
/* Copy private header information. */ |
bfd_boolean |
_bfd_elf_copy_private_header_data (bfd *ibfd, bfd *obfd) |
{ |
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour |
|| bfd_get_flavour (obfd) != bfd_target_elf_flavour) |
return TRUE; |
/* Copy over private BFD data if it has not already been copied. |
This must be done here, rather than in the copy_private_bfd_data |
entry point, because the latter is called after the section |
contents have been set, which means that the program headers have |
already been worked out. */ |
if (elf_seg_map (obfd) == NULL && elf_tdata (ibfd)->phdr != NULL) |
{ |
if (! copy_private_bfd_data (ibfd, obfd)) |
return FALSE; |
} |
return _bfd_elf_fixup_group_sections (ibfd, NULL); |
} |
/* Copy private symbol information. If this symbol is in a section |
which we did not map into a BFD section, try to map the section |
index correctly. We use special macro definitions for the mapped |
section indices; these definitions are interpreted by the |
swap_out_syms function. */ |
#define MAP_ONESYMTAB (SHN_HIOS + 1) |
#define MAP_DYNSYMTAB (SHN_HIOS + 2) |
#define MAP_STRTAB (SHN_HIOS + 3) |
#define MAP_SHSTRTAB (SHN_HIOS + 4) |
#define MAP_SYM_SHNDX (SHN_HIOS + 5) |
bfd_boolean |
_bfd_elf_copy_private_symbol_data (bfd *ibfd, |
asymbol *isymarg, |
bfd *obfd, |
asymbol *osymarg) |
{ |
elf_symbol_type *isym, *osym; |
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour |
|| bfd_get_flavour (obfd) != bfd_target_elf_flavour) |
return TRUE; |
isym = elf_symbol_from (ibfd, isymarg); |
osym = elf_symbol_from (obfd, osymarg); |
if (isym != NULL |
&& isym->internal_elf_sym.st_shndx != 0 |
&& osym != NULL |
&& bfd_is_abs_section (isym->symbol.section)) |
{ |
unsigned int shndx; |
shndx = isym->internal_elf_sym.st_shndx; |
if (shndx == elf_onesymtab (ibfd)) |
shndx = MAP_ONESYMTAB; |
else if (shndx == elf_dynsymtab (ibfd)) |
shndx = MAP_DYNSYMTAB; |
else if (shndx == elf_strtab_sec (ibfd)) |
shndx = MAP_STRTAB; |
else if (shndx == elf_shstrtab_sec (ibfd)) |
shndx = MAP_SHSTRTAB; |
else if (shndx == elf_symtab_shndx (ibfd)) |
shndx = MAP_SYM_SHNDX; |
osym->internal_elf_sym.st_shndx = shndx; |
} |
return TRUE; |
} |
/* Swap out the symbols. */ |
static bfd_boolean |
swap_out_syms (bfd *abfd, |
struct bfd_strtab_hash **sttp, |
int relocatable_p) |
{ |
const struct elf_backend_data *bed; |
int symcount; |
asymbol **syms; |
struct bfd_strtab_hash *stt; |
Elf_Internal_Shdr *symtab_hdr; |
Elf_Internal_Shdr *symtab_shndx_hdr; |
Elf_Internal_Shdr *symstrtab_hdr; |
bfd_byte *outbound_syms; |
bfd_byte *outbound_shndx; |
int idx; |
unsigned int num_locals; |
bfd_size_type amt; |
bfd_boolean name_local_sections; |
if (!elf_map_symbols (abfd, &num_locals)) |
return FALSE; |
/* Dump out the symtabs. */ |
stt = _bfd_elf_stringtab_init (); |
if (stt == NULL) |
return FALSE; |
bed = get_elf_backend_data (abfd); |
symcount = bfd_get_symcount (abfd); |
symtab_hdr = &elf_tdata (abfd)->symtab_hdr; |
symtab_hdr->sh_type = SHT_SYMTAB; |
symtab_hdr->sh_entsize = bed->s->sizeof_sym; |
symtab_hdr->sh_size = symtab_hdr->sh_entsize * (symcount + 1); |
symtab_hdr->sh_info = num_locals + 1; |
symtab_hdr->sh_addralign = (bfd_vma) 1 << bed->s->log_file_align; |
symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr; |
symstrtab_hdr->sh_type = SHT_STRTAB; |
outbound_syms = (bfd_byte *) bfd_alloc2 (abfd, 1 + symcount, |
bed->s->sizeof_sym); |
if (outbound_syms == NULL) |
{ |
_bfd_stringtab_free (stt); |
return FALSE; |
} |
symtab_hdr->contents = outbound_syms; |
outbound_shndx = NULL; |
symtab_shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr; |
if (symtab_shndx_hdr->sh_name != 0) |
{ |
amt = (bfd_size_type) (1 + symcount) * sizeof (Elf_External_Sym_Shndx); |
outbound_shndx = (bfd_byte *) |
bfd_zalloc2 (abfd, 1 + symcount, sizeof (Elf_External_Sym_Shndx)); |
if (outbound_shndx == NULL) |
{ |
_bfd_stringtab_free (stt); |
return FALSE; |
} |
symtab_shndx_hdr->contents = outbound_shndx; |
symtab_shndx_hdr->sh_type = SHT_SYMTAB_SHNDX; |
symtab_shndx_hdr->sh_size = amt; |
symtab_shndx_hdr->sh_addralign = sizeof (Elf_External_Sym_Shndx); |
symtab_shndx_hdr->sh_entsize = sizeof (Elf_External_Sym_Shndx); |
} |
/* Now generate the data (for "contents"). */ |
{ |
/* Fill in zeroth symbol and swap it out. */ |
Elf_Internal_Sym sym; |
sym.st_name = 0; |
sym.st_value = 0; |
sym.st_size = 0; |
sym.st_info = 0; |
sym.st_other = 0; |
sym.st_shndx = SHN_UNDEF; |
sym.st_target_internal = 0; |
bed->s->swap_symbol_out (abfd, &sym, outbound_syms, outbound_shndx); |
outbound_syms += bed->s->sizeof_sym; |
if (outbound_shndx != NULL) |
outbound_shndx += sizeof (Elf_External_Sym_Shndx); |
} |
name_local_sections |
= (bed->elf_backend_name_local_section_symbols |
&& bed->elf_backend_name_local_section_symbols (abfd)); |
syms = bfd_get_outsymbols (abfd); |
for (idx = 0; idx < symcount; idx++) |
{ |
Elf_Internal_Sym sym; |
bfd_vma value = syms[idx]->value; |
elf_symbol_type *type_ptr; |
flagword flags = syms[idx]->flags; |
int type; |
if (!name_local_sections |
&& (flags & (BSF_SECTION_SYM | BSF_GLOBAL)) == BSF_SECTION_SYM) |
{ |
/* Local section symbols have no name. */ |
sym.st_name = 0; |
} |
else |
{ |
sym.st_name = (unsigned long) _bfd_stringtab_add (stt, |
syms[idx]->name, |
TRUE, FALSE); |
if (sym.st_name == (unsigned long) -1) |
{ |
_bfd_stringtab_free (stt); |
return FALSE; |
} |
} |
type_ptr = elf_symbol_from (abfd, syms[idx]); |
if ((flags & BSF_SECTION_SYM) == 0 |
&& bfd_is_com_section (syms[idx]->section)) |
{ |
/* ELF common symbols put the alignment into the `value' field, |
and the size into the `size' field. This is backwards from |
how BFD handles it, so reverse it here. */ |
sym.st_size = value; |
if (type_ptr == NULL |
|| type_ptr->internal_elf_sym.st_value == 0) |
sym.st_value = value >= 16 ? 16 : (1 << bfd_log2 (value)); |
else |
sym.st_value = type_ptr->internal_elf_sym.st_value; |
sym.st_shndx = _bfd_elf_section_from_bfd_section |
(abfd, syms[idx]->section); |
} |
else |
{ |
asection *sec = syms[idx]->section; |
unsigned int shndx; |
if (sec->output_section) |
{ |
value += sec->output_offset; |
sec = sec->output_section; |
} |
/* Don't add in the section vma for relocatable output. */ |
if (! relocatable_p) |
value += sec->vma; |
sym.st_value = value; |
sym.st_size = type_ptr ? type_ptr->internal_elf_sym.st_size : 0; |
if (bfd_is_abs_section (sec) |
&& type_ptr != NULL |
&& type_ptr->internal_elf_sym.st_shndx != 0) |
{ |
/* This symbol is in a real ELF section which we did |
not create as a BFD section. Undo the mapping done |
by copy_private_symbol_data. */ |
shndx = type_ptr->internal_elf_sym.st_shndx; |
switch (shndx) |
{ |
case MAP_ONESYMTAB: |
shndx = elf_onesymtab (abfd); |
break; |
case MAP_DYNSYMTAB: |
shndx = elf_dynsymtab (abfd); |
break; |
case MAP_STRTAB: |
shndx = elf_strtab_sec (abfd); |
break; |
case MAP_SHSTRTAB: |
shndx = elf_shstrtab_sec (abfd); |
break; |
case MAP_SYM_SHNDX: |
shndx = elf_symtab_shndx (abfd); |
break; |
default: |
shndx = SHN_ABS; |
break; |
} |
} |
else |
{ |
shndx = _bfd_elf_section_from_bfd_section (abfd, sec); |
if (shndx == SHN_BAD) |
{ |
asection *sec2; |
/* Writing this would be a hell of a lot easier if |
we had some decent documentation on bfd, and |
knew what to expect of the library, and what to |
demand of applications. For example, it |
appears that `objcopy' might not set the |
section of a symbol to be a section that is |
actually in the output file. */ |
sec2 = bfd_get_section_by_name (abfd, sec->name); |
if (sec2 == NULL) |
{ |
_bfd_error_handler (_("\ |
Unable to find equivalent output section for symbol '%s' from section '%s'"), |
syms[idx]->name ? syms[idx]->name : "<Local sym>", |
sec->name); |
bfd_set_error (bfd_error_invalid_operation); |
_bfd_stringtab_free (stt); |
return FALSE; |
} |
shndx = _bfd_elf_section_from_bfd_section (abfd, sec2); |
BFD_ASSERT (shndx != SHN_BAD); |
} |
} |
sym.st_shndx = shndx; |
} |
if ((flags & BSF_THREAD_LOCAL) != 0) |
type = STT_TLS; |
else if ((flags & BSF_GNU_INDIRECT_FUNCTION) != 0) |
type = STT_GNU_IFUNC; |
else if ((flags & BSF_FUNCTION) != 0) |
type = STT_FUNC; |
else if ((flags & BSF_OBJECT) != 0) |
type = STT_OBJECT; |
else if ((flags & BSF_RELC) != 0) |
type = STT_RELC; |
else if ((flags & BSF_SRELC) != 0) |
type = STT_SRELC; |
else |
type = STT_NOTYPE; |
if (syms[idx]->section->flags & SEC_THREAD_LOCAL) |
type = STT_TLS; |
/* Processor-specific types. */ |
if (type_ptr != NULL |
&& bed->elf_backend_get_symbol_type) |
type = ((*bed->elf_backend_get_symbol_type) |
(&type_ptr->internal_elf_sym, type)); |
if (flags & BSF_SECTION_SYM) |
{ |
if (flags & BSF_GLOBAL) |
sym.st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION); |
else |
sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION); |
} |
else if (bfd_is_com_section (syms[idx]->section)) |
{ |
#ifdef USE_STT_COMMON |
if (type == STT_OBJECT) |
sym.st_info = ELF_ST_INFO (STB_GLOBAL, STT_COMMON); |
else |
#endif |
sym.st_info = ELF_ST_INFO (STB_GLOBAL, type); |
} |
else if (bfd_is_und_section (syms[idx]->section)) |
sym.st_info = ELF_ST_INFO (((flags & BSF_WEAK) |
? STB_WEAK |
: STB_GLOBAL), |
type); |
else if (flags & BSF_FILE) |
sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE); |
else |
{ |
int bind = STB_LOCAL; |
if (flags & BSF_LOCAL) |
bind = STB_LOCAL; |
else if (flags & BSF_GNU_UNIQUE) |
bind = STB_GNU_UNIQUE; |
else if (flags & BSF_WEAK) |
bind = STB_WEAK; |
else if (flags & BSF_GLOBAL) |
bind = STB_GLOBAL; |
sym.st_info = ELF_ST_INFO (bind, type); |
} |
if (type_ptr != NULL) |
{ |
sym.st_other = type_ptr->internal_elf_sym.st_other; |
sym.st_target_internal |
= type_ptr->internal_elf_sym.st_target_internal; |
} |
else |
{ |
sym.st_other = 0; |
sym.st_target_internal = 0; |
} |
bed->s->swap_symbol_out (abfd, &sym, outbound_syms, outbound_shndx); |
outbound_syms += bed->s->sizeof_sym; |
if (outbound_shndx != NULL) |
outbound_shndx += sizeof (Elf_External_Sym_Shndx); |
} |
*sttp = stt; |
symstrtab_hdr->sh_size = _bfd_stringtab_size (stt); |
symstrtab_hdr->sh_type = SHT_STRTAB; |
symstrtab_hdr->sh_flags = 0; |
symstrtab_hdr->sh_addr = 0; |
symstrtab_hdr->sh_entsize = 0; |
symstrtab_hdr->sh_link = 0; |
symstrtab_hdr->sh_info = 0; |
symstrtab_hdr->sh_addralign = 1; |
return TRUE; |
} |
/* Return the number of bytes required to hold the symtab vector. |
Note that we base it on the count plus 1, since we will null terminate |
the vector allocated based on this size. However, the ELF symbol table |
always has a dummy entry as symbol #0, so it ends up even. */ |
long |
_bfd_elf_get_symtab_upper_bound (bfd *abfd) |
{ |
long symcount; |
long symtab_size; |
Elf_Internal_Shdr *hdr = &elf_tdata (abfd)->symtab_hdr; |
symcount = hdr->sh_size / get_elf_backend_data (abfd)->s->sizeof_sym; |
symtab_size = (symcount + 1) * (sizeof (asymbol *)); |
if (symcount > 0) |
symtab_size -= sizeof (asymbol *); |
return symtab_size; |
} |
long |
_bfd_elf_get_dynamic_symtab_upper_bound (bfd *abfd) |
{ |
long symcount; |
long symtab_size; |
Elf_Internal_Shdr *hdr = &elf_tdata (abfd)->dynsymtab_hdr; |
if (elf_dynsymtab (abfd) == 0) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return -1; |
} |
symcount = hdr->sh_size / get_elf_backend_data (abfd)->s->sizeof_sym; |
symtab_size = (symcount + 1) * (sizeof (asymbol *)); |
if (symcount > 0) |
symtab_size -= sizeof (asymbol *); |
return symtab_size; |
} |
long |
_bfd_elf_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED, |
sec_ptr asect) |
{ |
return (asect->reloc_count + 1) * sizeof (arelent *); |
} |
/* Canonicalize the relocs. */ |
long |
_bfd_elf_canonicalize_reloc (bfd *abfd, |
sec_ptr section, |
arelent **relptr, |
asymbol **symbols) |
{ |
arelent *tblptr; |
unsigned int i; |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
if (! bed->s->slurp_reloc_table (abfd, section, symbols, FALSE)) |
return -1; |
tblptr = section->relocation; |
for (i = 0; i < section->reloc_count; i++) |
*relptr++ = tblptr++; |
*relptr = NULL; |
return section->reloc_count; |
} |
long |
_bfd_elf_canonicalize_symtab (bfd *abfd, asymbol **allocation) |
{ |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
long symcount = bed->s->slurp_symbol_table (abfd, allocation, FALSE); |
if (symcount >= 0) |
bfd_get_symcount (abfd) = symcount; |
return symcount; |
} |
long |
_bfd_elf_canonicalize_dynamic_symtab (bfd *abfd, |
asymbol **allocation) |
{ |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
long symcount = bed->s->slurp_symbol_table (abfd, allocation, TRUE); |
if (symcount >= 0) |
bfd_get_dynamic_symcount (abfd) = symcount; |
return symcount; |
} |
/* Return the size required for the dynamic reloc entries. Any loadable |
section that was actually installed in the BFD, and has type SHT_REL |
or SHT_RELA, and uses the dynamic symbol table, is considered to be a |
dynamic reloc section. */ |
long |
_bfd_elf_get_dynamic_reloc_upper_bound (bfd *abfd) |
{ |
long ret; |
asection *s; |
if (elf_dynsymtab (abfd) == 0) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return -1; |
} |
ret = sizeof (arelent *); |
for (s = abfd->sections; s != NULL; s = s->next) |
if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd) |
&& (elf_section_data (s)->this_hdr.sh_type == SHT_REL |
|| elf_section_data (s)->this_hdr.sh_type == SHT_RELA)) |
ret += ((s->size / elf_section_data (s)->this_hdr.sh_entsize) |
* sizeof (arelent *)); |
return ret; |
} |
/* Canonicalize the dynamic relocation entries. Note that we return the |
dynamic relocations as a single block, although they are actually |
associated with particular sections; the interface, which was |
designed for SunOS style shared libraries, expects that there is only |
one set of dynamic relocs. Any loadable section that was actually |
installed in the BFD, and has type SHT_REL or SHT_RELA, and uses the |
dynamic symbol table, is considered to be a dynamic reloc section. */ |
long |
_bfd_elf_canonicalize_dynamic_reloc (bfd *abfd, |
arelent **storage, |
asymbol **syms) |
{ |
bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean); |
asection *s; |
long ret; |
if (elf_dynsymtab (abfd) == 0) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return -1; |
} |
slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table; |
ret = 0; |
for (s = abfd->sections; s != NULL; s = s->next) |
{ |
if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd) |
&& (elf_section_data (s)->this_hdr.sh_type == SHT_REL |
|| elf_section_data (s)->this_hdr.sh_type == SHT_RELA)) |
{ |
arelent *p; |
long count, i; |
if (! (*slurp_relocs) (abfd, s, syms, TRUE)) |
return -1; |
count = s->size / elf_section_data (s)->this_hdr.sh_entsize; |
p = s->relocation; |
for (i = 0; i < count; i++) |
*storage++ = p++; |
ret += count; |
} |
} |
*storage = NULL; |
return ret; |
} |
/* Read in the version information. */ |
bfd_boolean |
_bfd_elf_slurp_version_tables (bfd *abfd, bfd_boolean default_imported_symver) |
{ |
bfd_byte *contents = NULL; |
unsigned int freeidx = 0; |
if (elf_dynverref (abfd) != 0) |
{ |
Elf_Internal_Shdr *hdr; |
Elf_External_Verneed *everneed; |
Elf_Internal_Verneed *iverneed; |
unsigned int i; |
bfd_byte *contents_end; |
hdr = &elf_tdata (abfd)->dynverref_hdr; |
elf_tdata (abfd)->verref = (Elf_Internal_Verneed *) |
bfd_zalloc2 (abfd, hdr->sh_info, sizeof (Elf_Internal_Verneed)); |
if (elf_tdata (abfd)->verref == NULL) |
goto error_return; |
elf_tdata (abfd)->cverrefs = hdr->sh_info; |
contents = (bfd_byte *) bfd_malloc (hdr->sh_size); |
if (contents == NULL) |
{ |
error_return_verref: |
elf_tdata (abfd)->verref = NULL; |
elf_tdata (abfd)->cverrefs = 0; |
goto error_return; |
} |
if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0 |
|| bfd_bread (contents, hdr->sh_size, abfd) != hdr->sh_size) |
goto error_return_verref; |
if (hdr->sh_info && hdr->sh_size < sizeof (Elf_External_Verneed)) |
goto error_return_verref; |
BFD_ASSERT (sizeof (Elf_External_Verneed) |
== sizeof (Elf_External_Vernaux)); |
contents_end = contents + hdr->sh_size - sizeof (Elf_External_Verneed); |
everneed = (Elf_External_Verneed *) contents; |
iverneed = elf_tdata (abfd)->verref; |
for (i = 0; i < hdr->sh_info; i++, iverneed++) |
{ |
Elf_External_Vernaux *evernaux; |
Elf_Internal_Vernaux *ivernaux; |
unsigned int j; |
_bfd_elf_swap_verneed_in (abfd, everneed, iverneed); |
iverneed->vn_bfd = abfd; |
iverneed->vn_filename = |
bfd_elf_string_from_elf_section (abfd, hdr->sh_link, |
iverneed->vn_file); |
if (iverneed->vn_filename == NULL) |
goto error_return_verref; |
if (iverneed->vn_cnt == 0) |
iverneed->vn_auxptr = NULL; |
else |
{ |
iverneed->vn_auxptr = (struct elf_internal_vernaux *) |
bfd_alloc2 (abfd, iverneed->vn_cnt, |
sizeof (Elf_Internal_Vernaux)); |
if (iverneed->vn_auxptr == NULL) |
goto error_return_verref; |
} |
if (iverneed->vn_aux |
> (size_t) (contents_end - (bfd_byte *) everneed)) |
goto error_return_verref; |
evernaux = ((Elf_External_Vernaux *) |
((bfd_byte *) everneed + iverneed->vn_aux)); |
ivernaux = iverneed->vn_auxptr; |
for (j = 0; j < iverneed->vn_cnt; j++, ivernaux++) |
{ |
_bfd_elf_swap_vernaux_in (abfd, evernaux, ivernaux); |
ivernaux->vna_nodename = |
bfd_elf_string_from_elf_section (abfd, hdr->sh_link, |
ivernaux->vna_name); |
if (ivernaux->vna_nodename == NULL) |
goto error_return_verref; |
if (j + 1 < iverneed->vn_cnt) |
ivernaux->vna_nextptr = ivernaux + 1; |
else |
ivernaux->vna_nextptr = NULL; |
if (ivernaux->vna_next |
> (size_t) (contents_end - (bfd_byte *) evernaux)) |
goto error_return_verref; |
evernaux = ((Elf_External_Vernaux *) |
((bfd_byte *) evernaux + ivernaux->vna_next)); |
if (ivernaux->vna_other > freeidx) |
freeidx = ivernaux->vna_other; |
} |
if (i + 1 < hdr->sh_info) |
iverneed->vn_nextref = iverneed + 1; |
else |
iverneed->vn_nextref = NULL; |
if (iverneed->vn_next |
> (size_t) (contents_end - (bfd_byte *) everneed)) |
goto error_return_verref; |
everneed = ((Elf_External_Verneed *) |
((bfd_byte *) everneed + iverneed->vn_next)); |
} |
free (contents); |
contents = NULL; |
} |
if (elf_dynverdef (abfd) != 0) |
{ |
Elf_Internal_Shdr *hdr; |
Elf_External_Verdef *everdef; |
Elf_Internal_Verdef *iverdef; |
Elf_Internal_Verdef *iverdefarr; |
Elf_Internal_Verdef iverdefmem; |
unsigned int i; |
unsigned int maxidx; |
bfd_byte *contents_end_def, *contents_end_aux; |
hdr = &elf_tdata (abfd)->dynverdef_hdr; |
contents = (bfd_byte *) bfd_malloc (hdr->sh_size); |
if (contents == NULL) |
goto error_return; |
if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0 |
|| bfd_bread (contents, hdr->sh_size, abfd) != hdr->sh_size) |
goto error_return; |
if (hdr->sh_info && hdr->sh_size < sizeof (Elf_External_Verdef)) |
goto error_return; |
BFD_ASSERT (sizeof (Elf_External_Verdef) |
>= sizeof (Elf_External_Verdaux)); |
contents_end_def = contents + hdr->sh_size |
- sizeof (Elf_External_Verdef); |
contents_end_aux = contents + hdr->sh_size |
- sizeof (Elf_External_Verdaux); |
/* We know the number of entries in the section but not the maximum |
index. Therefore we have to run through all entries and find |
the maximum. */ |
everdef = (Elf_External_Verdef *) contents; |
maxidx = 0; |
for (i = 0; i < hdr->sh_info; ++i) |
{ |
_bfd_elf_swap_verdef_in (abfd, everdef, &iverdefmem); |
if ((iverdefmem.vd_ndx & ((unsigned) VERSYM_VERSION)) > maxidx) |
maxidx = iverdefmem.vd_ndx & ((unsigned) VERSYM_VERSION); |
if (iverdefmem.vd_next |
> (size_t) (contents_end_def - (bfd_byte *) everdef)) |
goto error_return; |
everdef = ((Elf_External_Verdef *) |
((bfd_byte *) everdef + iverdefmem.vd_next)); |
} |
if (default_imported_symver) |
{ |
if (freeidx > maxidx) |
maxidx = ++freeidx; |
else |
freeidx = ++maxidx; |
} |
elf_tdata (abfd)->verdef = (Elf_Internal_Verdef *) |
bfd_zalloc2 (abfd, maxidx, sizeof (Elf_Internal_Verdef)); |
if (elf_tdata (abfd)->verdef == NULL) |
goto error_return; |
elf_tdata (abfd)->cverdefs = maxidx; |
everdef = (Elf_External_Verdef *) contents; |
iverdefarr = elf_tdata (abfd)->verdef; |
for (i = 0; i < hdr->sh_info; i++) |
{ |
Elf_External_Verdaux *everdaux; |
Elf_Internal_Verdaux *iverdaux; |
unsigned int j; |
_bfd_elf_swap_verdef_in (abfd, everdef, &iverdefmem); |
if ((iverdefmem.vd_ndx & VERSYM_VERSION) == 0) |
{ |
error_return_verdef: |
elf_tdata (abfd)->verdef = NULL; |
elf_tdata (abfd)->cverdefs = 0; |
goto error_return; |
} |
iverdef = &iverdefarr[(iverdefmem.vd_ndx & VERSYM_VERSION) - 1]; |
memcpy (iverdef, &iverdefmem, sizeof (Elf_Internal_Verdef)); |
iverdef->vd_bfd = abfd; |
if (iverdef->vd_cnt == 0) |
iverdef->vd_auxptr = NULL; |
else |
{ |
iverdef->vd_auxptr = (struct elf_internal_verdaux *) |
bfd_alloc2 (abfd, iverdef->vd_cnt, |
sizeof (Elf_Internal_Verdaux)); |
if (iverdef->vd_auxptr == NULL) |
goto error_return_verdef; |
} |
if (iverdef->vd_aux |
> (size_t) (contents_end_aux - (bfd_byte *) everdef)) |
goto error_return_verdef; |
everdaux = ((Elf_External_Verdaux *) |
((bfd_byte *) everdef + iverdef->vd_aux)); |
iverdaux = iverdef->vd_auxptr; |
for (j = 0; j < iverdef->vd_cnt; j++, iverdaux++) |
{ |
_bfd_elf_swap_verdaux_in (abfd, everdaux, iverdaux); |
iverdaux->vda_nodename = |
bfd_elf_string_from_elf_section (abfd, hdr->sh_link, |
iverdaux->vda_name); |
if (iverdaux->vda_nodename == NULL) |
goto error_return_verdef; |
if (j + 1 < iverdef->vd_cnt) |
iverdaux->vda_nextptr = iverdaux + 1; |
else |
iverdaux->vda_nextptr = NULL; |
if (iverdaux->vda_next |
> (size_t) (contents_end_aux - (bfd_byte *) everdaux)) |
goto error_return_verdef; |
everdaux = ((Elf_External_Verdaux *) |
((bfd_byte *) everdaux + iverdaux->vda_next)); |
} |
if (iverdef->vd_cnt) |
iverdef->vd_nodename = iverdef->vd_auxptr->vda_nodename; |
if ((size_t) (iverdef - iverdefarr) + 1 < maxidx) |
iverdef->vd_nextdef = iverdef + 1; |
else |
iverdef->vd_nextdef = NULL; |
everdef = ((Elf_External_Verdef *) |
((bfd_byte *) everdef + iverdef->vd_next)); |
} |
free (contents); |
contents = NULL; |
} |
else if (default_imported_symver) |
{ |
if (freeidx < 3) |
freeidx = 3; |
else |
freeidx++; |
elf_tdata (abfd)->verdef = (Elf_Internal_Verdef *) |
bfd_zalloc2 (abfd, freeidx, sizeof (Elf_Internal_Verdef)); |
if (elf_tdata (abfd)->verdef == NULL) |
goto error_return; |
elf_tdata (abfd)->cverdefs = freeidx; |
} |
/* Create a default version based on the soname. */ |
if (default_imported_symver) |
{ |
Elf_Internal_Verdef *iverdef; |
Elf_Internal_Verdaux *iverdaux; |
iverdef = &elf_tdata (abfd)->verdef[freeidx - 1]; |
iverdef->vd_version = VER_DEF_CURRENT; |
iverdef->vd_flags = 0; |
iverdef->vd_ndx = freeidx; |
iverdef->vd_cnt = 1; |
iverdef->vd_bfd = abfd; |
iverdef->vd_nodename = bfd_elf_get_dt_soname (abfd); |
if (iverdef->vd_nodename == NULL) |
goto error_return_verdef; |
iverdef->vd_nextdef = NULL; |
iverdef->vd_auxptr = (struct elf_internal_verdaux *) |
bfd_alloc (abfd, sizeof (Elf_Internal_Verdaux)); |
if (iverdef->vd_auxptr == NULL) |
goto error_return_verdef; |
iverdaux = iverdef->vd_auxptr; |
iverdaux->vda_nodename = iverdef->vd_nodename; |
iverdaux->vda_nextptr = NULL; |
} |
return TRUE; |
error_return: |
if (contents != NULL) |
free (contents); |
return FALSE; |
} |
asymbol * |
_bfd_elf_make_empty_symbol (bfd *abfd) |
{ |
elf_symbol_type *newsym; |
bfd_size_type amt = sizeof (elf_symbol_type); |
newsym = (elf_symbol_type *) bfd_zalloc (abfd, amt); |
if (!newsym) |
return NULL; |
else |
{ |
newsym->symbol.the_bfd = abfd; |
return &newsym->symbol; |
} |
} |
void |
_bfd_elf_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED, |
asymbol *symbol, |
symbol_info *ret) |
{ |
bfd_symbol_info (symbol, ret); |
} |
/* Return whether a symbol name implies a local symbol. Most targets |
use this function for the is_local_label_name entry point, but some |
override it. */ |
bfd_boolean |
_bfd_elf_is_local_label_name (bfd *abfd ATTRIBUTE_UNUSED, |
const char *name) |
{ |
/* Normal local symbols start with ``.L''. */ |
if (name[0] == '.' && name[1] == 'L') |
return TRUE; |
/* At least some SVR4 compilers (e.g., UnixWare 2.1 cc) generate |
DWARF debugging symbols starting with ``..''. */ |
if (name[0] == '.' && name[1] == '.') |
return TRUE; |
/* gcc will sometimes generate symbols beginning with ``_.L_'' when |
emitting DWARF debugging output. I suspect this is actually a |
small bug in gcc (it calls ASM_OUTPUT_LABEL when it should call |
ASM_GENERATE_INTERNAL_LABEL, and this causes the leading |
underscore to be emitted on some ELF targets). For ease of use, |
we treat such symbols as local. */ |
if (name[0] == '_' && name[1] == '.' && name[2] == 'L' && name[3] == '_') |
return TRUE; |
return FALSE; |
} |
alent * |
_bfd_elf_get_lineno (bfd *abfd ATTRIBUTE_UNUSED, |
asymbol *symbol ATTRIBUTE_UNUSED) |
{ |
abort (); |
return NULL; |
} |
bfd_boolean |
_bfd_elf_set_arch_mach (bfd *abfd, |
enum bfd_architecture arch, |
unsigned long machine) |
{ |
/* If this isn't the right architecture for this backend, and this |
isn't the generic backend, fail. */ |
if (arch != get_elf_backend_data (abfd)->arch |
&& arch != bfd_arch_unknown |
&& get_elf_backend_data (abfd)->arch != bfd_arch_unknown) |
return FALSE; |
return bfd_default_set_arch_mach (abfd, arch, machine); |
} |
/* Find the function to a particular section and offset, |
for error reporting. */ |
static bfd_boolean |
elf_find_function (bfd *abfd, |
asection *section, |
asymbol **symbols, |
bfd_vma offset, |
const char **filename_ptr, |
const char **functionname_ptr) |
{ |
struct elf_find_function_cache |
{ |
asection *last_section; |
asymbol *func; |
const char *filename; |
bfd_size_type func_size; |
} *cache; |
if (symbols == NULL) |
return FALSE; |
cache = elf_tdata (abfd)->elf_find_function_cache; |
if (cache == NULL) |
{ |
cache = bfd_zalloc (abfd, sizeof (*cache)); |
elf_tdata (abfd)->elf_find_function_cache = cache; |
if (cache == NULL) |
return FALSE; |
} |
if (cache->last_section != section |
|| cache->func == NULL |
|| offset < cache->func->value |
|| offset >= cache->func->value + cache->func_size) |
{ |
asymbol *file; |
bfd_vma low_func; |
asymbol **p; |
/* ??? Given multiple file symbols, it is impossible to reliably |
choose the right file name for global symbols. File symbols are |
local symbols, and thus all file symbols must sort before any |
global symbols. The ELF spec may be interpreted to say that a |
file symbol must sort before other local symbols, but currently |
ld -r doesn't do this. So, for ld -r output, it is possible to |
make a better choice of file name for local symbols by ignoring |
file symbols appearing after a given local symbol. */ |
enum { nothing_seen, symbol_seen, file_after_symbol_seen } state; |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
file = NULL; |
low_func = 0; |
state = nothing_seen; |
cache->filename = NULL; |
cache->func = NULL; |
cache->func_size = 0; |
cache->last_section = section; |
for (p = symbols; *p != NULL; p++) |
{ |
asymbol *sym = *p; |
bfd_vma code_off; |
bfd_size_type size; |
if ((sym->flags & BSF_FILE) != 0) |
{ |
file = sym; |
if (state == symbol_seen) |
state = file_after_symbol_seen; |
continue; |
} |
size = bed->maybe_function_sym (sym, section, &code_off); |
if (size != 0 |
&& code_off <= offset |
&& (code_off > low_func |
|| (code_off == low_func |
&& size > cache->func_size))) |
{ |
cache->func = sym; |
cache->func_size = size; |
cache->filename = NULL; |
low_func = code_off; |
if (file != NULL |
&& ((sym->flags & BSF_LOCAL) != 0 |
|| state != file_after_symbol_seen)) |
cache->filename = bfd_asymbol_name (file); |
} |
if (state == nothing_seen) |
state = symbol_seen; |
} |
} |
if (cache->func == NULL) |
return FALSE; |
if (filename_ptr) |
*filename_ptr = cache->filename; |
if (functionname_ptr) |
*functionname_ptr = bfd_asymbol_name (cache->func); |
return TRUE; |
} |
/* Find the nearest line to a particular section and offset, |
for error reporting. */ |
bfd_boolean |
_bfd_elf_find_nearest_line (bfd *abfd, |
asection *section, |
asymbol **symbols, |
bfd_vma offset, |
const char **filename_ptr, |
const char **functionname_ptr, |
unsigned int *line_ptr) |
{ |
return _bfd_elf_find_nearest_line_discriminator (abfd, section, symbols, |
offset, filename_ptr, |
functionname_ptr, |
line_ptr, |
NULL); |
} |
bfd_boolean |
_bfd_elf_find_nearest_line_discriminator (bfd *abfd, |
asection *section, |
asymbol **symbols, |
bfd_vma offset, |
const char **filename_ptr, |
const char **functionname_ptr, |
unsigned int *line_ptr, |
unsigned int *discriminator_ptr) |
{ |
bfd_boolean found; |
if (_bfd_dwarf1_find_nearest_line (abfd, section, symbols, offset, |
filename_ptr, functionname_ptr, |
line_ptr)) |
{ |
if (!*functionname_ptr) |
elf_find_function (abfd, section, symbols, offset, |
*filename_ptr ? NULL : filename_ptr, |
functionname_ptr); |
return TRUE; |
} |
if (_bfd_dwarf2_find_nearest_line (abfd, dwarf_debug_sections, |
section, symbols, offset, |
filename_ptr, functionname_ptr, |
line_ptr, discriminator_ptr, 0, |
&elf_tdata (abfd)->dwarf2_find_line_info)) |
{ |
if (!*functionname_ptr) |
elf_find_function (abfd, section, symbols, offset, |
*filename_ptr ? NULL : filename_ptr, |
functionname_ptr); |
return TRUE; |
} |
if (! _bfd_stab_section_find_nearest_line (abfd, symbols, section, offset, |
&found, filename_ptr, |
functionname_ptr, line_ptr, |
&elf_tdata (abfd)->line_info)) |
return FALSE; |
if (found && (*functionname_ptr || *line_ptr)) |
return TRUE; |
if (symbols == NULL) |
return FALSE; |
if (! elf_find_function (abfd, section, symbols, offset, |
filename_ptr, functionname_ptr)) |
return FALSE; |
*line_ptr = 0; |
return TRUE; |
} |
/* Find the line for a symbol. */ |
bfd_boolean |
_bfd_elf_find_line (bfd *abfd, asymbol **symbols, asymbol *symbol, |
const char **filename_ptr, unsigned int *line_ptr) |
{ |
return _bfd_elf_find_line_discriminator (abfd, symbols, symbol, |
filename_ptr, line_ptr, |
NULL); |
} |
bfd_boolean |
_bfd_elf_find_line_discriminator (bfd *abfd, asymbol **symbols, asymbol *symbol, |
const char **filename_ptr, |
unsigned int *line_ptr, |
unsigned int *discriminator_ptr) |
{ |
return _bfd_dwarf2_find_line (abfd, symbols, symbol, |
filename_ptr, line_ptr, discriminator_ptr, 0, |
&elf_tdata (abfd)->dwarf2_find_line_info); |
} |
/* After a call to bfd_find_nearest_line, successive calls to |
bfd_find_inliner_info can be used to get source information about |
each level of function inlining that terminated at the address |
passed to bfd_find_nearest_line. Currently this is only supported |
for DWARF2 with appropriate DWARF3 extensions. */ |
bfd_boolean |
_bfd_elf_find_inliner_info (bfd *abfd, |
const char **filename_ptr, |
const char **functionname_ptr, |
unsigned int *line_ptr) |
{ |
bfd_boolean found; |
found = _bfd_dwarf2_find_inliner_info (abfd, filename_ptr, |
functionname_ptr, line_ptr, |
& elf_tdata (abfd)->dwarf2_find_line_info); |
return found; |
} |
int |
_bfd_elf_sizeof_headers (bfd *abfd, struct bfd_link_info *info) |
{ |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
int ret = bed->s->sizeof_ehdr; |
if (!info->relocatable) |
{ |
bfd_size_type phdr_size = elf_program_header_size (abfd); |
if (phdr_size == (bfd_size_type) -1) |
{ |
struct elf_segment_map *m; |
phdr_size = 0; |
for (m = elf_seg_map (abfd); m != NULL; m = m->next) |
phdr_size += bed->s->sizeof_phdr; |
if (phdr_size == 0) |
phdr_size = get_program_header_size (abfd, info); |
} |
elf_program_header_size (abfd) = phdr_size; |
ret += phdr_size; |
} |
return ret; |
} |
bfd_boolean |
_bfd_elf_set_section_contents (bfd *abfd, |
sec_ptr section, |
const void *location, |
file_ptr offset, |
bfd_size_type count) |
{ |
Elf_Internal_Shdr *hdr; |
bfd_signed_vma pos; |
if (! abfd->output_has_begun |
&& ! _bfd_elf_compute_section_file_positions (abfd, NULL)) |
return FALSE; |
hdr = &elf_section_data (section)->this_hdr; |
pos = hdr->sh_offset + offset; |
if (bfd_seek (abfd, pos, SEEK_SET) != 0 |
|| bfd_bwrite (location, count, abfd) != count) |
return FALSE; |
return TRUE; |
} |
void |
_bfd_elf_no_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, |
arelent *cache_ptr ATTRIBUTE_UNUSED, |
Elf_Internal_Rela *dst ATTRIBUTE_UNUSED) |
{ |
abort (); |
} |
/* Try to convert a non-ELF reloc into an ELF one. */ |
bfd_boolean |
_bfd_elf_validate_reloc (bfd *abfd, arelent *areloc) |
{ |
/* Check whether we really have an ELF howto. */ |
if ((*areloc->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec) |
{ |
bfd_reloc_code_real_type code; |
reloc_howto_type *howto; |
/* Alien reloc: Try to determine its type to replace it with an |
equivalent ELF reloc. */ |
if (areloc->howto->pc_relative) |
{ |
switch (areloc->howto->bitsize) |
{ |
case 8: |
code = BFD_RELOC_8_PCREL; |
break; |
case 12: |
code = BFD_RELOC_12_PCREL; |
break; |
case 16: |
code = BFD_RELOC_16_PCREL; |
break; |
case 24: |
code = BFD_RELOC_24_PCREL; |
break; |
case 32: |
code = BFD_RELOC_32_PCREL; |
break; |
case 64: |
code = BFD_RELOC_64_PCREL; |
break; |
default: |
goto fail; |
} |
howto = bfd_reloc_type_lookup (abfd, code); |
if (areloc->howto->pcrel_offset != howto->pcrel_offset) |
{ |
if (howto->pcrel_offset) |
areloc->addend += areloc->address; |
else |
areloc->addend -= areloc->address; /* addend is unsigned!! */ |
} |
} |
else |
{ |
switch (areloc->howto->bitsize) |
{ |
case 8: |
code = BFD_RELOC_8; |
break; |
case 14: |
code = BFD_RELOC_14; |
break; |
case 16: |
code = BFD_RELOC_16; |
break; |
case 26: |
code = BFD_RELOC_26; |
break; |
case 32: |
code = BFD_RELOC_32; |
break; |
case 64: |
code = BFD_RELOC_64; |
break; |
default: |
goto fail; |
} |
howto = bfd_reloc_type_lookup (abfd, code); |
} |
if (howto) |
areloc->howto = howto; |
else |
goto fail; |
} |
return TRUE; |
fail: |
(*_bfd_error_handler) |
(_("%B: unsupported relocation type %s"), |
abfd, areloc->howto->name); |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
bfd_boolean |
_bfd_elf_close_and_cleanup (bfd *abfd) |
{ |
struct elf_obj_tdata *tdata = elf_tdata (abfd); |
if (bfd_get_format (abfd) == bfd_object && tdata != NULL) |
{ |
if (elf_tdata (abfd)->o != NULL && elf_shstrtab (abfd) != NULL) |
_bfd_elf_strtab_free (elf_shstrtab (abfd)); |
_bfd_dwarf2_cleanup_debug_info (abfd, &tdata->dwarf2_find_line_info); |
} |
return _bfd_generic_close_and_cleanup (abfd); |
} |
/* For Rel targets, we encode meaningful data for BFD_RELOC_VTABLE_ENTRY |
in the relocation's offset. Thus we cannot allow any sort of sanity |
range-checking to interfere. There is nothing else to do in processing |
this reloc. */ |
bfd_reloc_status_type |
_bfd_elf_rel_vtable_reloc_fn |
(bfd *abfd ATTRIBUTE_UNUSED, arelent *re ATTRIBUTE_UNUSED, |
struct bfd_symbol *symbol ATTRIBUTE_UNUSED, |
void *data ATTRIBUTE_UNUSED, asection *is ATTRIBUTE_UNUSED, |
bfd *obfd ATTRIBUTE_UNUSED, char **errmsg ATTRIBUTE_UNUSED) |
{ |
return bfd_reloc_ok; |
} |
/* Elf core file support. Much of this only works on native |
toolchains, since we rely on knowing the |
machine-dependent procfs structure in order to pick |
out details about the corefile. */ |
#ifdef HAVE_SYS_PROCFS_H |
/* Needed for new procfs interface on sparc-solaris. */ |
# define _STRUCTURED_PROC 1 |
# include <sys/procfs.h> |
#endif |
/* Return a PID that identifies a "thread" for threaded cores, or the |
PID of the main process for non-threaded cores. */ |
static int |
elfcore_make_pid (bfd *abfd) |
{ |
int pid; |
pid = elf_tdata (abfd)->core->lwpid; |
if (pid == 0) |
pid = elf_tdata (abfd)->core->pid; |
return pid; |
} |
/* If there isn't a section called NAME, make one, using |
data from SECT. Note, this function will generate a |
reference to NAME, so you shouldn't deallocate or |
overwrite it. */ |
static bfd_boolean |
elfcore_maybe_make_sect (bfd *abfd, char *name, asection *sect) |
{ |
asection *sect2; |
if (bfd_get_section_by_name (abfd, name) != NULL) |
return TRUE; |
sect2 = bfd_make_section_with_flags (abfd, name, sect->flags); |
if (sect2 == NULL) |
return FALSE; |
sect2->size = sect->size; |
sect2->filepos = sect->filepos; |
sect2->alignment_power = sect->alignment_power; |
return TRUE; |
} |
/* Create a pseudosection containing SIZE bytes at FILEPOS. This |
actually creates up to two pseudosections: |
- For the single-threaded case, a section named NAME, unless |
such a section already exists. |
- For the multi-threaded case, a section named "NAME/PID", where |
PID is elfcore_make_pid (abfd). |
Both pseudosections have identical contents. */ |
bfd_boolean |
_bfd_elfcore_make_pseudosection (bfd *abfd, |
char *name, |
size_t size, |
ufile_ptr filepos) |
{ |
char buf[100]; |
char *threaded_name; |
size_t len; |
asection *sect; |
/* Build the section name. */ |
sprintf (buf, "%s/%d", name, elfcore_make_pid (abfd)); |
len = strlen (buf) + 1; |
threaded_name = (char *) bfd_alloc (abfd, len); |
if (threaded_name == NULL) |
return FALSE; |
memcpy (threaded_name, buf, len); |
sect = bfd_make_section_anyway_with_flags (abfd, threaded_name, |
SEC_HAS_CONTENTS); |
if (sect == NULL) |
return FALSE; |
sect->size = size; |
sect->filepos = filepos; |
sect->alignment_power = 2; |
return elfcore_maybe_make_sect (abfd, name, sect); |
} |
/* prstatus_t exists on: |
solaris 2.5+ |
linux 2.[01] + glibc |
unixware 4.2 |
*/ |
#if defined (HAVE_PRSTATUS_T) |
static bfd_boolean |
elfcore_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) |
{ |
size_t size; |
int offset; |
if (note->descsz == sizeof (prstatus_t)) |
{ |
prstatus_t prstat; |
size = sizeof (prstat.pr_reg); |
offset = offsetof (prstatus_t, pr_reg); |
memcpy (&prstat, note->descdata, sizeof (prstat)); |
/* Do not overwrite the core signal if it |
has already been set by another thread. */ |
if (elf_tdata (abfd)->core->signal == 0) |
elf_tdata (abfd)->core->signal = prstat.pr_cursig; |
if (elf_tdata (abfd)->core->pid == 0) |
elf_tdata (abfd)->core->pid = prstat.pr_pid; |
/* pr_who exists on: |
solaris 2.5+ |
unixware 4.2 |
pr_who doesn't exist on: |
linux 2.[01] |
*/ |
#if defined (HAVE_PRSTATUS_T_PR_WHO) |
elf_tdata (abfd)->core->lwpid = prstat.pr_who; |
#else |
elf_tdata (abfd)->core->lwpid = prstat.pr_pid; |
#endif |
} |
#if defined (HAVE_PRSTATUS32_T) |
else if (note->descsz == sizeof (prstatus32_t)) |
{ |
/* 64-bit host, 32-bit corefile */ |
prstatus32_t prstat; |
size = sizeof (prstat.pr_reg); |
offset = offsetof (prstatus32_t, pr_reg); |
memcpy (&prstat, note->descdata, sizeof (prstat)); |
/* Do not overwrite the core signal if it |
has already been set by another thread. */ |
if (elf_tdata (abfd)->core->signal == 0) |
elf_tdata (abfd)->core->signal = prstat.pr_cursig; |
if (elf_tdata (abfd)->core->pid == 0) |
elf_tdata (abfd)->core->pid = prstat.pr_pid; |
/* pr_who exists on: |
solaris 2.5+ |
unixware 4.2 |
pr_who doesn't exist on: |
linux 2.[01] |
*/ |
#if defined (HAVE_PRSTATUS32_T_PR_WHO) |
elf_tdata (abfd)->core->lwpid = prstat.pr_who; |
#else |
elf_tdata (abfd)->core->lwpid = prstat.pr_pid; |
#endif |
} |
#endif /* HAVE_PRSTATUS32_T */ |
else |
{ |
/* Fail - we don't know how to handle any other |
note size (ie. data object type). */ |
return TRUE; |
} |
/* Make a ".reg/999" section and a ".reg" section. */ |
return _bfd_elfcore_make_pseudosection (abfd, ".reg", |
size, note->descpos + offset); |
} |
#endif /* defined (HAVE_PRSTATUS_T) */ |
/* Create a pseudosection containing the exact contents of NOTE. */ |
static bfd_boolean |
elfcore_make_note_pseudosection (bfd *abfd, |
char *name, |
Elf_Internal_Note *note) |
{ |
return _bfd_elfcore_make_pseudosection (abfd, name, |
note->descsz, note->descpos); |
} |
/* There isn't a consistent prfpregset_t across platforms, |
but it doesn't matter, because we don't have to pick this |
data structure apart. */ |
static bfd_boolean |
elfcore_grok_prfpreg (bfd *abfd, Elf_Internal_Note *note) |
{ |
return elfcore_make_note_pseudosection (abfd, ".reg2", note); |
} |
/* Linux dumps the Intel SSE regs in a note named "LINUX" with a note |
type of NT_PRXFPREG. Just include the whole note's contents |
literally. */ |
static bfd_boolean |
elfcore_grok_prxfpreg (bfd *abfd, Elf_Internal_Note *note) |
{ |
return elfcore_make_note_pseudosection (abfd, ".reg-xfp", note); |
} |
/* Linux dumps the Intel XSAVE extended state in a note named "LINUX" |
with a note type of NT_X86_XSTATE. Just include the whole note's |
contents literally. */ |
static bfd_boolean |
elfcore_grok_xstatereg (bfd *abfd, Elf_Internal_Note *note) |
{ |
return elfcore_make_note_pseudosection (abfd, ".reg-xstate", note); |
} |
static bfd_boolean |
elfcore_grok_ppc_vmx (bfd *abfd, Elf_Internal_Note *note) |
{ |
return elfcore_make_note_pseudosection (abfd, ".reg-ppc-vmx", note); |
} |
static bfd_boolean |
elfcore_grok_ppc_vsx (bfd *abfd, Elf_Internal_Note *note) |
{ |
return elfcore_make_note_pseudosection (abfd, ".reg-ppc-vsx", note); |
} |
static bfd_boolean |
elfcore_grok_s390_high_gprs (bfd *abfd, Elf_Internal_Note *note) |
{ |
return elfcore_make_note_pseudosection (abfd, ".reg-s390-high-gprs", note); |
} |
static bfd_boolean |
elfcore_grok_s390_timer (bfd *abfd, Elf_Internal_Note *note) |
{ |
return elfcore_make_note_pseudosection (abfd, ".reg-s390-timer", note); |
} |
static bfd_boolean |
elfcore_grok_s390_todcmp (bfd *abfd, Elf_Internal_Note *note) |
{ |
return elfcore_make_note_pseudosection (abfd, ".reg-s390-todcmp", note); |
} |
static bfd_boolean |
elfcore_grok_s390_todpreg (bfd *abfd, Elf_Internal_Note *note) |
{ |
return elfcore_make_note_pseudosection (abfd, ".reg-s390-todpreg", note); |
} |
static bfd_boolean |
elfcore_grok_s390_ctrs (bfd *abfd, Elf_Internal_Note *note) |
{ |
return elfcore_make_note_pseudosection (abfd, ".reg-s390-ctrs", note); |
} |
static bfd_boolean |
elfcore_grok_s390_prefix (bfd *abfd, Elf_Internal_Note *note) |
{ |
return elfcore_make_note_pseudosection (abfd, ".reg-s390-prefix", note); |
} |
static bfd_boolean |
elfcore_grok_s390_last_break (bfd *abfd, Elf_Internal_Note *note) |
{ |
return elfcore_make_note_pseudosection (abfd, ".reg-s390-last-break", note); |
} |
static bfd_boolean |
elfcore_grok_s390_system_call (bfd *abfd, Elf_Internal_Note *note) |
{ |
return elfcore_make_note_pseudosection (abfd, ".reg-s390-system-call", note); |
} |
static bfd_boolean |
elfcore_grok_s390_tdb (bfd *abfd, Elf_Internal_Note *note) |
{ |
return elfcore_make_note_pseudosection (abfd, ".reg-s390-tdb", note); |
} |
static bfd_boolean |
elfcore_grok_arm_vfp (bfd *abfd, Elf_Internal_Note *note) |
{ |
return elfcore_make_note_pseudosection (abfd, ".reg-arm-vfp", note); |
} |
static bfd_boolean |
elfcore_grok_aarch_tls (bfd *abfd, Elf_Internal_Note *note) |
{ |
return elfcore_make_note_pseudosection (abfd, ".reg-aarch-tls", note); |
} |
static bfd_boolean |
elfcore_grok_aarch_hw_break (bfd *abfd, Elf_Internal_Note *note) |
{ |
return elfcore_make_note_pseudosection (abfd, ".reg-aarch-hw-break", note); |
} |
static bfd_boolean |
elfcore_grok_aarch_hw_watch (bfd *abfd, Elf_Internal_Note *note) |
{ |
return elfcore_make_note_pseudosection (abfd, ".reg-aarch-hw-watch", note); |
} |
#if defined (HAVE_PRPSINFO_T) |
typedef prpsinfo_t elfcore_psinfo_t; |
#if defined (HAVE_PRPSINFO32_T) /* Sparc64 cross Sparc32 */ |
typedef prpsinfo32_t elfcore_psinfo32_t; |
#endif |
#endif |
#if defined (HAVE_PSINFO_T) |
typedef psinfo_t elfcore_psinfo_t; |
#if defined (HAVE_PSINFO32_T) /* Sparc64 cross Sparc32 */ |
typedef psinfo32_t elfcore_psinfo32_t; |
#endif |
#endif |
/* return a malloc'ed copy of a string at START which is at |
most MAX bytes long, possibly without a terminating '\0'. |
the copy will always have a terminating '\0'. */ |
char * |
_bfd_elfcore_strndup (bfd *abfd, char *start, size_t max) |
{ |
char *dups; |
char *end = (char *) memchr (start, '\0', max); |
size_t len; |
if (end == NULL) |
len = max; |
else |
len = end - start; |
dups = (char *) bfd_alloc (abfd, len + 1); |
if (dups == NULL) |
return NULL; |
memcpy (dups, start, len); |
dups[len] = '\0'; |
return dups; |
} |
#if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T) |
static bfd_boolean |
elfcore_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) |
{ |
if (note->descsz == sizeof (elfcore_psinfo_t)) |
{ |
elfcore_psinfo_t psinfo; |
memcpy (&psinfo, note->descdata, sizeof (psinfo)); |
#if defined (HAVE_PSINFO_T_PR_PID) || defined (HAVE_PRPSINFO_T_PR_PID) |
elf_tdata (abfd)->core->pid = psinfo.pr_pid; |
#endif |
elf_tdata (abfd)->core->program |
= _bfd_elfcore_strndup (abfd, psinfo.pr_fname, |
sizeof (psinfo.pr_fname)); |
elf_tdata (abfd)->core->command |
= _bfd_elfcore_strndup (abfd, psinfo.pr_psargs, |
sizeof (psinfo.pr_psargs)); |
} |
#if defined (HAVE_PRPSINFO32_T) || defined (HAVE_PSINFO32_T) |
else if (note->descsz == sizeof (elfcore_psinfo32_t)) |
{ |
/* 64-bit host, 32-bit corefile */ |
elfcore_psinfo32_t psinfo; |
memcpy (&psinfo, note->descdata, sizeof (psinfo)); |
#if defined (HAVE_PSINFO32_T_PR_PID) || defined (HAVE_PRPSINFO32_T_PR_PID) |
elf_tdata (abfd)->core->pid = psinfo.pr_pid; |
#endif |
elf_tdata (abfd)->core->program |
= _bfd_elfcore_strndup (abfd, psinfo.pr_fname, |
sizeof (psinfo.pr_fname)); |
elf_tdata (abfd)->core->command |
= _bfd_elfcore_strndup (abfd, psinfo.pr_psargs, |
sizeof (psinfo.pr_psargs)); |
} |
#endif |
else |
{ |
/* Fail - we don't know how to handle any other |
note size (ie. data object type). */ |
return TRUE; |
} |
/* Note that for some reason, a spurious space is tacked |
onto the end of the args in some (at least one anyway) |
implementations, so strip it off if it exists. */ |
{ |
char *command = elf_tdata (abfd)->core->command; |
int n = strlen (command); |
if (0 < n && command[n - 1] == ' ') |
command[n - 1] = '\0'; |
} |
return TRUE; |
} |
#endif /* defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T) */ |
#if defined (HAVE_PSTATUS_T) |
static bfd_boolean |
elfcore_grok_pstatus (bfd *abfd, Elf_Internal_Note *note) |
{ |
if (note->descsz == sizeof (pstatus_t) |
#if defined (HAVE_PXSTATUS_T) |
|| note->descsz == sizeof (pxstatus_t) |
#endif |
) |
{ |
pstatus_t pstat; |
memcpy (&pstat, note->descdata, sizeof (pstat)); |
elf_tdata (abfd)->core->pid = pstat.pr_pid; |
} |
#if defined (HAVE_PSTATUS32_T) |
else if (note->descsz == sizeof (pstatus32_t)) |
{ |
/* 64-bit host, 32-bit corefile */ |
pstatus32_t pstat; |
memcpy (&pstat, note->descdata, sizeof (pstat)); |
elf_tdata (abfd)->core->pid = pstat.pr_pid; |
} |
#endif |
/* Could grab some more details from the "representative" |
lwpstatus_t in pstat.pr_lwp, but we'll catch it all in an |
NT_LWPSTATUS note, presumably. */ |
return TRUE; |
} |
#endif /* defined (HAVE_PSTATUS_T) */ |
#if defined (HAVE_LWPSTATUS_T) |
static bfd_boolean |
elfcore_grok_lwpstatus (bfd *abfd, Elf_Internal_Note *note) |
{ |
lwpstatus_t lwpstat; |
char buf[100]; |
char *name; |
size_t len; |
asection *sect; |
if (note->descsz != sizeof (lwpstat) |
#if defined (HAVE_LWPXSTATUS_T) |
&& note->descsz != sizeof (lwpxstatus_t) |
#endif |
) |
return TRUE; |
memcpy (&lwpstat, note->descdata, sizeof (lwpstat)); |
elf_tdata (abfd)->core->lwpid = lwpstat.pr_lwpid; |
/* Do not overwrite the core signal if it has already been set by |
another thread. */ |
if (elf_tdata (abfd)->core->signal == 0) |
elf_tdata (abfd)->core->signal = lwpstat.pr_cursig; |
/* Make a ".reg/999" section. */ |
sprintf (buf, ".reg/%d", elfcore_make_pid (abfd)); |
len = strlen (buf) + 1; |
name = bfd_alloc (abfd, len); |
if (name == NULL) |
return FALSE; |
memcpy (name, buf, len); |
sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS); |
if (sect == NULL) |
return FALSE; |
#if defined (HAVE_LWPSTATUS_T_PR_CONTEXT) |
sect->size = sizeof (lwpstat.pr_context.uc_mcontext.gregs); |
sect->filepos = note->descpos |
+ offsetof (lwpstatus_t, pr_context.uc_mcontext.gregs); |
#endif |
#if defined (HAVE_LWPSTATUS_T_PR_REG) |
sect->size = sizeof (lwpstat.pr_reg); |
sect->filepos = note->descpos + offsetof (lwpstatus_t, pr_reg); |
#endif |
sect->alignment_power = 2; |
if (!elfcore_maybe_make_sect (abfd, ".reg", sect)) |
return FALSE; |
/* Make a ".reg2/999" section */ |
sprintf (buf, ".reg2/%d", elfcore_make_pid (abfd)); |
len = strlen (buf) + 1; |
name = bfd_alloc (abfd, len); |
if (name == NULL) |
return FALSE; |
memcpy (name, buf, len); |
sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS); |
if (sect == NULL) |
return FALSE; |
#if defined (HAVE_LWPSTATUS_T_PR_CONTEXT) |
sect->size = sizeof (lwpstat.pr_context.uc_mcontext.fpregs); |
sect->filepos = note->descpos |
+ offsetof (lwpstatus_t, pr_context.uc_mcontext.fpregs); |
#endif |
#if defined (HAVE_LWPSTATUS_T_PR_FPREG) |
sect->size = sizeof (lwpstat.pr_fpreg); |
sect->filepos = note->descpos + offsetof (lwpstatus_t, pr_fpreg); |
#endif |
sect->alignment_power = 2; |
return elfcore_maybe_make_sect (abfd, ".reg2", sect); |
} |
#endif /* defined (HAVE_LWPSTATUS_T) */ |
static bfd_boolean |
elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note) |
{ |
char buf[30]; |
char *name; |
size_t len; |
asection *sect; |
int type; |
int is_active_thread; |
bfd_vma base_addr; |
if (note->descsz < 728) |
return TRUE; |
if (! CONST_STRNEQ (note->namedata, "win32")) |
return TRUE; |
type = bfd_get_32 (abfd, note->descdata); |
switch (type) |
{ |
case 1 /* NOTE_INFO_PROCESS */: |
/* FIXME: need to add ->core->command. */ |
/* process_info.pid */ |
elf_tdata (abfd)->core->pid = bfd_get_32 (abfd, note->descdata + 8); |
/* process_info.signal */ |
elf_tdata (abfd)->core->signal = bfd_get_32 (abfd, note->descdata + 12); |
break; |
case 2 /* NOTE_INFO_THREAD */: |
/* Make a ".reg/999" section. */ |
/* thread_info.tid */ |
sprintf (buf, ".reg/%ld", (long) bfd_get_32 (abfd, note->descdata + 8)); |
len = strlen (buf) + 1; |
name = (char *) bfd_alloc (abfd, len); |
if (name == NULL) |
return FALSE; |
memcpy (name, buf, len); |
sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS); |
if (sect == NULL) |
return FALSE; |
/* sizeof (thread_info.thread_context) */ |
sect->size = 716; |
/* offsetof (thread_info.thread_context) */ |
sect->filepos = note->descpos + 12; |
sect->alignment_power = 2; |
/* thread_info.is_active_thread */ |
is_active_thread = bfd_get_32 (abfd, note->descdata + 8); |
if (is_active_thread) |
if (! elfcore_maybe_make_sect (abfd, ".reg", sect)) |
return FALSE; |
break; |
case 3 /* NOTE_INFO_MODULE */: |
/* Make a ".module/xxxxxxxx" section. */ |
/* module_info.base_address */ |
base_addr = bfd_get_32 (abfd, note->descdata + 4); |
sprintf (buf, ".module/%08lx", (unsigned long) base_addr); |
len = strlen (buf) + 1; |
name = (char *) bfd_alloc (abfd, len); |
if (name == NULL) |
return FALSE; |
memcpy (name, buf, len); |
sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS); |
if (sect == NULL) |
return FALSE; |
sect->size = note->descsz; |
sect->filepos = note->descpos; |
sect->alignment_power = 2; |
break; |
default: |
return TRUE; |
} |
return TRUE; |
} |
static bfd_boolean |
elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note) |
{ |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
switch (note->type) |
{ |
default: |
return TRUE; |
case NT_PRSTATUS: |
if (bed->elf_backend_grok_prstatus) |
if ((*bed->elf_backend_grok_prstatus) (abfd, note)) |
return TRUE; |
#if defined (HAVE_PRSTATUS_T) |
return elfcore_grok_prstatus (abfd, note); |
#else |
return TRUE; |
#endif |
#if defined (HAVE_PSTATUS_T) |
case NT_PSTATUS: |
return elfcore_grok_pstatus (abfd, note); |
#endif |
#if defined (HAVE_LWPSTATUS_T) |
case NT_LWPSTATUS: |
return elfcore_grok_lwpstatus (abfd, note); |
#endif |
case NT_FPREGSET: /* FIXME: rename to NT_PRFPREG */ |
return elfcore_grok_prfpreg (abfd, note); |
case NT_WIN32PSTATUS: |
return elfcore_grok_win32pstatus (abfd, note); |
case NT_PRXFPREG: /* Linux SSE extension */ |
if (note->namesz == 6 |
&& strcmp (note->namedata, "LINUX") == 0) |
return elfcore_grok_prxfpreg (abfd, note); |
else |
return TRUE; |
case NT_X86_XSTATE: /* Linux XSAVE extension */ |
if (note->namesz == 6 |
&& strcmp (note->namedata, "LINUX") == 0) |
return elfcore_grok_xstatereg (abfd, note); |
else |
return TRUE; |
case NT_PPC_VMX: |
if (note->namesz == 6 |
&& strcmp (note->namedata, "LINUX") == 0) |
return elfcore_grok_ppc_vmx (abfd, note); |
else |
return TRUE; |
case NT_PPC_VSX: |
if (note->namesz == 6 |
&& strcmp (note->namedata, "LINUX") == 0) |
return elfcore_grok_ppc_vsx (abfd, note); |
else |
return TRUE; |
case NT_S390_HIGH_GPRS: |
if (note->namesz == 6 |
&& strcmp (note->namedata, "LINUX") == 0) |
return elfcore_grok_s390_high_gprs (abfd, note); |
else |
return TRUE; |
case NT_S390_TIMER: |
if (note->namesz == 6 |
&& strcmp (note->namedata, "LINUX") == 0) |
return elfcore_grok_s390_timer (abfd, note); |
else |
return TRUE; |
case NT_S390_TODCMP: |
if (note->namesz == 6 |
&& strcmp (note->namedata, "LINUX") == 0) |
return elfcore_grok_s390_todcmp (abfd, note); |
else |
return TRUE; |
case NT_S390_TODPREG: |
if (note->namesz == 6 |
&& strcmp (note->namedata, "LINUX") == 0) |
return elfcore_grok_s390_todpreg (abfd, note); |
else |
return TRUE; |
case NT_S390_CTRS: |
if (note->namesz == 6 |
&& strcmp (note->namedata, "LINUX") == 0) |
return elfcore_grok_s390_ctrs (abfd, note); |
else |
return TRUE; |
case NT_S390_PREFIX: |
if (note->namesz == 6 |
&& strcmp (note->namedata, "LINUX") == 0) |
return elfcore_grok_s390_prefix (abfd, note); |
else |
return TRUE; |
case NT_S390_LAST_BREAK: |
if (note->namesz == 6 |
&& strcmp (note->namedata, "LINUX") == 0) |
return elfcore_grok_s390_last_break (abfd, note); |
else |
return TRUE; |
case NT_S390_SYSTEM_CALL: |
if (note->namesz == 6 |
&& strcmp (note->namedata, "LINUX") == 0) |
return elfcore_grok_s390_system_call (abfd, note); |
else |
return TRUE; |
case NT_S390_TDB: |
if (note->namesz == 6 |
&& strcmp (note->namedata, "LINUX") == 0) |
return elfcore_grok_s390_tdb (abfd, note); |
else |
return TRUE; |
case NT_ARM_VFP: |
if (note->namesz == 6 |
&& strcmp (note->namedata, "LINUX") == 0) |
return elfcore_grok_arm_vfp (abfd, note); |
else |
return TRUE; |
case NT_ARM_TLS: |
if (note->namesz == 6 |
&& strcmp (note->namedata, "LINUX") == 0) |
return elfcore_grok_aarch_tls (abfd, note); |
else |
return TRUE; |
case NT_ARM_HW_BREAK: |
if (note->namesz == 6 |
&& strcmp (note->namedata, "LINUX") == 0) |
return elfcore_grok_aarch_hw_break (abfd, note); |
else |
return TRUE; |
case NT_ARM_HW_WATCH: |
if (note->namesz == 6 |
&& strcmp (note->namedata, "LINUX") == 0) |
return elfcore_grok_aarch_hw_watch (abfd, note); |
else |
return TRUE; |
case NT_PRPSINFO: |
case NT_PSINFO: |
if (bed->elf_backend_grok_psinfo) |
if ((*bed->elf_backend_grok_psinfo) (abfd, note)) |
return TRUE; |
#if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T) |
return elfcore_grok_psinfo (abfd, note); |
#else |
return TRUE; |
#endif |
case NT_AUXV: |
{ |
asection *sect = bfd_make_section_anyway_with_flags (abfd, ".auxv", |
SEC_HAS_CONTENTS); |
if (sect == NULL) |
return FALSE; |
sect->size = note->descsz; |
sect->filepos = note->descpos; |
sect->alignment_power = 1 + bfd_get_arch_size (abfd) / 32; |
return TRUE; |
} |
case NT_FILE: |
return elfcore_make_note_pseudosection (abfd, ".note.linuxcore.file", |
note); |
case NT_SIGINFO: |
return elfcore_make_note_pseudosection (abfd, ".note.linuxcore.siginfo", |
note); |
} |
} |
static bfd_boolean |
elfobj_grok_gnu_build_id (bfd *abfd, Elf_Internal_Note *note) |
{ |
struct elf_obj_tdata *t; |
if (note->descsz == 0) |
return FALSE; |
t = elf_tdata (abfd); |
t->build_id = bfd_alloc (abfd, sizeof (*t->build_id) - 1 + note->descsz); |
if (t->build_id == NULL) |
return FALSE; |
t->build_id->size = note->descsz; |
memcpy (t->build_id->data, note->descdata, note->descsz); |
return TRUE; |
} |
static bfd_boolean |
elfobj_grok_gnu_note (bfd *abfd, Elf_Internal_Note *note) |
{ |
switch (note->type) |
{ |
default: |
return TRUE; |
case NT_GNU_BUILD_ID: |
return elfobj_grok_gnu_build_id (abfd, note); |
} |
} |
static bfd_boolean |
elfobj_grok_stapsdt_note_1 (bfd *abfd, Elf_Internal_Note *note) |
{ |
struct sdt_note *cur = |
(struct sdt_note *) bfd_alloc (abfd, sizeof (struct sdt_note) |
+ note->descsz); |
cur->next = (struct sdt_note *) (elf_tdata (abfd))->sdt_note_head; |
cur->size = (bfd_size_type) note->descsz; |
memcpy (cur->data, note->descdata, note->descsz); |
elf_tdata (abfd)->sdt_note_head = cur; |
return TRUE; |
} |
static bfd_boolean |
elfobj_grok_stapsdt_note (bfd *abfd, Elf_Internal_Note *note) |
{ |
switch (note->type) |
{ |
case NT_STAPSDT: |
return elfobj_grok_stapsdt_note_1 (abfd, note); |
default: |
return TRUE; |
} |
} |
static bfd_boolean |
elfcore_netbsd_get_lwpid (Elf_Internal_Note *note, int *lwpidp) |
{ |
char *cp; |
cp = strchr (note->namedata, '@'); |
if (cp != NULL) |
{ |
*lwpidp = atoi(cp + 1); |
return TRUE; |
} |
return FALSE; |
} |
static bfd_boolean |
elfcore_grok_netbsd_procinfo (bfd *abfd, Elf_Internal_Note *note) |
{ |
/* Signal number at offset 0x08. */ |
elf_tdata (abfd)->core->signal |
= bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + 0x08); |
/* Process ID at offset 0x50. */ |
elf_tdata (abfd)->core->pid |
= bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + 0x50); |
/* Command name at 0x7c (max 32 bytes, including nul). */ |
elf_tdata (abfd)->core->command |
= _bfd_elfcore_strndup (abfd, note->descdata + 0x7c, 31); |
return elfcore_make_note_pseudosection (abfd, ".note.netbsdcore.procinfo", |
note); |
} |
static bfd_boolean |
elfcore_grok_netbsd_note (bfd *abfd, Elf_Internal_Note *note) |
{ |
int lwp; |
if (elfcore_netbsd_get_lwpid (note, &lwp)) |
elf_tdata (abfd)->core->lwpid = lwp; |
if (note->type == NT_NETBSDCORE_PROCINFO) |
{ |
/* NetBSD-specific core "procinfo". Note that we expect to |
find this note before any of the others, which is fine, |
since the kernel writes this note out first when it |
creates a core file. */ |
return elfcore_grok_netbsd_procinfo (abfd, note); |
} |
/* As of Jan 2002 there are no other machine-independent notes |
defined for NetBSD core files. If the note type is less |
than the start of the machine-dependent note types, we don't |
understand it. */ |
if (note->type < NT_NETBSDCORE_FIRSTMACH) |
return TRUE; |
switch (bfd_get_arch (abfd)) |
{ |
/* On the Alpha, SPARC (32-bit and 64-bit), PT_GETREGS == mach+0 and |
PT_GETFPREGS == mach+2. */ |
case bfd_arch_alpha: |
case bfd_arch_sparc: |
switch (note->type) |
{ |
case NT_NETBSDCORE_FIRSTMACH+0: |
return elfcore_make_note_pseudosection (abfd, ".reg", note); |
case NT_NETBSDCORE_FIRSTMACH+2: |
return elfcore_make_note_pseudosection (abfd, ".reg2", note); |
default: |
return TRUE; |
} |
/* On all other arch's, PT_GETREGS == mach+1 and |
PT_GETFPREGS == mach+3. */ |
default: |
switch (note->type) |
{ |
case NT_NETBSDCORE_FIRSTMACH+1: |
return elfcore_make_note_pseudosection (abfd, ".reg", note); |
case NT_NETBSDCORE_FIRSTMACH+3: |
return elfcore_make_note_pseudosection (abfd, ".reg2", note); |
default: |
return TRUE; |
} |
} |
/* NOTREACHED */ |
} |
static bfd_boolean |
elfcore_grok_openbsd_procinfo (bfd *abfd, Elf_Internal_Note *note) |
{ |
/* Signal number at offset 0x08. */ |
elf_tdata (abfd)->core->signal |
= bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + 0x08); |
/* Process ID at offset 0x20. */ |
elf_tdata (abfd)->core->pid |
= bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + 0x20); |
/* Command name at 0x48 (max 32 bytes, including nul). */ |
elf_tdata (abfd)->core->command |
= _bfd_elfcore_strndup (abfd, note->descdata + 0x48, 31); |
return TRUE; |
} |
static bfd_boolean |
elfcore_grok_openbsd_note (bfd *abfd, Elf_Internal_Note *note) |
{ |
if (note->type == NT_OPENBSD_PROCINFO) |
return elfcore_grok_openbsd_procinfo (abfd, note); |
if (note->type == NT_OPENBSD_REGS) |
return elfcore_make_note_pseudosection (abfd, ".reg", note); |
if (note->type == NT_OPENBSD_FPREGS) |
return elfcore_make_note_pseudosection (abfd, ".reg2", note); |
if (note->type == NT_OPENBSD_XFPREGS) |
return elfcore_make_note_pseudosection (abfd, ".reg-xfp", note); |
if (note->type == NT_OPENBSD_AUXV) |
{ |
asection *sect = bfd_make_section_anyway_with_flags (abfd, ".auxv", |
SEC_HAS_CONTENTS); |
if (sect == NULL) |
return FALSE; |
sect->size = note->descsz; |
sect->filepos = note->descpos; |
sect->alignment_power = 1 + bfd_get_arch_size (abfd) / 32; |
return TRUE; |
} |
if (note->type == NT_OPENBSD_WCOOKIE) |
{ |
asection *sect = bfd_make_section_anyway_with_flags (abfd, ".wcookie", |
SEC_HAS_CONTENTS); |
if (sect == NULL) |
return FALSE; |
sect->size = note->descsz; |
sect->filepos = note->descpos; |
sect->alignment_power = 1 + bfd_get_arch_size (abfd) / 32; |
return TRUE; |
} |
return TRUE; |
} |
static bfd_boolean |
elfcore_grok_nto_status (bfd *abfd, Elf_Internal_Note *note, long *tid) |
{ |
void *ddata = note->descdata; |
char buf[100]; |
char *name; |
asection *sect; |
short sig; |
unsigned flags; |
/* nto_procfs_status 'pid' field is at offset 0. */ |
elf_tdata (abfd)->core->pid = bfd_get_32 (abfd, (bfd_byte *) ddata); |
/* nto_procfs_status 'tid' field is at offset 4. Pass it back. */ |
*tid = bfd_get_32 (abfd, (bfd_byte *) ddata + 4); |
/* nto_procfs_status 'flags' field is at offset 8. */ |
flags = bfd_get_32 (abfd, (bfd_byte *) ddata + 8); |
/* nto_procfs_status 'what' field is at offset 14. */ |
if ((sig = bfd_get_16 (abfd, (bfd_byte *) ddata + 14)) > 0) |
{ |
elf_tdata (abfd)->core->signal = sig; |
elf_tdata (abfd)->core->lwpid = *tid; |
} |
/* _DEBUG_FLAG_CURTID (current thread) is 0x80. Some cores |
do not come from signals so we make sure we set the current |
thread just in case. */ |
if (flags & 0x00000080) |
elf_tdata (abfd)->core->lwpid = *tid; |
/* Make a ".qnx_core_status/%d" section. */ |
sprintf (buf, ".qnx_core_status/%ld", *tid); |
name = (char *) bfd_alloc (abfd, strlen (buf) + 1); |
if (name == NULL) |
return FALSE; |
strcpy (name, buf); |
sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS); |
if (sect == NULL) |
return FALSE; |
sect->size = note->descsz; |
sect->filepos = note->descpos; |
sect->alignment_power = 2; |
return (elfcore_maybe_make_sect (abfd, ".qnx_core_status", sect)); |
} |
static bfd_boolean |
elfcore_grok_nto_regs (bfd *abfd, |
Elf_Internal_Note *note, |
long tid, |
char *base) |
{ |
char buf[100]; |
char *name; |
asection *sect; |
/* Make a "(base)/%d" section. */ |
sprintf (buf, "%s/%ld", base, tid); |
name = (char *) bfd_alloc (abfd, strlen (buf) + 1); |
if (name == NULL) |
return FALSE; |
strcpy (name, buf); |
sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS); |
if (sect == NULL) |
return FALSE; |
sect->size = note->descsz; |
sect->filepos = note->descpos; |
sect->alignment_power = 2; |
/* This is the current thread. */ |
if (elf_tdata (abfd)->core->lwpid == tid) |
return elfcore_maybe_make_sect (abfd, base, sect); |
return TRUE; |
} |
#define BFD_QNT_CORE_INFO 7 |
#define BFD_QNT_CORE_STATUS 8 |
#define BFD_QNT_CORE_GREG 9 |
#define BFD_QNT_CORE_FPREG 10 |
static bfd_boolean |
elfcore_grok_nto_note (bfd *abfd, Elf_Internal_Note *note) |
{ |
/* Every GREG section has a STATUS section before it. Store the |
tid from the previous call to pass down to the next gregs |
function. */ |
static long tid = 1; |
switch (note->type) |
{ |
case BFD_QNT_CORE_INFO: |
return elfcore_make_note_pseudosection (abfd, ".qnx_core_info", note); |
case BFD_QNT_CORE_STATUS: |
return elfcore_grok_nto_status (abfd, note, &tid); |
case BFD_QNT_CORE_GREG: |
return elfcore_grok_nto_regs (abfd, note, tid, ".reg"); |
case BFD_QNT_CORE_FPREG: |
return elfcore_grok_nto_regs (abfd, note, tid, ".reg2"); |
default: |
return TRUE; |
} |
} |
static bfd_boolean |
elfcore_grok_spu_note (bfd *abfd, Elf_Internal_Note *note) |
{ |
char *name; |
asection *sect; |
size_t len; |
/* Use note name as section name. */ |
len = note->namesz; |
name = (char *) bfd_alloc (abfd, len); |
if (name == NULL) |
return FALSE; |
memcpy (name, note->namedata, len); |
name[len - 1] = '\0'; |
sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS); |
if (sect == NULL) |
return FALSE; |
sect->size = note->descsz; |
sect->filepos = note->descpos; |
sect->alignment_power = 1; |
return TRUE; |
} |
/* Function: elfcore_write_note |
Inputs: |
buffer to hold note, and current size of buffer |
name of note |
type of note |
data for note |
size of data for note |
Writes note to end of buffer. ELF64 notes are written exactly as |
for ELF32, despite the current (as of 2006) ELF gabi specifying |
that they ought to have 8-byte namesz and descsz field, and have |
8-byte alignment. Other writers, eg. Linux kernel, do the same. |
Return: |
Pointer to realloc'd buffer, *BUFSIZ updated. */ |
char * |
elfcore_write_note (bfd *abfd, |
char *buf, |
int *bufsiz, |
const char *name, |
int type, |
const void *input, |
int size) |
{ |
Elf_External_Note *xnp; |
size_t namesz; |
size_t newspace; |
char *dest; |
namesz = 0; |
if (name != NULL) |
namesz = strlen (name) + 1; |
newspace = 12 + ((namesz + 3) & -4) + ((size + 3) & -4); |
buf = (char *) realloc (buf, *bufsiz + newspace); |
if (buf == NULL) |
return buf; |
dest = buf + *bufsiz; |
*bufsiz += newspace; |
xnp = (Elf_External_Note *) dest; |
H_PUT_32 (abfd, namesz, xnp->namesz); |
H_PUT_32 (abfd, size, xnp->descsz); |
H_PUT_32 (abfd, type, xnp->type); |
dest = xnp->name; |
if (name != NULL) |
{ |
memcpy (dest, name, namesz); |
dest += namesz; |
while (namesz & 3) |
{ |
*dest++ = '\0'; |
++namesz; |
} |
} |
memcpy (dest, input, size); |
dest += size; |
while (size & 3) |
{ |
*dest++ = '\0'; |
++size; |
} |
return buf; |
} |
char * |
elfcore_write_prpsinfo (bfd *abfd, |
char *buf, |
int *bufsiz, |
const char *fname, |
const char *psargs) |
{ |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
if (bed->elf_backend_write_core_note != NULL) |
{ |
char *ret; |
ret = (*bed->elf_backend_write_core_note) (abfd, buf, bufsiz, |
NT_PRPSINFO, fname, psargs); |
if (ret != NULL) |
return ret; |
} |
#if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T) |
#if defined (HAVE_PRPSINFO32_T) || defined (HAVE_PSINFO32_T) |
if (bed->s->elfclass == ELFCLASS32) |
{ |
#if defined (HAVE_PSINFO32_T) |
psinfo32_t data; |
int note_type = NT_PSINFO; |
#else |
prpsinfo32_t data; |
int note_type = NT_PRPSINFO; |
#endif |
memset (&data, 0, sizeof (data)); |
strncpy (data.pr_fname, fname, sizeof (data.pr_fname)); |
strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs)); |
return elfcore_write_note (abfd, buf, bufsiz, |
"CORE", note_type, &data, sizeof (data)); |
} |
else |
#endif |
{ |
#if defined (HAVE_PSINFO_T) |
psinfo_t data; |
int note_type = NT_PSINFO; |
#else |
prpsinfo_t data; |
int note_type = NT_PRPSINFO; |
#endif |
memset (&data, 0, sizeof (data)); |
strncpy (data.pr_fname, fname, sizeof (data.pr_fname)); |
strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs)); |
return elfcore_write_note (abfd, buf, bufsiz, |
"CORE", note_type, &data, sizeof (data)); |
} |
#endif /* PSINFO_T or PRPSINFO_T */ |
free (buf); |
return NULL; |
} |
char * |
elfcore_write_linux_prpsinfo32 |
(bfd *abfd, char *buf, int *bufsiz, |
const struct elf_internal_linux_prpsinfo *prpsinfo) |
{ |
struct elf_external_linux_prpsinfo32 data; |
memset (&data, 0, sizeof (data)); |
LINUX_PRPSINFO32_SWAP_FIELDS (abfd, prpsinfo, data); |
return elfcore_write_note (abfd, buf, bufsiz, "CORE", NT_PRPSINFO, |
&data, sizeof (data)); |
} |
char * |
elfcore_write_linux_prpsinfo64 |
(bfd *abfd, char *buf, int *bufsiz, |
const struct elf_internal_linux_prpsinfo *prpsinfo) |
{ |
struct elf_external_linux_prpsinfo64 data; |
memset (&data, 0, sizeof (data)); |
LINUX_PRPSINFO64_SWAP_FIELDS (abfd, prpsinfo, data); |
return elfcore_write_note (abfd, buf, bufsiz, |
"CORE", NT_PRPSINFO, &data, sizeof (data)); |
} |
char * |
elfcore_write_prstatus (bfd *abfd, |
char *buf, |
int *bufsiz, |
long pid, |
int cursig, |
const void *gregs) |
{ |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
if (bed->elf_backend_write_core_note != NULL) |
{ |
char *ret; |
ret = (*bed->elf_backend_write_core_note) (abfd, buf, bufsiz, |
NT_PRSTATUS, |
pid, cursig, gregs); |
if (ret != NULL) |
return ret; |
} |
#if defined (HAVE_PRSTATUS_T) |
#if defined (HAVE_PRSTATUS32_T) |
if (bed->s->elfclass == ELFCLASS32) |
{ |
prstatus32_t prstat; |
memset (&prstat, 0, sizeof (prstat)); |
prstat.pr_pid = pid; |
prstat.pr_cursig = cursig; |
memcpy (&prstat.pr_reg, gregs, sizeof (prstat.pr_reg)); |
return elfcore_write_note (abfd, buf, bufsiz, "CORE", |
NT_PRSTATUS, &prstat, sizeof (prstat)); |
} |
else |
#endif |
{ |
prstatus_t prstat; |
memset (&prstat, 0, sizeof (prstat)); |
prstat.pr_pid = pid; |
prstat.pr_cursig = cursig; |
memcpy (&prstat.pr_reg, gregs, sizeof (prstat.pr_reg)); |
return elfcore_write_note (abfd, buf, bufsiz, "CORE", |
NT_PRSTATUS, &prstat, sizeof (prstat)); |
} |
#endif /* HAVE_PRSTATUS_T */ |
free (buf); |
return NULL; |
} |
#if defined (HAVE_LWPSTATUS_T) |
char * |
elfcore_write_lwpstatus (bfd *abfd, |
char *buf, |
int *bufsiz, |
long pid, |
int cursig, |
const void *gregs) |
{ |
lwpstatus_t lwpstat; |
const char *note_name = "CORE"; |
memset (&lwpstat, 0, sizeof (lwpstat)); |
lwpstat.pr_lwpid = pid >> 16; |
lwpstat.pr_cursig = cursig; |
#if defined (HAVE_LWPSTATUS_T_PR_REG) |
memcpy (lwpstat.pr_reg, gregs, sizeof (lwpstat.pr_reg)); |
#elif defined (HAVE_LWPSTATUS_T_PR_CONTEXT) |
#if !defined(gregs) |
memcpy (lwpstat.pr_context.uc_mcontext.gregs, |
gregs, sizeof (lwpstat.pr_context.uc_mcontext.gregs)); |
#else |
memcpy (lwpstat.pr_context.uc_mcontext.__gregs, |
gregs, sizeof (lwpstat.pr_context.uc_mcontext.__gregs)); |
#endif |
#endif |
return elfcore_write_note (abfd, buf, bufsiz, note_name, |
NT_LWPSTATUS, &lwpstat, sizeof (lwpstat)); |
} |
#endif /* HAVE_LWPSTATUS_T */ |
#if defined (HAVE_PSTATUS_T) |
char * |
elfcore_write_pstatus (bfd *abfd, |
char *buf, |
int *bufsiz, |
long pid, |
int cursig ATTRIBUTE_UNUSED, |
const void *gregs ATTRIBUTE_UNUSED) |
{ |
const char *note_name = "CORE"; |
#if defined (HAVE_PSTATUS32_T) |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
if (bed->s->elfclass == ELFCLASS32) |
{ |
pstatus32_t pstat; |
memset (&pstat, 0, sizeof (pstat)); |
pstat.pr_pid = pid & 0xffff; |
buf = elfcore_write_note (abfd, buf, bufsiz, note_name, |
NT_PSTATUS, &pstat, sizeof (pstat)); |
return buf; |
} |
else |
#endif |
{ |
pstatus_t pstat; |
memset (&pstat, 0, sizeof (pstat)); |
pstat.pr_pid = pid & 0xffff; |
buf = elfcore_write_note (abfd, buf, bufsiz, note_name, |
NT_PSTATUS, &pstat, sizeof (pstat)); |
return buf; |
} |
} |
#endif /* HAVE_PSTATUS_T */ |
char * |
elfcore_write_prfpreg (bfd *abfd, |
char *buf, |
int *bufsiz, |
const void *fpregs, |
int size) |
{ |
const char *note_name = "CORE"; |
return elfcore_write_note (abfd, buf, bufsiz, |
note_name, NT_FPREGSET, fpregs, size); |
} |
char * |
elfcore_write_prxfpreg (bfd *abfd, |
char *buf, |
int *bufsiz, |
const void *xfpregs, |
int size) |
{ |
char *note_name = "LINUX"; |
return elfcore_write_note (abfd, buf, bufsiz, |
note_name, NT_PRXFPREG, xfpregs, size); |
} |
char * |
elfcore_write_xstatereg (bfd *abfd, char *buf, int *bufsiz, |
const void *xfpregs, int size) |
{ |
char *note_name = "LINUX"; |
return elfcore_write_note (abfd, buf, bufsiz, |
note_name, NT_X86_XSTATE, xfpregs, size); |
} |
char * |
elfcore_write_ppc_vmx (bfd *abfd, |
char *buf, |
int *bufsiz, |
const void *ppc_vmx, |
int size) |
{ |
char *note_name = "LINUX"; |
return elfcore_write_note (abfd, buf, bufsiz, |
note_name, NT_PPC_VMX, ppc_vmx, size); |
} |
char * |
elfcore_write_ppc_vsx (bfd *abfd, |
char *buf, |
int *bufsiz, |
const void *ppc_vsx, |
int size) |
{ |
char *note_name = "LINUX"; |
return elfcore_write_note (abfd, buf, bufsiz, |
note_name, NT_PPC_VSX, ppc_vsx, size); |
} |
static char * |
elfcore_write_s390_high_gprs (bfd *abfd, |
char *buf, |
int *bufsiz, |
const void *s390_high_gprs, |
int size) |
{ |
char *note_name = "LINUX"; |
return elfcore_write_note (abfd, buf, bufsiz, |
note_name, NT_S390_HIGH_GPRS, |
s390_high_gprs, size); |
} |
char * |
elfcore_write_s390_timer (bfd *abfd, |
char *buf, |
int *bufsiz, |
const void *s390_timer, |
int size) |
{ |
char *note_name = "LINUX"; |
return elfcore_write_note (abfd, buf, bufsiz, |
note_name, NT_S390_TIMER, s390_timer, size); |
} |
char * |
elfcore_write_s390_todcmp (bfd *abfd, |
char *buf, |
int *bufsiz, |
const void *s390_todcmp, |
int size) |
{ |
char *note_name = "LINUX"; |
return elfcore_write_note (abfd, buf, bufsiz, |
note_name, NT_S390_TODCMP, s390_todcmp, size); |
} |
char * |
elfcore_write_s390_todpreg (bfd *abfd, |
char *buf, |
int *bufsiz, |
const void *s390_todpreg, |
int size) |
{ |
char *note_name = "LINUX"; |
return elfcore_write_note (abfd, buf, bufsiz, |
note_name, NT_S390_TODPREG, s390_todpreg, size); |
} |
char * |
elfcore_write_s390_ctrs (bfd *abfd, |
char *buf, |
int *bufsiz, |
const void *s390_ctrs, |
int size) |
{ |
char *note_name = "LINUX"; |
return elfcore_write_note (abfd, buf, bufsiz, |
note_name, NT_S390_CTRS, s390_ctrs, size); |
} |
char * |
elfcore_write_s390_prefix (bfd *abfd, |
char *buf, |
int *bufsiz, |
const void *s390_prefix, |
int size) |
{ |
char *note_name = "LINUX"; |
return elfcore_write_note (abfd, buf, bufsiz, |
note_name, NT_S390_PREFIX, s390_prefix, size); |
} |
char * |
elfcore_write_s390_last_break (bfd *abfd, |
char *buf, |
int *bufsiz, |
const void *s390_last_break, |
int size) |
{ |
char *note_name = "LINUX"; |
return elfcore_write_note (abfd, buf, bufsiz, |
note_name, NT_S390_LAST_BREAK, |
s390_last_break, size); |
} |
char * |
elfcore_write_s390_system_call (bfd *abfd, |
char *buf, |
int *bufsiz, |
const void *s390_system_call, |
int size) |
{ |
char *note_name = "LINUX"; |
return elfcore_write_note (abfd, buf, bufsiz, |
note_name, NT_S390_SYSTEM_CALL, |
s390_system_call, size); |
} |
char * |
elfcore_write_s390_tdb (bfd *abfd, |
char *buf, |
int *bufsiz, |
const void *s390_tdb, |
int size) |
{ |
char *note_name = "LINUX"; |
return elfcore_write_note (abfd, buf, bufsiz, |
note_name, NT_S390_TDB, s390_tdb, size); |
} |
char * |
elfcore_write_arm_vfp (bfd *abfd, |
char *buf, |
int *bufsiz, |
const void *arm_vfp, |
int size) |
{ |
char *note_name = "LINUX"; |
return elfcore_write_note (abfd, buf, bufsiz, |
note_name, NT_ARM_VFP, arm_vfp, size); |
} |
char * |
elfcore_write_aarch_tls (bfd *abfd, |
char *buf, |
int *bufsiz, |
const void *aarch_tls, |
int size) |
{ |
char *note_name = "LINUX"; |
return elfcore_write_note (abfd, buf, bufsiz, |
note_name, NT_ARM_TLS, aarch_tls, size); |
} |
char * |
elfcore_write_aarch_hw_break (bfd *abfd, |
char *buf, |
int *bufsiz, |
const void *aarch_hw_break, |
int size) |
{ |
char *note_name = "LINUX"; |
return elfcore_write_note (abfd, buf, bufsiz, |
note_name, NT_ARM_HW_BREAK, aarch_hw_break, size); |
} |
char * |
elfcore_write_aarch_hw_watch (bfd *abfd, |
char *buf, |
int *bufsiz, |
const void *aarch_hw_watch, |
int size) |
{ |
char *note_name = "LINUX"; |
return elfcore_write_note (abfd, buf, bufsiz, |
note_name, NT_ARM_HW_WATCH, aarch_hw_watch, size); |
} |
char * |
elfcore_write_register_note (bfd *abfd, |
char *buf, |
int *bufsiz, |
const char *section, |
const void *data, |
int size) |
{ |
if (strcmp (section, ".reg2") == 0) |
return elfcore_write_prfpreg (abfd, buf, bufsiz, data, size); |
if (strcmp (section, ".reg-xfp") == 0) |
return elfcore_write_prxfpreg (abfd, buf, bufsiz, data, size); |
if (strcmp (section, ".reg-xstate") == 0) |
return elfcore_write_xstatereg (abfd, buf, bufsiz, data, size); |
if (strcmp (section, ".reg-ppc-vmx") == 0) |
return elfcore_write_ppc_vmx (abfd, buf, bufsiz, data, size); |
if (strcmp (section, ".reg-ppc-vsx") == 0) |
return elfcore_write_ppc_vsx (abfd, buf, bufsiz, data, size); |
if (strcmp (section, ".reg-s390-high-gprs") == 0) |
return elfcore_write_s390_high_gprs (abfd, buf, bufsiz, data, size); |
if (strcmp (section, ".reg-s390-timer") == 0) |
return elfcore_write_s390_timer (abfd, buf, bufsiz, data, size); |
if (strcmp (section, ".reg-s390-todcmp") == 0) |
return elfcore_write_s390_todcmp (abfd, buf, bufsiz, data, size); |
if (strcmp (section, ".reg-s390-todpreg") == 0) |
return elfcore_write_s390_todpreg (abfd, buf, bufsiz, data, size); |
if (strcmp (section, ".reg-s390-ctrs") == 0) |
return elfcore_write_s390_ctrs (abfd, buf, bufsiz, data, size); |
if (strcmp (section, ".reg-s390-prefix") == 0) |
return elfcore_write_s390_prefix (abfd, buf, bufsiz, data, size); |
if (strcmp (section, ".reg-s390-last-break") == 0) |
return elfcore_write_s390_last_break (abfd, buf, bufsiz, data, size); |
if (strcmp (section, ".reg-s390-system-call") == 0) |
return elfcore_write_s390_system_call (abfd, buf, bufsiz, data, size); |
if (strcmp (section, ".reg-s390-tdb") == 0) |
return elfcore_write_s390_tdb (abfd, buf, bufsiz, data, size); |
if (strcmp (section, ".reg-arm-vfp") == 0) |
return elfcore_write_arm_vfp (abfd, buf, bufsiz, data, size); |
if (strcmp (section, ".reg-aarch-tls") == 0) |
return elfcore_write_aarch_tls (abfd, buf, bufsiz, data, size); |
if (strcmp (section, ".reg-aarch-hw-break") == 0) |
return elfcore_write_aarch_hw_break (abfd, buf, bufsiz, data, size); |
if (strcmp (section, ".reg-aarch-hw-watch") == 0) |
return elfcore_write_aarch_hw_watch (abfd, buf, bufsiz, data, size); |
return NULL; |
} |
static bfd_boolean |
elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset) |
{ |
char *p; |
p = buf; |
while (p < buf + size) |
{ |
/* FIXME: bad alignment assumption. */ |
Elf_External_Note *xnp = (Elf_External_Note *) p; |
Elf_Internal_Note in; |
if (offsetof (Elf_External_Note, name) > buf - p + size) |
return FALSE; |
in.type = H_GET_32 (abfd, xnp->type); |
in.namesz = H_GET_32 (abfd, xnp->namesz); |
in.namedata = xnp->name; |
if (in.namesz > buf - in.namedata + size) |
return FALSE; |
in.descsz = H_GET_32 (abfd, xnp->descsz); |
in.descdata = in.namedata + BFD_ALIGN (in.namesz, 4); |
in.descpos = offset + (in.descdata - buf); |
if (in.descsz != 0 |
&& (in.descdata >= buf + size |
|| in.descsz > buf - in.descdata + size)) |
return FALSE; |
switch (bfd_get_format (abfd)) |
{ |
default: |
return TRUE; |
case bfd_core: |
if (CONST_STRNEQ (in.namedata, "NetBSD-CORE")) |
{ |
if (! elfcore_grok_netbsd_note (abfd, &in)) |
return FALSE; |
} |
else if (CONST_STRNEQ (in.namedata, "OpenBSD")) |
{ |
if (! elfcore_grok_openbsd_note (abfd, &in)) |
return FALSE; |
} |
else if (CONST_STRNEQ (in.namedata, "QNX")) |
{ |
if (! elfcore_grok_nto_note (abfd, &in)) |
return FALSE; |
} |
else if (CONST_STRNEQ (in.namedata, "SPU/")) |
{ |
if (! elfcore_grok_spu_note (abfd, &in)) |
return FALSE; |
} |
else |
{ |
if (! elfcore_grok_note (abfd, &in)) |
return FALSE; |
} |
break; |
case bfd_object: |
if (in.namesz == sizeof "GNU" && strcmp (in.namedata, "GNU") == 0) |
{ |
if (! elfobj_grok_gnu_note (abfd, &in)) |
return FALSE; |
} |
else if (in.namesz == sizeof "stapsdt" |
&& strcmp (in.namedata, "stapsdt") == 0) |
{ |
if (! elfobj_grok_stapsdt_note (abfd, &in)) |
return FALSE; |
} |
break; |
} |
p = in.descdata + BFD_ALIGN (in.descsz, 4); |
} |
return TRUE; |
} |
static bfd_boolean |
elf_read_notes (bfd *abfd, file_ptr offset, bfd_size_type size) |
{ |
char *buf; |
if (size <= 0) |
return TRUE; |
if (bfd_seek (abfd, offset, SEEK_SET) != 0) |
return FALSE; |
buf = (char *) bfd_malloc (size); |
if (buf == NULL) |
return FALSE; |
if (bfd_bread (buf, size, abfd) != size |
|| !elf_parse_notes (abfd, buf, size, offset)) |
{ |
free (buf); |
return FALSE; |
} |
free (buf); |
return TRUE; |
} |
/* Providing external access to the ELF program header table. */ |
/* Return an upper bound on the number of bytes required to store a |
copy of ABFD's program header table entries. Return -1 if an error |
occurs; bfd_get_error will return an appropriate code. */ |
long |
bfd_get_elf_phdr_upper_bound (bfd *abfd) |
{ |
if (abfd->xvec->flavour != bfd_target_elf_flavour) |
{ |
bfd_set_error (bfd_error_wrong_format); |
return -1; |
} |
return elf_elfheader (abfd)->e_phnum * sizeof (Elf_Internal_Phdr); |
} |
/* Copy ABFD's program header table entries to *PHDRS. The entries |
will be stored as an array of Elf_Internal_Phdr structures, as |
defined in include/elf/internal.h. To find out how large the |
buffer needs to be, call bfd_get_elf_phdr_upper_bound. |
Return the number of program header table entries read, or -1 if an |
error occurs; bfd_get_error will return an appropriate code. */ |
int |
bfd_get_elf_phdrs (bfd *abfd, void *phdrs) |
{ |
int num_phdrs; |
if (abfd->xvec->flavour != bfd_target_elf_flavour) |
{ |
bfd_set_error (bfd_error_wrong_format); |
return -1; |
} |
num_phdrs = elf_elfheader (abfd)->e_phnum; |
memcpy (phdrs, elf_tdata (abfd)->phdr, |
num_phdrs * sizeof (Elf_Internal_Phdr)); |
return num_phdrs; |
} |
enum elf_reloc_type_class |
_bfd_elf_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, |
const asection *rel_sec ATTRIBUTE_UNUSED, |
const Elf_Internal_Rela *rela ATTRIBUTE_UNUSED) |
{ |
return reloc_class_normal; |
} |
/* For RELA architectures, return the relocation value for a |
relocation against a local symbol. */ |
bfd_vma |
_bfd_elf_rela_local_sym (bfd *abfd, |
Elf_Internal_Sym *sym, |
asection **psec, |
Elf_Internal_Rela *rel) |
{ |
asection *sec = *psec; |
bfd_vma relocation; |
relocation = (sec->output_section->vma |
+ sec->output_offset |
+ sym->st_value); |
if ((sec->flags & SEC_MERGE) |
&& ELF_ST_TYPE (sym->st_info) == STT_SECTION |
&& sec->sec_info_type == SEC_INFO_TYPE_MERGE) |
{ |
rel->r_addend = |
_bfd_merged_section_offset (abfd, psec, |
elf_section_data (sec)->sec_info, |
sym->st_value + rel->r_addend); |
if (sec != *psec) |
{ |
/* If we have changed the section, and our original section is |
marked with SEC_EXCLUDE, it means that the original |
SEC_MERGE section has been completely subsumed in some |
other SEC_MERGE section. In this case, we need to leave |
some info around for --emit-relocs. */ |
if ((sec->flags & SEC_EXCLUDE) != 0) |
sec->kept_section = *psec; |
sec = *psec; |
} |
rel->r_addend -= relocation; |
rel->r_addend += sec->output_section->vma + sec->output_offset; |
} |
return relocation; |
} |
bfd_vma |
_bfd_elf_rel_local_sym (bfd *abfd, |
Elf_Internal_Sym *sym, |
asection **psec, |
bfd_vma addend) |
{ |
asection *sec = *psec; |
if (sec->sec_info_type != SEC_INFO_TYPE_MERGE) |
return sym->st_value + addend; |
return _bfd_merged_section_offset (abfd, psec, |
elf_section_data (sec)->sec_info, |
sym->st_value + addend); |
} |
bfd_vma |
_bfd_elf_section_offset (bfd *abfd, |
struct bfd_link_info *info, |
asection *sec, |
bfd_vma offset) |
{ |
switch (sec->sec_info_type) |
{ |
case SEC_INFO_TYPE_STABS: |
return _bfd_stab_section_offset (sec, elf_section_data (sec)->sec_info, |
offset); |
case SEC_INFO_TYPE_EH_FRAME: |
return _bfd_elf_eh_frame_section_offset (abfd, info, sec, offset); |
default: |
if ((sec->flags & SEC_ELF_REVERSE_COPY) != 0) |
{ |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
bfd_size_type address_size = bed->s->arch_size / 8; |
offset = sec->size - offset - address_size; |
} |
return offset; |
} |
} |
/* Create a new BFD as if by bfd_openr. Rather than opening a file, |
reconstruct an ELF file by reading the segments out of remote memory |
based on the ELF file header at EHDR_VMA and the ELF program headers it |
points to. If not null, *LOADBASEP is filled in with the difference |
between the VMAs from which the segments were read, and the VMAs the |
file headers (and hence BFD's idea of each section's VMA) put them at. |
The function TARGET_READ_MEMORY is called to copy LEN bytes from the |
remote memory at target address VMA into the local buffer at MYADDR; it |
should return zero on success or an `errno' code on failure. TEMPL must |
be a BFD for an ELF target with the word size and byte order found in |
the remote memory. */ |
bfd * |
bfd_elf_bfd_from_remote_memory |
(bfd *templ, |
bfd_vma ehdr_vma, |
bfd_vma *loadbasep, |
int (*target_read_memory) (bfd_vma, bfd_byte *, bfd_size_type)) |
{ |
return (*get_elf_backend_data (templ)->elf_backend_bfd_from_remote_memory) |
(templ, ehdr_vma, loadbasep, target_read_memory); |
} |
long |
_bfd_elf_get_synthetic_symtab (bfd *abfd, |
long symcount ATTRIBUTE_UNUSED, |
asymbol **syms ATTRIBUTE_UNUSED, |
long dynsymcount, |
asymbol **dynsyms, |
asymbol **ret) |
{ |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
asection *relplt; |
asymbol *s; |
const char *relplt_name; |
bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean); |
arelent *p; |
long count, i, n; |
size_t size; |
Elf_Internal_Shdr *hdr; |
char *names; |
asection *plt; |
*ret = NULL; |
if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0) |
return 0; |
if (dynsymcount <= 0) |
return 0; |
if (!bed->plt_sym_val) |
return 0; |
relplt_name = bed->relplt_name; |
if (relplt_name == NULL) |
relplt_name = bed->rela_plts_and_copies_p ? ".rela.plt" : ".rel.plt"; |
relplt = bfd_get_section_by_name (abfd, relplt_name); |
if (relplt == NULL) |
return 0; |
hdr = &elf_section_data (relplt)->this_hdr; |
if (hdr->sh_link != elf_dynsymtab (abfd) |
|| (hdr->sh_type != SHT_REL && hdr->sh_type != SHT_RELA)) |
return 0; |
plt = bfd_get_section_by_name (abfd, ".plt"); |
if (plt == NULL) |
return 0; |
slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table; |
if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE)) |
return -1; |
count = relplt->size / hdr->sh_entsize; |
size = count * sizeof (asymbol); |
p = relplt->relocation; |
for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel) |
{ |
size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt"); |
if (p->addend != 0) |
{ |
#ifdef BFD64 |
size += sizeof ("+0x") - 1 + 8 + 8 * (bed->s->elfclass == ELFCLASS64); |
#else |
size += sizeof ("+0x") - 1 + 8; |
#endif |
} |
} |
s = *ret = (asymbol *) bfd_malloc (size); |
if (s == NULL) |
return -1; |
names = (char *) (s + count); |
p = relplt->relocation; |
n = 0; |
for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel) |
{ |
size_t len; |
bfd_vma addr; |
addr = bed->plt_sym_val (i, plt, p); |
if (addr == (bfd_vma) -1) |
continue; |
*s = **p->sym_ptr_ptr; |
/* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set. Since |
we are defining a symbol, ensure one of them is set. */ |
if ((s->flags & BSF_LOCAL) == 0) |
s->flags |= BSF_GLOBAL; |
s->flags |= BSF_SYNTHETIC; |
s->section = plt; |
s->value = addr - plt->vma; |
s->name = names; |
s->udata.p = NULL; |
len = strlen ((*p->sym_ptr_ptr)->name); |
memcpy (names, (*p->sym_ptr_ptr)->name, len); |
names += len; |
if (p->addend != 0) |
{ |
char buf[30], *a; |
memcpy (names, "+0x", sizeof ("+0x") - 1); |
names += sizeof ("+0x") - 1; |
bfd_sprintf_vma (abfd, buf, p->addend); |
for (a = buf; *a == '0'; ++a) |
; |
len = strlen (a); |
memcpy (names, a, len); |
names += len; |
} |
memcpy (names, "@plt", sizeof ("@plt")); |
names += sizeof ("@plt"); |
++s, ++n; |
} |
return n; |
} |
/* It is only used by x86-64 so far. */ |
asection _bfd_elf_large_com_section |
= BFD_FAKE_SECTION (_bfd_elf_large_com_section, |
SEC_IS_COMMON, NULL, "LARGE_COMMON", 0); |
void |
_bfd_elf_set_osabi (bfd * abfd, |
struct bfd_link_info * link_info ATTRIBUTE_UNUSED) |
{ |
Elf_Internal_Ehdr * i_ehdrp; /* ELF file header, internal form. */ |
i_ehdrp = elf_elfheader (abfd); |
i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi; |
/* To make things simpler for the loader on Linux systems we set the |
osabi field to ELFOSABI_GNU if the binary contains symbols of |
the STT_GNU_IFUNC type or STB_GNU_UNIQUE binding. */ |
if (i_ehdrp->e_ident[EI_OSABI] == ELFOSABI_NONE |
&& elf_tdata (abfd)->has_gnu_symbols) |
i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_GNU; |
} |
/* Return TRUE for ELF symbol types that represent functions. |
This is the default version of this function, which is sufficient for |
most targets. It returns true if TYPE is STT_FUNC or STT_GNU_IFUNC. */ |
bfd_boolean |
_bfd_elf_is_function_type (unsigned int type) |
{ |
return (type == STT_FUNC |
|| type == STT_GNU_IFUNC); |
} |
/* If the ELF symbol SYM might be a function in SEC, return the |
function size and set *CODE_OFF to the function's entry point, |
otherwise return zero. */ |
bfd_size_type |
_bfd_elf_maybe_function_sym (const asymbol *sym, asection *sec, |
bfd_vma *code_off) |
{ |
bfd_size_type size; |
if ((sym->flags & (BSF_SECTION_SYM | BSF_FILE | BSF_OBJECT |
| BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC)) != 0 |
|| sym->section != sec) |
return 0; |
*code_off = sym->value; |
size = 0; |
if (!(sym->flags & BSF_SYNTHETIC)) |
size = ((elf_symbol_type *) sym)->internal_elf_sym.st_size; |
if (size == 0) |
size = 1; |
return size; |
} |
/contrib/toolchain/binutils/bfd/elf32-gen.c |
---|
0,0 → 1,103 |
/* Generic support for 32-bit ELF |
Copyright 1993, 1995, 1998, 1999, 2001, 2002, 2004, 2005, 2007 |
Free Software Foundation, Inc. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
#include "elf-bfd.h" |
/* This does not include any relocation information, but should be |
good enough for GDB or objdump to read the file. */ |
static reloc_howto_type dummy = |
HOWTO (0, /* type */ |
0, /* rightshift */ |
0, /* size (0 = byte, 1 = short, 2 = long) */ |
0, /* bitsize */ |
FALSE, /* pc_relative */ |
0, /* bitpos */ |
complain_overflow_dont, /* complain_on_overflow */ |
NULL, /* special_function */ |
"UNKNOWN", /* name */ |
FALSE, /* partial_inplace */ |
0, /* src_mask */ |
0, /* dst_mask */ |
FALSE); /* pcrel_offset */ |
static void |
elf_generic_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, |
arelent *bfd_reloc, |
Elf_Internal_Rela *elf_reloc ATTRIBUTE_UNUSED) |
{ |
bfd_reloc->howto = &dummy; |
} |
static void |
elf_generic_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, |
arelent *bfd_reloc, |
Elf_Internal_Rela *elf_reloc ATTRIBUTE_UNUSED) |
{ |
bfd_reloc->howto = &dummy; |
} |
static void |
check_for_relocs (bfd * abfd, asection * o, void * failed) |
{ |
if ((o->flags & SEC_RELOC) != 0) |
{ |
Elf_Internal_Ehdr *ehdrp; |
ehdrp = elf_elfheader (abfd); |
_bfd_error_handler (_("%B: Relocations in generic ELF (EM: %d)"), |
abfd, ehdrp->e_machine); |
bfd_set_error (bfd_error_wrong_format); |
* (bfd_boolean *) failed = TRUE; |
} |
} |
static bfd_boolean |
elf32_generic_link_add_symbols (bfd *abfd, struct bfd_link_info *info) |
{ |
bfd_boolean failed = FALSE; |
/* Check if there are any relocations. */ |
bfd_map_over_sections (abfd, check_for_relocs, & failed); |
if (failed) |
return FALSE; |
return bfd_elf_link_add_symbols (abfd, info); |
} |
#define TARGET_LITTLE_SYM bfd_elf32_little_generic_vec |
#define TARGET_LITTLE_NAME "elf32-little" |
#define TARGET_BIG_SYM bfd_elf32_big_generic_vec |
#define TARGET_BIG_NAME "elf32-big" |
#define ELF_ARCH bfd_arch_unknown |
#define ELF_MACHINE_CODE EM_NONE |
#define ELF_MAXPAGESIZE 0x1 |
#define bfd_elf32_bfd_reloc_type_lookup bfd_default_reloc_type_lookup |
#define bfd_elf32_bfd_reloc_name_lookup _bfd_norelocs_bfd_reloc_name_lookup |
#define bfd_elf32_bfd_link_add_symbols elf32_generic_link_add_symbols |
#define elf_info_to_howto elf_generic_info_to_howto |
#define elf_info_to_howto_rel elf_generic_info_to_howto_rel |
#include "elf32-target.h" |
/contrib/toolchain/binutils/bfd/elf32-i386.c |
---|
0,0 → 1,5369 |
/* Intel 80386/80486-specific support for 32-bit ELF |
Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, |
2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 |
Free Software Foundation, Inc. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "bfdlink.h" |
#include "libbfd.h" |
#include "elf-bfd.h" |
#include "elf-nacl.h" |
#include "elf-vxworks.h" |
#include "bfd_stdint.h" |
#include "objalloc.h" |
#include "hashtab.h" |
#include "dwarf2.h" |
/* 386 uses REL relocations instead of RELA. */ |
#define USE_REL 1 |
#include "elf/i386.h" |
static reloc_howto_type elf_howto_table[]= |
{ |
HOWTO(R_386_NONE, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_NONE", |
TRUE, 0x00000000, 0x00000000, FALSE), |
HOWTO(R_386_32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_32", |
TRUE, 0xffffffff, 0xffffffff, FALSE), |
HOWTO(R_386_PC32, 0, 2, 32, TRUE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_PC32", |
TRUE, 0xffffffff, 0xffffffff, TRUE), |
HOWTO(R_386_GOT32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_GOT32", |
TRUE, 0xffffffff, 0xffffffff, FALSE), |
HOWTO(R_386_PLT32, 0, 2, 32, TRUE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_PLT32", |
TRUE, 0xffffffff, 0xffffffff, TRUE), |
HOWTO(R_386_COPY, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_COPY", |
TRUE, 0xffffffff, 0xffffffff, FALSE), |
HOWTO(R_386_GLOB_DAT, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_GLOB_DAT", |
TRUE, 0xffffffff, 0xffffffff, FALSE), |
HOWTO(R_386_JUMP_SLOT, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_JUMP_SLOT", |
TRUE, 0xffffffff, 0xffffffff, FALSE), |
HOWTO(R_386_RELATIVE, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_RELATIVE", |
TRUE, 0xffffffff, 0xffffffff, FALSE), |
HOWTO(R_386_GOTOFF, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_GOTOFF", |
TRUE, 0xffffffff, 0xffffffff, FALSE), |
HOWTO(R_386_GOTPC, 0, 2, 32, TRUE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_GOTPC", |
TRUE, 0xffffffff, 0xffffffff, TRUE), |
/* We have a gap in the reloc numbers here. |
R_386_standard counts the number up to this point, and |
R_386_ext_offset is the value to subtract from a reloc type of |
R_386_16 thru R_386_PC8 to form an index into this table. */ |
#define R_386_standard (R_386_GOTPC + 1) |
#define R_386_ext_offset (R_386_TLS_TPOFF - R_386_standard) |
/* These relocs are a GNU extension. */ |
HOWTO(R_386_TLS_TPOFF, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_TLS_TPOFF", |
TRUE, 0xffffffff, 0xffffffff, FALSE), |
HOWTO(R_386_TLS_IE, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_TLS_IE", |
TRUE, 0xffffffff, 0xffffffff, FALSE), |
HOWTO(R_386_TLS_GOTIE, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_TLS_GOTIE", |
TRUE, 0xffffffff, 0xffffffff, FALSE), |
HOWTO(R_386_TLS_LE, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_TLS_LE", |
TRUE, 0xffffffff, 0xffffffff, FALSE), |
HOWTO(R_386_TLS_GD, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_TLS_GD", |
TRUE, 0xffffffff, 0xffffffff, FALSE), |
HOWTO(R_386_TLS_LDM, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_TLS_LDM", |
TRUE, 0xffffffff, 0xffffffff, FALSE), |
HOWTO(R_386_16, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_16", |
TRUE, 0xffff, 0xffff, FALSE), |
HOWTO(R_386_PC16, 0, 1, 16, TRUE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_PC16", |
TRUE, 0xffff, 0xffff, TRUE), |
HOWTO(R_386_8, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_8", |
TRUE, 0xff, 0xff, FALSE), |
HOWTO(R_386_PC8, 0, 0, 8, TRUE, 0, complain_overflow_signed, |
bfd_elf_generic_reloc, "R_386_PC8", |
TRUE, 0xff, 0xff, TRUE), |
#define R_386_ext (R_386_PC8 + 1 - R_386_ext_offset) |
#define R_386_tls_offset (R_386_TLS_LDO_32 - R_386_ext) |
/* These are common with Solaris TLS implementation. */ |
HOWTO(R_386_TLS_LDO_32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_TLS_LDO_32", |
TRUE, 0xffffffff, 0xffffffff, FALSE), |
HOWTO(R_386_TLS_IE_32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_TLS_IE_32", |
TRUE, 0xffffffff, 0xffffffff, FALSE), |
HOWTO(R_386_TLS_LE_32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_TLS_LE_32", |
TRUE, 0xffffffff, 0xffffffff, FALSE), |
HOWTO(R_386_TLS_DTPMOD32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_TLS_DTPMOD32", |
TRUE, 0xffffffff, 0xffffffff, FALSE), |
HOWTO(R_386_TLS_DTPOFF32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_TLS_DTPOFF32", |
TRUE, 0xffffffff, 0xffffffff, FALSE), |
HOWTO(R_386_TLS_TPOFF32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_TLS_TPOFF32", |
TRUE, 0xffffffff, 0xffffffff, FALSE), |
HOWTO(R_386_SIZE32, 0, 2, 32, FALSE, 0, complain_overflow_unsigned, |
bfd_elf_generic_reloc, "R_386_SIZE32", |
TRUE, 0xffffffff, 0xffffffff, FALSE), |
HOWTO(R_386_TLS_GOTDESC, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_TLS_GOTDESC", |
TRUE, 0xffffffff, 0xffffffff, FALSE), |
HOWTO(R_386_TLS_DESC_CALL, 0, 0, 0, FALSE, 0, complain_overflow_dont, |
bfd_elf_generic_reloc, "R_386_TLS_DESC_CALL", |
FALSE, 0, 0, FALSE), |
HOWTO(R_386_TLS_DESC, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_TLS_DESC", |
TRUE, 0xffffffff, 0xffffffff, FALSE), |
HOWTO(R_386_IRELATIVE, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, |
bfd_elf_generic_reloc, "R_386_IRELATIVE", |
TRUE, 0xffffffff, 0xffffffff, FALSE), |
/* Another gap. */ |
#define R_386_irelative (R_386_IRELATIVE + 1 - R_386_tls_offset) |
#define R_386_vt_offset (R_386_GNU_VTINHERIT - R_386_irelative) |
/* GNU extension to record C++ vtable hierarchy. */ |
HOWTO (R_386_GNU_VTINHERIT, /* type */ |
0, /* rightshift */ |
2, /* size (0 = byte, 1 = short, 2 = long) */ |
0, /* bitsize */ |
FALSE, /* pc_relative */ |
0, /* bitpos */ |
complain_overflow_dont, /* complain_on_overflow */ |
NULL, /* special_function */ |
"R_386_GNU_VTINHERIT", /* name */ |
FALSE, /* partial_inplace */ |
0, /* src_mask */ |
0, /* dst_mask */ |
FALSE), /* pcrel_offset */ |
/* GNU extension to record C++ vtable member usage. */ |
HOWTO (R_386_GNU_VTENTRY, /* type */ |
0, /* rightshift */ |
2, /* size (0 = byte, 1 = short, 2 = long) */ |
0, /* bitsize */ |
FALSE, /* pc_relative */ |
0, /* bitpos */ |
complain_overflow_dont, /* complain_on_overflow */ |
_bfd_elf_rel_vtable_reloc_fn, /* special_function */ |
"R_386_GNU_VTENTRY", /* name */ |
FALSE, /* partial_inplace */ |
0, /* src_mask */ |
0, /* dst_mask */ |
FALSE) /* pcrel_offset */ |
#define R_386_vt (R_386_GNU_VTENTRY + 1 - R_386_vt_offset) |
}; |
#ifdef DEBUG_GEN_RELOC |
#define TRACE(str) \ |
fprintf (stderr, "i386 bfd reloc lookup %d (%s)\n", code, str) |
#else |
#define TRACE(str) |
#endif |
static reloc_howto_type * |
elf_i386_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, |
bfd_reloc_code_real_type code) |
{ |
switch (code) |
{ |
case BFD_RELOC_NONE: |
TRACE ("BFD_RELOC_NONE"); |
return &elf_howto_table[R_386_NONE]; |
case BFD_RELOC_32: |
TRACE ("BFD_RELOC_32"); |
return &elf_howto_table[R_386_32]; |
case BFD_RELOC_CTOR: |
TRACE ("BFD_RELOC_CTOR"); |
return &elf_howto_table[R_386_32]; |
case BFD_RELOC_32_PCREL: |
TRACE ("BFD_RELOC_PC32"); |
return &elf_howto_table[R_386_PC32]; |
case BFD_RELOC_386_GOT32: |
TRACE ("BFD_RELOC_386_GOT32"); |
return &elf_howto_table[R_386_GOT32]; |
case BFD_RELOC_386_PLT32: |
TRACE ("BFD_RELOC_386_PLT32"); |
return &elf_howto_table[R_386_PLT32]; |
case BFD_RELOC_386_COPY: |
TRACE ("BFD_RELOC_386_COPY"); |
return &elf_howto_table[R_386_COPY]; |
case BFD_RELOC_386_GLOB_DAT: |
TRACE ("BFD_RELOC_386_GLOB_DAT"); |
return &elf_howto_table[R_386_GLOB_DAT]; |
case BFD_RELOC_386_JUMP_SLOT: |
TRACE ("BFD_RELOC_386_JUMP_SLOT"); |
return &elf_howto_table[R_386_JUMP_SLOT]; |
case BFD_RELOC_386_RELATIVE: |
TRACE ("BFD_RELOC_386_RELATIVE"); |
return &elf_howto_table[R_386_RELATIVE]; |
case BFD_RELOC_386_GOTOFF: |
TRACE ("BFD_RELOC_386_GOTOFF"); |
return &elf_howto_table[R_386_GOTOFF]; |
case BFD_RELOC_386_GOTPC: |
TRACE ("BFD_RELOC_386_GOTPC"); |
return &elf_howto_table[R_386_GOTPC]; |
/* These relocs are a GNU extension. */ |
case BFD_RELOC_386_TLS_TPOFF: |
TRACE ("BFD_RELOC_386_TLS_TPOFF"); |
return &elf_howto_table[R_386_TLS_TPOFF - R_386_ext_offset]; |
case BFD_RELOC_386_TLS_IE: |
TRACE ("BFD_RELOC_386_TLS_IE"); |
return &elf_howto_table[R_386_TLS_IE - R_386_ext_offset]; |
case BFD_RELOC_386_TLS_GOTIE: |
TRACE ("BFD_RELOC_386_TLS_GOTIE"); |
return &elf_howto_table[R_386_TLS_GOTIE - R_386_ext_offset]; |
case BFD_RELOC_386_TLS_LE: |
TRACE ("BFD_RELOC_386_TLS_LE"); |
return &elf_howto_table[R_386_TLS_LE - R_386_ext_offset]; |
case BFD_RELOC_386_TLS_GD: |
TRACE ("BFD_RELOC_386_TLS_GD"); |
return &elf_howto_table[R_386_TLS_GD - R_386_ext_offset]; |
case BFD_RELOC_386_TLS_LDM: |
TRACE ("BFD_RELOC_386_TLS_LDM"); |
return &elf_howto_table[R_386_TLS_LDM - R_386_ext_offset]; |
case BFD_RELOC_16: |
TRACE ("BFD_RELOC_16"); |
return &elf_howto_table[R_386_16 - R_386_ext_offset]; |
case BFD_RELOC_16_PCREL: |
TRACE ("BFD_RELOC_16_PCREL"); |
return &elf_howto_table[R_386_PC16 - R_386_ext_offset]; |
case BFD_RELOC_8: |
TRACE ("BFD_RELOC_8"); |
return &elf_howto_table[R_386_8 - R_386_ext_offset]; |
case BFD_RELOC_8_PCREL: |
TRACE ("BFD_RELOC_8_PCREL"); |
return &elf_howto_table[R_386_PC8 - R_386_ext_offset]; |
/* Common with Sun TLS implementation. */ |
case BFD_RELOC_386_TLS_LDO_32: |
TRACE ("BFD_RELOC_386_TLS_LDO_32"); |
return &elf_howto_table[R_386_TLS_LDO_32 - R_386_tls_offset]; |
case BFD_RELOC_386_TLS_IE_32: |
TRACE ("BFD_RELOC_386_TLS_IE_32"); |
return &elf_howto_table[R_386_TLS_IE_32 - R_386_tls_offset]; |
case BFD_RELOC_386_TLS_LE_32: |
TRACE ("BFD_RELOC_386_TLS_LE_32"); |
return &elf_howto_table[R_386_TLS_LE_32 - R_386_tls_offset]; |
case BFD_RELOC_386_TLS_DTPMOD32: |
TRACE ("BFD_RELOC_386_TLS_DTPMOD32"); |
return &elf_howto_table[R_386_TLS_DTPMOD32 - R_386_tls_offset]; |
case BFD_RELOC_386_TLS_DTPOFF32: |
TRACE ("BFD_RELOC_386_TLS_DTPOFF32"); |
return &elf_howto_table[R_386_TLS_DTPOFF32 - R_386_tls_offset]; |
case BFD_RELOC_386_TLS_TPOFF32: |
TRACE ("BFD_RELOC_386_TLS_TPOFF32"); |
return &elf_howto_table[R_386_TLS_TPOFF32 - R_386_tls_offset]; |
case BFD_RELOC_SIZE32: |
TRACE ("BFD_RELOC_SIZE32"); |
return &elf_howto_table[R_386_SIZE32 - R_386_tls_offset]; |
case BFD_RELOC_386_TLS_GOTDESC: |
TRACE ("BFD_RELOC_386_TLS_GOTDESC"); |
return &elf_howto_table[R_386_TLS_GOTDESC - R_386_tls_offset]; |
case BFD_RELOC_386_TLS_DESC_CALL: |
TRACE ("BFD_RELOC_386_TLS_DESC_CALL"); |
return &elf_howto_table[R_386_TLS_DESC_CALL - R_386_tls_offset]; |
case BFD_RELOC_386_TLS_DESC: |
TRACE ("BFD_RELOC_386_TLS_DESC"); |
return &elf_howto_table[R_386_TLS_DESC - R_386_tls_offset]; |
case BFD_RELOC_386_IRELATIVE: |
TRACE ("BFD_RELOC_386_IRELATIVE"); |
return &elf_howto_table[R_386_IRELATIVE - R_386_tls_offset]; |
case BFD_RELOC_VTABLE_INHERIT: |
TRACE ("BFD_RELOC_VTABLE_INHERIT"); |
return &elf_howto_table[R_386_GNU_VTINHERIT - R_386_vt_offset]; |
case BFD_RELOC_VTABLE_ENTRY: |
TRACE ("BFD_RELOC_VTABLE_ENTRY"); |
return &elf_howto_table[R_386_GNU_VTENTRY - R_386_vt_offset]; |
default: |
break; |
} |
TRACE ("Unknown"); |
return 0; |
} |
static reloc_howto_type * |
elf_i386_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, |
const char *r_name) |
{ |
unsigned int i; |
for (i = 0; i < sizeof (elf_howto_table) / sizeof (elf_howto_table[0]); i++) |
if (elf_howto_table[i].name != NULL |
&& strcasecmp (elf_howto_table[i].name, r_name) == 0) |
return &elf_howto_table[i]; |
return NULL; |
} |
static reloc_howto_type * |
elf_i386_rtype_to_howto (bfd *abfd, unsigned r_type) |
{ |
unsigned int indx; |
if ((indx = r_type) >= R_386_standard |
&& ((indx = r_type - R_386_ext_offset) - R_386_standard |
>= R_386_ext - R_386_standard) |
&& ((indx = r_type - R_386_tls_offset) - R_386_ext |
>= R_386_irelative - R_386_ext) |
&& ((indx = r_type - R_386_vt_offset) - R_386_irelative |
>= R_386_vt - R_386_irelative)) |
{ |
(*_bfd_error_handler) (_("%B: invalid relocation type %d"), |
abfd, (int) r_type); |
indx = R_386_NONE; |
} |
BFD_ASSERT (elf_howto_table [indx].type == r_type); |
return &elf_howto_table[indx]; |
} |
static void |
elf_i386_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, |
arelent *cache_ptr, |
Elf_Internal_Rela *dst) |
{ |
unsigned int r_type = ELF32_R_TYPE (dst->r_info); |
cache_ptr->howto = elf_i386_rtype_to_howto (abfd, r_type); |
} |
/* Return whether a symbol name implies a local label. The UnixWare |
2.1 cc generates temporary symbols that start with .X, so we |
recognize them here. FIXME: do other SVR4 compilers also use .X?. |
If so, we should move the .X recognition into |
_bfd_elf_is_local_label_name. */ |
static bfd_boolean |
elf_i386_is_local_label_name (bfd *abfd, const char *name) |
{ |
if (name[0] == '.' && name[1] == 'X') |
return TRUE; |
return _bfd_elf_is_local_label_name (abfd, name); |
} |
/* Support for core dump NOTE sections. */ |
static bfd_boolean |
elf_i386_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) |
{ |
int offset; |
size_t size; |
if (note->namesz == 8 && strcmp (note->namedata, "FreeBSD") == 0) |
{ |
int pr_version = bfd_get_32 (abfd, note->descdata); |
if (pr_version != 1) |
return FALSE; |
/* pr_cursig */ |
elf_tdata (abfd)->core->signal = bfd_get_32 (abfd, note->descdata + 20); |
/* pr_pid */ |
elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 24); |
/* pr_reg */ |
offset = 28; |
size = bfd_get_32 (abfd, note->descdata + 8); |
} |
else |
{ |
switch (note->descsz) |
{ |
default: |
return FALSE; |
case 144: /* Linux/i386 */ |
/* pr_cursig */ |
elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); |
/* pr_pid */ |
elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 24); |
/* pr_reg */ |
offset = 72; |
size = 68; |
break; |
} |
} |
/* Make a ".reg/999" section. */ |
return _bfd_elfcore_make_pseudosection (abfd, ".reg", |
size, note->descpos + offset); |
} |
static bfd_boolean |
elf_i386_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) |
{ |
if (note->namesz == 8 && strcmp (note->namedata, "FreeBSD") == 0) |
{ |
int pr_version = bfd_get_32 (abfd, note->descdata); |
if (pr_version != 1) |
return FALSE; |
elf_tdata (abfd)->core->program |
= _bfd_elfcore_strndup (abfd, note->descdata + 8, 17); |
elf_tdata (abfd)->core->command |
= _bfd_elfcore_strndup (abfd, note->descdata + 25, 81); |
} |
else |
{ |
switch (note->descsz) |
{ |
default: |
return FALSE; |
case 124: /* Linux/i386 elf_prpsinfo. */ |
elf_tdata (abfd)->core->pid |
= bfd_get_32 (abfd, note->descdata + 12); |
elf_tdata (abfd)->core->program |
= _bfd_elfcore_strndup (abfd, note->descdata + 28, 16); |
elf_tdata (abfd)->core->command |
= _bfd_elfcore_strndup (abfd, note->descdata + 44, 80); |
} |
} |
/* Note that for some reason, a spurious space is tacked |
onto the end of the args in some (at least one anyway) |
implementations, so strip it off if it exists. */ |
{ |
char *command = elf_tdata (abfd)->core->command; |
int n = strlen (command); |
if (0 < n && command[n - 1] == ' ') |
command[n - 1] = '\0'; |
} |
return TRUE; |
} |
/* Functions for the i386 ELF linker. |
In order to gain some understanding of code in this file without |
knowing all the intricate details of the linker, note the |
following: |
Functions named elf_i386_* are called by external routines, other |
functions are only called locally. elf_i386_* functions appear |
in this file more or less in the order in which they are called |
from external routines. eg. elf_i386_check_relocs is called |
early in the link process, elf_i386_finish_dynamic_sections is |
one of the last functions. */ |
/* The name of the dynamic interpreter. This is put in the .interp |
section. */ |
#define ELF_DYNAMIC_INTERPRETER "/usr/lib/libc.so.1" |
/* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid |
copying dynamic variables from a shared lib into an app's dynbss |
section, and instead use a dynamic relocation to point into the |
shared lib. */ |
#define ELIMINATE_COPY_RELOCS 1 |
/* The size in bytes of an entry in the procedure linkage table. */ |
#define PLT_ENTRY_SIZE 16 |
/* The first entry in an absolute procedure linkage table looks like |
this. See the SVR4 ABI i386 supplement to see how this works. |
Will be padded to PLT_ENTRY_SIZE with htab->plt0_pad_byte. */ |
static const bfd_byte elf_i386_plt0_entry[12] = |
{ |
0xff, 0x35, /* pushl contents of address */ |
0, 0, 0, 0, /* replaced with address of .got + 4. */ |
0xff, 0x25, /* jmp indirect */ |
0, 0, 0, 0 /* replaced with address of .got + 8. */ |
}; |
/* Subsequent entries in an absolute procedure linkage table look like |
this. */ |
static const bfd_byte elf_i386_plt_entry[PLT_ENTRY_SIZE] = |
{ |
0xff, 0x25, /* jmp indirect */ |
0, 0, 0, 0, /* replaced with address of this symbol in .got. */ |
0x68, /* pushl immediate */ |
0, 0, 0, 0, /* replaced with offset into relocation table. */ |
0xe9, /* jmp relative */ |
0, 0, 0, 0 /* replaced with offset to start of .plt. */ |
}; |
/* The first entry in a PIC procedure linkage table look like this. |
Will be padded to PLT_ENTRY_SIZE with htab->plt0_pad_byte. */ |
static const bfd_byte elf_i386_pic_plt0_entry[12] = |
{ |
0xff, 0xb3, 4, 0, 0, 0, /* pushl 4(%ebx) */ |
0xff, 0xa3, 8, 0, 0, 0 /* jmp *8(%ebx) */ |
}; |
/* Subsequent entries in a PIC procedure linkage table look like this. */ |
static const bfd_byte elf_i386_pic_plt_entry[PLT_ENTRY_SIZE] = |
{ |
0xff, 0xa3, /* jmp *offset(%ebx) */ |
0, 0, 0, 0, /* replaced with offset of this symbol in .got. */ |
0x68, /* pushl immediate */ |
0, 0, 0, 0, /* replaced with offset into relocation table. */ |
0xe9, /* jmp relative */ |
0, 0, 0, 0 /* replaced with offset to start of .plt. */ |
}; |
/* .eh_frame covering the .plt section. */ |
static const bfd_byte elf_i386_eh_frame_plt[] = |
{ |
#define PLT_CIE_LENGTH 20 |
#define PLT_FDE_LENGTH 36 |
#define PLT_FDE_START_OFFSET 4 + PLT_CIE_LENGTH + 8 |
#define PLT_FDE_LEN_OFFSET 4 + PLT_CIE_LENGTH + 12 |
PLT_CIE_LENGTH, 0, 0, 0, /* CIE length */ |
0, 0, 0, 0, /* CIE ID */ |
1, /* CIE version */ |
'z', 'R', 0, /* Augmentation string */ |
1, /* Code alignment factor */ |
0x7c, /* Data alignment factor */ |
8, /* Return address column */ |
1, /* Augmentation size */ |
DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding */ |
DW_CFA_def_cfa, 4, 4, /* DW_CFA_def_cfa: r4 (esp) ofs 4 */ |
DW_CFA_offset + 8, 1, /* DW_CFA_offset: r8 (eip) at cfa-4 */ |
DW_CFA_nop, DW_CFA_nop, |
PLT_FDE_LENGTH, 0, 0, 0, /* FDE length */ |
PLT_CIE_LENGTH + 8, 0, 0, 0, /* CIE pointer */ |
0, 0, 0, 0, /* R_386_PC32 .plt goes here */ |
0, 0, 0, 0, /* .plt size goes here */ |
0, /* Augmentation size */ |
DW_CFA_def_cfa_offset, 8, /* DW_CFA_def_cfa_offset: 8 */ |
DW_CFA_advance_loc + 6, /* DW_CFA_advance_loc: 6 to __PLT__+6 */ |
DW_CFA_def_cfa_offset, 12, /* DW_CFA_def_cfa_offset: 12 */ |
DW_CFA_advance_loc + 10, /* DW_CFA_advance_loc: 10 to __PLT__+16 */ |
DW_CFA_def_cfa_expression, /* DW_CFA_def_cfa_expression */ |
11, /* Block length */ |
DW_OP_breg4, 4, /* DW_OP_breg4 (esp): 4 */ |
DW_OP_breg8, 0, /* DW_OP_breg8 (eip): 0 */ |
DW_OP_lit15, DW_OP_and, DW_OP_lit11, DW_OP_ge, |
DW_OP_lit2, DW_OP_shl, DW_OP_plus, |
DW_CFA_nop, DW_CFA_nop, DW_CFA_nop, DW_CFA_nop |
}; |
struct elf_i386_plt_layout |
{ |
/* The first entry in an absolute procedure linkage table looks like this. */ |
const bfd_byte *plt0_entry; |
unsigned int plt0_entry_size; |
/* Offsets into plt0_entry that are to be replaced with GOT[1] and GOT[2]. */ |
unsigned int plt0_got1_offset; |
unsigned int plt0_got2_offset; |
/* Later entries in an absolute procedure linkage table look like this. */ |
const bfd_byte *plt_entry; |
unsigned int plt_entry_size; |
/* Offsets into plt_entry that are to be replaced with... */ |
unsigned int plt_got_offset; /* ... address of this symbol in .got. */ |
unsigned int plt_reloc_offset; /* ... offset into relocation table. */ |
unsigned int plt_plt_offset; /* ... offset to start of .plt. */ |
/* Offset into plt_entry where the initial value of the GOT entry points. */ |
unsigned int plt_lazy_offset; |
/* The first entry in a PIC procedure linkage table looks like this. */ |
const bfd_byte *pic_plt0_entry; |
/* Subsequent entries in a PIC procedure linkage table look like this. */ |
const bfd_byte *pic_plt_entry; |
/* .eh_frame covering the .plt section. */ |
const bfd_byte *eh_frame_plt; |
unsigned int eh_frame_plt_size; |
}; |
#define GET_PLT_ENTRY_SIZE(abfd) \ |
get_elf_i386_backend_data (abfd)->plt->plt_entry_size |
/* These are the standard parameters. */ |
static const struct elf_i386_plt_layout elf_i386_plt = |
{ |
elf_i386_plt0_entry, /* plt0_entry */ |
sizeof (elf_i386_plt0_entry), /* plt0_entry_size */ |
2, /* plt0_got1_offset */ |
8, /* plt0_got2_offset */ |
elf_i386_plt_entry, /* plt_entry */ |
PLT_ENTRY_SIZE, /* plt_entry_size */ |
2, /* plt_got_offset */ |
7, /* plt_reloc_offset */ |
12, /* plt_plt_offset */ |
6, /* plt_lazy_offset */ |
elf_i386_pic_plt0_entry, /* pic_plt0_entry */ |
elf_i386_pic_plt_entry, /* pic_plt_entry */ |
elf_i386_eh_frame_plt, /* eh_frame_plt */ |
sizeof (elf_i386_eh_frame_plt), /* eh_frame_plt_size */ |
}; |
/* On VxWorks, the .rel.plt.unloaded section has absolute relocations |
for the PLTResolve stub and then for each PLT entry. */ |
#define PLTRESOLVE_RELOCS_SHLIB 0 |
#define PLTRESOLVE_RELOCS 2 |
#define PLT_NON_JUMP_SLOT_RELOCS 2 |
/* Architecture-specific backend data for i386. */ |
struct elf_i386_backend_data |
{ |
/* Parameters describing PLT generation. */ |
const struct elf_i386_plt_layout *plt; |
/* Value used to fill the unused bytes of the first PLT entry. */ |
bfd_byte plt0_pad_byte; |
/* True if the target system is VxWorks. */ |
int is_vxworks; |
}; |
#define get_elf_i386_backend_data(abfd) \ |
((const struct elf_i386_backend_data *) \ |
get_elf_backend_data (abfd)->arch_data) |
/* These are the standard parameters. */ |
static const struct elf_i386_backend_data elf_i386_arch_bed = |
{ |
&elf_i386_plt, /* plt */ |
0, /* plt0_pad_byte */ |
0, /* is_vxworks */ |
}; |
#define elf_backend_arch_data &elf_i386_arch_bed |
/* i386 ELF linker hash entry. */ |
struct elf_i386_link_hash_entry |
{ |
struct elf_link_hash_entry elf; |
/* Track dynamic relocs copied for this symbol. */ |
struct elf_dyn_relocs *dyn_relocs; |
#define GOT_UNKNOWN 0 |
#define GOT_NORMAL 1 |
#define GOT_TLS_GD 2 |
#define GOT_TLS_IE 4 |
#define GOT_TLS_IE_POS 5 |
#define GOT_TLS_IE_NEG 6 |
#define GOT_TLS_IE_BOTH 7 |
#define GOT_TLS_GDESC 8 |
#define GOT_TLS_GD_BOTH_P(type) \ |
((type) == (GOT_TLS_GD | GOT_TLS_GDESC)) |
#define GOT_TLS_GD_P(type) \ |
((type) == GOT_TLS_GD || GOT_TLS_GD_BOTH_P (type)) |
#define GOT_TLS_GDESC_P(type) \ |
((type) == GOT_TLS_GDESC || GOT_TLS_GD_BOTH_P (type)) |
#define GOT_TLS_GD_ANY_P(type) \ |
(GOT_TLS_GD_P (type) || GOT_TLS_GDESC_P (type)) |
unsigned char tls_type; |
/* Offset of the GOTPLT entry reserved for the TLS descriptor, |
starting at the end of the jump table. */ |
bfd_vma tlsdesc_got; |
}; |
#define elf_i386_hash_entry(ent) ((struct elf_i386_link_hash_entry *)(ent)) |
struct elf_i386_obj_tdata |
{ |
struct elf_obj_tdata root; |
/* tls_type for each local got entry. */ |
char *local_got_tls_type; |
/* GOTPLT entries for TLS descriptors. */ |
bfd_vma *local_tlsdesc_gotent; |
}; |
#define elf_i386_tdata(abfd) \ |
((struct elf_i386_obj_tdata *) (abfd)->tdata.any) |
#define elf_i386_local_got_tls_type(abfd) \ |
(elf_i386_tdata (abfd)->local_got_tls_type) |
#define elf_i386_local_tlsdesc_gotent(abfd) \ |
(elf_i386_tdata (abfd)->local_tlsdesc_gotent) |
#define is_i386_elf(bfd) \ |
(bfd_get_flavour (bfd) == bfd_target_elf_flavour \ |
&& elf_tdata (bfd) != NULL \ |
&& elf_object_id (bfd) == I386_ELF_DATA) |
static bfd_boolean |
elf_i386_mkobject (bfd *abfd) |
{ |
return bfd_elf_allocate_object (abfd, sizeof (struct elf_i386_obj_tdata), |
I386_ELF_DATA); |
} |
/* i386 ELF linker hash table. */ |
struct elf_i386_link_hash_table |
{ |
struct elf_link_hash_table elf; |
/* Short-cuts to get to dynamic linker sections. */ |
asection *sdynbss; |
asection *srelbss; |
asection *plt_eh_frame; |
union |
{ |
bfd_signed_vma refcount; |
bfd_vma offset; |
} tls_ldm_got; |
/* The amount of space used by the reserved portion of the sgotplt |
section, plus whatever space is used by the jump slots. */ |
bfd_vma sgotplt_jump_table_size; |
/* Small local sym cache. */ |
struct sym_cache sym_cache; |
/* _TLS_MODULE_BASE_ symbol. */ |
struct bfd_link_hash_entry *tls_module_base; |
/* Used by local STT_GNU_IFUNC symbols. */ |
htab_t loc_hash_table; |
void * loc_hash_memory; |
/* The (unloaded but important) .rel.plt.unloaded section on VxWorks. */ |
asection *srelplt2; |
/* The index of the next unused R_386_TLS_DESC slot in .rel.plt. */ |
bfd_vma next_tls_desc_index; |
/* The index of the next unused R_386_JUMP_SLOT slot in .rel.plt. */ |
bfd_vma next_jump_slot_index; |
/* The index of the next unused R_386_IRELATIVE slot in .rel.plt. */ |
bfd_vma next_irelative_index; |
}; |
/* Get the i386 ELF linker hash table from a link_info structure. */ |
#define elf_i386_hash_table(p) \ |
(elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ |
== I386_ELF_DATA ? ((struct elf_i386_link_hash_table *) ((p)->hash)) : NULL) |
#define elf_i386_compute_jump_table_size(htab) \ |
((htab)->next_tls_desc_index * 4) |
/* Create an entry in an i386 ELF linker hash table. */ |
static struct bfd_hash_entry * |
elf_i386_link_hash_newfunc (struct bfd_hash_entry *entry, |
struct bfd_hash_table *table, |
const char *string) |
{ |
/* Allocate the structure if it has not already been allocated by a |
subclass. */ |
if (entry == NULL) |
{ |
entry = (struct bfd_hash_entry *) |
bfd_hash_allocate (table, sizeof (struct elf_i386_link_hash_entry)); |
if (entry == NULL) |
return entry; |
} |
/* Call the allocation method of the superclass. */ |
entry = _bfd_elf_link_hash_newfunc (entry, table, string); |
if (entry != NULL) |
{ |
struct elf_i386_link_hash_entry *eh; |
eh = (struct elf_i386_link_hash_entry *) entry; |
eh->dyn_relocs = NULL; |
eh->tls_type = GOT_UNKNOWN; |
eh->tlsdesc_got = (bfd_vma) -1; |
} |
return entry; |
} |
/* Compute a hash of a local hash entry. We use elf_link_hash_entry |
for local symbol so that we can handle local STT_GNU_IFUNC symbols |
as global symbol. We reuse indx and dynstr_index for local symbol |
hash since they aren't used by global symbols in this backend. */ |
static hashval_t |
elf_i386_local_htab_hash (const void *ptr) |
{ |
struct elf_link_hash_entry *h |
= (struct elf_link_hash_entry *) ptr; |
return ELF_LOCAL_SYMBOL_HASH (h->indx, h->dynstr_index); |
} |
/* Compare local hash entries. */ |
static int |
elf_i386_local_htab_eq (const void *ptr1, const void *ptr2) |
{ |
struct elf_link_hash_entry *h1 |
= (struct elf_link_hash_entry *) ptr1; |
struct elf_link_hash_entry *h2 |
= (struct elf_link_hash_entry *) ptr2; |
return h1->indx == h2->indx && h1->dynstr_index == h2->dynstr_index; |
} |
/* Find and/or create a hash entry for local symbol. */ |
static struct elf_link_hash_entry * |
elf_i386_get_local_sym_hash (struct elf_i386_link_hash_table *htab, |
bfd *abfd, const Elf_Internal_Rela *rel, |
bfd_boolean create) |
{ |
struct elf_i386_link_hash_entry e, *ret; |
asection *sec = abfd->sections; |
hashval_t h = ELF_LOCAL_SYMBOL_HASH (sec->id, |
ELF32_R_SYM (rel->r_info)); |
void **slot; |
e.elf.indx = sec->id; |
e.elf.dynstr_index = ELF32_R_SYM (rel->r_info); |
slot = htab_find_slot_with_hash (htab->loc_hash_table, &e, h, |
create ? INSERT : NO_INSERT); |
if (!slot) |
return NULL; |
if (*slot) |
{ |
ret = (struct elf_i386_link_hash_entry *) *slot; |
return &ret->elf; |
} |
ret = (struct elf_i386_link_hash_entry *) |
objalloc_alloc ((struct objalloc *) htab->loc_hash_memory, |
sizeof (struct elf_i386_link_hash_entry)); |
if (ret) |
{ |
memset (ret, 0, sizeof (*ret)); |
ret->elf.indx = sec->id; |
ret->elf.dynstr_index = ELF32_R_SYM (rel->r_info); |
ret->elf.dynindx = -1; |
*slot = ret; |
} |
return &ret->elf; |
} |
/* Create an i386 ELF linker hash table. */ |
static struct bfd_link_hash_table * |
elf_i386_link_hash_table_create (bfd *abfd) |
{ |
struct elf_i386_link_hash_table *ret; |
bfd_size_type amt = sizeof (struct elf_i386_link_hash_table); |
ret = (struct elf_i386_link_hash_table *) bfd_zmalloc (amt); |
if (ret == NULL) |
return NULL; |
if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, |
elf_i386_link_hash_newfunc, |
sizeof (struct elf_i386_link_hash_entry), |
I386_ELF_DATA)) |
{ |
free (ret); |
return NULL; |
} |
ret->loc_hash_table = htab_try_create (1024, |
elf_i386_local_htab_hash, |
elf_i386_local_htab_eq, |
NULL); |
ret->loc_hash_memory = objalloc_create (); |
if (!ret->loc_hash_table || !ret->loc_hash_memory) |
{ |
free (ret); |
return NULL; |
} |
return &ret->elf.root; |
} |
/* Destroy an i386 ELF linker hash table. */ |
static void |
elf_i386_link_hash_table_free (struct bfd_link_hash_table *hash) |
{ |
struct elf_i386_link_hash_table *htab |
= (struct elf_i386_link_hash_table *) hash; |
if (htab->loc_hash_table) |
htab_delete (htab->loc_hash_table); |
if (htab->loc_hash_memory) |
objalloc_free ((struct objalloc *) htab->loc_hash_memory); |
_bfd_elf_link_hash_table_free (hash); |
} |
/* Create .plt, .rel.plt, .got, .got.plt, .rel.got, .dynbss, and |
.rel.bss sections in DYNOBJ, and set up shortcuts to them in our |
hash table. */ |
static bfd_boolean |
elf_i386_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) |
{ |
struct elf_i386_link_hash_table *htab; |
if (!_bfd_elf_create_dynamic_sections (dynobj, info)) |
return FALSE; |
htab = elf_i386_hash_table (info); |
if (htab == NULL) |
return FALSE; |
htab->sdynbss = bfd_get_linker_section (dynobj, ".dynbss"); |
if (!info->shared) |
htab->srelbss = bfd_get_linker_section (dynobj, ".rel.bss"); |
if (!htab->sdynbss |
|| (!info->shared && !htab->srelbss)) |
abort (); |
if (get_elf_i386_backend_data (dynobj)->is_vxworks |
&& !elf_vxworks_create_dynamic_sections (dynobj, info, |
&htab->srelplt2)) |
return FALSE; |
if (!info->no_ld_generated_unwind_info |
&& htab->plt_eh_frame == NULL |
&& htab->elf.splt != NULL) |
{ |
flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY |
| SEC_HAS_CONTENTS | SEC_IN_MEMORY |
| SEC_LINKER_CREATED); |
htab->plt_eh_frame |
= bfd_make_section_anyway_with_flags (dynobj, ".eh_frame", flags); |
if (htab->plt_eh_frame == NULL |
|| !bfd_set_section_alignment (dynobj, htab->plt_eh_frame, 2)) |
return FALSE; |
} |
return TRUE; |
} |
/* Copy the extra info we tack onto an elf_link_hash_entry. */ |
static void |
elf_i386_copy_indirect_symbol (struct bfd_link_info *info, |
struct elf_link_hash_entry *dir, |
struct elf_link_hash_entry *ind) |
{ |
struct elf_i386_link_hash_entry *edir, *eind; |
edir = (struct elf_i386_link_hash_entry *) dir; |
eind = (struct elf_i386_link_hash_entry *) ind; |
if (eind->dyn_relocs != NULL) |
{ |
if (edir->dyn_relocs != NULL) |
{ |
struct elf_dyn_relocs **pp; |
struct elf_dyn_relocs *p; |
/* Add reloc counts against the indirect sym to the direct sym |
list. Merge any entries against the same section. */ |
for (pp = &eind->dyn_relocs; (p = *pp) != NULL; ) |
{ |
struct elf_dyn_relocs *q; |
for (q = edir->dyn_relocs; q != NULL; q = q->next) |
if (q->sec == p->sec) |
{ |
q->pc_count += p->pc_count; |
q->count += p->count; |
*pp = p->next; |
break; |
} |
if (q == NULL) |
pp = &p->next; |
} |
*pp = edir->dyn_relocs; |
} |
edir->dyn_relocs = eind->dyn_relocs; |
eind->dyn_relocs = NULL; |
} |
if (ind->root.type == bfd_link_hash_indirect |
&& dir->got.refcount <= 0) |
{ |
edir->tls_type = eind->tls_type; |
eind->tls_type = GOT_UNKNOWN; |
} |
if (ELIMINATE_COPY_RELOCS |
&& ind->root.type != bfd_link_hash_indirect |
&& dir->dynamic_adjusted) |
{ |
/* If called to transfer flags for a weakdef during processing |
of elf_adjust_dynamic_symbol, don't copy non_got_ref. |
We clear it ourselves for ELIMINATE_COPY_RELOCS. */ |
dir->ref_dynamic |= ind->ref_dynamic; |
dir->ref_regular |= ind->ref_regular; |
dir->ref_regular_nonweak |= ind->ref_regular_nonweak; |
dir->needs_plt |= ind->needs_plt; |
dir->pointer_equality_needed |= ind->pointer_equality_needed; |
} |
else |
_bfd_elf_link_hash_copy_indirect (info, dir, ind); |
} |
/* Return TRUE if the TLS access code sequence support transition |
from R_TYPE. */ |
static bfd_boolean |
elf_i386_check_tls_transition (bfd *abfd, asection *sec, |
bfd_byte *contents, |
Elf_Internal_Shdr *symtab_hdr, |
struct elf_link_hash_entry **sym_hashes, |
unsigned int r_type, |
const Elf_Internal_Rela *rel, |
const Elf_Internal_Rela *relend) |
{ |
unsigned int val, type; |
unsigned long r_symndx; |
struct elf_link_hash_entry *h; |
bfd_vma offset; |
/* Get the section contents. */ |
if (contents == NULL) |
{ |
if (elf_section_data (sec)->this_hdr.contents != NULL) |
contents = elf_section_data (sec)->this_hdr.contents; |
else |
{ |
/* FIXME: How to better handle error condition? */ |
if (!bfd_malloc_and_get_section (abfd, sec, &contents)) |
return FALSE; |
/* Cache the section contents for elf_link_input_bfd. */ |
elf_section_data (sec)->this_hdr.contents = contents; |
} |
} |
offset = rel->r_offset; |
switch (r_type) |
{ |
case R_386_TLS_GD: |
case R_386_TLS_LDM: |
if (offset < 2 || (rel + 1) >= relend) |
return FALSE; |
type = bfd_get_8 (abfd, contents + offset - 2); |
if (r_type == R_386_TLS_GD) |
{ |
/* Check transition from GD access model. Only |
leal foo@tlsgd(,%reg,1), %eax; call ___tls_get_addr |
leal foo@tlsgd(%reg), %eax; call ___tls_get_addr; nop |
can transit to different access model. */ |
if ((offset + 10) > sec->size || |
(type != 0x8d && type != 0x04)) |
return FALSE; |
val = bfd_get_8 (abfd, contents + offset - 1); |
if (type == 0x04) |
{ |
/* leal foo@tlsgd(,%reg,1), %eax; call ___tls_get_addr */ |
if (offset < 3) |
return FALSE; |
if (bfd_get_8 (abfd, contents + offset - 3) != 0x8d) |
return FALSE; |
if ((val & 0xc7) != 0x05 || val == (4 << 3)) |
return FALSE; |
} |
else |
{ |
/* leal foo@tlsgd(%reg), %eax; call ___tls_get_addr; nop */ |
if ((val & 0xf8) != 0x80 || (val & 7) == 4) |
return FALSE; |
if (bfd_get_8 (abfd, contents + offset + 9) != 0x90) |
return FALSE; |
} |
} |
else |
{ |
/* Check transition from LD access model. Only |
leal foo@tlsgd(%reg), %eax; call ___tls_get_addr |
can transit to different access model. */ |
if (type != 0x8d || (offset + 9) > sec->size) |
return FALSE; |
val = bfd_get_8 (abfd, contents + offset - 1); |
if ((val & 0xf8) != 0x80 || (val & 7) == 4) |
return FALSE; |
} |
if (bfd_get_8 (abfd, contents + offset + 4) != 0xe8) |
return FALSE; |
r_symndx = ELF32_R_SYM (rel[1].r_info); |
if (r_symndx < symtab_hdr->sh_info) |
return FALSE; |
h = sym_hashes[r_symndx - symtab_hdr->sh_info]; |
/* Use strncmp to check ___tls_get_addr since ___tls_get_addr |
may be versioned. */ |
return (h != NULL |
&& h->root.root.string != NULL |
&& (ELF32_R_TYPE (rel[1].r_info) == R_386_PC32 |
|| ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32) |
&& (strncmp (h->root.root.string, "___tls_get_addr", |
15) == 0)); |
case R_386_TLS_IE: |
/* Check transition from IE access model: |
movl foo@indntpoff(%rip), %eax |
movl foo@indntpoff(%rip), %reg |
addl foo@indntpoff(%rip), %reg |
*/ |
if (offset < 1 || (offset + 4) > sec->size) |
return FALSE; |
/* Check "movl foo@tpoff(%rip), %eax" first. */ |
val = bfd_get_8 (abfd, contents + offset - 1); |
if (val == 0xa1) |
return TRUE; |
if (offset < 2) |
return FALSE; |
/* Check movl|addl foo@tpoff(%rip), %reg. */ |
type = bfd_get_8 (abfd, contents + offset - 2); |
return ((type == 0x8b || type == 0x03) |
&& (val & 0xc7) == 0x05); |
case R_386_TLS_GOTIE: |
case R_386_TLS_IE_32: |
/* Check transition from {IE_32,GOTIE} access model: |
subl foo@{tpoff,gontoff}(%reg1), %reg2 |
movl foo@{tpoff,gontoff}(%reg1), %reg2 |
addl foo@{tpoff,gontoff}(%reg1), %reg2 |
*/ |
if (offset < 2 || (offset + 4) > sec->size) |
return FALSE; |
val = bfd_get_8 (abfd, contents + offset - 1); |
if ((val & 0xc0) != 0x80 || (val & 7) == 4) |
return FALSE; |
type = bfd_get_8 (abfd, contents + offset - 2); |
return type == 0x8b || type == 0x2b || type == 0x03; |
case R_386_TLS_GOTDESC: |
/* Check transition from GDesc access model: |
leal x@tlsdesc(%ebx), %eax |
Make sure it's a leal adding ebx to a 32-bit offset |
into any register, although it's probably almost always |
going to be eax. */ |
if (offset < 2 || (offset + 4) > sec->size) |
return FALSE; |
if (bfd_get_8 (abfd, contents + offset - 2) != 0x8d) |
return FALSE; |
val = bfd_get_8 (abfd, contents + offset - 1); |
return (val & 0xc7) == 0x83; |
case R_386_TLS_DESC_CALL: |
/* Check transition from GDesc access model: |
call *x@tlsdesc(%rax) |
*/ |
if (offset + 2 <= sec->size) |
{ |
/* Make sure that it's a call *x@tlsdesc(%rax). */ |
static const unsigned char call[] = { 0xff, 0x10 }; |
return memcmp (contents + offset, call, 2) == 0; |
} |
return FALSE; |
default: |
abort (); |
} |
} |
/* Return TRUE if the TLS access transition is OK or no transition |
will be performed. Update R_TYPE if there is a transition. */ |
static bfd_boolean |
elf_i386_tls_transition (struct bfd_link_info *info, bfd *abfd, |
asection *sec, bfd_byte *contents, |
Elf_Internal_Shdr *symtab_hdr, |
struct elf_link_hash_entry **sym_hashes, |
unsigned int *r_type, int tls_type, |
const Elf_Internal_Rela *rel, |
const Elf_Internal_Rela *relend, |
struct elf_link_hash_entry *h, |
unsigned long r_symndx) |
{ |
unsigned int from_type = *r_type; |
unsigned int to_type = from_type; |
bfd_boolean check = TRUE; |
/* Skip TLS transition for functions. */ |
if (h != NULL |
&& (h->type == STT_FUNC |
|| h->type == STT_GNU_IFUNC)) |
return TRUE; |
switch (from_type) |
{ |
case R_386_TLS_GD: |
case R_386_TLS_GOTDESC: |
case R_386_TLS_DESC_CALL: |
case R_386_TLS_IE_32: |
case R_386_TLS_IE: |
case R_386_TLS_GOTIE: |
if (info->executable) |
{ |
if (h == NULL) |
to_type = R_386_TLS_LE_32; |
else if (from_type != R_386_TLS_IE |
&& from_type != R_386_TLS_GOTIE) |
to_type = R_386_TLS_IE_32; |
} |
/* When we are called from elf_i386_relocate_section, CONTENTS |
isn't NULL and there may be additional transitions based on |
TLS_TYPE. */ |
if (contents != NULL) |
{ |
unsigned int new_to_type = to_type; |
if (info->executable |
&& h != NULL |
&& h->dynindx == -1 |
&& (tls_type & GOT_TLS_IE)) |
new_to_type = R_386_TLS_LE_32; |
if (to_type == R_386_TLS_GD |
|| to_type == R_386_TLS_GOTDESC |
|| to_type == R_386_TLS_DESC_CALL) |
{ |
if (tls_type == GOT_TLS_IE_POS) |
new_to_type = R_386_TLS_GOTIE; |
else if (tls_type & GOT_TLS_IE) |
new_to_type = R_386_TLS_IE_32; |
} |
/* We checked the transition before when we were called from |
elf_i386_check_relocs. We only want to check the new |
transition which hasn't been checked before. */ |
check = new_to_type != to_type && from_type == to_type; |
to_type = new_to_type; |
} |
break; |
case R_386_TLS_LDM: |
if (info->executable) |
to_type = R_386_TLS_LE_32; |
break; |
default: |
return TRUE; |
} |
/* Return TRUE if there is no transition. */ |
if (from_type == to_type) |
return TRUE; |
/* Check if the transition can be performed. */ |
if (check |
&& ! elf_i386_check_tls_transition (abfd, sec, contents, |
symtab_hdr, sym_hashes, |
from_type, rel, relend)) |
{ |
reloc_howto_type *from, *to; |
const char *name; |
from = elf_i386_rtype_to_howto (abfd, from_type); |
to = elf_i386_rtype_to_howto (abfd, to_type); |
if (h) |
name = h->root.root.string; |
else |
{ |
struct elf_i386_link_hash_table *htab; |
htab = elf_i386_hash_table (info); |
if (htab == NULL) |
name = "*unknown*"; |
else |
{ |
Elf_Internal_Sym *isym; |
isym = bfd_sym_from_r_symndx (&htab->sym_cache, |
abfd, r_symndx); |
name = bfd_elf_sym_name (abfd, symtab_hdr, isym, NULL); |
} |
} |
(*_bfd_error_handler) |
(_("%B: TLS transition from %s to %s against `%s' at 0x%lx " |
"in section `%A' failed"), |
abfd, sec, from->name, to->name, name, |
(unsigned long) rel->r_offset); |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
*r_type = to_type; |
return TRUE; |
} |
/* Look through the relocs for a section during the first phase, and |
calculate needed space in the global offset table, procedure linkage |
table, and dynamic reloc sections. */ |
static bfd_boolean |
elf_i386_check_relocs (bfd *abfd, |
struct bfd_link_info *info, |
asection *sec, |
const Elf_Internal_Rela *relocs) |
{ |
struct elf_i386_link_hash_table *htab; |
Elf_Internal_Shdr *symtab_hdr; |
struct elf_link_hash_entry **sym_hashes; |
const Elf_Internal_Rela *rel; |
const Elf_Internal_Rela *rel_end; |
asection *sreloc; |
if (info->relocatable) |
return TRUE; |
BFD_ASSERT (is_i386_elf (abfd)); |
htab = elf_i386_hash_table (info); |
if (htab == NULL) |
return FALSE; |
symtab_hdr = &elf_symtab_hdr (abfd); |
sym_hashes = elf_sym_hashes (abfd); |
sreloc = NULL; |
rel_end = relocs + sec->reloc_count; |
for (rel = relocs; rel < rel_end; rel++) |
{ |
unsigned int r_type; |
unsigned long r_symndx; |
struct elf_link_hash_entry *h; |
Elf_Internal_Sym *isym; |
const char *name; |
bfd_boolean size_reloc; |
r_symndx = ELF32_R_SYM (rel->r_info); |
r_type = ELF32_R_TYPE (rel->r_info); |
if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr)) |
{ |
(*_bfd_error_handler) (_("%B: bad symbol index: %d"), |
abfd, |
r_symndx); |
return FALSE; |
} |
if (r_symndx < symtab_hdr->sh_info) |
{ |
/* A local symbol. */ |
isym = bfd_sym_from_r_symndx (&htab->sym_cache, |
abfd, r_symndx); |
if (isym == NULL) |
return FALSE; |
/* Check relocation against local STT_GNU_IFUNC symbol. */ |
if (ELF32_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) |
{ |
h = elf_i386_get_local_sym_hash (htab, abfd, rel, TRUE); |
if (h == NULL) |
return FALSE; |
/* Fake a STT_GNU_IFUNC symbol. */ |
h->type = STT_GNU_IFUNC; |
h->def_regular = 1; |
h->ref_regular = 1; |
h->forced_local = 1; |
h->root.type = bfd_link_hash_defined; |
} |
else |
h = NULL; |
} |
else |
{ |
isym = NULL; |
h = sym_hashes[r_symndx - symtab_hdr->sh_info]; |
while (h->root.type == bfd_link_hash_indirect |
|| h->root.type == bfd_link_hash_warning) |
h = (struct elf_link_hash_entry *) h->root.u.i.link; |
} |
if (h != NULL) |
{ |
/* Create the ifunc sections for static executables. If we |
never see an indirect function symbol nor we are building |
a static executable, those sections will be empty and |
won't appear in output. */ |
switch (r_type) |
{ |
default: |
break; |
case R_386_32: |
case R_386_PC32: |
case R_386_PLT32: |
case R_386_GOT32: |
case R_386_GOTOFF: |
if (htab->elf.dynobj == NULL) |
htab->elf.dynobj = abfd; |
if (!_bfd_elf_create_ifunc_sections (htab->elf.dynobj, info)) |
return FALSE; |
break; |
} |
/* It is referenced by a non-shared object. */ |
h->ref_regular = 1; |
h->root.non_ir_ref = 1; |
} |
if (! elf_i386_tls_transition (info, abfd, sec, NULL, |
symtab_hdr, sym_hashes, |
&r_type, GOT_UNKNOWN, |
rel, rel_end, h, r_symndx)) |
return FALSE; |
switch (r_type) |
{ |
case R_386_TLS_LDM: |
htab->tls_ldm_got.refcount += 1; |
goto create_got; |
case R_386_PLT32: |
/* This symbol requires a procedure linkage table entry. We |
actually build the entry in adjust_dynamic_symbol, |
because this might be a case of linking PIC code which is |
never referenced by a dynamic object, in which case we |
don't need to generate a procedure linkage table entry |
after all. */ |
/* If this is a local symbol, we resolve it directly without |
creating a procedure linkage table entry. */ |
if (h == NULL) |
continue; |
h->needs_plt = 1; |
h->plt.refcount += 1; |
break; |
case R_386_SIZE32: |
size_reloc = TRUE; |
goto do_size; |
case R_386_TLS_IE_32: |
case R_386_TLS_IE: |
case R_386_TLS_GOTIE: |
if (!info->executable) |
info->flags |= DF_STATIC_TLS; |
/* Fall through */ |
case R_386_GOT32: |
case R_386_TLS_GD: |
case R_386_TLS_GOTDESC: |
case R_386_TLS_DESC_CALL: |
/* This symbol requires a global offset table entry. */ |
{ |
int tls_type, old_tls_type; |
switch (r_type) |
{ |
default: |
case R_386_GOT32: tls_type = GOT_NORMAL; break; |
case R_386_TLS_GD: tls_type = GOT_TLS_GD; break; |
case R_386_TLS_GOTDESC: |
case R_386_TLS_DESC_CALL: |
tls_type = GOT_TLS_GDESC; break; |
case R_386_TLS_IE_32: |
if (ELF32_R_TYPE (rel->r_info) == r_type) |
tls_type = GOT_TLS_IE_NEG; |
else |
/* If this is a GD->IE transition, we may use either of |
R_386_TLS_TPOFF and R_386_TLS_TPOFF32. */ |
tls_type = GOT_TLS_IE; |
break; |
case R_386_TLS_IE: |
case R_386_TLS_GOTIE: |
tls_type = GOT_TLS_IE_POS; break; |
} |
if (h != NULL) |
{ |
h->got.refcount += 1; |
old_tls_type = elf_i386_hash_entry(h)->tls_type; |
} |
else |
{ |
bfd_signed_vma *local_got_refcounts; |
/* This is a global offset table entry for a local symbol. */ |
local_got_refcounts = elf_local_got_refcounts (abfd); |
if (local_got_refcounts == NULL) |
{ |
bfd_size_type size; |
size = symtab_hdr->sh_info; |
size *= (sizeof (bfd_signed_vma) |
+ sizeof (bfd_vma) + sizeof(char)); |
local_got_refcounts = (bfd_signed_vma *) |
bfd_zalloc (abfd, size); |
if (local_got_refcounts == NULL) |
return FALSE; |
elf_local_got_refcounts (abfd) = local_got_refcounts; |
elf_i386_local_tlsdesc_gotent (abfd) |
= (bfd_vma *) (local_got_refcounts + symtab_hdr->sh_info); |
elf_i386_local_got_tls_type (abfd) |
= (char *) (local_got_refcounts + 2 * symtab_hdr->sh_info); |
} |
local_got_refcounts[r_symndx] += 1; |
old_tls_type = elf_i386_local_got_tls_type (abfd) [r_symndx]; |
} |
if ((old_tls_type & GOT_TLS_IE) && (tls_type & GOT_TLS_IE)) |
tls_type |= old_tls_type; |
/* If a TLS symbol is accessed using IE at least once, |
there is no point to use dynamic model for it. */ |
else if (old_tls_type != tls_type && old_tls_type != GOT_UNKNOWN |
&& (! GOT_TLS_GD_ANY_P (old_tls_type) |
|| (tls_type & GOT_TLS_IE) == 0)) |
{ |
if ((old_tls_type & GOT_TLS_IE) && GOT_TLS_GD_ANY_P (tls_type)) |
tls_type = old_tls_type; |
else if (GOT_TLS_GD_ANY_P (old_tls_type) |
&& GOT_TLS_GD_ANY_P (tls_type)) |
tls_type |= old_tls_type; |
else |
{ |
if (h) |
name = h->root.root.string; |
else |
name = bfd_elf_sym_name (abfd, symtab_hdr, isym, |
NULL); |
(*_bfd_error_handler) |
(_("%B: `%s' accessed both as normal and " |
"thread local symbol"), |
abfd, name); |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
} |
if (old_tls_type != tls_type) |
{ |
if (h != NULL) |
elf_i386_hash_entry (h)->tls_type = tls_type; |
else |
elf_i386_local_got_tls_type (abfd) [r_symndx] = tls_type; |
} |
} |
/* Fall through */ |
case R_386_GOTOFF: |
case R_386_GOTPC: |
create_got: |
if (htab->elf.sgot == NULL) |
{ |
if (htab->elf.dynobj == NULL) |
htab->elf.dynobj = abfd; |
if (!_bfd_elf_create_got_section (htab->elf.dynobj, info)) |
return FALSE; |
} |
if (r_type != R_386_TLS_IE) |
break; |
/* Fall through */ |
case R_386_TLS_LE_32: |
case R_386_TLS_LE: |
if (info->executable) |
break; |
info->flags |= DF_STATIC_TLS; |
/* Fall through */ |
case R_386_32: |
case R_386_PC32: |
if (h != NULL && info->executable) |
{ |
/* If this reloc is in a read-only section, we might |
need a copy reloc. We can't check reliably at this |
stage whether the section is read-only, as input |
sections have not yet been mapped to output sections. |
Tentatively set the flag for now, and correct in |
adjust_dynamic_symbol. */ |
h->non_got_ref = 1; |
/* We may need a .plt entry if the function this reloc |
refers to is in a shared lib. */ |
h->plt.refcount += 1; |
if (r_type != R_386_PC32) |
h->pointer_equality_needed = 1; |
} |
size_reloc = FALSE; |
do_size: |
/* If we are creating a shared library, and this is a reloc |
against a global symbol, or a non PC relative reloc |
against a local symbol, then we need to copy the reloc |
into the shared library. However, if we are linking with |
-Bsymbolic, we do not need to copy a reloc against a |
global symbol which is defined in an object we are |
including in the link (i.e., DEF_REGULAR is set). At |
this point we have not seen all the input files, so it is |
possible that DEF_REGULAR is not set now but will be set |
later (it is never cleared). In case of a weak definition, |
DEF_REGULAR may be cleared later by a strong definition in |
a shared library. We account for that possibility below by |
storing information in the relocs_copied field of the hash |
table entry. A similar situation occurs when creating |
shared libraries and symbol visibility changes render the |
symbol local. |
If on the other hand, we are creating an executable, we |
may need to keep relocations for symbols satisfied by a |
dynamic library if we manage to avoid copy relocs for the |
symbol. */ |
if ((info->shared |
&& (sec->flags & SEC_ALLOC) != 0 |
&& (r_type != R_386_PC32 |
|| (h != NULL |
&& (! SYMBOLIC_BIND (info, h) |
|| h->root.type == bfd_link_hash_defweak |
|| !h->def_regular)))) |
|| (ELIMINATE_COPY_RELOCS |
&& !info->shared |
&& (sec->flags & SEC_ALLOC) != 0 |
&& h != NULL |
&& (h->root.type == bfd_link_hash_defweak |
|| !h->def_regular))) |
{ |
struct elf_dyn_relocs *p; |
struct elf_dyn_relocs **head; |
/* We must copy these reloc types into the output file. |
Create a reloc section in dynobj and make room for |
this reloc. */ |
if (sreloc == NULL) |
{ |
if (htab->elf.dynobj == NULL) |
htab->elf.dynobj = abfd; |
sreloc = _bfd_elf_make_dynamic_reloc_section |
(sec, htab->elf.dynobj, 2, abfd, /*rela?*/ FALSE); |
if (sreloc == NULL) |
return FALSE; |
} |
/* If this is a global symbol, we count the number of |
relocations we need for this symbol. */ |
if (h != NULL) |
{ |
head = &((struct elf_i386_link_hash_entry *) h)->dyn_relocs; |
} |
else |
{ |
/* Track dynamic relocs needed for local syms too. |
We really need local syms available to do this |
easily. Oh well. */ |
void **vpp; |
asection *s; |
isym = bfd_sym_from_r_symndx (&htab->sym_cache, |
abfd, r_symndx); |
if (isym == NULL) |
return FALSE; |
s = bfd_section_from_elf_index (abfd, isym->st_shndx); |
if (s == NULL) |
s = sec; |
vpp = &elf_section_data (s)->local_dynrel; |
head = (struct elf_dyn_relocs **)vpp; |
} |
p = *head; |
if (p == NULL || p->sec != sec) |
{ |
bfd_size_type amt = sizeof *p; |
p = (struct elf_dyn_relocs *) bfd_alloc (htab->elf.dynobj, |
amt); |
if (p == NULL) |
return FALSE; |
p->next = *head; |
*head = p; |
p->sec = sec; |
p->count = 0; |
p->pc_count = 0; |
} |
p->count += 1; |
/* Count size relocation as PC-relative relocation. */ |
if (r_type == R_386_PC32 || size_reloc) |
p->pc_count += 1; |
} |
break; |
/* This relocation describes the C++ object vtable hierarchy. |
Reconstruct it for later use during GC. */ |
case R_386_GNU_VTINHERIT: |
if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) |
return FALSE; |
break; |
/* This relocation describes which C++ vtable entries are actually |
used. Record for later use during GC. */ |
case R_386_GNU_VTENTRY: |
BFD_ASSERT (h != NULL); |
if (h != NULL |
&& !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset)) |
return FALSE; |
break; |
default: |
break; |
} |
} |
return TRUE; |
} |
/* Return the section that should be marked against GC for a given |
relocation. */ |
static asection * |
elf_i386_gc_mark_hook (asection *sec, |
struct bfd_link_info *info, |
Elf_Internal_Rela *rel, |
struct elf_link_hash_entry *h, |
Elf_Internal_Sym *sym) |
{ |
if (h != NULL) |
switch (ELF32_R_TYPE (rel->r_info)) |
{ |
case R_386_GNU_VTINHERIT: |
case R_386_GNU_VTENTRY: |
return NULL; |
} |
return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); |
} |
/* Update the got entry reference counts for the section being removed. */ |
static bfd_boolean |
elf_i386_gc_sweep_hook (bfd *abfd, |
struct bfd_link_info *info, |
asection *sec, |
const Elf_Internal_Rela *relocs) |
{ |
struct elf_i386_link_hash_table *htab; |
Elf_Internal_Shdr *symtab_hdr; |
struct elf_link_hash_entry **sym_hashes; |
bfd_signed_vma *local_got_refcounts; |
const Elf_Internal_Rela *rel, *relend; |
if (info->relocatable) |
return TRUE; |
htab = elf_i386_hash_table (info); |
if (htab == NULL) |
return FALSE; |
elf_section_data (sec)->local_dynrel = NULL; |
symtab_hdr = &elf_symtab_hdr (abfd); |
sym_hashes = elf_sym_hashes (abfd); |
local_got_refcounts = elf_local_got_refcounts (abfd); |
relend = relocs + sec->reloc_count; |
for (rel = relocs; rel < relend; rel++) |
{ |
unsigned long r_symndx; |
unsigned int r_type; |
struct elf_link_hash_entry *h = NULL; |
r_symndx = ELF32_R_SYM (rel->r_info); |
if (r_symndx >= symtab_hdr->sh_info) |
{ |
h = sym_hashes[r_symndx - symtab_hdr->sh_info]; |
while (h->root.type == bfd_link_hash_indirect |
|| h->root.type == bfd_link_hash_warning) |
h = (struct elf_link_hash_entry *) h->root.u.i.link; |
} |
else |
{ |
/* A local symbol. */ |
Elf_Internal_Sym *isym; |
isym = bfd_sym_from_r_symndx (&htab->sym_cache, |
abfd, r_symndx); |
/* Check relocation against local STT_GNU_IFUNC symbol. */ |
if (isym != NULL |
&& ELF32_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) |
{ |
h = elf_i386_get_local_sym_hash (htab, abfd, rel, FALSE); |
if (h == NULL) |
abort (); |
} |
} |
if (h) |
{ |
struct elf_i386_link_hash_entry *eh; |
struct elf_dyn_relocs **pp; |
struct elf_dyn_relocs *p; |
eh = (struct elf_i386_link_hash_entry *) h; |
for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next) |
if (p->sec == sec) |
{ |
/* Everything must go for SEC. */ |
*pp = p->next; |
break; |
} |
} |
r_type = ELF32_R_TYPE (rel->r_info); |
if (! elf_i386_tls_transition (info, abfd, sec, NULL, |
symtab_hdr, sym_hashes, |
&r_type, GOT_UNKNOWN, |
rel, relend, h, r_symndx)) |
return FALSE; |
switch (r_type) |
{ |
case R_386_TLS_LDM: |
if (htab->tls_ldm_got.refcount > 0) |
htab->tls_ldm_got.refcount -= 1; |
break; |
case R_386_TLS_GD: |
case R_386_TLS_GOTDESC: |
case R_386_TLS_DESC_CALL: |
case R_386_TLS_IE_32: |
case R_386_TLS_IE: |
case R_386_TLS_GOTIE: |
case R_386_GOT32: |
if (h != NULL) |
{ |
if (h->got.refcount > 0) |
h->got.refcount -= 1; |
if (h->type == STT_GNU_IFUNC) |
{ |
if (h->plt.refcount > 0) |
h->plt.refcount -= 1; |
} |
} |
else if (local_got_refcounts != NULL) |
{ |
if (local_got_refcounts[r_symndx] > 0) |
local_got_refcounts[r_symndx] -= 1; |
} |
break; |
case R_386_32: |
case R_386_PC32: |
case R_386_SIZE32: |
if (info->shared |
&& (h == NULL || h->type != STT_GNU_IFUNC)) |
break; |
/* Fall through */ |
case R_386_PLT32: |
if (h != NULL) |
{ |
if (h->plt.refcount > 0) |
h->plt.refcount -= 1; |
} |
break; |
case R_386_GOTOFF: |
if (h != NULL && h->type == STT_GNU_IFUNC) |
{ |
if (h->got.refcount > 0) |
h->got.refcount -= 1; |
if (h->plt.refcount > 0) |
h->plt.refcount -= 1; |
} |
break; |
default: |
break; |
} |
} |
return TRUE; |
} |
/* Adjust a symbol defined by a dynamic object and referenced by a |
regular object. The current definition is in some section of the |
dynamic object, but we're not including those sections. We have to |
change the definition to something the rest of the link can |
understand. */ |
static bfd_boolean |
elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info, |
struct elf_link_hash_entry *h) |
{ |
struct elf_i386_link_hash_table *htab; |
asection *s; |
struct elf_i386_link_hash_entry *eh; |
struct elf_dyn_relocs *p; |
/* STT_GNU_IFUNC symbol must go through PLT. */ |
if (h->type == STT_GNU_IFUNC) |
{ |
/* All local STT_GNU_IFUNC references must be treate as local |
calls via local PLT. */ |
if (h->ref_regular |
&& SYMBOL_CALLS_LOCAL (info, h)) |
{ |
bfd_size_type pc_count = 0, count = 0; |
struct elf_dyn_relocs **pp; |
eh = (struct elf_i386_link_hash_entry *) h; |
for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) |
{ |
pc_count += p->pc_count; |
p->count -= p->pc_count; |
p->pc_count = 0; |
count += p->count; |
if (p->count == 0) |
*pp = p->next; |
else |
pp = &p->next; |
} |
if (pc_count || count) |
{ |
h->needs_plt = 1; |
h->non_got_ref = 1; |
if (h->plt.refcount <= 0) |
h->plt.refcount = 1; |
else |
h->plt.refcount += 1; |
} |
} |
if (h->plt.refcount <= 0) |
{ |
h->plt.offset = (bfd_vma) -1; |
h->needs_plt = 0; |
} |
return TRUE; |
} |
/* If this is a function, put it in the procedure linkage table. We |
will fill in the contents of the procedure linkage table later, |
when we know the address of the .got section. */ |
if (h->type == STT_FUNC |
|| h->needs_plt) |
{ |
if (h->plt.refcount <= 0 |
|| SYMBOL_CALLS_LOCAL (info, h) |
|| (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT |
&& h->root.type == bfd_link_hash_undefweak)) |
{ |
/* This case can occur if we saw a PLT32 reloc in an input |
file, but the symbol was never referred to by a dynamic |
object, or if all references were garbage collected. In |
such a case, we don't actually need to build a procedure |
linkage table, and we can just do a PC32 reloc instead. */ |
h->plt.offset = (bfd_vma) -1; |
h->needs_plt = 0; |
} |
return TRUE; |
} |
else |
/* It's possible that we incorrectly decided a .plt reloc was |
needed for an R_386_PC32 reloc to a non-function sym in |
check_relocs. We can't decide accurately between function and |
non-function syms in check-relocs; Objects loaded later in |
the link may change h->type. So fix it now. */ |
h->plt.offset = (bfd_vma) -1; |
/* If this is a weak symbol, and there is a real definition, the |
processor independent code will have arranged for us to see the |
real definition first, and we can just use the same value. */ |
if (h->u.weakdef != NULL) |
{ |
BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined |
|| h->u.weakdef->root.type == bfd_link_hash_defweak); |
h->root.u.def.section = h->u.weakdef->root.u.def.section; |
h->root.u.def.value = h->u.weakdef->root.u.def.value; |
if (ELIMINATE_COPY_RELOCS || info->nocopyreloc) |
h->non_got_ref = h->u.weakdef->non_got_ref; |
return TRUE; |
} |
/* This is a reference to a symbol defined by a dynamic object which |
is not a function. */ |
/* If we are creating a shared library, we must presume that the |
only references to the symbol are via the global offset table. |
For such cases we need not do anything here; the relocations will |
be handled correctly by relocate_section. */ |
if (info->shared) |
return TRUE; |
/* If there are no references to this symbol that do not use the |
GOT, we don't need to generate a copy reloc. */ |
if (!h->non_got_ref) |
return TRUE; |
/* If -z nocopyreloc was given, we won't generate them either. */ |
if (info->nocopyreloc) |
{ |
h->non_got_ref = 0; |
return TRUE; |
} |
htab = elf_i386_hash_table (info); |
if (htab == NULL) |
return FALSE; |
/* If there aren't any dynamic relocs in read-only sections, then |
we can keep the dynamic relocs and avoid the copy reloc. This |
doesn't work on VxWorks, where we can not have dynamic relocations |
(other than copy and jump slot relocations) in an executable. */ |
if (ELIMINATE_COPY_RELOCS |
&& !get_elf_i386_backend_data (info->output_bfd)->is_vxworks) |
{ |
eh = (struct elf_i386_link_hash_entry *) h; |
for (p = eh->dyn_relocs; p != NULL; p = p->next) |
{ |
s = p->sec->output_section; |
if (s != NULL && (s->flags & SEC_READONLY) != 0) |
break; |
} |
if (p == NULL) |
{ |
h->non_got_ref = 0; |
return TRUE; |
} |
} |
/* We must allocate the symbol in our .dynbss section, which will |
become part of the .bss section of the executable. There will be |
an entry for this symbol in the .dynsym section. The dynamic |
object will contain position independent code, so all references |
from the dynamic object to this symbol will go through the global |
offset table. The dynamic linker will use the .dynsym entry to |
determine the address it must put in the global offset table, so |
both the dynamic object and the regular object will refer to the |
same memory location for the variable. */ |
/* We must generate a R_386_COPY reloc to tell the dynamic linker to |
copy the initial value out of the dynamic object and into the |
runtime process image. */ |
if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) |
{ |
htab->srelbss->size += sizeof (Elf32_External_Rel); |
h->needs_copy = 1; |
} |
s = htab->sdynbss; |
return _bfd_elf_adjust_dynamic_copy (h, s); |
} |
/* Allocate space in .plt, .got and associated reloc sections for |
dynamic relocs. */ |
static bfd_boolean |
elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) |
{ |
struct bfd_link_info *info; |
struct elf_i386_link_hash_table *htab; |
struct elf_i386_link_hash_entry *eh; |
struct elf_dyn_relocs *p; |
unsigned plt_entry_size; |
if (h->root.type == bfd_link_hash_indirect) |
return TRUE; |
eh = (struct elf_i386_link_hash_entry *) h; |
info = (struct bfd_link_info *) inf; |
htab = elf_i386_hash_table (info); |
if (htab == NULL) |
return FALSE; |
plt_entry_size = GET_PLT_ENTRY_SIZE (info->output_bfd); |
/* Since STT_GNU_IFUNC symbol must go through PLT, we handle it |
here if it is defined and referenced in a non-shared object. */ |
if (h->type == STT_GNU_IFUNC |
&& h->def_regular) |
return _bfd_elf_allocate_ifunc_dyn_relocs (info, h, &eh->dyn_relocs, |
plt_entry_size, |
plt_entry_size, 4); |
else if (htab->elf.dynamic_sections_created |
&& h->plt.refcount > 0) |
{ |
/* Make sure this symbol is output as a dynamic symbol. |
Undefined weak syms won't yet be marked as dynamic. */ |
if (h->dynindx == -1 |
&& !h->forced_local) |
{ |
if (! bfd_elf_link_record_dynamic_symbol (info, h)) |
return FALSE; |
} |
if (info->shared |
|| WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h)) |
{ |
asection *s = htab->elf.splt; |
/* If this is the first .plt entry, make room for the special |
first entry. */ |
if (s->size == 0) |
s->size += plt_entry_size; |
h->plt.offset = s->size; |
/* If this symbol is not defined in a regular file, and we are |
not generating a shared library, then set the symbol to this |
location in the .plt. This is required to make function |
pointers compare as equal between the normal executable and |
the shared library. */ |
if (! info->shared |
&& !h->def_regular) |
{ |
h->root.u.def.section = s; |
h->root.u.def.value = h->plt.offset; |
} |
/* Make room for this entry. */ |
s->size += plt_entry_size; |
/* We also need to make an entry in the .got.plt section, which |
will be placed in the .got section by the linker script. */ |
htab->elf.sgotplt->size += 4; |
/* We also need to make an entry in the .rel.plt section. */ |
htab->elf.srelplt->size += sizeof (Elf32_External_Rel); |
htab->elf.srelplt->reloc_count++; |
if (get_elf_i386_backend_data (info->output_bfd)->is_vxworks |
&& !info->shared) |
{ |
/* VxWorks has a second set of relocations for each PLT entry |
in executables. They go in a separate relocation section, |
which is processed by the kernel loader. */ |
/* There are two relocations for the initial PLT entry: an |
R_386_32 relocation for _GLOBAL_OFFSET_TABLE_ + 4 and an |
R_386_32 relocation for _GLOBAL_OFFSET_TABLE_ + 8. */ |
if (h->plt.offset == plt_entry_size) |
htab->srelplt2->size += (sizeof (Elf32_External_Rel) * 2); |
/* There are two extra relocations for each subsequent PLT entry: |
an R_386_32 relocation for the GOT entry, and an R_386_32 |
relocation for the PLT entry. */ |
htab->srelplt2->size += (sizeof (Elf32_External_Rel) * 2); |
} |
} |
else |
{ |
h->plt.offset = (bfd_vma) -1; |
h->needs_plt = 0; |
} |
} |
else |
{ |
h->plt.offset = (bfd_vma) -1; |
h->needs_plt = 0; |
} |
eh->tlsdesc_got = (bfd_vma) -1; |
/* If R_386_TLS_{IE_32,IE,GOTIE} symbol is now local to the binary, |
make it a R_386_TLS_LE_32 requiring no TLS entry. */ |
if (h->got.refcount > 0 |
&& info->executable |
&& h->dynindx == -1 |
&& (elf_i386_hash_entry(h)->tls_type & GOT_TLS_IE)) |
h->got.offset = (bfd_vma) -1; |
else if (h->got.refcount > 0) |
{ |
asection *s; |
bfd_boolean dyn; |
int tls_type = elf_i386_hash_entry(h)->tls_type; |
/* Make sure this symbol is output as a dynamic symbol. |
Undefined weak syms won't yet be marked as dynamic. */ |
if (h->dynindx == -1 |
&& !h->forced_local) |
{ |
if (! bfd_elf_link_record_dynamic_symbol (info, h)) |
return FALSE; |
} |
s = htab->elf.sgot; |
if (GOT_TLS_GDESC_P (tls_type)) |
{ |
eh->tlsdesc_got = htab->elf.sgotplt->size |
- elf_i386_compute_jump_table_size (htab); |
htab->elf.sgotplt->size += 8; |
h->got.offset = (bfd_vma) -2; |
} |
if (! GOT_TLS_GDESC_P (tls_type) |
|| GOT_TLS_GD_P (tls_type)) |
{ |
h->got.offset = s->size; |
s->size += 4; |
/* R_386_TLS_GD needs 2 consecutive GOT slots. */ |
if (GOT_TLS_GD_P (tls_type) || tls_type == GOT_TLS_IE_BOTH) |
s->size += 4; |
} |
dyn = htab->elf.dynamic_sections_created; |
/* R_386_TLS_IE_32 needs one dynamic relocation, |
R_386_TLS_IE resp. R_386_TLS_GOTIE needs one dynamic relocation, |
(but if both R_386_TLS_IE_32 and R_386_TLS_IE is present, we |
need two), R_386_TLS_GD needs one if local symbol and two if |
global. */ |
if (tls_type == GOT_TLS_IE_BOTH) |
htab->elf.srelgot->size += 2 * sizeof (Elf32_External_Rel); |
else if ((GOT_TLS_GD_P (tls_type) && h->dynindx == -1) |
|| (tls_type & GOT_TLS_IE)) |
htab->elf.srelgot->size += sizeof (Elf32_External_Rel); |
else if (GOT_TLS_GD_P (tls_type)) |
htab->elf.srelgot->size += 2 * sizeof (Elf32_External_Rel); |
else if (! GOT_TLS_GDESC_P (tls_type) |
&& (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT |
|| h->root.type != bfd_link_hash_undefweak) |
&& (info->shared |
|| WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))) |
htab->elf.srelgot->size += sizeof (Elf32_External_Rel); |
if (GOT_TLS_GDESC_P (tls_type)) |
htab->elf.srelplt->size += sizeof (Elf32_External_Rel); |
} |
else |
h->got.offset = (bfd_vma) -1; |
if (eh->dyn_relocs == NULL) |
return TRUE; |
/* In the shared -Bsymbolic case, discard space allocated for |
dynamic pc-relative relocs against symbols which turn out to be |
defined in regular objects. For the normal shared case, discard |
space for pc-relative relocs that have become local due to symbol |
visibility changes. */ |
if (info->shared) |
{ |
/* The only reloc that uses pc_count is R_386_PC32, which will |
appear on a call or on something like ".long foo - .". We |
want calls to protected symbols to resolve directly to the |
function rather than going via the plt. If people want |
function pointer comparisons to work as expected then they |
should avoid writing assembly like ".long foo - .". */ |
if (SYMBOL_CALLS_LOCAL (info, h)) |
{ |
struct elf_dyn_relocs **pp; |
for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) |
{ |
p->count -= p->pc_count; |
p->pc_count = 0; |
if (p->count == 0) |
*pp = p->next; |
else |
pp = &p->next; |
} |
} |
if (get_elf_i386_backend_data (info->output_bfd)->is_vxworks) |
{ |
struct elf_dyn_relocs **pp; |
for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) |
{ |
if (strcmp (p->sec->output_section->name, ".tls_vars") == 0) |
*pp = p->next; |
else |
pp = &p->next; |
} |
} |
/* Also discard relocs on undefined weak syms with non-default |
visibility. */ |
if (eh->dyn_relocs != NULL |
&& h->root.type == bfd_link_hash_undefweak) |
{ |
if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) |
eh->dyn_relocs = NULL; |
/* Make sure undefined weak symbols are output as a dynamic |
symbol in PIEs. */ |
else if (h->dynindx == -1 |
&& !h->forced_local) |
{ |
if (! bfd_elf_link_record_dynamic_symbol (info, h)) |
return FALSE; |
} |
} |
} |
else if (ELIMINATE_COPY_RELOCS) |
{ |
/* For the non-shared case, discard space for relocs against |
symbols which turn out to need copy relocs or are not |
dynamic. */ |
if (!h->non_got_ref |
&& ((h->def_dynamic |
&& !h->def_regular) |
|| (htab->elf.dynamic_sections_created |
&& (h->root.type == bfd_link_hash_undefweak |
|| h->root.type == bfd_link_hash_undefined)))) |
{ |
/* Make sure this symbol is output as a dynamic symbol. |
Undefined weak syms won't yet be marked as dynamic. */ |
if (h->dynindx == -1 |
&& !h->forced_local) |
{ |
if (! bfd_elf_link_record_dynamic_symbol (info, h)) |
return FALSE; |
} |
/* If that succeeded, we know we'll be keeping all the |
relocs. */ |
if (h->dynindx != -1) |
goto keep; |
} |
eh->dyn_relocs = NULL; |
keep: ; |
} |
/* Finally, allocate space. */ |
for (p = eh->dyn_relocs; p != NULL; p = p->next) |
{ |
asection *sreloc; |
sreloc = elf_section_data (p->sec)->sreloc; |
BFD_ASSERT (sreloc != NULL); |
sreloc->size += p->count * sizeof (Elf32_External_Rel); |
} |
return TRUE; |
} |
/* Allocate space in .plt, .got and associated reloc sections for |
local dynamic relocs. */ |
static bfd_boolean |
elf_i386_allocate_local_dynrelocs (void **slot, void *inf) |
{ |
struct elf_link_hash_entry *h |
= (struct elf_link_hash_entry *) *slot; |
if (h->type != STT_GNU_IFUNC |
|| !h->def_regular |
|| !h->ref_regular |
|| !h->forced_local |
|| h->root.type != bfd_link_hash_defined) |
abort (); |
return elf_i386_allocate_dynrelocs (h, inf); |
} |
/* Find any dynamic relocs that apply to read-only sections. */ |
static bfd_boolean |
elf_i386_readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf) |
{ |
struct elf_i386_link_hash_entry *eh; |
struct elf_dyn_relocs *p; |
/* Skip local IFUNC symbols. */ |
if (h->forced_local && h->type == STT_GNU_IFUNC) |
return TRUE; |
eh = (struct elf_i386_link_hash_entry *) h; |
for (p = eh->dyn_relocs; p != NULL; p = p->next) |
{ |
asection *s = p->sec->output_section; |
if (s != NULL && (s->flags & SEC_READONLY) != 0) |
{ |
struct bfd_link_info *info = (struct bfd_link_info *) inf; |
info->flags |= DF_TEXTREL; |
if (info->warn_shared_textrel && info->shared) |
info->callbacks->einfo (_("%P: %B: warning: relocation against `%s' in readonly section `%A'.\n"), |
p->sec->owner, h->root.root.string, |
p->sec); |
/* Not an error, just cut short the traversal. */ |
return FALSE; |
} |
} |
return TRUE; |
} |
/* Convert |
mov foo@GOT(%reg), %reg |
to |
lea foo@GOTOFF(%reg), %reg |
with the local symbol, foo. */ |
static bfd_boolean |
elf_i386_convert_mov_to_lea (bfd *abfd, asection *sec, |
struct bfd_link_info *link_info) |
{ |
Elf_Internal_Shdr *symtab_hdr; |
Elf_Internal_Rela *internal_relocs; |
Elf_Internal_Rela *irel, *irelend; |
bfd_byte *contents; |
struct elf_i386_link_hash_table *htab; |
bfd_boolean changed_contents; |
bfd_boolean changed_relocs; |
bfd_signed_vma *local_got_refcounts; |
/* Don't even try to convert non-ELF outputs. */ |
if (!is_elf_hash_table (link_info->hash)) |
return FALSE; |
/* Nothing to do if there are no codes, no relocations or no output. */ |
if ((sec->flags & (SEC_CODE | SEC_RELOC)) != (SEC_CODE | SEC_RELOC) |
|| sec->reloc_count == 0 |
|| discarded_section (sec)) |
return TRUE; |
symtab_hdr = &elf_tdata (abfd)->symtab_hdr; |
/* Load the relocations for this section. */ |
internal_relocs = (_bfd_elf_link_read_relocs |
(abfd, sec, NULL, (Elf_Internal_Rela *) NULL, |
link_info->keep_memory)); |
if (internal_relocs == NULL) |
return FALSE; |
htab = elf_i386_hash_table (link_info); |
changed_contents = FALSE; |
changed_relocs = FALSE; |
local_got_refcounts = elf_local_got_refcounts (abfd); |
/* Get the section contents. */ |
if (elf_section_data (sec)->this_hdr.contents != NULL) |
contents = elf_section_data (sec)->this_hdr.contents; |
else |
{ |
if (!bfd_malloc_and_get_section (abfd, sec, &contents)) |
goto error_return; |
} |
irelend = internal_relocs + sec->reloc_count; |
for (irel = internal_relocs; irel < irelend; irel++) |
{ |
unsigned int r_type = ELF32_R_TYPE (irel->r_info); |
unsigned int r_symndx = ELF32_R_SYM (irel->r_info); |
unsigned int indx; |
struct elf_link_hash_entry *h; |
if (r_type != R_386_GOT32) |
continue; |
/* Get the symbol referred to by the reloc. */ |
if (r_symndx < symtab_hdr->sh_info) |
{ |
Elf_Internal_Sym *isym; |
isym = bfd_sym_from_r_symndx (&htab->sym_cache, |
abfd, r_symndx); |
/* STT_GNU_IFUNC must keep R_386_GOT32 relocation. */ |
if (ELF_ST_TYPE (isym->st_info) != STT_GNU_IFUNC |
&& bfd_get_8 (input_bfd, |
contents + irel->r_offset - 2) == 0x8b) |
{ |
bfd_put_8 (output_bfd, 0x8d, |
contents + irel->r_offset - 2); |
irel->r_info = ELF32_R_INFO (r_symndx, R_386_GOTOFF); |
if (local_got_refcounts != NULL |
&& local_got_refcounts[r_symndx] > 0) |
local_got_refcounts[r_symndx] -= 1; |
changed_contents = TRUE; |
changed_relocs = TRUE; |
} |
continue; |
} |
indx = r_symndx - symtab_hdr->sh_info; |
h = elf_sym_hashes (abfd)[indx]; |
BFD_ASSERT (h != NULL); |
while (h->root.type == bfd_link_hash_indirect |
|| h->root.type == bfd_link_hash_warning) |
h = (struct elf_link_hash_entry *) h->root.u.i.link; |
/* STT_GNU_IFUNC must keep R_386_GOT32 relocation. We also avoid |
optimizing _DYNAMIC since ld.so may use its link-time address. */ |
if (h->def_regular |
&& h->type != STT_GNU_IFUNC |
&& h != htab->elf.hdynamic |
&& SYMBOL_REFERENCES_LOCAL (link_info, h) |
&& bfd_get_8 (input_bfd, |
contents + irel->r_offset - 2) == 0x8b) |
{ |
bfd_put_8 (output_bfd, 0x8d, |
contents + irel->r_offset - 2); |
irel->r_info = ELF32_R_INFO (r_symndx, R_386_GOTOFF); |
if (h->got.refcount > 0) |
h->got.refcount -= 1; |
changed_contents = TRUE; |
changed_relocs = TRUE; |
} |
} |
if (contents != NULL |
&& elf_section_data (sec)->this_hdr.contents != contents) |
{ |
if (!changed_contents && !link_info->keep_memory) |
free (contents); |
else |
{ |
/* Cache the section contents for elf_link_input_bfd. */ |
elf_section_data (sec)->this_hdr.contents = contents; |
} |
} |
if (elf_section_data (sec)->relocs != internal_relocs) |
{ |
if (!changed_relocs) |
free (internal_relocs); |
else |
elf_section_data (sec)->relocs = internal_relocs; |
} |
return TRUE; |
error_return: |
if (contents != NULL |
&& elf_section_data (sec)->this_hdr.contents != contents) |
free (contents); |
if (internal_relocs != NULL |
&& elf_section_data (sec)->relocs != internal_relocs) |
free (internal_relocs); |
return FALSE; |
} |
/* Set the sizes of the dynamic sections. */ |
static bfd_boolean |
elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) |
{ |
struct elf_i386_link_hash_table *htab; |
bfd *dynobj; |
asection *s; |
bfd_boolean relocs; |
bfd *ibfd; |
htab = elf_i386_hash_table (info); |
if (htab == NULL) |
return FALSE; |
dynobj = htab->elf.dynobj; |
if (dynobj == NULL) |
abort (); |
if (htab->elf.dynamic_sections_created) |
{ |
/* Set the contents of the .interp section to the interpreter. */ |
if (info->executable) |
{ |
s = bfd_get_linker_section (dynobj, ".interp"); |
if (s == NULL) |
abort (); |
s->size = sizeof ELF_DYNAMIC_INTERPRETER; |
s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; |
} |
} |
/* Set up .got offsets for local syms, and space for local dynamic |
relocs. */ |
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) |
{ |
bfd_signed_vma *local_got; |
bfd_signed_vma *end_local_got; |
char *local_tls_type; |
bfd_vma *local_tlsdesc_gotent; |
bfd_size_type locsymcount; |
Elf_Internal_Shdr *symtab_hdr; |
asection *srel; |
if (! is_i386_elf (ibfd)) |
continue; |
for (s = ibfd->sections; s != NULL; s = s->next) |
{ |
struct elf_dyn_relocs *p; |
if (!elf_i386_convert_mov_to_lea (ibfd, s, info)) |
return FALSE; |
for (p = ((struct elf_dyn_relocs *) |
elf_section_data (s)->local_dynrel); |
p != NULL; |
p = p->next) |
{ |
if (!bfd_is_abs_section (p->sec) |
&& bfd_is_abs_section (p->sec->output_section)) |
{ |
/* Input section has been discarded, either because |
it is a copy of a linkonce section or due to |
linker script /DISCARD/, so we'll be discarding |
the relocs too. */ |
} |
else if (get_elf_i386_backend_data (output_bfd)->is_vxworks |
&& strcmp (p->sec->output_section->name, |
".tls_vars") == 0) |
{ |
/* Relocations in vxworks .tls_vars sections are |
handled specially by the loader. */ |
} |
else if (p->count != 0) |
{ |
srel = elf_section_data (p->sec)->sreloc; |
srel->size += p->count * sizeof (Elf32_External_Rel); |
if ((p->sec->output_section->flags & SEC_READONLY) != 0 |
&& (info->flags & DF_TEXTREL) == 0) |
{ |
info->flags |= DF_TEXTREL; |
if (info->warn_shared_textrel && info->shared) |
info->callbacks->einfo (_("%P: %B: warning: relocation in readonly section `%A'.\n"), |
p->sec->owner, p->sec); |
} |
} |
} |
} |
local_got = elf_local_got_refcounts (ibfd); |
if (!local_got) |
continue; |
symtab_hdr = &elf_symtab_hdr (ibfd); |
locsymcount = symtab_hdr->sh_info; |
end_local_got = local_got + locsymcount; |
local_tls_type = elf_i386_local_got_tls_type (ibfd); |
local_tlsdesc_gotent = elf_i386_local_tlsdesc_gotent (ibfd); |
s = htab->elf.sgot; |
srel = htab->elf.srelgot; |
for (; local_got < end_local_got; |
++local_got, ++local_tls_type, ++local_tlsdesc_gotent) |
{ |
*local_tlsdesc_gotent = (bfd_vma) -1; |
if (*local_got > 0) |
{ |
if (GOT_TLS_GDESC_P (*local_tls_type)) |
{ |
*local_tlsdesc_gotent = htab->elf.sgotplt->size |
- elf_i386_compute_jump_table_size (htab); |
htab->elf.sgotplt->size += 8; |
*local_got = (bfd_vma) -2; |
} |
if (! GOT_TLS_GDESC_P (*local_tls_type) |
|| GOT_TLS_GD_P (*local_tls_type)) |
{ |
*local_got = s->size; |
s->size += 4; |
if (GOT_TLS_GD_P (*local_tls_type) |
|| *local_tls_type == GOT_TLS_IE_BOTH) |
s->size += 4; |
} |
if (info->shared |
|| GOT_TLS_GD_ANY_P (*local_tls_type) |
|| (*local_tls_type & GOT_TLS_IE)) |
{ |
if (*local_tls_type == GOT_TLS_IE_BOTH) |
srel->size += 2 * sizeof (Elf32_External_Rel); |
else if (GOT_TLS_GD_P (*local_tls_type) |
|| ! GOT_TLS_GDESC_P (*local_tls_type)) |
srel->size += sizeof (Elf32_External_Rel); |
if (GOT_TLS_GDESC_P (*local_tls_type)) |
htab->elf.srelplt->size += sizeof (Elf32_External_Rel); |
} |
} |
else |
*local_got = (bfd_vma) -1; |
} |
} |
if (htab->tls_ldm_got.refcount > 0) |
{ |
/* Allocate 2 got entries and 1 dynamic reloc for R_386_TLS_LDM |
relocs. */ |
htab->tls_ldm_got.offset = htab->elf.sgot->size; |
htab->elf.sgot->size += 8; |
htab->elf.srelgot->size += sizeof (Elf32_External_Rel); |
} |
else |
htab->tls_ldm_got.offset = -1; |
/* Allocate global sym .plt and .got entries, and space for global |
sym dynamic relocs. */ |
elf_link_hash_traverse (&htab->elf, elf_i386_allocate_dynrelocs, info); |
/* Allocate .plt and .got entries, and space for local symbols. */ |
htab_traverse (htab->loc_hash_table, |
elf_i386_allocate_local_dynrelocs, |
info); |
/* For every jump slot reserved in the sgotplt, reloc_count is |
incremented. However, when we reserve space for TLS descriptors, |
it's not incremented, so in order to compute the space reserved |
for them, it suffices to multiply the reloc count by the jump |
slot size. |
PR ld/13302: We start next_irelative_index at the end of .rela.plt |
so that R_386_IRELATIVE entries come last. */ |
if (htab->elf.srelplt) |
{ |
htab->next_tls_desc_index = htab->elf.srelplt->reloc_count; |
htab->sgotplt_jump_table_size = htab->next_tls_desc_index * 4; |
htab->next_irelative_index = htab->elf.srelplt->reloc_count - 1; |
} |
else if (htab->elf.irelplt) |
htab->next_irelative_index = htab->elf.irelplt->reloc_count - 1; |
if (htab->elf.sgotplt) |
{ |
/* Don't allocate .got.plt section if there are no GOT nor PLT |
entries and there is no reference to _GLOBAL_OFFSET_TABLE_. */ |
if ((htab->elf.hgot == NULL |
|| !htab->elf.hgot->ref_regular_nonweak) |
&& (htab->elf.sgotplt->size |
== get_elf_backend_data (output_bfd)->got_header_size) |
&& (htab->elf.splt == NULL |
|| htab->elf.splt->size == 0) |
&& (htab->elf.sgot == NULL |
|| htab->elf.sgot->size == 0) |
&& (htab->elf.iplt == NULL |
|| htab->elf.iplt->size == 0) |
&& (htab->elf.igotplt == NULL |
|| htab->elf.igotplt->size == 0)) |
htab->elf.sgotplt->size = 0; |
} |
if (htab->plt_eh_frame != NULL |
&& htab->elf.splt != NULL |
&& htab->elf.splt->size != 0 |
&& !bfd_is_abs_section (htab->elf.splt->output_section) |
&& _bfd_elf_eh_frame_present (info)) |
htab->plt_eh_frame->size = sizeof (elf_i386_eh_frame_plt); |
/* We now have determined the sizes of the various dynamic sections. |
Allocate memory for them. */ |
relocs = FALSE; |
for (s = dynobj->sections; s != NULL; s = s->next) |
{ |
bfd_boolean strip_section = TRUE; |
if ((s->flags & SEC_LINKER_CREATED) == 0) |
continue; |
if (s == htab->elf.splt |
|| s == htab->elf.sgot) |
{ |
/* Strip this section if we don't need it; see the |
comment below. */ |
/* We'd like to strip these sections if they aren't needed, but if |
we've exported dynamic symbols from them we must leave them. |
It's too late to tell BFD to get rid of the symbols. */ |
if (htab->elf.hplt != NULL) |
strip_section = FALSE; |
} |
else if (s == htab->elf.sgotplt |
|| s == htab->elf.iplt |
|| s == htab->elf.igotplt |
|| s == htab->plt_eh_frame |
|| s == htab->sdynbss) |
{ |
/* Strip these too. */ |
} |
else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rel")) |
{ |
if (s->size != 0 |
&& s != htab->elf.srelplt |
&& s != htab->srelplt2) |
relocs = TRUE; |
/* We use the reloc_count field as a counter if we need |
to copy relocs into the output file. */ |
s->reloc_count = 0; |
} |
else |
{ |
/* It's not one of our sections, so don't allocate space. */ |
continue; |
} |
if (s->size == 0) |
{ |
/* If we don't need this section, strip it from the |
output file. This is mostly to handle .rel.bss and |
.rel.plt. We must create both sections in |
create_dynamic_sections, because they must be created |
before the linker maps input sections to output |
sections. The linker does that before |
adjust_dynamic_symbol is called, and it is that |
function which decides whether anything needs to go |
into these sections. */ |
if (strip_section) |
s->flags |= SEC_EXCLUDE; |
continue; |
} |
if ((s->flags & SEC_HAS_CONTENTS) == 0) |
continue; |
/* Allocate memory for the section contents. We use bfd_zalloc |
here in case unused entries are not reclaimed before the |
section's contents are written out. This should not happen, |
but this way if it does, we get a R_386_NONE reloc instead |
of garbage. */ |
s->contents = (unsigned char *) bfd_zalloc (dynobj, s->size); |
if (s->contents == NULL) |
return FALSE; |
} |
if (htab->plt_eh_frame != NULL |
&& htab->plt_eh_frame->contents != NULL) |
{ |
memcpy (htab->plt_eh_frame->contents, elf_i386_eh_frame_plt, |
sizeof (elf_i386_eh_frame_plt)); |
bfd_put_32 (dynobj, htab->elf.splt->size, |
htab->plt_eh_frame->contents + PLT_FDE_LEN_OFFSET); |
} |
if (htab->elf.dynamic_sections_created) |
{ |
/* Add some entries to the .dynamic section. We fill in the |
values later, in elf_i386_finish_dynamic_sections, but we |
must add the entries now so that we get the correct size for |
the .dynamic section. The DT_DEBUG entry is filled in by the |
dynamic linker and used by the debugger. */ |
#define add_dynamic_entry(TAG, VAL) \ |
_bfd_elf_add_dynamic_entry (info, TAG, VAL) |
if (info->executable) |
{ |
if (!add_dynamic_entry (DT_DEBUG, 0)) |
return FALSE; |
} |
if (htab->elf.splt->size != 0) |
{ |
if (!add_dynamic_entry (DT_PLTGOT, 0) |
|| !add_dynamic_entry (DT_PLTRELSZ, 0) |
|| !add_dynamic_entry (DT_PLTREL, DT_REL) |
|| !add_dynamic_entry (DT_JMPREL, 0)) |
return FALSE; |
} |
if (relocs) |
{ |
if (!add_dynamic_entry (DT_REL, 0) |
|| !add_dynamic_entry (DT_RELSZ, 0) |
|| !add_dynamic_entry (DT_RELENT, sizeof (Elf32_External_Rel))) |
return FALSE; |
/* If any dynamic relocs apply to a read-only section, |
then we need a DT_TEXTREL entry. */ |
if ((info->flags & DF_TEXTREL) == 0) |
elf_link_hash_traverse (&htab->elf, |
elf_i386_readonly_dynrelocs, info); |
if ((info->flags & DF_TEXTREL) != 0) |
{ |
if (!add_dynamic_entry (DT_TEXTREL, 0)) |
return FALSE; |
} |
} |
if (get_elf_i386_backend_data (output_bfd)->is_vxworks |
&& !elf_vxworks_add_dynamic_entries (output_bfd, info)) |
return FALSE; |
} |
#undef add_dynamic_entry |
return TRUE; |
} |
static bfd_boolean |
elf_i386_always_size_sections (bfd *output_bfd, |
struct bfd_link_info *info) |
{ |
asection *tls_sec = elf_hash_table (info)->tls_sec; |
if (tls_sec) |
{ |
struct elf_link_hash_entry *tlsbase; |
tlsbase = elf_link_hash_lookup (elf_hash_table (info), |
"_TLS_MODULE_BASE_", |
FALSE, FALSE, FALSE); |
if (tlsbase && tlsbase->type == STT_TLS) |
{ |
struct elf_i386_link_hash_table *htab; |
struct bfd_link_hash_entry *bh = NULL; |
const struct elf_backend_data *bed |
= get_elf_backend_data (output_bfd); |
htab = elf_i386_hash_table (info); |
if (htab == NULL) |
return FALSE; |
if (!(_bfd_generic_link_add_one_symbol |
(info, output_bfd, "_TLS_MODULE_BASE_", BSF_LOCAL, |
tls_sec, 0, NULL, FALSE, |
bed->collect, &bh))) |
return FALSE; |
htab->tls_module_base = bh; |
tlsbase = (struct elf_link_hash_entry *)bh; |
tlsbase->def_regular = 1; |
tlsbase->other = STV_HIDDEN; |
(*bed->elf_backend_hide_symbol) (info, tlsbase, TRUE); |
} |
} |
return TRUE; |
} |
/* Set the correct type for an x86 ELF section. We do this by the |
section name, which is a hack, but ought to work. */ |
static bfd_boolean |
elf_i386_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, |
Elf_Internal_Shdr *hdr, |
asection *sec) |
{ |
const char *name; |
name = bfd_get_section_name (abfd, sec); |
/* This is an ugly, but unfortunately necessary hack that is |
needed when producing EFI binaries on x86. It tells |
elf.c:elf_fake_sections() not to consider ".reloc" as a section |
containing ELF relocation info. We need this hack in order to |
be able to generate ELF binaries that can be translated into |
EFI applications (which are essentially COFF objects). Those |
files contain a COFF ".reloc" section inside an ELFNN object, |
which would normally cause BFD to segfault because it would |
attempt to interpret this section as containing relocation |
entries for section "oc". With this hack enabled, ".reloc" |
will be treated as a normal data section, which will avoid the |
segfault. However, you won't be able to create an ELFNN binary |
with a section named "oc" that needs relocations, but that's |
the kind of ugly side-effects you get when detecting section |
types based on their names... In practice, this limitation is |
unlikely to bite. */ |
if (strcmp (name, ".reloc") == 0) |
hdr->sh_type = SHT_PROGBITS; |
return TRUE; |
} |
/* _TLS_MODULE_BASE_ needs to be treated especially when linking |
executables. Rather than setting it to the beginning of the TLS |
section, we have to set it to the end. This function may be called |
multiple times, it is idempotent. */ |
static void |
elf_i386_set_tls_module_base (struct bfd_link_info *info) |
{ |
struct elf_i386_link_hash_table *htab; |
struct bfd_link_hash_entry *base; |
if (!info->executable) |
return; |
htab = elf_i386_hash_table (info); |
if (htab == NULL) |
return; |
base = htab->tls_module_base; |
if (base == NULL) |
return; |
base->u.def.value = htab->elf.tls_size; |
} |
/* Return the base VMA address which should be subtracted from real addresses |
when resolving @dtpoff relocation. |
This is PT_TLS segment p_vaddr. */ |
static bfd_vma |
elf_i386_dtpoff_base (struct bfd_link_info *info) |
{ |
/* If tls_sec is NULL, we should have signalled an error already. */ |
if (elf_hash_table (info)->tls_sec == NULL) |
return 0; |
return elf_hash_table (info)->tls_sec->vma; |
} |
/* Return the relocation value for @tpoff relocation |
if STT_TLS virtual address is ADDRESS. */ |
static bfd_vma |
elf_i386_tpoff (struct bfd_link_info *info, bfd_vma address) |
{ |
struct elf_link_hash_table *htab = elf_hash_table (info); |
const struct elf_backend_data *bed = get_elf_backend_data (info->output_bfd); |
bfd_vma static_tls_size; |
/* If tls_sec is NULL, we should have signalled an error already. */ |
if (htab->tls_sec == NULL) |
return 0; |
/* Consider special static TLS alignment requirements. */ |
static_tls_size = BFD_ALIGN (htab->tls_size, bed->static_tls_alignment); |
return static_tls_size + htab->tls_sec->vma - address; |
} |
/* Relocate an i386 ELF section. */ |
static bfd_boolean |
elf_i386_relocate_section (bfd *output_bfd, |
struct bfd_link_info *info, |
bfd *input_bfd, |
asection *input_section, |
bfd_byte *contents, |
Elf_Internal_Rela *relocs, |
Elf_Internal_Sym *local_syms, |
asection **local_sections) |
{ |
struct elf_i386_link_hash_table *htab; |
Elf_Internal_Shdr *symtab_hdr; |
struct elf_link_hash_entry **sym_hashes; |
bfd_vma *local_got_offsets; |
bfd_vma *local_tlsdesc_gotents; |
Elf_Internal_Rela *rel; |
Elf_Internal_Rela *relend; |
bfd_boolean is_vxworks_tls; |
unsigned plt_entry_size; |
BFD_ASSERT (is_i386_elf (input_bfd)); |
htab = elf_i386_hash_table (info); |
if (htab == NULL) |
return FALSE; |
symtab_hdr = &elf_symtab_hdr (input_bfd); |
sym_hashes = elf_sym_hashes (input_bfd); |
local_got_offsets = elf_local_got_offsets (input_bfd); |
local_tlsdesc_gotents = elf_i386_local_tlsdesc_gotent (input_bfd); |
/* We have to handle relocations in vxworks .tls_vars sections |
specially, because the dynamic loader is 'weird'. */ |
is_vxworks_tls = (get_elf_i386_backend_data (output_bfd)->is_vxworks |
&& info->shared |
&& !strcmp (input_section->output_section->name, |
".tls_vars")); |
elf_i386_set_tls_module_base (info); |
plt_entry_size = GET_PLT_ENTRY_SIZE (output_bfd); |
rel = relocs; |
relend = relocs + input_section->reloc_count; |
for (; rel < relend; rel++) |
{ |
unsigned int r_type; |
reloc_howto_type *howto; |
unsigned long r_symndx; |
struct elf_link_hash_entry *h; |
Elf_Internal_Sym *sym; |
asection *sec; |
bfd_vma off, offplt; |
bfd_vma relocation; |
bfd_boolean unresolved_reloc; |
bfd_reloc_status_type r; |
unsigned int indx; |
int tls_type; |
bfd_vma st_size; |
r_type = ELF32_R_TYPE (rel->r_info); |
if (r_type == R_386_GNU_VTINHERIT |
|| r_type == R_386_GNU_VTENTRY) |
continue; |
if ((indx = r_type) >= R_386_standard |
&& ((indx = r_type - R_386_ext_offset) - R_386_standard |
>= R_386_ext - R_386_standard) |
&& ((indx = r_type - R_386_tls_offset) - R_386_ext |
>= R_386_irelative - R_386_ext)) |
{ |
(*_bfd_error_handler) |
(_("%B: unrecognized relocation (0x%x) in section `%A'"), |
input_bfd, input_section, r_type); |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
howto = elf_howto_table + indx; |
r_symndx = ELF32_R_SYM (rel->r_info); |
h = NULL; |
sym = NULL; |
sec = NULL; |
unresolved_reloc = FALSE; |
if (r_symndx < symtab_hdr->sh_info) |
{ |
sym = local_syms + r_symndx; |
sec = local_sections[r_symndx]; |
relocation = (sec->output_section->vma |
+ sec->output_offset |
+ sym->st_value); |
st_size = sym->st_size; |
if (ELF_ST_TYPE (sym->st_info) == STT_SECTION |
&& ((sec->flags & SEC_MERGE) != 0 |
|| (info->relocatable |
&& sec->output_offset != 0))) |
{ |
bfd_vma addend; |
bfd_byte *where = contents + rel->r_offset; |
switch (howto->size) |
{ |
case 0: |
addend = bfd_get_8 (input_bfd, where); |
if (howto->pc_relative) |
{ |
addend = (addend ^ 0x80) - 0x80; |
addend += 1; |
} |
break; |
case 1: |
addend = bfd_get_16 (input_bfd, where); |
if (howto->pc_relative) |
{ |
addend = (addend ^ 0x8000) - 0x8000; |
addend += 2; |
} |
break; |
case 2: |
addend = bfd_get_32 (input_bfd, where); |
if (howto->pc_relative) |
{ |
addend = (addend ^ 0x80000000) - 0x80000000; |
addend += 4; |
} |
break; |
default: |
abort (); |
} |
if (info->relocatable) |
addend += sec->output_offset; |
else |
{ |
asection *msec = sec; |
addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, |
addend); |
addend -= relocation; |
addend += msec->output_section->vma + msec->output_offset; |
} |
switch (howto->size) |
{ |
case 0: |
/* FIXME: overflow checks. */ |
if (howto->pc_relative) |
addend -= 1; |
bfd_put_8 (input_bfd, addend, where); |
break; |
case 1: |
if (howto->pc_relative) |
addend -= 2; |
bfd_put_16 (input_bfd, addend, where); |
break; |
case 2: |
if (howto->pc_relative) |
addend -= 4; |
bfd_put_32 (input_bfd, addend, where); |
break; |
} |
} |
else if (!info->relocatable |
&& ELF32_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) |
{ |
/* Relocate against local STT_GNU_IFUNC symbol. */ |
h = elf_i386_get_local_sym_hash (htab, input_bfd, rel, |
FALSE); |
if (h == NULL) |
abort (); |
/* Set STT_GNU_IFUNC symbol value. */ |
h->root.u.def.value = sym->st_value; |
h->root.u.def.section = sec; |
} |
} |
else |
{ |
bfd_boolean warned ATTRIBUTE_UNUSED; |
RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, |
r_symndx, symtab_hdr, sym_hashes, |
h, sec, relocation, |
unresolved_reloc, warned); |
st_size = h->size; |
} |
if (sec != NULL && discarded_section (sec)) |
RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, |
rel, 1, relend, howto, 0, contents); |
if (info->relocatable) |
continue; |
/* Since STT_GNU_IFUNC symbol must go through PLT, we handle |
it here if it is defined in a non-shared object. */ |
if (h != NULL |
&& h->type == STT_GNU_IFUNC |
&& h->def_regular) |
{ |
asection *plt, *gotplt, *base_got; |
bfd_vma plt_index; |
const char *name; |
if ((input_section->flags & SEC_ALLOC) == 0 |
|| h->plt.offset == (bfd_vma) -1) |
abort (); |
/* STT_GNU_IFUNC symbol must go through PLT. */ |
if (htab->elf.splt != NULL) |
{ |
plt = htab->elf.splt; |
gotplt = htab->elf.sgotplt; |
} |
else |
{ |
plt = htab->elf.iplt; |
gotplt = htab->elf.igotplt; |
} |
relocation = (plt->output_section->vma |
+ plt->output_offset + h->plt.offset); |
switch (r_type) |
{ |
default: |
if (h->root.root.string) |
name = h->root.root.string; |
else |
name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, |
NULL); |
(*_bfd_error_handler) |
(_("%B: relocation %s against STT_GNU_IFUNC " |
"symbol `%s' isn't handled by %s"), input_bfd, |
elf_howto_table[r_type].name, |
name, __FUNCTION__); |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
case R_386_32: |
/* Generate dynamic relcoation only when there is a |
non-GOT reference in a shared object. */ |
if (info->shared && h->non_got_ref) |
{ |
Elf_Internal_Rela outrel; |
asection *sreloc; |
bfd_vma offset; |
/* Need a dynamic relocation to get the real function |
adddress. */ |
offset = _bfd_elf_section_offset (output_bfd, |
info, |
input_section, |
rel->r_offset); |
if (offset == (bfd_vma) -1 |
|| offset == (bfd_vma) -2) |
abort (); |
outrel.r_offset = (input_section->output_section->vma |
+ input_section->output_offset |
+ offset); |
if (h->dynindx == -1 |
|| h->forced_local |
|| info->executable) |
{ |
/* This symbol is resolved locally. */ |
outrel.r_info = ELF32_R_INFO (0, R_386_IRELATIVE); |
bfd_put_32 (output_bfd, |
(h->root.u.def.value |
+ h->root.u.def.section->output_section->vma |
+ h->root.u.def.section->output_offset), |
contents + offset); |
} |
else |
outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); |
sreloc = htab->elf.irelifunc; |
elf_append_rel (output_bfd, sreloc, &outrel); |
/* If this reloc is against an external symbol, we |
do not want to fiddle with the addend. Otherwise, |
we need to include the symbol value so that it |
becomes an addend for the dynamic reloc. For an |
internal symbol, we have updated addend. */ |
continue; |
} |
/* FALLTHROUGH */ |
case R_386_PC32: |
case R_386_PLT32: |
goto do_relocation; |
case R_386_GOT32: |
base_got = htab->elf.sgot; |
off = h->got.offset; |
if (base_got == NULL) |
abort (); |
if (off == (bfd_vma) -1) |
{ |
/* We can't use h->got.offset here to save state, or |
even just remember the offset, as finish_dynamic_symbol |
would use that as offset into .got. */ |
if (htab->elf.splt != NULL) |
{ |
plt_index = h->plt.offset / plt_entry_size - 1; |
off = (plt_index + 3) * 4; |
base_got = htab->elf.sgotplt; |
} |
else |
{ |
plt_index = h->plt.offset / plt_entry_size; |
off = plt_index * 4; |
base_got = htab->elf.igotplt; |
} |
if (h->dynindx == -1 |
|| h->forced_local |
|| info->symbolic) |
{ |
/* This references the local defitionion. We must |
initialize this entry in the global offset table. |
Since the offset must always be a multiple of 8, |
we use the least significant bit to record |
whether we have initialized it already. |
When doing a dynamic link, we create a .rela.got |
relocation entry to initialize the value. This |
is done in the finish_dynamic_symbol routine. */ |
if ((off & 1) != 0) |
off &= ~1; |
else |
{ |
bfd_put_32 (output_bfd, relocation, |
base_got->contents + off); |
h->got.offset |= 1; |
} |
} |
relocation = off; |
/* Adjust for static executables. */ |
if (htab->elf.splt == NULL) |
relocation += gotplt->output_offset; |
} |
else |
{ |
relocation = (base_got->output_section->vma |
+ base_got->output_offset + off |
- gotplt->output_section->vma |
- gotplt->output_offset); |
/* Adjust for static executables. */ |
if (htab->elf.splt == NULL) |
relocation += gotplt->output_offset; |
} |
goto do_relocation; |
case R_386_GOTOFF: |
relocation -= (gotplt->output_section->vma |
+ gotplt->output_offset); |
goto do_relocation; |
} |
} |
switch (r_type) |
{ |
case R_386_GOT32: |
/* Relocation is to the entry for this symbol in the global |
offset table. */ |
if (htab->elf.sgot == NULL) |
abort (); |
if (h != NULL) |
{ |
bfd_boolean dyn; |
off = h->got.offset; |
dyn = htab->elf.dynamic_sections_created; |
if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) |
|| (info->shared |
&& SYMBOL_REFERENCES_LOCAL (info, h)) |
|| (ELF_ST_VISIBILITY (h->other) |
&& h->root.type == bfd_link_hash_undefweak)) |
{ |
/* This is actually a static link, or it is a |
-Bsymbolic link and the symbol is defined |
locally, or the symbol was forced to be local |
because of a version file. We must initialize |
this entry in the global offset table. Since the |
offset must always be a multiple of 4, we use the |
least significant bit to record whether we have |
initialized it already. |
When doing a dynamic link, we create a .rel.got |
relocation entry to initialize the value. This |
is done in the finish_dynamic_symbol routine. */ |
if ((off & 1) != 0) |
off &= ~1; |
else |
{ |
bfd_put_32 (output_bfd, relocation, |
htab->elf.sgot->contents + off); |
h->got.offset |= 1; |
} |
} |
else |
unresolved_reloc = FALSE; |
} |
else |
{ |
if (local_got_offsets == NULL) |
abort (); |
off = local_got_offsets[r_symndx]; |
/* The offset must always be a multiple of 4. We use |
the least significant bit to record whether we have |
already generated the necessary reloc. */ |
if ((off & 1) != 0) |
off &= ~1; |
else |
{ |
bfd_put_32 (output_bfd, relocation, |
htab->elf.sgot->contents + off); |
if (info->shared) |
{ |
asection *s; |
Elf_Internal_Rela outrel; |
s = htab->elf.srelgot; |
if (s == NULL) |
abort (); |
outrel.r_offset = (htab->elf.sgot->output_section->vma |
+ htab->elf.sgot->output_offset |
+ off); |
outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); |
elf_append_rel (output_bfd, s, &outrel); |
} |
local_got_offsets[r_symndx] |= 1; |
} |
} |
if (off >= (bfd_vma) -2) |
abort (); |
relocation = htab->elf.sgot->output_section->vma |
+ htab->elf.sgot->output_offset + off |
- htab->elf.sgotplt->output_section->vma |
- htab->elf.sgotplt->output_offset; |
break; |
case R_386_GOTOFF: |
/* Relocation is relative to the start of the global offset |
table. */ |
/* Check to make sure it isn't a protected function symbol |
for shared library since it may not be local when used |
as function address. We also need to make sure that a |
symbol is defined locally. */ |
if (info->shared && h) |
{ |
if (!h->def_regular) |
{ |
const char *v; |
switch (ELF_ST_VISIBILITY (h->other)) |
{ |
case STV_HIDDEN: |
v = _("hidden symbol"); |
break; |
case STV_INTERNAL: |
v = _("internal symbol"); |
break; |
case STV_PROTECTED: |
v = _("protected symbol"); |
break; |
default: |
v = _("symbol"); |
break; |
} |
(*_bfd_error_handler) |
(_("%B: relocation R_386_GOTOFF against undefined %s `%s' can not be used when making a shared object"), |
input_bfd, v, h->root.root.string); |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
else if (!info->executable |
&& !SYMBOLIC_BIND (info, h) |
&& h->type == STT_FUNC |
&& ELF_ST_VISIBILITY (h->other) == STV_PROTECTED) |
{ |
(*_bfd_error_handler) |
(_("%B: relocation R_386_GOTOFF against protected function `%s' can not be used when making a shared object"), |
input_bfd, h->root.root.string); |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
} |
/* Note that sgot is not involved in this |
calculation. We always want the start of .got.plt. If we |
defined _GLOBAL_OFFSET_TABLE_ in a different way, as is |
permitted by the ABI, we might have to change this |
calculation. */ |
relocation -= htab->elf.sgotplt->output_section->vma |
+ htab->elf.sgotplt->output_offset; |
break; |
case R_386_GOTPC: |
/* Use global offset table as symbol value. */ |
relocation = htab->elf.sgotplt->output_section->vma |
+ htab->elf.sgotplt->output_offset; |
unresolved_reloc = FALSE; |
break; |
case R_386_PLT32: |
/* Relocation is to the entry for this symbol in the |
procedure linkage table. */ |
/* Resolve a PLT32 reloc against a local symbol directly, |
without using the procedure linkage table. */ |
if (h == NULL) |
break; |
if (h->plt.offset == (bfd_vma) -1 |
|| htab->elf.splt == NULL) |
{ |
/* We didn't make a PLT entry for this symbol. This |
happens when statically linking PIC code, or when |
using -Bsymbolic. */ |
break; |
} |
relocation = (htab->elf.splt->output_section->vma |
+ htab->elf.splt->output_offset |
+ h->plt.offset); |
unresolved_reloc = FALSE; |
break; |
case R_386_SIZE32: |
/* Set to symbol size. */ |
relocation = st_size; |
/* Fall through. */ |
case R_386_32: |
case R_386_PC32: |
if ((input_section->flags & SEC_ALLOC) == 0 |
|| is_vxworks_tls) |
break; |
if ((info->shared |
&& (h == NULL |
|| ELF_ST_VISIBILITY (h->other) == STV_DEFAULT |
|| h->root.type != bfd_link_hash_undefweak) |
&& ((r_type != R_386_PC32 && r_type != R_386_SIZE32) |
|| !SYMBOL_CALLS_LOCAL (info, h))) |
|| (ELIMINATE_COPY_RELOCS |
&& !info->shared |
&& h != NULL |
&& h->dynindx != -1 |
&& !h->non_got_ref |
&& ((h->def_dynamic |
&& !h->def_regular) |
|| h->root.type == bfd_link_hash_undefweak |
|| h->root.type == bfd_link_hash_undefined))) |
{ |
Elf_Internal_Rela outrel; |
bfd_boolean skip, relocate; |
asection *sreloc; |
/* When generating a shared object, these relocations |
are copied into the output file to be resolved at run |
time. */ |
skip = FALSE; |
relocate = FALSE; |
outrel.r_offset = |
_bfd_elf_section_offset (output_bfd, info, input_section, |
rel->r_offset); |
if (outrel.r_offset == (bfd_vma) -1) |
skip = TRUE; |
else if (outrel.r_offset == (bfd_vma) -2) |
skip = TRUE, relocate = TRUE; |
outrel.r_offset += (input_section->output_section->vma |
+ input_section->output_offset); |
if (skip) |
memset (&outrel, 0, sizeof outrel); |
else if (h != NULL |
&& h->dynindx != -1 |
&& (r_type == R_386_PC32 |
|| !info->shared |
|| !SYMBOLIC_BIND (info, h) |
|| !h->def_regular)) |
outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); |
else |
{ |
/* This symbol is local, or marked to become local. */ |
relocate = TRUE; |
outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); |
} |
sreloc = elf_section_data (input_section)->sreloc; |
if (sreloc == NULL || sreloc->contents == NULL) |
{ |
r = bfd_reloc_notsupported; |
goto check_relocation_error; |
} |
elf_append_rel (output_bfd, sreloc, &outrel); |
/* If this reloc is against an external symbol, we do |
not want to fiddle with the addend. Otherwise, we |
need to include the symbol value so that it becomes |
an addend for the dynamic reloc. */ |
if (! relocate) |
continue; |
} |
break; |
case R_386_TLS_IE: |
if (!info->executable) |
{ |
Elf_Internal_Rela outrel; |
asection *sreloc; |
outrel.r_offset = rel->r_offset |
+ input_section->output_section->vma |
+ input_section->output_offset; |
outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); |
sreloc = elf_section_data (input_section)->sreloc; |
if (sreloc == NULL) |
abort (); |
elf_append_rel (output_bfd, sreloc, &outrel); |
} |
/* Fall through */ |
case R_386_TLS_GD: |
case R_386_TLS_GOTDESC: |
case R_386_TLS_DESC_CALL: |
case R_386_TLS_IE_32: |
case R_386_TLS_GOTIE: |
tls_type = GOT_UNKNOWN; |
if (h == NULL && local_got_offsets) |
tls_type = elf_i386_local_got_tls_type (input_bfd) [r_symndx]; |
else if (h != NULL) |
tls_type = elf_i386_hash_entry(h)->tls_type; |
if (tls_type == GOT_TLS_IE) |
tls_type = GOT_TLS_IE_NEG; |
if (! elf_i386_tls_transition (info, input_bfd, |
input_section, contents, |
symtab_hdr, sym_hashes, |
&r_type, tls_type, rel, |
relend, h, r_symndx)) |
return FALSE; |
if (r_type == R_386_TLS_LE_32) |
{ |
BFD_ASSERT (! unresolved_reloc); |
if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GD) |
{ |
unsigned int type; |
bfd_vma roff; |
/* GD->LE transition. */ |
type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2); |
if (type == 0x04) |
{ |
/* leal foo(,%reg,1), %eax; call ___tls_get_addr |
Change it into: |
movl %gs:0, %eax; subl $foo@tpoff, %eax |
(6 byte form of subl). */ |
memcpy (contents + rel->r_offset - 3, |
"\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12); |
roff = rel->r_offset + 5; |
} |
else |
{ |
/* leal foo(%reg), %eax; call ___tls_get_addr; nop |
Change it into: |
movl %gs:0, %eax; subl $foo@tpoff, %eax |
(6 byte form of subl). */ |
memcpy (contents + rel->r_offset - 2, |
"\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12); |
roff = rel->r_offset + 6; |
} |
bfd_put_32 (output_bfd, elf_i386_tpoff (info, relocation), |
contents + roff); |
/* Skip R_386_PC32/R_386_PLT32. */ |
rel++; |
continue; |
} |
else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GOTDESC) |
{ |
/* GDesc -> LE transition. |
It's originally something like: |
leal x@tlsdesc(%ebx), %eax |
leal x@ntpoff, %eax |
Registers other than %eax may be set up here. */ |
unsigned int val; |
bfd_vma roff; |
roff = rel->r_offset; |
val = bfd_get_8 (input_bfd, contents + roff - 1); |
/* Now modify the instruction as appropriate. */ |
/* aoliva FIXME: remove the above and xor the byte |
below with 0x86. */ |
bfd_put_8 (output_bfd, val ^ 0x86, |
contents + roff - 1); |
bfd_put_32 (output_bfd, -elf_i386_tpoff (info, relocation), |
contents + roff); |
continue; |
} |
else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_DESC_CALL) |
{ |
/* GDesc -> LE transition. |
It's originally: |
call *(%eax) |
Turn it into: |
xchg %ax,%ax */ |
bfd_vma roff; |
roff = rel->r_offset; |
bfd_put_8 (output_bfd, 0x66, contents + roff); |
bfd_put_8 (output_bfd, 0x90, contents + roff + 1); |
continue; |
} |
else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_IE) |
{ |
unsigned int val; |
/* IE->LE transition: |
Originally it can be one of: |
movl foo, %eax |
movl foo, %reg |
addl foo, %reg |
We change it into: |
movl $foo, %eax |
movl $foo, %reg |
addl $foo, %reg. */ |
val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1); |
if (val == 0xa1) |
{ |
/* movl foo, %eax. */ |
bfd_put_8 (output_bfd, 0xb8, |
contents + rel->r_offset - 1); |
} |
else |
{ |
unsigned int type; |
type = bfd_get_8 (input_bfd, |
contents + rel->r_offset - 2); |
switch (type) |
{ |
case 0x8b: |
/* movl */ |
bfd_put_8 (output_bfd, 0xc7, |
contents + rel->r_offset - 2); |
bfd_put_8 (output_bfd, |
0xc0 | ((val >> 3) & 7), |
contents + rel->r_offset - 1); |
break; |
case 0x03: |
/* addl */ |
bfd_put_8 (output_bfd, 0x81, |
contents + rel->r_offset - 2); |
bfd_put_8 (output_bfd, |
0xc0 | ((val >> 3) & 7), |
contents + rel->r_offset - 1); |
break; |
default: |
BFD_FAIL (); |
break; |
} |
} |
bfd_put_32 (output_bfd, -elf_i386_tpoff (info, relocation), |
contents + rel->r_offset); |
continue; |
} |
else |
{ |
unsigned int val, type; |
/* {IE_32,GOTIE}->LE transition: |
Originally it can be one of: |
subl foo(%reg1), %reg2 |
movl foo(%reg1), %reg2 |
addl foo(%reg1), %reg2 |
We change it into: |
subl $foo, %reg2 |
movl $foo, %reg2 (6 byte form) |
addl $foo, %reg2. */ |
type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2); |
val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1); |
if (type == 0x8b) |
{ |
/* movl */ |
bfd_put_8 (output_bfd, 0xc7, |
contents + rel->r_offset - 2); |
bfd_put_8 (output_bfd, 0xc0 | ((val >> 3) & 7), |
contents + rel->r_offset - 1); |
} |
else if (type == 0x2b) |
{ |
/* subl */ |
bfd_put_8 (output_bfd, 0x81, |
contents + rel->r_offset - 2); |
bfd_put_8 (output_bfd, 0xe8 | ((val >> 3) & 7), |
contents + rel->r_offset - 1); |
} |
else if (type == 0x03) |
{ |
/* addl */ |
bfd_put_8 (output_bfd, 0x81, |
contents + rel->r_offset - 2); |
bfd_put_8 (output_bfd, 0xc0 | ((val >> 3) & 7), |
contents + rel->r_offset - 1); |
} |
else |
BFD_FAIL (); |
if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GOTIE) |
bfd_put_32 (output_bfd, -elf_i386_tpoff (info, relocation), |
contents + rel->r_offset); |
else |
bfd_put_32 (output_bfd, elf_i386_tpoff (info, relocation), |
contents + rel->r_offset); |
continue; |
} |
} |
if (htab->elf.sgot == NULL) |
abort (); |
if (h != NULL) |
{ |
off = h->got.offset; |
offplt = elf_i386_hash_entry (h)->tlsdesc_got; |
} |
else |
{ |
if (local_got_offsets == NULL) |
abort (); |
off = local_got_offsets[r_symndx]; |
offplt = local_tlsdesc_gotents[r_symndx]; |
} |
if ((off & 1) != 0) |
off &= ~1; |
else |
{ |
Elf_Internal_Rela outrel; |
int dr_type; |
asection *sreloc; |
if (htab->elf.srelgot == NULL) |
abort (); |
indx = h && h->dynindx != -1 ? h->dynindx : 0; |
if (GOT_TLS_GDESC_P (tls_type)) |
{ |
bfd_byte *loc; |
outrel.r_info = ELF32_R_INFO (indx, R_386_TLS_DESC); |
BFD_ASSERT (htab->sgotplt_jump_table_size + offplt + 8 |
<= htab->elf.sgotplt->size); |
outrel.r_offset = (htab->elf.sgotplt->output_section->vma |
+ htab->elf.sgotplt->output_offset |
+ offplt |
+ htab->sgotplt_jump_table_size); |
sreloc = htab->elf.srelplt; |
loc = sreloc->contents; |
loc += (htab->next_tls_desc_index++ |
* sizeof (Elf32_External_Rel)); |
BFD_ASSERT (loc + sizeof (Elf32_External_Rel) |
<= sreloc->contents + sreloc->size); |
bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); |
if (indx == 0) |
{ |
BFD_ASSERT (! unresolved_reloc); |
bfd_put_32 (output_bfd, |
relocation - elf_i386_dtpoff_base (info), |
htab->elf.sgotplt->contents + offplt |
+ htab->sgotplt_jump_table_size + 4); |
} |
else |
{ |
bfd_put_32 (output_bfd, 0, |
htab->elf.sgotplt->contents + offplt |
+ htab->sgotplt_jump_table_size + 4); |
} |
} |
sreloc = htab->elf.srelgot; |
outrel.r_offset = (htab->elf.sgot->output_section->vma |
+ htab->elf.sgot->output_offset + off); |
if (GOT_TLS_GD_P (tls_type)) |
dr_type = R_386_TLS_DTPMOD32; |
else if (GOT_TLS_GDESC_P (tls_type)) |
goto dr_done; |
else if (tls_type == GOT_TLS_IE_POS) |
dr_type = R_386_TLS_TPOFF; |
else |
dr_type = R_386_TLS_TPOFF32; |
if (dr_type == R_386_TLS_TPOFF && indx == 0) |
bfd_put_32 (output_bfd, |
relocation - elf_i386_dtpoff_base (info), |
htab->elf.sgot->contents + off); |
else if (dr_type == R_386_TLS_TPOFF32 && indx == 0) |
bfd_put_32 (output_bfd, |
elf_i386_dtpoff_base (info) - relocation, |
htab->elf.sgot->contents + off); |
else if (dr_type != R_386_TLS_DESC) |
bfd_put_32 (output_bfd, 0, |
htab->elf.sgot->contents + off); |
outrel.r_info = ELF32_R_INFO (indx, dr_type); |
elf_append_rel (output_bfd, sreloc, &outrel); |
if (GOT_TLS_GD_P (tls_type)) |
{ |
if (indx == 0) |
{ |
BFD_ASSERT (! unresolved_reloc); |
bfd_put_32 (output_bfd, |
relocation - elf_i386_dtpoff_base (info), |
htab->elf.sgot->contents + off + 4); |
} |
else |
{ |
bfd_put_32 (output_bfd, 0, |
htab->elf.sgot->contents + off + 4); |
outrel.r_info = ELF32_R_INFO (indx, |
R_386_TLS_DTPOFF32); |
outrel.r_offset += 4; |
elf_append_rel (output_bfd, sreloc, &outrel); |
} |
} |
else if (tls_type == GOT_TLS_IE_BOTH) |
{ |
bfd_put_32 (output_bfd, |
(indx == 0 |
? relocation - elf_i386_dtpoff_base (info) |
: 0), |
htab->elf.sgot->contents + off + 4); |
outrel.r_info = ELF32_R_INFO (indx, R_386_TLS_TPOFF); |
outrel.r_offset += 4; |
elf_append_rel (output_bfd, sreloc, &outrel); |
} |
dr_done: |
if (h != NULL) |
h->got.offset |= 1; |
else |
local_got_offsets[r_symndx] |= 1; |
} |
if (off >= (bfd_vma) -2 |
&& ! GOT_TLS_GDESC_P (tls_type)) |
abort (); |
if (r_type == R_386_TLS_GOTDESC |
|| r_type == R_386_TLS_DESC_CALL) |
{ |
relocation = htab->sgotplt_jump_table_size + offplt; |
unresolved_reloc = FALSE; |
} |
else if (r_type == ELF32_R_TYPE (rel->r_info)) |
{ |
bfd_vma g_o_t = htab->elf.sgotplt->output_section->vma |
+ htab->elf.sgotplt->output_offset; |
relocation = htab->elf.sgot->output_section->vma |
+ htab->elf.sgot->output_offset + off - g_o_t; |
if ((r_type == R_386_TLS_IE || r_type == R_386_TLS_GOTIE) |
&& tls_type == GOT_TLS_IE_BOTH) |
relocation += 4; |
if (r_type == R_386_TLS_IE) |
relocation += g_o_t; |
unresolved_reloc = FALSE; |
} |
else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GD) |
{ |
unsigned int val, type; |
bfd_vma roff; |
/* GD->IE transition. */ |
type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2); |
val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1); |
if (type == 0x04) |
{ |
/* leal foo(,%reg,1), %eax; call ___tls_get_addr |
Change it into: |
movl %gs:0, %eax; subl $foo@gottpoff(%reg), %eax. */ |
val >>= 3; |
roff = rel->r_offset - 3; |
} |
else |
{ |
/* leal foo(%reg), %eax; call ___tls_get_addr; nop |
Change it into: |
movl %gs:0, %eax; subl $foo@gottpoff(%reg), %eax. */ |
roff = rel->r_offset - 2; |
} |
memcpy (contents + roff, |
"\x65\xa1\0\0\0\0\x2b\x80\0\0\0", 12); |
contents[roff + 7] = 0x80 | (val & 7); |
/* If foo is used only with foo@gotntpoff(%reg) and |
foo@indntpoff, but not with foo@gottpoff(%reg), change |
subl $foo@gottpoff(%reg), %eax |
into: |
addl $foo@gotntpoff(%reg), %eax. */ |
if (tls_type == GOT_TLS_IE_POS) |
contents[roff + 6] = 0x03; |
bfd_put_32 (output_bfd, |
htab->elf.sgot->output_section->vma |
+ htab->elf.sgot->output_offset + off |
- htab->elf.sgotplt->output_section->vma |
- htab->elf.sgotplt->output_offset, |
contents + roff + 8); |
/* Skip R_386_PLT32. */ |
rel++; |
continue; |
} |
else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GOTDESC) |
{ |
/* GDesc -> IE transition. |
It's originally something like: |
leal x@tlsdesc(%ebx), %eax |
Change it to: |
movl x@gotntpoff(%ebx), %eax # before xchg %ax,%ax |
or: |
movl x@gottpoff(%ebx), %eax # before negl %eax |
Registers other than %eax may be set up here. */ |
bfd_vma roff; |
/* First, make sure it's a leal adding ebx to a 32-bit |
offset into any register, although it's probably |
almost always going to be eax. */ |
roff = rel->r_offset; |
/* Now modify the instruction as appropriate. */ |
/* To turn a leal into a movl in the form we use it, it |
suffices to change the first byte from 0x8d to 0x8b. |
aoliva FIXME: should we decide to keep the leal, all |
we have to do is remove the statement below, and |
adjust the relaxation of R_386_TLS_DESC_CALL. */ |
bfd_put_8 (output_bfd, 0x8b, contents + roff - 2); |
if (tls_type == GOT_TLS_IE_BOTH) |
off += 4; |
bfd_put_32 (output_bfd, |
htab->elf.sgot->output_section->vma |
+ htab->elf.sgot->output_offset + off |
- htab->elf.sgotplt->output_section->vma |
- htab->elf.sgotplt->output_offset, |
contents + roff); |
continue; |
} |
else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_DESC_CALL) |
{ |
/* GDesc -> IE transition. |
It's originally: |
call *(%eax) |
Change it to: |
xchg %ax,%ax |
or |
negl %eax |
depending on how we transformed the TLS_GOTDESC above. |
*/ |
bfd_vma roff; |
roff = rel->r_offset; |
/* Now modify the instruction as appropriate. */ |
if (tls_type != GOT_TLS_IE_NEG) |
{ |
/* xchg %ax,%ax */ |
bfd_put_8 (output_bfd, 0x66, contents + roff); |
bfd_put_8 (output_bfd, 0x90, contents + roff + 1); |
} |
else |
{ |
/* negl %eax */ |
bfd_put_8 (output_bfd, 0xf7, contents + roff); |
bfd_put_8 (output_bfd, 0xd8, contents + roff + 1); |
} |
continue; |
} |
else |
BFD_ASSERT (FALSE); |
break; |
case R_386_TLS_LDM: |
if (! elf_i386_tls_transition (info, input_bfd, |
input_section, contents, |
symtab_hdr, sym_hashes, |
&r_type, GOT_UNKNOWN, rel, |
relend, h, r_symndx)) |
return FALSE; |
if (r_type != R_386_TLS_LDM) |
{ |
/* LD->LE transition: |
leal foo(%reg), %eax; call ___tls_get_addr. |
We change it into: |
movl %gs:0, %eax; nop; leal 0(%esi,1), %esi. */ |
BFD_ASSERT (r_type == R_386_TLS_LE_32); |
memcpy (contents + rel->r_offset - 2, |
"\x65\xa1\0\0\0\0\x90\x8d\x74\x26", 11); |
/* Skip R_386_PC32/R_386_PLT32. */ |
rel++; |
continue; |
} |
if (htab->elf.sgot == NULL) |
abort (); |
off = htab->tls_ldm_got.offset; |
if (off & 1) |
off &= ~1; |
else |
{ |
Elf_Internal_Rela outrel; |
if (htab->elf.srelgot == NULL) |
abort (); |
outrel.r_offset = (htab->elf.sgot->output_section->vma |
+ htab->elf.sgot->output_offset + off); |
bfd_put_32 (output_bfd, 0, |
htab->elf.sgot->contents + off); |
bfd_put_32 (output_bfd, 0, |
htab->elf.sgot->contents + off + 4); |
outrel.r_info = ELF32_R_INFO (0, R_386_TLS_DTPMOD32); |
elf_append_rel (output_bfd, htab->elf.srelgot, &outrel); |
htab->tls_ldm_got.offset |= 1; |
} |
relocation = htab->elf.sgot->output_section->vma |
+ htab->elf.sgot->output_offset + off |
- htab->elf.sgotplt->output_section->vma |
- htab->elf.sgotplt->output_offset; |
unresolved_reloc = FALSE; |
break; |
case R_386_TLS_LDO_32: |
if (!info->executable || (input_section->flags & SEC_CODE) == 0) |
relocation -= elf_i386_dtpoff_base (info); |
else |
/* When converting LDO to LE, we must negate. */ |
relocation = -elf_i386_tpoff (info, relocation); |
break; |
case R_386_TLS_LE_32: |
case R_386_TLS_LE: |
if (!info->executable) |
{ |
Elf_Internal_Rela outrel; |
asection *sreloc; |
outrel.r_offset = rel->r_offset |
+ input_section->output_section->vma |
+ input_section->output_offset; |
if (h != NULL && h->dynindx != -1) |
indx = h->dynindx; |
else |
indx = 0; |
if (r_type == R_386_TLS_LE_32) |
outrel.r_info = ELF32_R_INFO (indx, R_386_TLS_TPOFF32); |
else |
outrel.r_info = ELF32_R_INFO (indx, R_386_TLS_TPOFF); |
sreloc = elf_section_data (input_section)->sreloc; |
if (sreloc == NULL) |
abort (); |
elf_append_rel (output_bfd, sreloc, &outrel); |
if (indx) |
continue; |
else if (r_type == R_386_TLS_LE_32) |
relocation = elf_i386_dtpoff_base (info) - relocation; |
else |
relocation -= elf_i386_dtpoff_base (info); |
} |
else if (r_type == R_386_TLS_LE_32) |
relocation = elf_i386_tpoff (info, relocation); |
else |
relocation = -elf_i386_tpoff (info, relocation); |
break; |
default: |
break; |
} |
/* Dynamic relocs are not propagated for SEC_DEBUGGING sections |
because such sections are not SEC_ALLOC and thus ld.so will |
not process them. */ |
if (unresolved_reloc |
&& !((input_section->flags & SEC_DEBUGGING) != 0 |
&& h->def_dynamic) |
&& _bfd_elf_section_offset (output_bfd, info, input_section, |
rel->r_offset) != (bfd_vma) -1) |
{ |
(*_bfd_error_handler) |
(_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"), |
input_bfd, |
input_section, |
(long) rel->r_offset, |
howto->name, |
h->root.root.string); |
return FALSE; |
} |
do_relocation: |
r = _bfd_final_link_relocate (howto, input_bfd, input_section, |
contents, rel->r_offset, |
relocation, 0); |
check_relocation_error: |
if (r != bfd_reloc_ok) |
{ |
const char *name; |
if (h != NULL) |
name = h->root.root.string; |
else |
{ |
name = bfd_elf_string_from_elf_section (input_bfd, |
symtab_hdr->sh_link, |
sym->st_name); |
if (name == NULL) |
return FALSE; |
if (*name == '\0') |
name = bfd_section_name (input_bfd, sec); |
} |
if (r == bfd_reloc_overflow) |
{ |
if (! ((*info->callbacks->reloc_overflow) |
(info, (h ? &h->root : NULL), name, howto->name, |
(bfd_vma) 0, input_bfd, input_section, |
rel->r_offset))) |
return FALSE; |
} |
else |
{ |
(*_bfd_error_handler) |
(_("%B(%A+0x%lx): reloc against `%s': error %d"), |
input_bfd, input_section, |
(long) rel->r_offset, name, (int) r); |
return FALSE; |
} |
} |
} |
return TRUE; |
} |
/* Finish up dynamic symbol handling. We set the contents of various |
dynamic sections here. */ |
static bfd_boolean |
elf_i386_finish_dynamic_symbol (bfd *output_bfd, |
struct bfd_link_info *info, |
struct elf_link_hash_entry *h, |
Elf_Internal_Sym *sym) |
{ |
struct elf_i386_link_hash_table *htab; |
unsigned plt_entry_size; |
const struct elf_i386_backend_data *abed; |
htab = elf_i386_hash_table (info); |
if (htab == NULL) |
return FALSE; |
abed = get_elf_i386_backend_data (output_bfd); |
plt_entry_size = GET_PLT_ENTRY_SIZE (output_bfd); |
if (h->plt.offset != (bfd_vma) -1) |
{ |
bfd_vma plt_index; |
bfd_vma got_offset; |
Elf_Internal_Rela rel; |
bfd_byte *loc; |
asection *plt, *gotplt, *relplt; |
/* When building a static executable, use .iplt, .igot.plt and |
.rel.iplt sections for STT_GNU_IFUNC symbols. */ |
if (htab->elf.splt != NULL) |
{ |
plt = htab->elf.splt; |
gotplt = htab->elf.sgotplt; |
relplt = htab->elf.srelplt; |
} |
else |
{ |
plt = htab->elf.iplt; |
gotplt = htab->elf.igotplt; |
relplt = htab->elf.irelplt; |
} |
/* This symbol has an entry in the procedure linkage table. Set |
it up. */ |
if ((h->dynindx == -1 |
&& !((h->forced_local || info->executable) |
&& h->def_regular |
&& h->type == STT_GNU_IFUNC)) |
|| plt == NULL |
|| gotplt == NULL |
|| relplt == NULL) |
abort (); |
/* Get the index in the procedure linkage table which |
corresponds to this symbol. This is the index of this symbol |
in all the symbols for which we are making plt entries. The |
first entry in the procedure linkage table is reserved. |
Get the offset into the .got table of the entry that |
corresponds to this function. Each .got entry is 4 bytes. |
The first three are reserved. |
For static executables, we don't reserve anything. */ |
if (plt == htab->elf.splt) |
{ |
got_offset = h->plt.offset / plt_entry_size - 1; |
got_offset = (got_offset + 3) * 4; |
} |
else |
{ |
got_offset = h->plt.offset / plt_entry_size; |
got_offset = got_offset * 4; |
} |
/* Fill in the entry in the procedure linkage table. */ |
if (! info->shared) |
{ |
memcpy (plt->contents + h->plt.offset, abed->plt->plt_entry, |
abed->plt->plt_entry_size); |
bfd_put_32 (output_bfd, |
(gotplt->output_section->vma |
+ gotplt->output_offset |
+ got_offset), |
plt->contents + h->plt.offset |
+ abed->plt->plt_got_offset); |
if (abed->is_vxworks) |
{ |
int s, k, reloc_index; |
/* Create the R_386_32 relocation referencing the GOT |
for this PLT entry. */ |
/* S: Current slot number (zero-based). */ |
s = ((h->plt.offset - abed->plt->plt_entry_size) |
/ abed->plt->plt_entry_size); |
/* K: Number of relocations for PLTResolve. */ |
if (info->shared) |
k = PLTRESOLVE_RELOCS_SHLIB; |
else |
k = PLTRESOLVE_RELOCS; |
/* Skip the PLTresolve relocations, and the relocations for |
the other PLT slots. */ |
reloc_index = k + s * PLT_NON_JUMP_SLOT_RELOCS; |
loc = (htab->srelplt2->contents + reloc_index |
* sizeof (Elf32_External_Rel)); |
rel.r_offset = (htab->elf.splt->output_section->vma |
+ htab->elf.splt->output_offset |
+ h->plt.offset + 2), |
rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_386_32); |
bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); |
/* Create the R_386_32 relocation referencing the beginning of |
the PLT for this GOT entry. */ |
rel.r_offset = (htab->elf.sgotplt->output_section->vma |
+ htab->elf.sgotplt->output_offset |
+ got_offset); |
rel.r_info = ELF32_R_INFO (htab->elf.hplt->indx, R_386_32); |
bfd_elf32_swap_reloc_out (output_bfd, &rel, |
loc + sizeof (Elf32_External_Rel)); |
} |
} |
else |
{ |
memcpy (plt->contents + h->plt.offset, abed->plt->pic_plt_entry, |
abed->plt->plt_entry_size); |
bfd_put_32 (output_bfd, got_offset, |
plt->contents + h->plt.offset |
+ abed->plt->plt_got_offset); |
} |
/* Fill in the entry in the global offset table. */ |
bfd_put_32 (output_bfd, |
(plt->output_section->vma |
+ plt->output_offset |
+ h->plt.offset |
+ abed->plt->plt_lazy_offset), |
gotplt->contents + got_offset); |
/* Fill in the entry in the .rel.plt section. */ |
rel.r_offset = (gotplt->output_section->vma |
+ gotplt->output_offset |
+ got_offset); |
if (h->dynindx == -1 |
|| ((info->executable |
|| ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) |
&& h->def_regular |
&& h->type == STT_GNU_IFUNC)) |
{ |
/* If an STT_GNU_IFUNC symbol is locally defined, generate |
R_386_IRELATIVE instead of R_386_JUMP_SLOT. Store addend |
in the .got.plt section. */ |
bfd_put_32 (output_bfd, |
(h->root.u.def.value |
+ h->root.u.def.section->output_section->vma |
+ h->root.u.def.section->output_offset), |
gotplt->contents + got_offset); |
rel.r_info = ELF32_R_INFO (0, R_386_IRELATIVE); |
/* R_386_IRELATIVE comes last. */ |
plt_index = htab->next_irelative_index--; |
} |
else |
{ |
rel.r_info = ELF32_R_INFO (h->dynindx, R_386_JUMP_SLOT); |
plt_index = htab->next_jump_slot_index++; |
} |
loc = relplt->contents + plt_index * sizeof (Elf32_External_Rel); |
bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); |
/* Don't fill PLT entry for static executables. */ |
if (plt == htab->elf.splt) |
{ |
bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rel), |
plt->contents + h->plt.offset |
+ abed->plt->plt_reloc_offset); |
bfd_put_32 (output_bfd, - (h->plt.offset |
+ abed->plt->plt_plt_offset + 4), |
plt->contents + h->plt.offset |
+ abed->plt->plt_plt_offset); |
} |
if (!h->def_regular) |
{ |
/* Mark the symbol as undefined, rather than as defined in |
the .plt section. Leave the value if there were any |
relocations where pointer equality matters (this is a clue |
for the dynamic linker, to make function pointer |
comparisons work between an application and shared |
library), otherwise set it to zero. If a function is only |
called from a binary, there is no need to slow down |
shared libraries because of that. */ |
sym->st_shndx = SHN_UNDEF; |
if (!h->pointer_equality_needed) |
sym->st_value = 0; |
} |
} |
if (h->got.offset != (bfd_vma) -1 |
&& ! GOT_TLS_GD_ANY_P (elf_i386_hash_entry(h)->tls_type) |
&& (elf_i386_hash_entry(h)->tls_type & GOT_TLS_IE) == 0) |
{ |
Elf_Internal_Rela rel; |
/* This symbol has an entry in the global offset table. Set it |
up. */ |
if (htab->elf.sgot == NULL || htab->elf.srelgot == NULL) |
abort (); |
rel.r_offset = (htab->elf.sgot->output_section->vma |
+ htab->elf.sgot->output_offset |
+ (h->got.offset & ~(bfd_vma) 1)); |
/* If this is a static link, or it is a -Bsymbolic link and the |
symbol is defined locally or was forced to be local because |
of a version file, we just want to emit a RELATIVE reloc. |
The entry in the global offset table will already have been |
initialized in the relocate_section function. */ |
if (h->def_regular |
&& h->type == STT_GNU_IFUNC) |
{ |
if (info->shared) |
{ |
/* Generate R_386_GLOB_DAT. */ |
goto do_glob_dat; |
} |
else |
{ |
asection *plt; |
if (!h->pointer_equality_needed) |
abort (); |
/* For non-shared object, we can't use .got.plt, which |
contains the real function addres if we need pointer |
equality. We load the GOT entry with the PLT entry. */ |
plt = htab->elf.splt ? htab->elf.splt : htab->elf.iplt; |
bfd_put_32 (output_bfd, |
(plt->output_section->vma |
+ plt->output_offset + h->plt.offset), |
htab->elf.sgot->contents + h->got.offset); |
return TRUE; |
} |
} |
else if (info->shared |
&& SYMBOL_REFERENCES_LOCAL (info, h)) |
{ |
BFD_ASSERT((h->got.offset & 1) != 0); |
rel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); |
} |
else |
{ |
BFD_ASSERT((h->got.offset & 1) == 0); |
do_glob_dat: |
bfd_put_32 (output_bfd, (bfd_vma) 0, |
htab->elf.sgot->contents + h->got.offset); |
rel.r_info = ELF32_R_INFO (h->dynindx, R_386_GLOB_DAT); |
} |
elf_append_rel (output_bfd, htab->elf.srelgot, &rel); |
} |
if (h->needs_copy) |
{ |
Elf_Internal_Rela rel; |
/* This symbol needs a copy reloc. Set it up. */ |
if (h->dynindx == -1 |
|| (h->root.type != bfd_link_hash_defined |
&& h->root.type != bfd_link_hash_defweak) |
|| htab->srelbss == NULL) |
abort (); |
rel.r_offset = (h->root.u.def.value |
+ h->root.u.def.section->output_section->vma |
+ h->root.u.def.section->output_offset); |
rel.r_info = ELF32_R_INFO (h->dynindx, R_386_COPY); |
elf_append_rel (output_bfd, htab->srelbss, &rel); |
} |
return TRUE; |
} |
/* Finish up local dynamic symbol handling. We set the contents of |
various dynamic sections here. */ |
static bfd_boolean |
elf_i386_finish_local_dynamic_symbol (void **slot, void *inf) |
{ |
struct elf_link_hash_entry *h |
= (struct elf_link_hash_entry *) *slot; |
struct bfd_link_info *info |
= (struct bfd_link_info *) inf; |
return elf_i386_finish_dynamic_symbol (info->output_bfd, info, |
h, NULL); |
} |
/* Used to decide how to sort relocs in an optimal manner for the |
dynamic linker, before writing them out. */ |
static enum elf_reloc_type_class |
elf_i386_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, |
const asection *rel_sec ATTRIBUTE_UNUSED, |
const Elf_Internal_Rela *rela) |
{ |
switch (ELF32_R_TYPE (rela->r_info)) |
{ |
case R_386_RELATIVE: |
return reloc_class_relative; |
case R_386_JUMP_SLOT: |
return reloc_class_plt; |
case R_386_COPY: |
return reloc_class_copy; |
default: |
return reloc_class_normal; |
} |
} |
/* Finish up the dynamic sections. */ |
static bfd_boolean |
elf_i386_finish_dynamic_sections (bfd *output_bfd, |
struct bfd_link_info *info) |
{ |
struct elf_i386_link_hash_table *htab; |
bfd *dynobj; |
asection *sdyn; |
const struct elf_i386_backend_data *abed; |
htab = elf_i386_hash_table (info); |
if (htab == NULL) |
return FALSE; |
dynobj = htab->elf.dynobj; |
sdyn = bfd_get_linker_section (dynobj, ".dynamic"); |
abed = get_elf_i386_backend_data (output_bfd); |
if (htab->elf.dynamic_sections_created) |
{ |
Elf32_External_Dyn *dyncon, *dynconend; |
if (sdyn == NULL || htab->elf.sgot == NULL) |
abort (); |
dyncon = (Elf32_External_Dyn *) sdyn->contents; |
dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); |
for (; dyncon < dynconend; dyncon++) |
{ |
Elf_Internal_Dyn dyn; |
asection *s; |
bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); |
switch (dyn.d_tag) |
{ |
default: |
if (abed->is_vxworks |
&& elf_vxworks_finish_dynamic_entry (output_bfd, &dyn)) |
break; |
continue; |
case DT_PLTGOT: |
s = htab->elf.sgotplt; |
dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; |
break; |
case DT_JMPREL: |
s = htab->elf.srelplt; |
dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; |
break; |
case DT_PLTRELSZ: |
s = htab->elf.srelplt; |
dyn.d_un.d_val = s->size; |
break; |
case DT_RELSZ: |
/* My reading of the SVR4 ABI indicates that the |
procedure linkage table relocs (DT_JMPREL) should be |
included in the overall relocs (DT_REL). This is |
what Solaris does. However, UnixWare can not handle |
that case. Therefore, we override the DT_RELSZ entry |
here to make it not include the JMPREL relocs. */ |
s = htab->elf.srelplt; |
if (s == NULL) |
continue; |
dyn.d_un.d_val -= s->size; |
break; |
case DT_REL: |
/* We may not be using the standard ELF linker script. |
If .rel.plt is the first .rel section, we adjust |
DT_REL to not include it. */ |
s = htab->elf.srelplt; |
if (s == NULL) |
continue; |
if (dyn.d_un.d_ptr != s->output_section->vma + s->output_offset) |
continue; |
dyn.d_un.d_ptr += s->size; |
break; |
} |
bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); |
} |
/* Fill in the first entry in the procedure linkage table. */ |
if (htab->elf.splt && htab->elf.splt->size > 0) |
{ |
if (info->shared) |
{ |
memcpy (htab->elf.splt->contents, abed->plt->pic_plt0_entry, |
abed->plt->plt0_entry_size); |
memset (htab->elf.splt->contents + abed->plt->plt0_entry_size, |
abed->plt0_pad_byte, |
abed->plt->plt_entry_size - abed->plt->plt0_entry_size); |
} |
else |
{ |
memcpy (htab->elf.splt->contents, abed->plt->plt0_entry, |
abed->plt->plt0_entry_size); |
memset (htab->elf.splt->contents + abed->plt->plt0_entry_size, |
abed->plt0_pad_byte, |
abed->plt->plt_entry_size - abed->plt->plt0_entry_size); |
bfd_put_32 (output_bfd, |
(htab->elf.sgotplt->output_section->vma |
+ htab->elf.sgotplt->output_offset |
+ 4), |
htab->elf.splt->contents |
+ abed->plt->plt0_got1_offset); |
bfd_put_32 (output_bfd, |
(htab->elf.sgotplt->output_section->vma |
+ htab->elf.sgotplt->output_offset |
+ 8), |
htab->elf.splt->contents |
+ abed->plt->plt0_got2_offset); |
if (abed->is_vxworks) |
{ |
Elf_Internal_Rela rel; |
/* Generate a relocation for _GLOBAL_OFFSET_TABLE_ + 4. |
On IA32 we use REL relocations so the addend goes in |
the PLT directly. */ |
rel.r_offset = (htab->elf.splt->output_section->vma |
+ htab->elf.splt->output_offset |
+ abed->plt->plt0_got1_offset); |
rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_386_32); |
bfd_elf32_swap_reloc_out (output_bfd, &rel, |
htab->srelplt2->contents); |
/* Generate a relocation for _GLOBAL_OFFSET_TABLE_ + 8. */ |
rel.r_offset = (htab->elf.splt->output_section->vma |
+ htab->elf.splt->output_offset |
+ abed->plt->plt0_got2_offset); |
rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_386_32); |
bfd_elf32_swap_reloc_out (output_bfd, &rel, |
htab->srelplt2->contents + |
sizeof (Elf32_External_Rel)); |
} |
} |
/* UnixWare sets the entsize of .plt to 4, although that doesn't |
really seem like the right value. */ |
elf_section_data (htab->elf.splt->output_section) |
->this_hdr.sh_entsize = 4; |
/* Correct the .rel.plt.unloaded relocations. */ |
if (abed->is_vxworks && !info->shared) |
{ |
int num_plts = (htab->elf.splt->size |
/ abed->plt->plt_entry_size) - 1; |
unsigned char *p; |
p = htab->srelplt2->contents; |
if (info->shared) |
p += PLTRESOLVE_RELOCS_SHLIB * sizeof (Elf32_External_Rel); |
else |
p += PLTRESOLVE_RELOCS * sizeof (Elf32_External_Rel); |
for (; num_plts; num_plts--) |
{ |
Elf_Internal_Rela rel; |
bfd_elf32_swap_reloc_in (output_bfd, p, &rel); |
rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_386_32); |
bfd_elf32_swap_reloc_out (output_bfd, &rel, p); |
p += sizeof (Elf32_External_Rel); |
bfd_elf32_swap_reloc_in (output_bfd, p, &rel); |
rel.r_info = ELF32_R_INFO (htab->elf.hplt->indx, R_386_32); |
bfd_elf32_swap_reloc_out (output_bfd, &rel, p); |
p += sizeof (Elf32_External_Rel); |
} |
} |
} |
} |
if (htab->elf.sgotplt) |
{ |
if (bfd_is_abs_section (htab->elf.sgotplt->output_section)) |
{ |
(*_bfd_error_handler) |
(_("discarded output section: `%A'"), htab->elf.sgotplt); |
return FALSE; |
} |
/* Fill in the first three entries in the global offset table. */ |
if (htab->elf.sgotplt->size > 0) |
{ |
bfd_put_32 (output_bfd, |
(sdyn == NULL ? 0 |
: sdyn->output_section->vma + sdyn->output_offset), |
htab->elf.sgotplt->contents); |
bfd_put_32 (output_bfd, 0, htab->elf.sgotplt->contents + 4); |
bfd_put_32 (output_bfd, 0, htab->elf.sgotplt->contents + 8); |
} |
elf_section_data (htab->elf.sgotplt->output_section)->this_hdr.sh_entsize = 4; |
} |
/* Adjust .eh_frame for .plt section. */ |
if (htab->plt_eh_frame != NULL |
&& htab->plt_eh_frame->contents != NULL) |
{ |
if (htab->elf.splt != NULL |
&& htab->elf.splt->size != 0 |
&& (htab->elf.splt->flags & SEC_EXCLUDE) == 0 |
&& htab->elf.splt->output_section != NULL |
&& htab->plt_eh_frame->output_section != NULL) |
{ |
bfd_vma plt_start = htab->elf.splt->output_section->vma; |
bfd_vma eh_frame_start = htab->plt_eh_frame->output_section->vma |
+ htab->plt_eh_frame->output_offset |
+ PLT_FDE_START_OFFSET; |
bfd_put_signed_32 (dynobj, plt_start - eh_frame_start, |
htab->plt_eh_frame->contents |
+ PLT_FDE_START_OFFSET); |
} |
if (htab->plt_eh_frame->sec_info_type |
== SEC_INFO_TYPE_EH_FRAME) |
{ |
if (! _bfd_elf_write_section_eh_frame (output_bfd, info, |
htab->plt_eh_frame, |
htab->plt_eh_frame->contents)) |
return FALSE; |
} |
} |
if (htab->elf.sgot && htab->elf.sgot->size > 0) |
elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize = 4; |
/* Fill PLT and GOT entries for local STT_GNU_IFUNC symbols. */ |
htab_traverse (htab->loc_hash_table, |
elf_i386_finish_local_dynamic_symbol, |
info); |
return TRUE; |
} |
/* Return address for Ith PLT stub in section PLT, for relocation REL |
or (bfd_vma) -1 if it should not be included. */ |
static bfd_vma |
elf_i386_plt_sym_val (bfd_vma i, const asection *plt, |
const arelent *rel ATTRIBUTE_UNUSED) |
{ |
return plt->vma + (i + 1) * GET_PLT_ENTRY_SIZE (plt->owner); |
} |
/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ |
static bfd_boolean |
elf_i386_hash_symbol (struct elf_link_hash_entry *h) |
{ |
if (h->plt.offset != (bfd_vma) -1 |
&& !h->def_regular |
&& !h->pointer_equality_needed) |
return FALSE; |
return _bfd_elf_hash_symbol (h); |
} |
/* Hook called by the linker routine which adds symbols from an object |
file. */ |
static bfd_boolean |
elf_i386_add_symbol_hook (bfd * abfd, |
struct bfd_link_info * info ATTRIBUTE_UNUSED, |
Elf_Internal_Sym * sym, |
const char ** namep ATTRIBUTE_UNUSED, |
flagword * flagsp ATTRIBUTE_UNUSED, |
asection ** secp ATTRIBUTE_UNUSED, |
bfd_vma * valp ATTRIBUTE_UNUSED) |
{ |
if ((abfd->flags & DYNAMIC) == 0 |
&& (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC |
|| ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE)) |
elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE; |
return TRUE; |
} |
#define TARGET_LITTLE_SYM bfd_elf32_i386_vec |
#define TARGET_LITTLE_NAME "elf32-i386" |
#define ELF_ARCH bfd_arch_i386 |
#define ELF_TARGET_ID I386_ELF_DATA |
#define ELF_MACHINE_CODE EM_386 |
#define ELF_MAXPAGESIZE 0x1000 |
#define elf_backend_can_gc_sections 1 |
#define elf_backend_can_refcount 1 |
#define elf_backend_want_got_plt 1 |
#define elf_backend_plt_readonly 1 |
#define elf_backend_want_plt_sym 0 |
#define elf_backend_got_header_size 12 |
#define elf_backend_plt_alignment 4 |
/* Support RELA for objdump of prelink objects. */ |
#define elf_info_to_howto elf_i386_info_to_howto_rel |
#define elf_info_to_howto_rel elf_i386_info_to_howto_rel |
#define bfd_elf32_mkobject elf_i386_mkobject |
#define bfd_elf32_bfd_is_local_label_name elf_i386_is_local_label_name |
#define bfd_elf32_bfd_link_hash_table_create elf_i386_link_hash_table_create |
#define bfd_elf32_bfd_link_hash_table_free elf_i386_link_hash_table_free |
#define bfd_elf32_bfd_reloc_type_lookup elf_i386_reloc_type_lookup |
#define bfd_elf32_bfd_reloc_name_lookup elf_i386_reloc_name_lookup |
#define elf_backend_adjust_dynamic_symbol elf_i386_adjust_dynamic_symbol |
#define elf_backend_relocs_compatible _bfd_elf_relocs_compatible |
#define elf_backend_check_relocs elf_i386_check_relocs |
#define elf_backend_copy_indirect_symbol elf_i386_copy_indirect_symbol |
#define elf_backend_create_dynamic_sections elf_i386_create_dynamic_sections |
#define elf_backend_fake_sections elf_i386_fake_sections |
#define elf_backend_finish_dynamic_sections elf_i386_finish_dynamic_sections |
#define elf_backend_finish_dynamic_symbol elf_i386_finish_dynamic_symbol |
#define elf_backend_gc_mark_hook elf_i386_gc_mark_hook |
#define elf_backend_gc_sweep_hook elf_i386_gc_sweep_hook |
#define elf_backend_grok_prstatus elf_i386_grok_prstatus |
#define elf_backend_grok_psinfo elf_i386_grok_psinfo |
#define elf_backend_reloc_type_class elf_i386_reloc_type_class |
#define elf_backend_relocate_section elf_i386_relocate_section |
#define elf_backend_size_dynamic_sections elf_i386_size_dynamic_sections |
#define elf_backend_always_size_sections elf_i386_always_size_sections |
#define elf_backend_omit_section_dynsym \ |
((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) |
#define elf_backend_plt_sym_val elf_i386_plt_sym_val |
#define elf_backend_hash_symbol elf_i386_hash_symbol |
#define elf_backend_add_symbol_hook elf_i386_add_symbol_hook |
#undef elf_backend_post_process_headers |
#define elf_backend_post_process_headers _bfd_elf_set_osabi |
#include "elf32-target.h" |
/* FreeBSD support. */ |
#undef TARGET_LITTLE_SYM |
#define TARGET_LITTLE_SYM bfd_elf32_i386_freebsd_vec |
#undef TARGET_LITTLE_NAME |
#define TARGET_LITTLE_NAME "elf32-i386-freebsd" |
#undef ELF_OSABI |
#define ELF_OSABI ELFOSABI_FREEBSD |
/* The kernel recognizes executables as valid only if they carry a |
"FreeBSD" label in the ELF header. So we put this label on all |
executables and (for simplicity) also all other object files. */ |
static void |
elf_i386_fbsd_post_process_headers (bfd *abfd, struct bfd_link_info *info) |
{ |
_bfd_elf_set_osabi (abfd, info); |
#ifdef OLD_FREEBSD_ABI_LABEL |
/* The ABI label supported by FreeBSD <= 4.0 is quite nonstandard. */ |
memcpy (&i_ehdrp->e_ident[EI_ABIVERSION], "FreeBSD", 8); |
#endif |
} |
#undef elf_backend_post_process_headers |
#define elf_backend_post_process_headers elf_i386_fbsd_post_process_headers |
#undef elf32_bed |
#define elf32_bed elf32_i386_fbsd_bed |
#undef elf_backend_add_symbol_hook |
#include "elf32-target.h" |
/* Solaris 2. */ |
#undef TARGET_LITTLE_SYM |
#define TARGET_LITTLE_SYM bfd_elf32_i386_sol2_vec |
#undef TARGET_LITTLE_NAME |
#define TARGET_LITTLE_NAME "elf32-i386-sol2" |
/* Restore default: we cannot use ELFOSABI_SOLARIS, otherwise ELFOSABI_NONE |
objects won't be recognized. */ |
#undef ELF_OSABI |
#undef elf32_bed |
#define elf32_bed elf32_i386_sol2_bed |
/* The 32-bit static TLS arena size is rounded to the nearest 8-byte |
boundary. */ |
#undef elf_backend_static_tls_alignment |
#define elf_backend_static_tls_alignment 8 |
/* The Solaris 2 ABI requires a plt symbol on all platforms. |
Cf. Linker and Libraries Guide, Ch. 2, Link-Editor, Generating the Output |
File, p.63. */ |
#undef elf_backend_want_plt_sym |
#define elf_backend_want_plt_sym 1 |
#include "elf32-target.h" |
/* Native Client support. */ |
#undef TARGET_LITTLE_SYM |
#define TARGET_LITTLE_SYM bfd_elf32_i386_nacl_vec |
#undef TARGET_LITTLE_NAME |
#define TARGET_LITTLE_NAME "elf32-i386-nacl" |
#undef elf32_bed |
#define elf32_bed elf32_i386_nacl_bed |
#undef ELF_MAXPAGESIZE |
#define ELF_MAXPAGESIZE 0x10000 |
/* Restore defaults. */ |
#undef ELF_OSABI |
#undef elf_backend_want_plt_sym |
#define elf_backend_want_plt_sym 0 |
#undef elf_backend_post_process_headers |
#define elf_backend_post_process_headers _bfd_elf_set_osabi |
#undef elf_backend_static_tls_alignment |
/* NaCl uses substantially different PLT entries for the same effects. */ |
#undef elf_backend_plt_alignment |
#define elf_backend_plt_alignment 5 |
#define NACL_PLT_ENTRY_SIZE 64 |
#define NACLMASK 0xe0 /* 32-byte alignment mask. */ |
static const bfd_byte elf_i386_nacl_plt0_entry[] = |
{ |
0xff, 0x35, /* pushl contents of address */ |
0, 0, 0, 0, /* replaced with address of .got + 4. */ |
0x8b, 0x0d, /* movl contents of address, %ecx */ |
0, 0, 0, 0, /* replaced with address of .got + 8. */ |
0x83, 0xe1, NACLMASK, /* andl $NACLMASK, %ecx */ |
0xff, 0xe1 /* jmp *%ecx */ |
}; |
static const bfd_byte elf_i386_nacl_plt_entry[NACL_PLT_ENTRY_SIZE] = |
{ |
0x8b, 0x0d, /* movl contents of address, %ecx */ |
0, 0, 0, 0, /* replaced with GOT slot address. */ |
0x83, 0xe1, NACLMASK, /* andl $NACLMASK, %ecx */ |
0xff, 0xe1, /* jmp *%ecx */ |
/* Pad to the next 32-byte boundary with nop instructions. */ |
0x90, |
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, |
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, |
/* Lazy GOT entries point here (32-byte aligned). */ |
0x68, /* pushl immediate */ |
0, 0, 0, 0, /* replaced with reloc offset. */ |
0xe9, /* jmp relative */ |
0, 0, 0, 0, /* replaced with offset to .plt. */ |
/* Pad to the next 32-byte boundary with nop instructions. */ |
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, |
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, |
0x90, 0x90 |
}; |
static const bfd_byte |
elf_i386_nacl_pic_plt0_entry[sizeof (elf_i386_nacl_plt0_entry)] = |
{ |
0xff, 0x73, 0x04, /* pushl 4(%ebx) */ |
0x8b, 0x4b, 0x08, /* mov 0x8(%ebx), %ecx */ |
0x83, 0xe1, 0xe0, /* and $NACLMASK, %ecx */ |
0xff, 0xe1, /* jmp *%ecx */ |
/* This is expected to be the same size as elf_i386_nacl_plt0_entry, |
so pad to that size with nop instructions. */ |
0x90, 0x90, 0x90, 0x90, 0x90, 0x90 |
}; |
static const bfd_byte elf_i386_nacl_pic_plt_entry[NACL_PLT_ENTRY_SIZE] = |
{ |
0x8b, 0x8b, /* movl offset(%ebx), %ecx */ |
0, 0, 0, 0, /* replaced with offset of this symbol in .got. */ |
0x83, 0xe1, 0xe0, /* andl $NACLMASK, %ecx */ |
0xff, 0xe1, /* jmp *%ecx */ |
/* Pad to the next 32-byte boundary with nop instructions. */ |
0x90, |
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, |
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, |
/* Lazy GOT entries point here (32-byte aligned). */ |
0x68, /* pushl immediate */ |
0, 0, 0, 0, /* replaced with offset into relocation table. */ |
0xe9, /* jmp relative */ |
0, 0, 0, 0, /* replaced with offset to start of .plt. */ |
/* Pad to the next 32-byte boundary with nop instructions. */ |
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, |
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, |
0x90, 0x90 |
}; |
static const bfd_byte elf_i386_nacl_eh_frame_plt[] = |
{ |
#if (PLT_CIE_LENGTH != 20 \ |
|| PLT_FDE_LENGTH != 36 \ |
|| PLT_FDE_START_OFFSET != 4 + PLT_CIE_LENGTH + 8 \ |
|| PLT_FDE_LEN_OFFSET != 4 + PLT_CIE_LENGTH + 12) |
# error "Need elf_i386_backend_data parameters for eh_frame_plt offsets!" |
#endif |
PLT_CIE_LENGTH, 0, 0, 0, /* CIE length */ |
0, 0, 0, 0, /* CIE ID */ |
1, /* CIE version */ |
'z', 'R', 0, /* Augmentation string */ |
1, /* Code alignment factor */ |
0x7c, /* Data alignment factor: -4 */ |
8, /* Return address column */ |
1, /* Augmentation size */ |
DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding */ |
DW_CFA_def_cfa, 4, 4, /* DW_CFA_def_cfa: r4 (esp) ofs 4 */ |
DW_CFA_offset + 8, 1, /* DW_CFA_offset: r8 (eip) at cfa-4 */ |
DW_CFA_nop, DW_CFA_nop, |
PLT_FDE_LENGTH, 0, 0, 0, /* FDE length */ |
PLT_CIE_LENGTH + 8, 0, 0, 0, /* CIE pointer */ |
0, 0, 0, 0, /* R_386_PC32 .plt goes here */ |
0, 0, 0, 0, /* .plt size goes here */ |
0, /* Augmentation size */ |
DW_CFA_def_cfa_offset, 8, /* DW_CFA_def_cfa_offset: 8 */ |
DW_CFA_advance_loc + 6, /* DW_CFA_advance_loc: 6 to __PLT__+6 */ |
DW_CFA_def_cfa_offset, 12, /* DW_CFA_def_cfa_offset: 12 */ |
DW_CFA_advance_loc + 58, /* DW_CFA_advance_loc: 58 to __PLT__+64 */ |
DW_CFA_def_cfa_expression, /* DW_CFA_def_cfa_expression */ |
13, /* Block length */ |
DW_OP_breg4, 4, /* DW_OP_breg4 (esp): 4 */ |
DW_OP_breg8, 0, /* DW_OP_breg8 (eip): 0 */ |
DW_OP_const1u, 63, DW_OP_and, DW_OP_const1u, 37, DW_OP_ge, |
DW_OP_lit2, DW_OP_shl, DW_OP_plus, |
DW_CFA_nop, DW_CFA_nop |
}; |
static const struct elf_i386_plt_layout elf_i386_nacl_plt = |
{ |
elf_i386_nacl_plt0_entry, /* plt0_entry */ |
sizeof (elf_i386_nacl_plt0_entry), /* plt0_entry_size */ |
2, /* plt0_got1_offset */ |
8, /* plt0_got2_offset */ |
elf_i386_nacl_plt_entry, /* plt_entry */ |
NACL_PLT_ENTRY_SIZE, /* plt_entry_size */ |
2, /* plt_got_offset */ |
33, /* plt_reloc_offset */ |
38, /* plt_plt_offset */ |
32, /* plt_lazy_offset */ |
elf_i386_nacl_pic_plt0_entry, /* pic_plt0_entry */ |
elf_i386_nacl_pic_plt_entry, /* pic_plt_entry */ |
elf_i386_nacl_eh_frame_plt, /* eh_frame_plt */ |
sizeof (elf_i386_nacl_eh_frame_plt),/* eh_frame_plt_size */ |
}; |
static const struct elf_i386_backend_data elf_i386_nacl_arch_bed = |
{ |
&elf_i386_nacl_plt, /* plt */ |
0x90, /* plt0_pad_byte: nop insn */ |
0, /* is_vxworks */ |
}; |
static bfd_boolean |
elf32_i386_nacl_elf_object_p (bfd *abfd) |
{ |
/* Set the right machine number for a NaCl i386 ELF32 file. */ |
bfd_default_set_arch_mach (abfd, bfd_arch_i386, bfd_mach_i386_i386_nacl); |
return TRUE; |
} |
#undef elf_backend_arch_data |
#define elf_backend_arch_data &elf_i386_nacl_arch_bed |
#undef elf_backend_object_p |
#define elf_backend_object_p elf32_i386_nacl_elf_object_p |
#undef elf_backend_modify_segment_map |
#define elf_backend_modify_segment_map nacl_modify_segment_map |
#undef elf_backend_modify_program_headers |
#define elf_backend_modify_program_headers nacl_modify_program_headers |
#undef elf_backend_final_write_processing |
#define elf_backend_final_write_processing nacl_final_write_processing |
#include "elf32-target.h" |
/* Restore defaults. */ |
#undef elf_backend_object_p |
#undef elf_backend_modify_segment_map |
#undef elf_backend_modify_program_headers |
#undef elf_backend_final_write_processing |
/* VxWorks support. */ |
#undef TARGET_LITTLE_SYM |
#define TARGET_LITTLE_SYM bfd_elf32_i386_vxworks_vec |
#undef TARGET_LITTLE_NAME |
#define TARGET_LITTLE_NAME "elf32-i386-vxworks" |
#undef ELF_OSABI |
#undef elf_backend_plt_alignment |
#define elf_backend_plt_alignment 4 |
static const struct elf_i386_backend_data elf_i386_vxworks_arch_bed = |
{ |
&elf_i386_plt, /* plt */ |
0x90, /* plt0_pad_byte */ |
1, /* is_vxworks */ |
}; |
#undef elf_backend_arch_data |
#define elf_backend_arch_data &elf_i386_vxworks_arch_bed |
#undef elf_backend_relocs_compatible |
#undef elf_backend_post_process_headers |
#undef elf_backend_add_symbol_hook |
#define elf_backend_add_symbol_hook \ |
elf_vxworks_add_symbol_hook |
#undef elf_backend_link_output_symbol_hook |
#define elf_backend_link_output_symbol_hook \ |
elf_vxworks_link_output_symbol_hook |
#undef elf_backend_emit_relocs |
#define elf_backend_emit_relocs elf_vxworks_emit_relocs |
#undef elf_backend_final_write_processing |
#define elf_backend_final_write_processing \ |
elf_vxworks_final_write_processing |
#undef elf_backend_static_tls_alignment |
/* On VxWorks, we emit relocations against _PROCEDURE_LINKAGE_TABLE_, so |
define it. */ |
#undef elf_backend_want_plt_sym |
#define elf_backend_want_plt_sym 1 |
#undef elf32_bed |
#define elf32_bed elf32_i386_vxworks_bed |
#include "elf32-target.h" |
/contrib/toolchain/binutils/bfd/elf32-target.h |
---|
0,0 → 1,999 |
/* Target definitions for 32-bit ELF |
Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, |
2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 |
Free Software Foundation, Inc. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* This structure contains everything that BFD knows about a target. |
It includes things like its byte order, name, what routines to call |
to do various operations, etc. Every BFD points to a target structure |
with its "xvec" member. |
There are two such structures here: one for big-endian machines and |
one for little-endian machines. */ |
#ifndef bfd_elf32_close_and_cleanup |
#define bfd_elf32_close_and_cleanup _bfd_elf_close_and_cleanup |
#endif |
#ifndef bfd_elf32_bfd_free_cached_info |
#define bfd_elf32_bfd_free_cached_info _bfd_free_cached_info |
#endif |
#ifndef bfd_elf32_get_section_contents |
#define bfd_elf32_get_section_contents _bfd_generic_get_section_contents |
#endif |
#define bfd_elf32_canonicalize_dynamic_symtab \ |
_bfd_elf_canonicalize_dynamic_symtab |
#ifndef bfd_elf32_get_synthetic_symtab |
#define bfd_elf32_get_synthetic_symtab \ |
_bfd_elf_get_synthetic_symtab |
#endif |
#ifndef bfd_elf32_canonicalize_reloc |
#define bfd_elf32_canonicalize_reloc _bfd_elf_canonicalize_reloc |
#endif |
#ifndef bfd_elf32_find_nearest_line |
#define bfd_elf32_find_nearest_line _bfd_elf_find_nearest_line |
#endif |
#ifndef bfd_elf32_find_inliner_info |
#define bfd_elf32_find_inliner_info _bfd_elf_find_inliner_info |
#endif |
#define bfd_elf32_read_minisymbols _bfd_elf_read_minisymbols |
#define bfd_elf32_minisymbol_to_symbol _bfd_elf_minisymbol_to_symbol |
#define bfd_elf32_get_dynamic_symtab_upper_bound \ |
_bfd_elf_get_dynamic_symtab_upper_bound |
#define bfd_elf32_get_lineno _bfd_elf_get_lineno |
#ifndef bfd_elf32_get_reloc_upper_bound |
#define bfd_elf32_get_reloc_upper_bound _bfd_elf_get_reloc_upper_bound |
#endif |
#ifndef bfd_elf32_get_symbol_info |
#define bfd_elf32_get_symbol_info _bfd_elf_get_symbol_info |
#endif |
#define bfd_elf32_canonicalize_symtab _bfd_elf_canonicalize_symtab |
#define bfd_elf32_get_symtab_upper_bound _bfd_elf_get_symtab_upper_bound |
#define bfd_elf32_make_empty_symbol _bfd_elf_make_empty_symbol |
#ifndef bfd_elf32_new_section_hook |
#define bfd_elf32_new_section_hook _bfd_elf_new_section_hook |
#endif |
#define bfd_elf32_set_arch_mach _bfd_elf_set_arch_mach |
#ifndef bfd_elf32_set_section_contents |
#define bfd_elf32_set_section_contents _bfd_elf_set_section_contents |
#endif |
#define bfd_elf32_sizeof_headers _bfd_elf_sizeof_headers |
#define bfd_elf32_write_object_contents _bfd_elf_write_object_contents |
#define bfd_elf32_write_corefile_contents _bfd_elf_write_corefile_contents |
#define bfd_elf32_get_section_contents_in_window \ |
_bfd_generic_get_section_contents_in_window |
#ifndef elf_backend_can_refcount |
#define elf_backend_can_refcount 0 |
#endif |
#ifndef elf_backend_want_got_plt |
#define elf_backend_want_got_plt 0 |
#endif |
#ifndef elf_backend_plt_readonly |
#define elf_backend_plt_readonly 0 |
#endif |
#ifndef elf_backend_want_plt_sym |
#define elf_backend_want_plt_sym 0 |
#endif |
#ifndef elf_backend_plt_not_loaded |
#define elf_backend_plt_not_loaded 0 |
#endif |
#ifndef elf_backend_plt_alignment |
#define elf_backend_plt_alignment 2 |
#endif |
#ifndef elf_backend_want_dynbss |
#define elf_backend_want_dynbss 1 |
#endif |
#ifndef elf_backend_want_p_paddr_set_to_zero |
#define elf_backend_want_p_paddr_set_to_zero 0 |
#endif |
#ifndef elf_backend_default_execstack |
#define elf_backend_default_execstack 1 |
#endif |
#ifndef elf_backend_stack_align |
#define elf_backend_stack_align 16 |
#endif |
#define bfd_elf32_bfd_debug_info_start bfd_void |
#define bfd_elf32_bfd_debug_info_end bfd_void |
#define bfd_elf32_bfd_debug_info_accumulate \ |
((void (*) (bfd*, struct bfd_section *)) bfd_void) |
#ifndef bfd_elf32_bfd_get_relocated_section_contents |
#define bfd_elf32_bfd_get_relocated_section_contents \ |
bfd_generic_get_relocated_section_contents |
#endif |
#ifndef bfd_elf32_bfd_relax_section |
#define bfd_elf32_bfd_relax_section bfd_generic_relax_section |
#endif |
#ifndef elf_backend_can_gc_sections |
#define elf_backend_can_gc_sections 0 |
#endif |
#ifndef elf_backend_can_refcount |
#define elf_backend_can_refcount 0 |
#endif |
#ifndef elf_backend_want_got_sym |
#define elf_backend_want_got_sym 1 |
#endif |
#ifndef elf_backend_gc_keep |
#define elf_backend_gc_keep _bfd_elf_gc_keep |
#endif |
#ifndef elf_backend_gc_mark_dynamic_ref |
#define elf_backend_gc_mark_dynamic_ref bfd_elf_gc_mark_dynamic_ref_symbol |
#endif |
#ifndef elf_backend_gc_mark_hook |
#define elf_backend_gc_mark_hook _bfd_elf_gc_mark_hook |
#endif |
#ifndef elf_backend_gc_mark_extra_sections |
#define elf_backend_gc_mark_extra_sections _bfd_elf_gc_mark_extra_sections |
#endif |
#ifndef elf_backend_gc_sweep_hook |
#define elf_backend_gc_sweep_hook NULL |
#endif |
#ifndef bfd_elf32_bfd_gc_sections |
#define bfd_elf32_bfd_gc_sections bfd_elf_gc_sections |
#endif |
#ifndef bfd_elf32_bfd_merge_sections |
#define bfd_elf32_bfd_merge_sections \ |
_bfd_elf_merge_sections |
#endif |
#ifndef bfd_elf32_bfd_is_group_section |
#define bfd_elf32_bfd_is_group_section bfd_elf_is_group_section |
#endif |
#ifndef bfd_elf32_bfd_discard_group |
#define bfd_elf32_bfd_discard_group bfd_generic_discard_group |
#endif |
#ifndef bfd_elf32_section_already_linked |
#define bfd_elf32_section_already_linked \ |
_bfd_elf_section_already_linked |
#endif |
#ifndef bfd_elf32_bfd_define_common_symbol |
#define bfd_elf32_bfd_define_common_symbol bfd_generic_define_common_symbol |
#endif |
#ifndef bfd_elf32_bfd_lookup_section_flags |
#define bfd_elf32_bfd_lookup_section_flags bfd_elf_lookup_section_flags |
#endif |
#ifndef bfd_elf32_bfd_make_debug_symbol |
#define bfd_elf32_bfd_make_debug_symbol \ |
((asymbol * (*) (bfd *, void *, unsigned long)) bfd_nullvoidptr) |
#endif |
#ifndef bfd_elf32_bfd_copy_private_symbol_data |
#define bfd_elf32_bfd_copy_private_symbol_data \ |
_bfd_elf_copy_private_symbol_data |
#endif |
#ifndef bfd_elf32_bfd_copy_private_section_data |
#define bfd_elf32_bfd_copy_private_section_data \ |
_bfd_elf_copy_private_section_data |
#endif |
#ifndef bfd_elf32_bfd_copy_private_header_data |
#define bfd_elf32_bfd_copy_private_header_data \ |
_bfd_elf_copy_private_header_data |
#endif |
#ifndef bfd_elf32_bfd_copy_private_bfd_data |
#define bfd_elf32_bfd_copy_private_bfd_data \ |
_bfd_elf_copy_private_bfd_data |
#endif |
#ifndef bfd_elf32_bfd_print_private_bfd_data |
#define bfd_elf32_bfd_print_private_bfd_data \ |
_bfd_elf_print_private_bfd_data |
#endif |
#ifndef bfd_elf32_bfd_merge_private_bfd_data |
#define bfd_elf32_bfd_merge_private_bfd_data \ |
((bfd_boolean (*) (bfd *, bfd *)) bfd_true) |
#endif |
#ifndef bfd_elf32_bfd_set_private_flags |
#define bfd_elf32_bfd_set_private_flags \ |
((bfd_boolean (*) (bfd *, flagword)) bfd_true) |
#endif |
#ifndef bfd_elf32_bfd_is_local_label_name |
#define bfd_elf32_bfd_is_local_label_name _bfd_elf_is_local_label_name |
#endif |
#ifndef bfd_elf32_bfd_is_target_special_symbol |
#define bfd_elf32_bfd_is_target_special_symbol \ |
((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) |
#endif |
#ifndef bfd_elf32_get_dynamic_reloc_upper_bound |
#define bfd_elf32_get_dynamic_reloc_upper_bound \ |
_bfd_elf_get_dynamic_reloc_upper_bound |
#endif |
#ifndef bfd_elf32_canonicalize_dynamic_reloc |
#define bfd_elf32_canonicalize_dynamic_reloc \ |
_bfd_elf_canonicalize_dynamic_reloc |
#endif |
#ifdef elf_backend_relocate_section |
#ifndef bfd_elf32_bfd_link_hash_table_create |
#define bfd_elf32_bfd_link_hash_table_create _bfd_elf_link_hash_table_create |
#endif |
#ifndef bfd_elf32_bfd_link_hash_table_free |
#define bfd_elf32_bfd_link_hash_table_free _bfd_elf_link_hash_table_free |
#endif |
#ifndef bfd_elf32_bfd_link_add_symbols |
#define bfd_elf32_bfd_link_add_symbols bfd_elf_link_add_symbols |
#endif |
#ifndef bfd_elf32_bfd_final_link |
#define bfd_elf32_bfd_final_link bfd_elf_final_link |
#endif |
#else /* ! defined (elf_backend_relocate_section) */ |
/* If no backend relocate_section routine, use the generic linker. |
Note - this will prevent the port from being able to use some of |
the other features of the ELF linker, because the generic hash structure |
does not have the fields needed by the ELF linker. In particular it |
means that linking directly to S-records will not work. */ |
#ifndef bfd_elf32_bfd_link_hash_table_create |
#define bfd_elf32_bfd_link_hash_table_create \ |
_bfd_generic_link_hash_table_create |
#endif |
#ifndef bfd_elf32_bfd_link_hash_table_free |
#define bfd_elf32_bfd_link_hash_table_free _bfd_generic_link_hash_table_free |
#endif |
#ifndef bfd_elf32_bfd_link_add_symbols |
#define bfd_elf32_bfd_link_add_symbols _bfd_generic_link_add_symbols |
#endif |
#ifndef bfd_elf32_bfd_final_link |
#define bfd_elf32_bfd_final_link _bfd_generic_final_link |
#endif |
#endif /* ! defined (elf_backend_relocate_section) */ |
#ifndef bfd_elf32_bfd_link_just_syms |
#define bfd_elf32_bfd_link_just_syms _bfd_elf_link_just_syms |
#endif |
#ifndef bfd_elf32_bfd_copy_link_hash_symbol_type |
#define bfd_elf32_bfd_copy_link_hash_symbol_type \ |
_bfd_elf_copy_link_hash_symbol_type |
#endif |
#ifndef bfd_elf32_bfd_link_split_section |
#define bfd_elf32_bfd_link_split_section _bfd_generic_link_split_section |
#endif |
#ifndef bfd_elf32_archive_p |
#define bfd_elf32_archive_p bfd_generic_archive_p |
#endif |
#ifndef bfd_elf32_write_archive_contents |
#define bfd_elf32_write_archive_contents _bfd_write_archive_contents |
#endif |
#ifndef bfd_elf32_mkobject |
#define bfd_elf32_mkobject bfd_elf_make_object |
#endif |
#ifndef bfd_elf32_mkcorefile |
#define bfd_elf32_mkcorefile bfd_elf_mkcorefile |
#endif |
#ifndef bfd_elf32_mkarchive |
#define bfd_elf32_mkarchive _bfd_generic_mkarchive |
#endif |
#ifndef bfd_elf32_print_symbol |
#define bfd_elf32_print_symbol bfd_elf_print_symbol |
#endif |
#ifndef elf_symbol_leading_char |
#define elf_symbol_leading_char 0 |
#endif |
#ifndef elf_info_to_howto |
#define elf_info_to_howto 0 |
#endif |
#ifndef elf_info_to_howto_rel |
#define elf_info_to_howto_rel 0 |
#endif |
#ifndef elf_backend_arch_data |
#define elf_backend_arch_data NULL |
#endif |
#ifndef ELF_TARGET_ID |
#define ELF_TARGET_ID GENERIC_ELF_DATA |
#endif |
#ifndef ELF_OSABI |
#define ELF_OSABI ELFOSABI_NONE |
#endif |
#ifndef ELF_MAXPAGESIZE |
# error ELF_MAXPAGESIZE is not defined |
#define ELF_MAXPAGESIZE 1 |
#endif |
#ifndef ELF_COMMONPAGESIZE |
#define ELF_COMMONPAGESIZE ELF_MAXPAGESIZE |
#endif |
#ifndef ELF_MINPAGESIZE |
#define ELF_MINPAGESIZE ELF_COMMONPAGESIZE |
#endif |
#if ELF_COMMONPAGESIZE > ELF_MAXPAGESIZE |
# error ELF_COMMONPAGESIZE > ELF_MAXPAGESIZE |
#endif |
#if ELF_MINPAGESIZE > ELF_COMMONPAGESIZE |
# error ELF_MINPAGESIZE > ELF_COMMONPAGESIZE |
#endif |
#ifndef ELF_DYNAMIC_SEC_FLAGS |
/* Note that we set the SEC_IN_MEMORY flag for these sections. */ |
#define ELF_DYNAMIC_SEC_FLAGS \ |
(SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS \ |
| SEC_IN_MEMORY | SEC_LINKER_CREATED) |
#endif |
#ifndef elf_backend_collect |
#define elf_backend_collect FALSE |
#endif |
#ifndef elf_backend_type_change_ok |
#define elf_backend_type_change_ok FALSE |
#endif |
#ifndef elf_backend_sym_is_global |
#define elf_backend_sym_is_global 0 |
#endif |
#ifndef elf_backend_object_p |
#define elf_backend_object_p 0 |
#endif |
#ifndef elf_backend_symbol_processing |
#define elf_backend_symbol_processing 0 |
#endif |
#ifndef elf_backend_symbol_table_processing |
#define elf_backend_symbol_table_processing 0 |
#endif |
#ifndef elf_backend_get_symbol_type |
#define elf_backend_get_symbol_type 0 |
#endif |
#ifndef elf_backend_archive_symbol_lookup |
#define elf_backend_archive_symbol_lookup _bfd_elf_archive_symbol_lookup |
#endif |
#ifndef elf_backend_name_local_section_symbols |
#define elf_backend_name_local_section_symbols 0 |
#endif |
#ifndef elf_backend_section_processing |
#define elf_backend_section_processing 0 |
#endif |
#ifndef elf_backend_section_from_shdr |
#define elf_backend_section_from_shdr _bfd_elf_make_section_from_shdr |
#endif |
#ifndef elf_backend_section_flags |
#define elf_backend_section_flags 0 |
#endif |
#ifndef elf_backend_get_sec_type_attr |
#define elf_backend_get_sec_type_attr _bfd_elf_get_sec_type_attr |
#endif |
#ifndef elf_backend_section_from_phdr |
#define elf_backend_section_from_phdr _bfd_elf_make_section_from_phdr |
#endif |
#ifndef elf_backend_fake_sections |
#define elf_backend_fake_sections 0 |
#endif |
#ifndef elf_backend_section_from_bfd_section |
#define elf_backend_section_from_bfd_section 0 |
#endif |
#ifndef elf_backend_add_symbol_hook |
#define elf_backend_add_symbol_hook 0 |
#endif |
#ifndef elf_backend_link_output_symbol_hook |
#define elf_backend_link_output_symbol_hook 0 |
#endif |
#ifndef elf_backend_create_dynamic_sections |
#define elf_backend_create_dynamic_sections 0 |
#endif |
#ifndef elf_backend_omit_section_dynsym |
#define elf_backend_omit_section_dynsym _bfd_elf_link_omit_section_dynsym |
#endif |
#ifndef elf_backend_relocs_compatible |
#define elf_backend_relocs_compatible _bfd_elf_default_relocs_compatible |
#endif |
#ifndef elf_backend_check_relocs |
#define elf_backend_check_relocs 0 |
#endif |
#ifndef elf_backend_check_directives |
#define elf_backend_check_directives 0 |
#endif |
#ifndef elf_backend_notice_as_needed |
#define elf_backend_notice_as_needed _bfd_elf_notice_as_needed |
#endif |
#ifndef elf_backend_adjust_dynamic_symbol |
#define elf_backend_adjust_dynamic_symbol 0 |
#endif |
#ifndef elf_backend_always_size_sections |
#define elf_backend_always_size_sections 0 |
#endif |
#ifndef elf_backend_size_dynamic_sections |
#define elf_backend_size_dynamic_sections 0 |
#endif |
#ifndef elf_backend_init_index_section |
#define elf_backend_init_index_section \ |
((void (*) (bfd *, struct bfd_link_info *)) bfd_void) |
#endif |
#ifndef elf_backend_relocate_section |
#define elf_backend_relocate_section 0 |
#endif |
#ifndef elf_backend_finish_dynamic_symbol |
#define elf_backend_finish_dynamic_symbol 0 |
#endif |
#ifndef elf_backend_finish_dynamic_sections |
#define elf_backend_finish_dynamic_sections 0 |
#endif |
#ifndef elf_backend_begin_write_processing |
#define elf_backend_begin_write_processing 0 |
#endif |
#ifndef elf_backend_final_write_processing |
#define elf_backend_final_write_processing 0 |
#endif |
#ifndef elf_backend_additional_program_headers |
#define elf_backend_additional_program_headers 0 |
#endif |
#ifndef elf_backend_modify_segment_map |
#define elf_backend_modify_segment_map 0 |
#endif |
#ifndef elf_backend_modify_program_headers |
#define elf_backend_modify_program_headers 0 |
#endif |
#ifndef elf_backend_ecoff_debug_swap |
#define elf_backend_ecoff_debug_swap 0 |
#endif |
#ifndef elf_backend_bfd_from_remote_memory |
#define elf_backend_bfd_from_remote_memory _bfd_elf32_bfd_from_remote_memory |
#endif |
#ifndef elf_backend_got_header_size |
#define elf_backend_got_header_size 0 |
#endif |
#ifndef elf_backend_got_elt_size |
#define elf_backend_got_elt_size _bfd_elf_default_got_elt_size |
#endif |
#ifndef elf_backend_obj_attrs_vendor |
#define elf_backend_obj_attrs_vendor NULL |
#endif |
#ifndef elf_backend_obj_attrs_section |
#define elf_backend_obj_attrs_section NULL |
#endif |
#ifndef elf_backend_obj_attrs_arg_type |
#define elf_backend_obj_attrs_arg_type NULL |
#endif |
#ifndef elf_backend_obj_attrs_section_type |
#define elf_backend_obj_attrs_section_type SHT_GNU_ATTRIBUTES |
#endif |
#ifndef elf_backend_obj_attrs_order |
#define elf_backend_obj_attrs_order NULL |
#endif |
#ifndef elf_backend_obj_attrs_handle_unknown |
#define elf_backend_obj_attrs_handle_unknown NULL |
#endif |
#ifndef elf_backend_static_tls_alignment |
#define elf_backend_static_tls_alignment 1 |
#endif |
#ifndef elf_backend_post_process_headers |
#define elf_backend_post_process_headers NULL |
#endif |
#ifndef elf_backend_print_symbol_all |
#define elf_backend_print_symbol_all NULL |
#endif |
#ifndef elf_backend_output_arch_local_syms |
#define elf_backend_output_arch_local_syms NULL |
#endif |
#ifndef elf_backend_output_arch_syms |
#define elf_backend_output_arch_syms NULL |
#endif |
#ifndef elf_backend_copy_indirect_symbol |
#define elf_backend_copy_indirect_symbol _bfd_elf_link_hash_copy_indirect |
#endif |
#ifndef elf_backend_hide_symbol |
#define elf_backend_hide_symbol _bfd_elf_link_hash_hide_symbol |
#endif |
#ifndef elf_backend_fixup_symbol |
#define elf_backend_fixup_symbol NULL |
#endif |
#ifndef elf_backend_merge_symbol_attribute |
#define elf_backend_merge_symbol_attribute NULL |
#endif |
#ifndef elf_backend_get_target_dtag |
#define elf_backend_get_target_dtag NULL |
#endif |
#ifndef elf_backend_ignore_undef_symbol |
#define elf_backend_ignore_undef_symbol NULL |
#endif |
#ifndef elf_backend_emit_relocs |
#define elf_backend_emit_relocs _bfd_elf_link_output_relocs |
#endif |
#ifndef elf_backend_count_relocs |
#define elf_backend_count_relocs NULL |
#endif |
#ifndef elf_backend_grok_prstatus |
#define elf_backend_grok_prstatus NULL |
#endif |
#ifndef elf_backend_grok_psinfo |
#define elf_backend_grok_psinfo NULL |
#endif |
#ifndef elf_backend_write_core_note |
#define elf_backend_write_core_note NULL |
#endif |
#ifndef elf_backend_lookup_section_flags_hook |
#define elf_backend_lookup_section_flags_hook NULL |
#endif |
#ifndef elf_backend_reloc_type_class |
#define elf_backend_reloc_type_class _bfd_elf_reloc_type_class |
#endif |
#ifndef elf_backend_discard_info |
#define elf_backend_discard_info NULL |
#endif |
#ifndef elf_backend_ignore_discarded_relocs |
#define elf_backend_ignore_discarded_relocs NULL |
#endif |
#ifndef elf_backend_action_discarded |
#define elf_backend_action_discarded _bfd_elf_default_action_discarded |
#endif |
#ifndef elf_backend_eh_frame_address_size |
#define elf_backend_eh_frame_address_size _bfd_elf_eh_frame_address_size |
#endif |
#ifndef elf_backend_can_make_relative_eh_frame |
#define elf_backend_can_make_relative_eh_frame _bfd_elf_can_make_relative |
#endif |
#ifndef elf_backend_can_make_lsda_relative_eh_frame |
#define elf_backend_can_make_lsda_relative_eh_frame _bfd_elf_can_make_relative |
#endif |
#ifndef elf_backend_encode_eh_address |
#define elf_backend_encode_eh_address _bfd_elf_encode_eh_address |
#endif |
#ifndef elf_backend_write_section |
#define elf_backend_write_section NULL |
#endif |
#ifndef elf_backend_mips_irix_compat |
#define elf_backend_mips_irix_compat NULL |
#endif |
#ifndef elf_backend_mips_rtype_to_howto |
#define elf_backend_mips_rtype_to_howto NULL |
#endif |
/* Previously, backends could only use SHT_REL or SHT_RELA relocation |
sections, but not both. They defined USE_REL to indicate SHT_REL |
sections, and left it undefined to indicated SHT_RELA sections. |
For backwards compatibility, we still support this usage. */ |
#ifndef USE_REL |
#define USE_REL 0 |
#endif |
/* Use these in new code. */ |
#ifndef elf_backend_may_use_rel_p |
#define elf_backend_may_use_rel_p USE_REL |
#endif |
#ifndef elf_backend_may_use_rela_p |
#define elf_backend_may_use_rela_p !USE_REL |
#endif |
#ifndef elf_backend_default_use_rela_p |
#define elf_backend_default_use_rela_p !USE_REL |
#endif |
#ifndef elf_backend_rela_plts_and_copies_p |
#define elf_backend_rela_plts_and_copies_p elf_backend_default_use_rela_p |
#endif |
#ifndef elf_backend_rela_normal |
#define elf_backend_rela_normal 0 |
#endif |
#ifndef elf_backend_plt_sym_val |
#define elf_backend_plt_sym_val NULL |
#endif |
#ifndef elf_backend_relplt_name |
#define elf_backend_relplt_name NULL |
#endif |
#ifndef ELF_MACHINE_ALT1 |
#define ELF_MACHINE_ALT1 0 |
#endif |
#ifndef ELF_MACHINE_ALT2 |
#define ELF_MACHINE_ALT2 0 |
#endif |
#ifndef elf_backend_size_info |
#define elf_backend_size_info _bfd_elf32_size_info |
#endif |
#ifndef elf_backend_special_sections |
#define elf_backend_special_sections NULL |
#endif |
#ifndef elf_backend_sign_extend_vma |
#define elf_backend_sign_extend_vma 0 |
#endif |
#ifndef elf_backend_link_order_error_handler |
#define elf_backend_link_order_error_handler _bfd_default_error_handler |
#endif |
#ifndef elf_backend_common_definition |
#define elf_backend_common_definition _bfd_elf_common_definition |
#endif |
#ifndef elf_backend_common_section_index |
#define elf_backend_common_section_index _bfd_elf_common_section_index |
#endif |
#ifndef elf_backend_common_section |
#define elf_backend_common_section _bfd_elf_common_section |
#endif |
#ifndef elf_backend_merge_symbol |
#define elf_backend_merge_symbol NULL |
#endif |
#ifndef elf_backend_hash_symbol |
#define elf_backend_hash_symbol _bfd_elf_hash_symbol |
#endif |
#ifndef elf_backend_is_function_type |
#define elf_backend_is_function_type _bfd_elf_is_function_type |
#endif |
#ifndef elf_backend_maybe_function_sym |
#define elf_backend_maybe_function_sym _bfd_elf_maybe_function_sym |
#endif |
#ifndef elf_match_priority |
#define elf_match_priority \ |
(ELF_ARCH == bfd_arch_unknown ? 2 : ELF_OSABI == ELFOSABI_NONE ? 1 : 0) |
#endif |
extern const struct elf_size_info _bfd_elf32_size_info; |
static struct elf_backend_data elf32_bed = |
{ |
ELF_ARCH, /* arch */ |
ELF_TARGET_ID, /* target_id */ |
ELF_MACHINE_CODE, /* elf_machine_code */ |
ELF_OSABI, /* elf_osabi */ |
ELF_MAXPAGESIZE, /* maxpagesize */ |
ELF_MINPAGESIZE, /* minpagesize */ |
ELF_COMMONPAGESIZE, /* commonpagesize */ |
ELF_DYNAMIC_SEC_FLAGS, /* dynamic_sec_flags */ |
elf_backend_arch_data, |
elf_info_to_howto, |
elf_info_to_howto_rel, |
elf_backend_sym_is_global, |
elf_backend_object_p, |
elf_backend_symbol_processing, |
elf_backend_symbol_table_processing, |
elf_backend_get_symbol_type, |
elf_backend_archive_symbol_lookup, |
elf_backend_name_local_section_symbols, |
elf_backend_section_processing, |
elf_backend_section_from_shdr, |
elf_backend_section_flags, |
elf_backend_get_sec_type_attr, |
elf_backend_section_from_phdr, |
elf_backend_fake_sections, |
elf_backend_section_from_bfd_section, |
elf_backend_add_symbol_hook, |
elf_backend_link_output_symbol_hook, |
elf_backend_create_dynamic_sections, |
elf_backend_omit_section_dynsym, |
elf_backend_relocs_compatible, |
elf_backend_check_relocs, |
elf_backend_check_directives, |
elf_backend_notice_as_needed, |
elf_backend_adjust_dynamic_symbol, |
elf_backend_always_size_sections, |
elf_backend_size_dynamic_sections, |
elf_backend_init_index_section, |
elf_backend_relocate_section, |
elf_backend_finish_dynamic_symbol, |
elf_backend_finish_dynamic_sections, |
elf_backend_begin_write_processing, |
elf_backend_final_write_processing, |
elf_backend_additional_program_headers, |
elf_backend_modify_segment_map, |
elf_backend_modify_program_headers, |
elf_backend_gc_keep, |
elf_backend_gc_mark_dynamic_ref, |
elf_backend_gc_mark_hook, |
elf_backend_gc_mark_extra_sections, |
elf_backend_gc_sweep_hook, |
elf_backend_post_process_headers, |
elf_backend_print_symbol_all, |
elf_backend_output_arch_local_syms, |
elf_backend_output_arch_syms, |
elf_backend_copy_indirect_symbol, |
elf_backend_hide_symbol, |
elf_backend_fixup_symbol, |
elf_backend_merge_symbol_attribute, |
elf_backend_get_target_dtag, |
elf_backend_ignore_undef_symbol, |
elf_backend_emit_relocs, |
elf_backend_count_relocs, |
elf_backend_grok_prstatus, |
elf_backend_grok_psinfo, |
elf_backend_write_core_note, |
elf_backend_lookup_section_flags_hook, |
elf_backend_reloc_type_class, |
elf_backend_discard_info, |
elf_backend_ignore_discarded_relocs, |
elf_backend_action_discarded, |
elf_backend_eh_frame_address_size, |
elf_backend_can_make_relative_eh_frame, |
elf_backend_can_make_lsda_relative_eh_frame, |
elf_backend_encode_eh_address, |
elf_backend_write_section, |
elf_backend_mips_irix_compat, |
elf_backend_mips_rtype_to_howto, |
elf_backend_ecoff_debug_swap, |
elf_backend_bfd_from_remote_memory, |
elf_backend_plt_sym_val, |
elf_backend_common_definition, |
elf_backend_common_section_index, |
elf_backend_common_section, |
elf_backend_merge_symbol, |
elf_backend_hash_symbol, |
elf_backend_is_function_type, |
elf_backend_maybe_function_sym, |
elf_backend_link_order_error_handler, |
elf_backend_relplt_name, |
ELF_MACHINE_ALT1, |
ELF_MACHINE_ALT2, |
&elf_backend_size_info, |
elf_backend_special_sections, |
elf_backend_got_header_size, |
elf_backend_got_elt_size, |
elf_backend_obj_attrs_vendor, |
elf_backend_obj_attrs_section, |
elf_backend_obj_attrs_arg_type, |
elf_backend_obj_attrs_section_type, |
elf_backend_obj_attrs_order, |
elf_backend_obj_attrs_handle_unknown, |
elf_backend_static_tls_alignment, |
elf_backend_stack_align, |
elf_backend_collect, |
elf_backend_type_change_ok, |
elf_backend_may_use_rel_p, |
elf_backend_may_use_rela_p, |
elf_backend_default_use_rela_p, |
elf_backend_rela_plts_and_copies_p, |
elf_backend_rela_normal, |
elf_backend_sign_extend_vma, |
elf_backend_want_got_plt, |
elf_backend_plt_readonly, |
elf_backend_want_plt_sym, |
elf_backend_plt_not_loaded, |
elf_backend_plt_alignment, |
elf_backend_can_gc_sections, |
elf_backend_can_refcount, |
elf_backend_want_got_sym, |
elf_backend_want_dynbss, |
elf_backend_want_p_paddr_set_to_zero, |
elf_backend_default_execstack |
}; |
/* Forward declaration for use when initialising alternative_target field. */ |
#ifdef TARGET_LITTLE_SYM |
extern const bfd_target TARGET_LITTLE_SYM; |
#endif |
#ifdef TARGET_BIG_SYM |
const bfd_target TARGET_BIG_SYM = |
{ |
/* name: identify kind of target */ |
TARGET_BIG_NAME, |
/* flavour: general indication about file */ |
bfd_target_elf_flavour, |
/* byteorder: data is big endian */ |
BFD_ENDIAN_BIG, |
/* header_byteorder: header is also big endian */ |
BFD_ENDIAN_BIG, |
/* object_flags: mask of all file flags */ |
(HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS |
| DYNAMIC | WP_TEXT | D_PAGED | BFD_COMPRESS | BFD_DECOMPRESS), |
/* section_flags: mask of all section flags */ |
(SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY |
| SEC_CODE | SEC_DATA | SEC_DEBUGGING | SEC_EXCLUDE | SEC_SORT_ENTRIES |
| SEC_SMALL_DATA | SEC_MERGE | SEC_STRINGS | SEC_GROUP), |
/* leading_symbol_char: is the first char of a user symbol |
predictable, and if so what is it */ |
elf_symbol_leading_char, |
/* ar_pad_char: pad character for filenames within an archive header |
FIXME: this really has nothing to do with ELF, this is a characteristic |
of the archiver and/or os and should be independently tunable */ |
'/', |
/* ar_max_namelen: maximum number of characters in an archive header |
FIXME: this really has nothing to do with ELF, this is a characteristic |
of the archiver and should be independently tunable. The System V ABI, |
Chapter 7 (Formats & Protocols), Archive section sets this as 15. */ |
15, |
elf_match_priority, |
/* Routines to byte-swap various sized integers from the data sections */ |
bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
bfd_getb16, bfd_getb_signed_16, bfd_putb16, |
/* Routines to byte-swap various sized integers from the file headers */ |
bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
bfd_getb16, bfd_getb_signed_16, bfd_putb16, |
/* bfd_check_format: check the format of a file being read */ |
{ _bfd_dummy_target, /* unknown format */ |
bfd_elf32_object_p, /* assembler/linker output (object file) */ |
bfd_elf32_archive_p, /* an archive */ |
bfd_elf32_core_file_p /* a core file */ |
}, |
/* bfd_set_format: set the format of a file being written */ |
{ bfd_false, |
bfd_elf32_mkobject, |
bfd_elf32_mkarchive, |
bfd_elf32_mkcorefile |
}, |
/* bfd_write_contents: write cached information into a file being written */ |
{ bfd_false, |
bfd_elf32_write_object_contents, |
bfd_elf32_write_archive_contents, |
bfd_elf32_write_corefile_contents, |
}, |
BFD_JUMP_TABLE_GENERIC (bfd_elf32), |
BFD_JUMP_TABLE_COPY (bfd_elf32), |
BFD_JUMP_TABLE_CORE (bfd_elf32), |
#ifdef bfd_elf32_archive_functions |
BFD_JUMP_TABLE_ARCHIVE (bfd_elf32_archive), |
#else |
BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), |
#endif |
BFD_JUMP_TABLE_SYMBOLS (bfd_elf32), |
BFD_JUMP_TABLE_RELOCS (bfd_elf32), |
BFD_JUMP_TABLE_WRITE (bfd_elf32), |
BFD_JUMP_TABLE_LINK (bfd_elf32), |
BFD_JUMP_TABLE_DYNAMIC (bfd_elf32), |
/* Alternative endian target. */ |
#ifdef TARGET_LITTLE_SYM |
& TARGET_LITTLE_SYM, |
#else |
NULL, |
#endif |
/* backend_data: */ |
&elf32_bed |
}; |
#endif |
#ifdef TARGET_LITTLE_SYM |
const bfd_target TARGET_LITTLE_SYM = |
{ |
/* name: identify kind of target */ |
TARGET_LITTLE_NAME, |
/* flavour: general indication about file */ |
bfd_target_elf_flavour, |
/* byteorder: data is little endian */ |
BFD_ENDIAN_LITTLE, |
/* header_byteorder: header is also little endian */ |
BFD_ENDIAN_LITTLE, |
/* object_flags: mask of all file flags */ |
(HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS |
| DYNAMIC | WP_TEXT | D_PAGED | BFD_COMPRESS | BFD_DECOMPRESS), |
/* section_flags: mask of all section flags */ |
(SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY |
| SEC_CODE | SEC_DATA | SEC_DEBUGGING | SEC_EXCLUDE | SEC_SORT_ENTRIES |
| SEC_SMALL_DATA | SEC_MERGE | SEC_STRINGS | SEC_GROUP), |
/* leading_symbol_char: is the first char of a user symbol |
predictable, and if so what is it */ |
elf_symbol_leading_char, |
/* ar_pad_char: pad character for filenames within an archive header |
FIXME: this really has nothing to do with ELF, this is a characteristic |
of the archiver and/or os and should be independently tunable */ |
'/', |
/* ar_max_namelen: maximum number of characters in an archive header |
FIXME: this really has nothing to do with ELF, this is a characteristic |
of the archiver and should be independently tunable. The System V ABI, |
Chapter 7 (Formats & Protocols), Archive section sets this as 15. */ |
15, |
elf_match_priority, |
/* Routines to byte-swap various sized integers from the data sections */ |
bfd_getl64, bfd_getl_signed_64, bfd_putl64, |
bfd_getl32, bfd_getl_signed_32, bfd_putl32, |
bfd_getl16, bfd_getl_signed_16, bfd_putl16, |
/* Routines to byte-swap various sized integers from the file headers */ |
bfd_getl64, bfd_getl_signed_64, bfd_putl64, |
bfd_getl32, bfd_getl_signed_32, bfd_putl32, |
bfd_getl16, bfd_getl_signed_16, bfd_putl16, |
/* bfd_check_format: check the format of a file being read */ |
{ _bfd_dummy_target, /* unknown format */ |
bfd_elf32_object_p, /* assembler/linker output (object file) */ |
bfd_elf32_archive_p, /* an archive */ |
bfd_elf32_core_file_p /* a core file */ |
}, |
/* bfd_set_format: set the format of a file being written */ |
{ bfd_false, |
bfd_elf32_mkobject, |
bfd_elf32_mkarchive, |
bfd_elf32_mkcorefile |
}, |
/* bfd_write_contents: write cached information into a file being written */ |
{ bfd_false, |
bfd_elf32_write_object_contents, |
bfd_elf32_write_archive_contents, |
bfd_elf32_write_corefile_contents, |
}, |
BFD_JUMP_TABLE_GENERIC (bfd_elf32), |
BFD_JUMP_TABLE_COPY (bfd_elf32), |
BFD_JUMP_TABLE_CORE (bfd_elf32), |
#ifdef bfd_elf32_archive_functions |
BFD_JUMP_TABLE_ARCHIVE (bfd_elf32_archive), |
#else |
BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), |
#endif |
BFD_JUMP_TABLE_SYMBOLS (bfd_elf32), |
BFD_JUMP_TABLE_RELOCS (bfd_elf32), |
BFD_JUMP_TABLE_WRITE (bfd_elf32), |
BFD_JUMP_TABLE_LINK (bfd_elf32), |
BFD_JUMP_TABLE_DYNAMIC (bfd_elf32), |
/* Alternative endian target. */ |
#ifdef TARGET_BIG_SYM |
& TARGET_BIG_SYM, |
#else |
NULL, |
#endif |
/* backend_data: */ |
&elf32_bed |
}; |
#endif |
/contrib/toolchain/binutils/bfd/elf32.c |
---|
0,0 → 1,24 |
/* ELF 32-bit executable support for BFD. |
Copyright 1993, 2001, 2004, 2005, 2006, 2007, 2008, 2009 |
Free Software Foundation, Inc. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#define ARCH_SIZE 32 |
#include "elfcode.h" |
/contrib/toolchain/binutils/bfd/elf64-target.h |
---|
0,0 → 1,999 |
/* Target definitions for 64-bit ELF |
Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, |
2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 |
Free Software Foundation, Inc. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* This structure contains everything that BFD knows about a target. |
It includes things like its byte order, name, what routines to call |
to do various operations, etc. Every BFD points to a target structure |
with its "xvec" member. |
There are two such structures here: one for big-endian machines and |
one for little-endian machines. */ |
#ifndef bfd_elf64_close_and_cleanup |
#define bfd_elf64_close_and_cleanup _bfd_elf_close_and_cleanup |
#endif |
#ifndef bfd_elf64_bfd_free_cached_info |
#define bfd_elf64_bfd_free_cached_info _bfd_free_cached_info |
#endif |
#ifndef bfd_elf64_get_section_contents |
#define bfd_elf64_get_section_contents _bfd_generic_get_section_contents |
#endif |
#define bfd_elf64_canonicalize_dynamic_symtab \ |
_bfd_elf_canonicalize_dynamic_symtab |
#ifndef bfd_elf64_get_synthetic_symtab |
#define bfd_elf64_get_synthetic_symtab \ |
_bfd_elf_get_synthetic_symtab |
#endif |
#ifndef bfd_elf64_canonicalize_reloc |
#define bfd_elf64_canonicalize_reloc _bfd_elf_canonicalize_reloc |
#endif |
#ifndef bfd_elf64_find_nearest_line |
#define bfd_elf64_find_nearest_line _bfd_elf_find_nearest_line |
#endif |
#ifndef bfd_elf64_find_inliner_info |
#define bfd_elf64_find_inliner_info _bfd_elf_find_inliner_info |
#endif |
#define bfd_elf64_read_minisymbols _bfd_elf_read_minisymbols |
#define bfd_elf64_minisymbol_to_symbol _bfd_elf_minisymbol_to_symbol |
#define bfd_elf64_get_dynamic_symtab_upper_bound \ |
_bfd_elf_get_dynamic_symtab_upper_bound |
#define bfd_elf64_get_lineno _bfd_elf_get_lineno |
#ifndef bfd_elf64_get_reloc_upper_bound |
#define bfd_elf64_get_reloc_upper_bound _bfd_elf_get_reloc_upper_bound |
#endif |
#ifndef bfd_elf64_get_symbol_info |
#define bfd_elf64_get_symbol_info _bfd_elf_get_symbol_info |
#endif |
#define bfd_elf64_canonicalize_symtab _bfd_elf_canonicalize_symtab |
#define bfd_elf64_get_symtab_upper_bound _bfd_elf_get_symtab_upper_bound |
#define bfd_elf64_make_empty_symbol _bfd_elf_make_empty_symbol |
#ifndef bfd_elf64_new_section_hook |
#define bfd_elf64_new_section_hook _bfd_elf_new_section_hook |
#endif |
#define bfd_elf64_set_arch_mach _bfd_elf_set_arch_mach |
#ifndef bfd_elf64_set_section_contents |
#define bfd_elf64_set_section_contents _bfd_elf_set_section_contents |
#endif |
#define bfd_elf64_sizeof_headers _bfd_elf_sizeof_headers |
#define bfd_elf64_write_object_contents _bfd_elf_write_object_contents |
#define bfd_elf64_write_corefile_contents _bfd_elf_write_corefile_contents |
#define bfd_elf64_get_section_contents_in_window \ |
_bfd_generic_get_section_contents_in_window |
#ifndef elf_backend_can_refcount |
#define elf_backend_can_refcount 0 |
#endif |
#ifndef elf_backend_want_got_plt |
#define elf_backend_want_got_plt 0 |
#endif |
#ifndef elf_backend_plt_readonly |
#define elf_backend_plt_readonly 0 |
#endif |
#ifndef elf_backend_want_plt_sym |
#define elf_backend_want_plt_sym 0 |
#endif |
#ifndef elf_backend_plt_not_loaded |
#define elf_backend_plt_not_loaded 0 |
#endif |
#ifndef elf_backend_plt_alignment |
#define elf_backend_plt_alignment 2 |
#endif |
#ifndef elf_backend_want_dynbss |
#define elf_backend_want_dynbss 1 |
#endif |
#ifndef elf_backend_want_p_paddr_set_to_zero |
#define elf_backend_want_p_paddr_set_to_zero 0 |
#endif |
#ifndef elf_backend_default_execstack |
#define elf_backend_default_execstack 1 |
#endif |
#ifndef elf_backend_stack_align |
#define elf_backend_stack_align 16 |
#endif |
#define bfd_elf64_bfd_debug_info_start bfd_void |
#define bfd_elf64_bfd_debug_info_end bfd_void |
#define bfd_elf64_bfd_debug_info_accumulate \ |
((void (*) (bfd*, struct bfd_section *)) bfd_void) |
#ifndef bfd_elf64_bfd_get_relocated_section_contents |
#define bfd_elf64_bfd_get_relocated_section_contents \ |
bfd_generic_get_relocated_section_contents |
#endif |
#ifndef bfd_elf64_bfd_relax_section |
#define bfd_elf64_bfd_relax_section bfd_generic_relax_section |
#endif |
#ifndef elf_backend_can_gc_sections |
#define elf_backend_can_gc_sections 0 |
#endif |
#ifndef elf_backend_can_refcount |
#define elf_backend_can_refcount 0 |
#endif |
#ifndef elf_backend_want_got_sym |
#define elf_backend_want_got_sym 1 |
#endif |
#ifndef elf_backend_gc_keep |
#define elf_backend_gc_keep _bfd_elf_gc_keep |
#endif |
#ifndef elf_backend_gc_mark_dynamic_ref |
#define elf_backend_gc_mark_dynamic_ref bfd_elf_gc_mark_dynamic_ref_symbol |
#endif |
#ifndef elf_backend_gc_mark_hook |
#define elf_backend_gc_mark_hook _bfd_elf_gc_mark_hook |
#endif |
#ifndef elf_backend_gc_mark_extra_sections |
#define elf_backend_gc_mark_extra_sections _bfd_elf_gc_mark_extra_sections |
#endif |
#ifndef elf_backend_gc_sweep_hook |
#define elf_backend_gc_sweep_hook NULL |
#endif |
#ifndef bfd_elf64_bfd_gc_sections |
#define bfd_elf64_bfd_gc_sections bfd_elf_gc_sections |
#endif |
#ifndef bfd_elf64_bfd_merge_sections |
#define bfd_elf64_bfd_merge_sections \ |
_bfd_elf_merge_sections |
#endif |
#ifndef bfd_elf64_bfd_is_group_section |
#define bfd_elf64_bfd_is_group_section bfd_elf_is_group_section |
#endif |
#ifndef bfd_elf64_bfd_discard_group |
#define bfd_elf64_bfd_discard_group bfd_generic_discard_group |
#endif |
#ifndef bfd_elf64_section_already_linked |
#define bfd_elf64_section_already_linked \ |
_bfd_elf_section_already_linked |
#endif |
#ifndef bfd_elf64_bfd_define_common_symbol |
#define bfd_elf64_bfd_define_common_symbol bfd_generic_define_common_symbol |
#endif |
#ifndef bfd_elf64_bfd_lookup_section_flags |
#define bfd_elf64_bfd_lookup_section_flags bfd_elf_lookup_section_flags |
#endif |
#ifndef bfd_elf64_bfd_make_debug_symbol |
#define bfd_elf64_bfd_make_debug_symbol \ |
((asymbol * (*) (bfd *, void *, unsigned long)) bfd_nullvoidptr) |
#endif |
#ifndef bfd_elf64_bfd_copy_private_symbol_data |
#define bfd_elf64_bfd_copy_private_symbol_data \ |
_bfd_elf_copy_private_symbol_data |
#endif |
#ifndef bfd_elf64_bfd_copy_private_section_data |
#define bfd_elf64_bfd_copy_private_section_data \ |
_bfd_elf_copy_private_section_data |
#endif |
#ifndef bfd_elf64_bfd_copy_private_header_data |
#define bfd_elf64_bfd_copy_private_header_data \ |
_bfd_elf_copy_private_header_data |
#endif |
#ifndef bfd_elf64_bfd_copy_private_bfd_data |
#define bfd_elf64_bfd_copy_private_bfd_data \ |
_bfd_elf_copy_private_bfd_data |
#endif |
#ifndef bfd_elf64_bfd_print_private_bfd_data |
#define bfd_elf64_bfd_print_private_bfd_data \ |
_bfd_elf_print_private_bfd_data |
#endif |
#ifndef bfd_elf64_bfd_merge_private_bfd_data |
#define bfd_elf64_bfd_merge_private_bfd_data \ |
((bfd_boolean (*) (bfd *, bfd *)) bfd_true) |
#endif |
#ifndef bfd_elf64_bfd_set_private_flags |
#define bfd_elf64_bfd_set_private_flags \ |
((bfd_boolean (*) (bfd *, flagword)) bfd_true) |
#endif |
#ifndef bfd_elf64_bfd_is_local_label_name |
#define bfd_elf64_bfd_is_local_label_name _bfd_elf_is_local_label_name |
#endif |
#ifndef bfd_elf64_bfd_is_target_special_symbol |
#define bfd_elf64_bfd_is_target_special_symbol \ |
((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) |
#endif |
#ifndef bfd_elf64_get_dynamic_reloc_upper_bound |
#define bfd_elf64_get_dynamic_reloc_upper_bound \ |
_bfd_elf_get_dynamic_reloc_upper_bound |
#endif |
#ifndef bfd_elf64_canonicalize_dynamic_reloc |
#define bfd_elf64_canonicalize_dynamic_reloc \ |
_bfd_elf_canonicalize_dynamic_reloc |
#endif |
#ifdef elf_backend_relocate_section |
#ifndef bfd_elf64_bfd_link_hash_table_create |
#define bfd_elf64_bfd_link_hash_table_create _bfd_elf_link_hash_table_create |
#endif |
#ifndef bfd_elf64_bfd_link_hash_table_free |
#define bfd_elf64_bfd_link_hash_table_free _bfd_elf_link_hash_table_free |
#endif |
#ifndef bfd_elf64_bfd_link_add_symbols |
#define bfd_elf64_bfd_link_add_symbols bfd_elf_link_add_symbols |
#endif |
#ifndef bfd_elf64_bfd_final_link |
#define bfd_elf64_bfd_final_link bfd_elf_final_link |
#endif |
#else /* ! defined (elf_backend_relocate_section) */ |
/* If no backend relocate_section routine, use the generic linker. |
Note - this will prevent the port from being able to use some of |
the other features of the ELF linker, because the generic hash structure |
does not have the fields needed by the ELF linker. In particular it |
means that linking directly to S-records will not work. */ |
#ifndef bfd_elf64_bfd_link_hash_table_create |
#define bfd_elf64_bfd_link_hash_table_create \ |
_bfd_generic_link_hash_table_create |
#endif |
#ifndef bfd_elf64_bfd_link_hash_table_free |
#define bfd_elf64_bfd_link_hash_table_free _bfd_generic_link_hash_table_free |
#endif |
#ifndef bfd_elf64_bfd_link_add_symbols |
#define bfd_elf64_bfd_link_add_symbols _bfd_generic_link_add_symbols |
#endif |
#ifndef bfd_elf64_bfd_final_link |
#define bfd_elf64_bfd_final_link _bfd_generic_final_link |
#endif |
#endif /* ! defined (elf_backend_relocate_section) */ |
#ifndef bfd_elf64_bfd_link_just_syms |
#define bfd_elf64_bfd_link_just_syms _bfd_elf_link_just_syms |
#endif |
#ifndef bfd_elf64_bfd_copy_link_hash_symbol_type |
#define bfd_elf64_bfd_copy_link_hash_symbol_type \ |
_bfd_elf_copy_link_hash_symbol_type |
#endif |
#ifndef bfd_elf64_bfd_link_split_section |
#define bfd_elf64_bfd_link_split_section _bfd_generic_link_split_section |
#endif |
#ifndef bfd_elf64_archive_p |
#define bfd_elf64_archive_p bfd_generic_archive_p |
#endif |
#ifndef bfd_elf64_write_archive_contents |
#define bfd_elf64_write_archive_contents _bfd_write_archive_contents |
#endif |
#ifndef bfd_elf64_mkobject |
#define bfd_elf64_mkobject bfd_elf_make_object |
#endif |
#ifndef bfd_elf64_mkcorefile |
#define bfd_elf64_mkcorefile bfd_elf_mkcorefile |
#endif |
#ifndef bfd_elf64_mkarchive |
#define bfd_elf64_mkarchive _bfd_generic_mkarchive |
#endif |
#ifndef bfd_elf64_print_symbol |
#define bfd_elf64_print_symbol bfd_elf_print_symbol |
#endif |
#ifndef elf_symbol_leading_char |
#define elf_symbol_leading_char 0 |
#endif |
#ifndef elf_info_to_howto |
#define elf_info_to_howto 0 |
#endif |
#ifndef elf_info_to_howto_rel |
#define elf_info_to_howto_rel 0 |
#endif |
#ifndef elf_backend_arch_data |
#define elf_backend_arch_data NULL |
#endif |
#ifndef ELF_TARGET_ID |
#define ELF_TARGET_ID GENERIC_ELF_DATA |
#endif |
#ifndef ELF_OSABI |
#define ELF_OSABI ELFOSABI_NONE |
#endif |
#ifndef ELF_MAXPAGESIZE |
# error ELF_MAXPAGESIZE is not defined |
#define ELF_MAXPAGESIZE 1 |
#endif |
#ifndef ELF_COMMONPAGESIZE |
#define ELF_COMMONPAGESIZE ELF_MAXPAGESIZE |
#endif |
#ifndef ELF_MINPAGESIZE |
#define ELF_MINPAGESIZE ELF_COMMONPAGESIZE |
#endif |
#if ELF_COMMONPAGESIZE > ELF_MAXPAGESIZE |
# error ELF_COMMONPAGESIZE > ELF_MAXPAGESIZE |
#endif |
#if ELF_MINPAGESIZE > ELF_COMMONPAGESIZE |
# error ELF_MINPAGESIZE > ELF_COMMONPAGESIZE |
#endif |
#ifndef ELF_DYNAMIC_SEC_FLAGS |
/* Note that we set the SEC_IN_MEMORY flag for these sections. */ |
#define ELF_DYNAMIC_SEC_FLAGS \ |
(SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS \ |
| SEC_IN_MEMORY | SEC_LINKER_CREATED) |
#endif |
#ifndef elf_backend_collect |
#define elf_backend_collect FALSE |
#endif |
#ifndef elf_backend_type_change_ok |
#define elf_backend_type_change_ok FALSE |
#endif |
#ifndef elf_backend_sym_is_global |
#define elf_backend_sym_is_global 0 |
#endif |
#ifndef elf_backend_object_p |
#define elf_backend_object_p 0 |
#endif |
#ifndef elf_backend_symbol_processing |
#define elf_backend_symbol_processing 0 |
#endif |
#ifndef elf_backend_symbol_table_processing |
#define elf_backend_symbol_table_processing 0 |
#endif |
#ifndef elf_backend_get_symbol_type |
#define elf_backend_get_symbol_type 0 |
#endif |
#ifndef elf_backend_archive_symbol_lookup |
#define elf_backend_archive_symbol_lookup _bfd_elf_archive_symbol_lookup |
#endif |
#ifndef elf_backend_name_local_section_symbols |
#define elf_backend_name_local_section_symbols 0 |
#endif |
#ifndef elf_backend_section_processing |
#define elf_backend_section_processing 0 |
#endif |
#ifndef elf_backend_section_from_shdr |
#define elf_backend_section_from_shdr _bfd_elf_make_section_from_shdr |
#endif |
#ifndef elf_backend_section_flags |
#define elf_backend_section_flags 0 |
#endif |
#ifndef elf_backend_get_sec_type_attr |
#define elf_backend_get_sec_type_attr _bfd_elf_get_sec_type_attr |
#endif |
#ifndef elf_backend_section_from_phdr |
#define elf_backend_section_from_phdr _bfd_elf_make_section_from_phdr |
#endif |
#ifndef elf_backend_fake_sections |
#define elf_backend_fake_sections 0 |
#endif |
#ifndef elf_backend_section_from_bfd_section |
#define elf_backend_section_from_bfd_section 0 |
#endif |
#ifndef elf_backend_add_symbol_hook |
#define elf_backend_add_symbol_hook 0 |
#endif |
#ifndef elf_backend_link_output_symbol_hook |
#define elf_backend_link_output_symbol_hook 0 |
#endif |
#ifndef elf_backend_create_dynamic_sections |
#define elf_backend_create_dynamic_sections 0 |
#endif |
#ifndef elf_backend_omit_section_dynsym |
#define elf_backend_omit_section_dynsym _bfd_elf_link_omit_section_dynsym |
#endif |
#ifndef elf_backend_relocs_compatible |
#define elf_backend_relocs_compatible _bfd_elf_default_relocs_compatible |
#endif |
#ifndef elf_backend_check_relocs |
#define elf_backend_check_relocs 0 |
#endif |
#ifndef elf_backend_check_directives |
#define elf_backend_check_directives 0 |
#endif |
#ifndef elf_backend_notice_as_needed |
#define elf_backend_notice_as_needed _bfd_elf_notice_as_needed |
#endif |
#ifndef elf_backend_adjust_dynamic_symbol |
#define elf_backend_adjust_dynamic_symbol 0 |
#endif |
#ifndef elf_backend_always_size_sections |
#define elf_backend_always_size_sections 0 |
#endif |
#ifndef elf_backend_size_dynamic_sections |
#define elf_backend_size_dynamic_sections 0 |
#endif |
#ifndef elf_backend_init_index_section |
#define elf_backend_init_index_section \ |
((void (*) (bfd *, struct bfd_link_info *)) bfd_void) |
#endif |
#ifndef elf_backend_relocate_section |
#define elf_backend_relocate_section 0 |
#endif |
#ifndef elf_backend_finish_dynamic_symbol |
#define elf_backend_finish_dynamic_symbol 0 |
#endif |
#ifndef elf_backend_finish_dynamic_sections |
#define elf_backend_finish_dynamic_sections 0 |
#endif |
#ifndef elf_backend_begin_write_processing |
#define elf_backend_begin_write_processing 0 |
#endif |
#ifndef elf_backend_final_write_processing |
#define elf_backend_final_write_processing 0 |
#endif |
#ifndef elf_backend_additional_program_headers |
#define elf_backend_additional_program_headers 0 |
#endif |
#ifndef elf_backend_modify_segment_map |
#define elf_backend_modify_segment_map 0 |
#endif |
#ifndef elf_backend_modify_program_headers |
#define elf_backend_modify_program_headers 0 |
#endif |
#ifndef elf_backend_ecoff_debug_swap |
#define elf_backend_ecoff_debug_swap 0 |
#endif |
#ifndef elf_backend_bfd_from_remote_memory |
#define elf_backend_bfd_from_remote_memory _bfd_elf64_bfd_from_remote_memory |
#endif |
#ifndef elf_backend_got_header_size |
#define elf_backend_got_header_size 0 |
#endif |
#ifndef elf_backend_got_elt_size |
#define elf_backend_got_elt_size _bfd_elf_default_got_elt_size |
#endif |
#ifndef elf_backend_obj_attrs_vendor |
#define elf_backend_obj_attrs_vendor NULL |
#endif |
#ifndef elf_backend_obj_attrs_section |
#define elf_backend_obj_attrs_section NULL |
#endif |
#ifndef elf_backend_obj_attrs_arg_type |
#define elf_backend_obj_attrs_arg_type NULL |
#endif |
#ifndef elf_backend_obj_attrs_section_type |
#define elf_backend_obj_attrs_section_type SHT_GNU_ATTRIBUTES |
#endif |
#ifndef elf_backend_obj_attrs_order |
#define elf_backend_obj_attrs_order NULL |
#endif |
#ifndef elf_backend_obj_attrs_handle_unknown |
#define elf_backend_obj_attrs_handle_unknown NULL |
#endif |
#ifndef elf_backend_static_tls_alignment |
#define elf_backend_static_tls_alignment 1 |
#endif |
#ifndef elf_backend_post_process_headers |
#define elf_backend_post_process_headers NULL |
#endif |
#ifndef elf_backend_print_symbol_all |
#define elf_backend_print_symbol_all NULL |
#endif |
#ifndef elf_backend_output_arch_local_syms |
#define elf_backend_output_arch_local_syms NULL |
#endif |
#ifndef elf_backend_output_arch_syms |
#define elf_backend_output_arch_syms NULL |
#endif |
#ifndef elf_backend_copy_indirect_symbol |
#define elf_backend_copy_indirect_symbol _bfd_elf_link_hash_copy_indirect |
#endif |
#ifndef elf_backend_hide_symbol |
#define elf_backend_hide_symbol _bfd_elf_link_hash_hide_symbol |
#endif |
#ifndef elf_backend_fixup_symbol |
#define elf_backend_fixup_symbol NULL |
#endif |
#ifndef elf_backend_merge_symbol_attribute |
#define elf_backend_merge_symbol_attribute NULL |
#endif |
#ifndef elf_backend_get_target_dtag |
#define elf_backend_get_target_dtag NULL |
#endif |
#ifndef elf_backend_ignore_undef_symbol |
#define elf_backend_ignore_undef_symbol NULL |
#endif |
#ifndef elf_backend_emit_relocs |
#define elf_backend_emit_relocs _bfd_elf_link_output_relocs |
#endif |
#ifndef elf_backend_count_relocs |
#define elf_backend_count_relocs NULL |
#endif |
#ifndef elf_backend_grok_prstatus |
#define elf_backend_grok_prstatus NULL |
#endif |
#ifndef elf_backend_grok_psinfo |
#define elf_backend_grok_psinfo NULL |
#endif |
#ifndef elf_backend_write_core_note |
#define elf_backend_write_core_note NULL |
#endif |
#ifndef elf_backend_lookup_section_flags_hook |
#define elf_backend_lookup_section_flags_hook NULL |
#endif |
#ifndef elf_backend_reloc_type_class |
#define elf_backend_reloc_type_class _bfd_elf_reloc_type_class |
#endif |
#ifndef elf_backend_discard_info |
#define elf_backend_discard_info NULL |
#endif |
#ifndef elf_backend_ignore_discarded_relocs |
#define elf_backend_ignore_discarded_relocs NULL |
#endif |
#ifndef elf_backend_action_discarded |
#define elf_backend_action_discarded _bfd_elf_default_action_discarded |
#endif |
#ifndef elf_backend_eh_frame_address_size |
#define elf_backend_eh_frame_address_size _bfd_elf_eh_frame_address_size |
#endif |
#ifndef elf_backend_can_make_relative_eh_frame |
#define elf_backend_can_make_relative_eh_frame _bfd_elf_can_make_relative |
#endif |
#ifndef elf_backend_can_make_lsda_relative_eh_frame |
#define elf_backend_can_make_lsda_relative_eh_frame _bfd_elf_can_make_relative |
#endif |
#ifndef elf_backend_encode_eh_address |
#define elf_backend_encode_eh_address _bfd_elf_encode_eh_address |
#endif |
#ifndef elf_backend_write_section |
#define elf_backend_write_section NULL |
#endif |
#ifndef elf_backend_mips_irix_compat |
#define elf_backend_mips_irix_compat NULL |
#endif |
#ifndef elf_backend_mips_rtype_to_howto |
#define elf_backend_mips_rtype_to_howto NULL |
#endif |
/* Previously, backends could only use SHT_REL or SHT_RELA relocation |
sections, but not both. They defined USE_REL to indicate SHT_REL |
sections, and left it undefined to indicated SHT_RELA sections. |
For backwards compatibility, we still support this usage. */ |
#ifndef USE_REL |
#define USE_REL 0 |
#endif |
/* Use these in new code. */ |
#ifndef elf_backend_may_use_rel_p |
#define elf_backend_may_use_rel_p USE_REL |
#endif |
#ifndef elf_backend_may_use_rela_p |
#define elf_backend_may_use_rela_p !USE_REL |
#endif |
#ifndef elf_backend_default_use_rela_p |
#define elf_backend_default_use_rela_p !USE_REL |
#endif |
#ifndef elf_backend_rela_plts_and_copies_p |
#define elf_backend_rela_plts_and_copies_p elf_backend_default_use_rela_p |
#endif |
#ifndef elf_backend_rela_normal |
#define elf_backend_rela_normal 0 |
#endif |
#ifndef elf_backend_plt_sym_val |
#define elf_backend_plt_sym_val NULL |
#endif |
#ifndef elf_backend_relplt_name |
#define elf_backend_relplt_name NULL |
#endif |
#ifndef ELF_MACHINE_ALT1 |
#define ELF_MACHINE_ALT1 0 |
#endif |
#ifndef ELF_MACHINE_ALT2 |
#define ELF_MACHINE_ALT2 0 |
#endif |
#ifndef elf_backend_size_info |
#define elf_backend_size_info _bfd_elf64_size_info |
#endif |
#ifndef elf_backend_special_sections |
#define elf_backend_special_sections NULL |
#endif |
#ifndef elf_backend_sign_extend_vma |
#define elf_backend_sign_extend_vma 0 |
#endif |
#ifndef elf_backend_link_order_error_handler |
#define elf_backend_link_order_error_handler _bfd_default_error_handler |
#endif |
#ifndef elf_backend_common_definition |
#define elf_backend_common_definition _bfd_elf_common_definition |
#endif |
#ifndef elf_backend_common_section_index |
#define elf_backend_common_section_index _bfd_elf_common_section_index |
#endif |
#ifndef elf_backend_common_section |
#define elf_backend_common_section _bfd_elf_common_section |
#endif |
#ifndef elf_backend_merge_symbol |
#define elf_backend_merge_symbol NULL |
#endif |
#ifndef elf_backend_hash_symbol |
#define elf_backend_hash_symbol _bfd_elf_hash_symbol |
#endif |
#ifndef elf_backend_is_function_type |
#define elf_backend_is_function_type _bfd_elf_is_function_type |
#endif |
#ifndef elf_backend_maybe_function_sym |
#define elf_backend_maybe_function_sym _bfd_elf_maybe_function_sym |
#endif |
#ifndef elf_match_priority |
#define elf_match_priority \ |
(ELF_ARCH == bfd_arch_unknown ? 2 : ELF_OSABI == ELFOSABI_NONE ? 1 : 0) |
#endif |
extern const struct elf_size_info _bfd_elf64_size_info; |
static struct elf_backend_data elf64_bed = |
{ |
ELF_ARCH, /* arch */ |
ELF_TARGET_ID, /* target_id */ |
ELF_MACHINE_CODE, /* elf_machine_code */ |
ELF_OSABI, /* elf_osabi */ |
ELF_MAXPAGESIZE, /* maxpagesize */ |
ELF_MINPAGESIZE, /* minpagesize */ |
ELF_COMMONPAGESIZE, /* commonpagesize */ |
ELF_DYNAMIC_SEC_FLAGS, /* dynamic_sec_flags */ |
elf_backend_arch_data, |
elf_info_to_howto, |
elf_info_to_howto_rel, |
elf_backend_sym_is_global, |
elf_backend_object_p, |
elf_backend_symbol_processing, |
elf_backend_symbol_table_processing, |
elf_backend_get_symbol_type, |
elf_backend_archive_symbol_lookup, |
elf_backend_name_local_section_symbols, |
elf_backend_section_processing, |
elf_backend_section_from_shdr, |
elf_backend_section_flags, |
elf_backend_get_sec_type_attr, |
elf_backend_section_from_phdr, |
elf_backend_fake_sections, |
elf_backend_section_from_bfd_section, |
elf_backend_add_symbol_hook, |
elf_backend_link_output_symbol_hook, |
elf_backend_create_dynamic_sections, |
elf_backend_omit_section_dynsym, |
elf_backend_relocs_compatible, |
elf_backend_check_relocs, |
elf_backend_check_directives, |
elf_backend_notice_as_needed, |
elf_backend_adjust_dynamic_symbol, |
elf_backend_always_size_sections, |
elf_backend_size_dynamic_sections, |
elf_backend_init_index_section, |
elf_backend_relocate_section, |
elf_backend_finish_dynamic_symbol, |
elf_backend_finish_dynamic_sections, |
elf_backend_begin_write_processing, |
elf_backend_final_write_processing, |
elf_backend_additional_program_headers, |
elf_backend_modify_segment_map, |
elf_backend_modify_program_headers, |
elf_backend_gc_keep, |
elf_backend_gc_mark_dynamic_ref, |
elf_backend_gc_mark_hook, |
elf_backend_gc_mark_extra_sections, |
elf_backend_gc_sweep_hook, |
elf_backend_post_process_headers, |
elf_backend_print_symbol_all, |
elf_backend_output_arch_local_syms, |
elf_backend_output_arch_syms, |
elf_backend_copy_indirect_symbol, |
elf_backend_hide_symbol, |
elf_backend_fixup_symbol, |
elf_backend_merge_symbol_attribute, |
elf_backend_get_target_dtag, |
elf_backend_ignore_undef_symbol, |
elf_backend_emit_relocs, |
elf_backend_count_relocs, |
elf_backend_grok_prstatus, |
elf_backend_grok_psinfo, |
elf_backend_write_core_note, |
elf_backend_lookup_section_flags_hook, |
elf_backend_reloc_type_class, |
elf_backend_discard_info, |
elf_backend_ignore_discarded_relocs, |
elf_backend_action_discarded, |
elf_backend_eh_frame_address_size, |
elf_backend_can_make_relative_eh_frame, |
elf_backend_can_make_lsda_relative_eh_frame, |
elf_backend_encode_eh_address, |
elf_backend_write_section, |
elf_backend_mips_irix_compat, |
elf_backend_mips_rtype_to_howto, |
elf_backend_ecoff_debug_swap, |
elf_backend_bfd_from_remote_memory, |
elf_backend_plt_sym_val, |
elf_backend_common_definition, |
elf_backend_common_section_index, |
elf_backend_common_section, |
elf_backend_merge_symbol, |
elf_backend_hash_symbol, |
elf_backend_is_function_type, |
elf_backend_maybe_function_sym, |
elf_backend_link_order_error_handler, |
elf_backend_relplt_name, |
ELF_MACHINE_ALT1, |
ELF_MACHINE_ALT2, |
&elf_backend_size_info, |
elf_backend_special_sections, |
elf_backend_got_header_size, |
elf_backend_got_elt_size, |
elf_backend_obj_attrs_vendor, |
elf_backend_obj_attrs_section, |
elf_backend_obj_attrs_arg_type, |
elf_backend_obj_attrs_section_type, |
elf_backend_obj_attrs_order, |
elf_backend_obj_attrs_handle_unknown, |
elf_backend_static_tls_alignment, |
elf_backend_stack_align, |
elf_backend_collect, |
elf_backend_type_change_ok, |
elf_backend_may_use_rel_p, |
elf_backend_may_use_rela_p, |
elf_backend_default_use_rela_p, |
elf_backend_rela_plts_and_copies_p, |
elf_backend_rela_normal, |
elf_backend_sign_extend_vma, |
elf_backend_want_got_plt, |
elf_backend_plt_readonly, |
elf_backend_want_plt_sym, |
elf_backend_plt_not_loaded, |
elf_backend_plt_alignment, |
elf_backend_can_gc_sections, |
elf_backend_can_refcount, |
elf_backend_want_got_sym, |
elf_backend_want_dynbss, |
elf_backend_want_p_paddr_set_to_zero, |
elf_backend_default_execstack |
}; |
/* Forward declaration for use when initialising alternative_target field. */ |
#ifdef TARGET_LITTLE_SYM |
extern const bfd_target TARGET_LITTLE_SYM; |
#endif |
#ifdef TARGET_BIG_SYM |
const bfd_target TARGET_BIG_SYM = |
{ |
/* name: identify kind of target */ |
TARGET_BIG_NAME, |
/* flavour: general indication about file */ |
bfd_target_elf_flavour, |
/* byteorder: data is big endian */ |
BFD_ENDIAN_BIG, |
/* header_byteorder: header is also big endian */ |
BFD_ENDIAN_BIG, |
/* object_flags: mask of all file flags */ |
(HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS |
| DYNAMIC | WP_TEXT | D_PAGED | BFD_COMPRESS | BFD_DECOMPRESS), |
/* section_flags: mask of all section flags */ |
(SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY |
| SEC_CODE | SEC_DATA | SEC_DEBUGGING | SEC_EXCLUDE | SEC_SORT_ENTRIES |
| SEC_SMALL_DATA | SEC_MERGE | SEC_STRINGS | SEC_GROUP), |
/* leading_symbol_char: is the first char of a user symbol |
predictable, and if so what is it */ |
elf_symbol_leading_char, |
/* ar_pad_char: pad character for filenames within an archive header |
FIXME: this really has nothing to do with ELF, this is a characteristic |
of the archiver and/or os and should be independently tunable */ |
'/', |
/* ar_max_namelen: maximum number of characters in an archive header |
FIXME: this really has nothing to do with ELF, this is a characteristic |
of the archiver and should be independently tunable. The System V ABI, |
Chapter 7 (Formats & Protocols), Archive section sets this as 15. */ |
15, |
elf_match_priority, |
/* Routines to byte-swap various sized integers from the data sections */ |
bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
bfd_getb16, bfd_getb_signed_16, bfd_putb16, |
/* Routines to byte-swap various sized integers from the file headers */ |
bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
bfd_getb16, bfd_getb_signed_16, bfd_putb16, |
/* bfd_check_format: check the format of a file being read */ |
{ _bfd_dummy_target, /* unknown format */ |
bfd_elf64_object_p, /* assembler/linker output (object file) */ |
bfd_elf64_archive_p, /* an archive */ |
bfd_elf64_core_file_p /* a core file */ |
}, |
/* bfd_set_format: set the format of a file being written */ |
{ bfd_false, |
bfd_elf64_mkobject, |
bfd_elf64_mkarchive, |
bfd_elf64_mkcorefile |
}, |
/* bfd_write_contents: write cached information into a file being written */ |
{ bfd_false, |
bfd_elf64_write_object_contents, |
bfd_elf64_write_archive_contents, |
bfd_elf64_write_corefile_contents, |
}, |
BFD_JUMP_TABLE_GENERIC (bfd_elf64), |
BFD_JUMP_TABLE_COPY (bfd_elf64), |
BFD_JUMP_TABLE_CORE (bfd_elf64), |
#ifdef bfd_elf64_archive_functions |
BFD_JUMP_TABLE_ARCHIVE (bfd_elf64_archive), |
#else |
BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), |
#endif |
BFD_JUMP_TABLE_SYMBOLS (bfd_elf64), |
BFD_JUMP_TABLE_RELOCS (bfd_elf64), |
BFD_JUMP_TABLE_WRITE (bfd_elf64), |
BFD_JUMP_TABLE_LINK (bfd_elf64), |
BFD_JUMP_TABLE_DYNAMIC (bfd_elf64), |
/* Alternative endian target. */ |
#ifdef TARGET_LITTLE_SYM |
& TARGET_LITTLE_SYM, |
#else |
NULL, |
#endif |
/* backend_data: */ |
&elf64_bed |
}; |
#endif |
#ifdef TARGET_LITTLE_SYM |
const bfd_target TARGET_LITTLE_SYM = |
{ |
/* name: identify kind of target */ |
TARGET_LITTLE_NAME, |
/* flavour: general indication about file */ |
bfd_target_elf_flavour, |
/* byteorder: data is little endian */ |
BFD_ENDIAN_LITTLE, |
/* header_byteorder: header is also little endian */ |
BFD_ENDIAN_LITTLE, |
/* object_flags: mask of all file flags */ |
(HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS |
| DYNAMIC | WP_TEXT | D_PAGED | BFD_COMPRESS | BFD_DECOMPRESS), |
/* section_flags: mask of all section flags */ |
(SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY |
| SEC_CODE | SEC_DATA | SEC_DEBUGGING | SEC_EXCLUDE | SEC_SORT_ENTRIES |
| SEC_SMALL_DATA | SEC_MERGE | SEC_STRINGS | SEC_GROUP), |
/* leading_symbol_char: is the first char of a user symbol |
predictable, and if so what is it */ |
elf_symbol_leading_char, |
/* ar_pad_char: pad character for filenames within an archive header |
FIXME: this really has nothing to do with ELF, this is a characteristic |
of the archiver and/or os and should be independently tunable */ |
'/', |
/* ar_max_namelen: maximum number of characters in an archive header |
FIXME: this really has nothing to do with ELF, this is a characteristic |
of the archiver and should be independently tunable. The System V ABI, |
Chapter 7 (Formats & Protocols), Archive section sets this as 15. */ |
15, |
elf_match_priority, |
/* Routines to byte-swap various sized integers from the data sections */ |
bfd_getl64, bfd_getl_signed_64, bfd_putl64, |
bfd_getl32, bfd_getl_signed_32, bfd_putl32, |
bfd_getl16, bfd_getl_signed_16, bfd_putl16, |
/* Routines to byte-swap various sized integers from the file headers */ |
bfd_getl64, bfd_getl_signed_64, bfd_putl64, |
bfd_getl32, bfd_getl_signed_32, bfd_putl32, |
bfd_getl16, bfd_getl_signed_16, bfd_putl16, |
/* bfd_check_format: check the format of a file being read */ |
{ _bfd_dummy_target, /* unknown format */ |
bfd_elf64_object_p, /* assembler/linker output (object file) */ |
bfd_elf64_archive_p, /* an archive */ |
bfd_elf64_core_file_p /* a core file */ |
}, |
/* bfd_set_format: set the format of a file being written */ |
{ bfd_false, |
bfd_elf64_mkobject, |
bfd_elf64_mkarchive, |
bfd_elf64_mkcorefile |
}, |
/* bfd_write_contents: write cached information into a file being written */ |
{ bfd_false, |
bfd_elf64_write_object_contents, |
bfd_elf64_write_archive_contents, |
bfd_elf64_write_corefile_contents, |
}, |
BFD_JUMP_TABLE_GENERIC (bfd_elf64), |
BFD_JUMP_TABLE_COPY (bfd_elf64), |
BFD_JUMP_TABLE_CORE (bfd_elf64), |
#ifdef bfd_elf64_archive_functions |
BFD_JUMP_TABLE_ARCHIVE (bfd_elf64_archive), |
#else |
BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), |
#endif |
BFD_JUMP_TABLE_SYMBOLS (bfd_elf64), |
BFD_JUMP_TABLE_RELOCS (bfd_elf64), |
BFD_JUMP_TABLE_WRITE (bfd_elf64), |
BFD_JUMP_TABLE_LINK (bfd_elf64), |
BFD_JUMP_TABLE_DYNAMIC (bfd_elf64), |
/* Alternative endian target. */ |
#ifdef TARGET_BIG_SYM |
& TARGET_BIG_SYM, |
#else |
NULL, |
#endif |
/* backend_data: */ |
&elf64_bed |
}; |
#endif |
/contrib/toolchain/binutils/bfd/elfcode.h |
---|
0,0 → 1,1870 |
/* ELF executable support for BFD. |
Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, |
2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 |
Free Software Foundation, Inc. |
Written by Fred Fish @ Cygnus Support, from information published |
in "UNIX System V Release 4, Programmers Guide: ANSI C and |
Programming Support Tools". Sufficient support for gdb. |
Rewritten by Mark Eichin @ Cygnus Support, from information |
published in "System V Application Binary Interface", chapters 4 |
and 5, as well as the various "Processor Supplement" documents |
derived from it. Added support for assembler and other object file |
utilities. Further work done by Ken Raeburn (Cygnus Support), Michael |
Meissner (Open Software Foundation), and Peter Hoogenboom (University |
of Utah) to finish and extend this. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* Problems and other issues to resolve. |
(1) BFD expects there to be some fixed number of "sections" in |
the object file. I.E. there is a "section_count" variable in the |
bfd structure which contains the number of sections. However, ELF |
supports multiple "views" of a file. In particular, with current |
implementations, executable files typically have two tables, a |
program header table and a section header table, both of which |
partition the executable. |
In ELF-speak, the "linking view" of the file uses the section header |
table to access "sections" within the file, and the "execution view" |
uses the program header table to access "segments" within the file. |
"Segments" typically may contain all the data from one or more |
"sections". |
Note that the section header table is optional in ELF executables, |
but it is this information that is most useful to gdb. If the |
section header table is missing, then gdb should probably try |
to make do with the program header table. (FIXME) |
(2) The code in this file is compiled twice, once in 32-bit mode and |
once in 64-bit mode. More of it should be made size-independent |
and moved into elf.c. |
(3) ELF section symbols are handled rather sloppily now. This should |
be cleaned up, and ELF section symbols reconciled with BFD section |
symbols. |
(4) We need a published spec for 64-bit ELF. We've got some stuff here |
that we're using for SPARC V9 64-bit chips, but don't assume that |
it's cast in stone. |
*/ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libiberty.h" |
#include "bfdlink.h" |
#include "libbfd.h" |
#include "elf-bfd.h" |
/* Renaming structures, typedefs, macros and functions to be size-specific. */ |
#define Elf_External_Ehdr NAME(Elf,External_Ehdr) |
#define Elf_External_Sym NAME(Elf,External_Sym) |
#define Elf_External_Shdr NAME(Elf,External_Shdr) |
#define Elf_External_Phdr NAME(Elf,External_Phdr) |
#define Elf_External_Rel NAME(Elf,External_Rel) |
#define Elf_External_Rela NAME(Elf,External_Rela) |
#define Elf_External_Dyn NAME(Elf,External_Dyn) |
#define elf_core_file_failing_command NAME(bfd_elf,core_file_failing_command) |
#define elf_core_file_failing_signal NAME(bfd_elf,core_file_failing_signal) |
#define elf_core_file_matches_executable_p \ |
NAME(bfd_elf,core_file_matches_executable_p) |
#define elf_core_file_pid NAME(bfd_elf,core_file_pid) |
#define elf_object_p NAME(bfd_elf,object_p) |
#define elf_core_file_p NAME(bfd_elf,core_file_p) |
#define elf_get_symtab_upper_bound NAME(bfd_elf,get_symtab_upper_bound) |
#define elf_get_dynamic_symtab_upper_bound \ |
NAME(bfd_elf,get_dynamic_symtab_upper_bound) |
#define elf_swap_reloc_in NAME(bfd_elf,swap_reloc_in) |
#define elf_swap_reloca_in NAME(bfd_elf,swap_reloca_in) |
#define elf_swap_reloc_out NAME(bfd_elf,swap_reloc_out) |
#define elf_swap_reloca_out NAME(bfd_elf,swap_reloca_out) |
#define elf_swap_symbol_in NAME(bfd_elf,swap_symbol_in) |
#define elf_swap_symbol_out NAME(bfd_elf,swap_symbol_out) |
#define elf_swap_phdr_in NAME(bfd_elf,swap_phdr_in) |
#define elf_swap_phdr_out NAME(bfd_elf,swap_phdr_out) |
#define elf_swap_dyn_in NAME(bfd_elf,swap_dyn_in) |
#define elf_swap_dyn_out NAME(bfd_elf,swap_dyn_out) |
#define elf_get_reloc_upper_bound NAME(bfd_elf,get_reloc_upper_bound) |
#define elf_canonicalize_reloc NAME(bfd_elf,canonicalize_reloc) |
#define elf_slurp_symbol_table NAME(bfd_elf,slurp_symbol_table) |
#define elf_canonicalize_symtab NAME(bfd_elf,canonicalize_symtab) |
#define elf_canonicalize_dynamic_symtab \ |
NAME(bfd_elf,canonicalize_dynamic_symtab) |
#define elf_get_synthetic_symtab \ |
NAME(bfd_elf,get_synthetic_symtab) |
#define elf_make_empty_symbol NAME(bfd_elf,make_empty_symbol) |
#define elf_get_symbol_info NAME(bfd_elf,get_symbol_info) |
#define elf_get_lineno NAME(bfd_elf,get_lineno) |
#define elf_set_arch_mach NAME(bfd_elf,set_arch_mach) |
#define elf_find_nearest_line NAME(bfd_elf,find_nearest_line) |
#define elf_sizeof_headers NAME(bfd_elf,sizeof_headers) |
#define elf_set_section_contents NAME(bfd_elf,set_section_contents) |
#define elf_no_info_to_howto NAME(bfd_elf,no_info_to_howto) |
#define elf_no_info_to_howto_rel NAME(bfd_elf,no_info_to_howto_rel) |
#define elf_find_section NAME(bfd_elf,find_section) |
#define elf_write_shdrs_and_ehdr NAME(bfd_elf,write_shdrs_and_ehdr) |
#define elf_write_out_phdrs NAME(bfd_elf,write_out_phdrs) |
#define elf_checksum_contents NAME(bfd_elf,checksum_contents) |
#define elf_write_relocs NAME(bfd_elf,write_relocs) |
#define elf_slurp_reloc_table NAME(bfd_elf,slurp_reloc_table) |
#if ARCH_SIZE == 64 |
#define ELF_R_INFO(X,Y) ELF64_R_INFO(X,Y) |
#define ELF_R_SYM(X) ELF64_R_SYM(X) |
#define ELF_R_TYPE(X) ELF64_R_TYPE(X) |
#define ELFCLASS ELFCLASS64 |
#define FILE_ALIGN 8 |
#define LOG_FILE_ALIGN 3 |
#endif |
#if ARCH_SIZE == 32 |
#define ELF_R_INFO(X,Y) ELF32_R_INFO(X,Y) |
#define ELF_R_SYM(X) ELF32_R_SYM(X) |
#define ELF_R_TYPE(X) ELF32_R_TYPE(X) |
#define ELFCLASS ELFCLASS32 |
#define FILE_ALIGN 4 |
#define LOG_FILE_ALIGN 2 |
#endif |
#if DEBUG & 2 |
static void elf_debug_section (int, Elf_Internal_Shdr *); |
#endif |
#if DEBUG & 1 |
static void elf_debug_file (Elf_Internal_Ehdr *); |
#endif |
/* Structure swapping routines */ |
/* Should perhaps use put_offset, put_word, etc. For now, the two versions |
can be handled by explicitly specifying 32 bits or "the long type". */ |
#if ARCH_SIZE == 64 |
#define H_PUT_WORD H_PUT_64 |
#define H_PUT_SIGNED_WORD H_PUT_S64 |
#define H_GET_WORD H_GET_64 |
#define H_GET_SIGNED_WORD H_GET_S64 |
#endif |
#if ARCH_SIZE == 32 |
#define H_PUT_WORD H_PUT_32 |
#define H_PUT_SIGNED_WORD H_PUT_S32 |
#define H_GET_WORD H_GET_32 |
#define H_GET_SIGNED_WORD H_GET_S32 |
#endif |
/* Translate an ELF symbol in external format into an ELF symbol in internal |
format. */ |
bfd_boolean |
elf_swap_symbol_in (bfd *abfd, |
const void *psrc, |
const void *pshn, |
Elf_Internal_Sym *dst) |
{ |
const Elf_External_Sym *src = (const Elf_External_Sym *) psrc; |
const Elf_External_Sym_Shndx *shndx = (const Elf_External_Sym_Shndx *) pshn; |
int signed_vma = get_elf_backend_data (abfd)->sign_extend_vma; |
dst->st_name = H_GET_32 (abfd, src->st_name); |
if (signed_vma) |
dst->st_value = H_GET_SIGNED_WORD (abfd, src->st_value); |
else |
dst->st_value = H_GET_WORD (abfd, src->st_value); |
dst->st_size = H_GET_WORD (abfd, src->st_size); |
dst->st_info = H_GET_8 (abfd, src->st_info); |
dst->st_other = H_GET_8 (abfd, src->st_other); |
dst->st_shndx = H_GET_16 (abfd, src->st_shndx); |
if (dst->st_shndx == (SHN_XINDEX & 0xffff)) |
{ |
if (shndx == NULL) |
return FALSE; |
dst->st_shndx = H_GET_32 (abfd, shndx->est_shndx); |
} |
else if (dst->st_shndx >= (SHN_LORESERVE & 0xffff)) |
dst->st_shndx += SHN_LORESERVE - (SHN_LORESERVE & 0xffff); |
dst->st_target_internal = 0; |
return TRUE; |
} |
/* Translate an ELF symbol in internal format into an ELF symbol in external |
format. */ |
void |
elf_swap_symbol_out (bfd *abfd, |
const Elf_Internal_Sym *src, |
void *cdst, |
void *shndx) |
{ |
unsigned int tmp; |
Elf_External_Sym *dst = (Elf_External_Sym *) cdst; |
H_PUT_32 (abfd, src->st_name, dst->st_name); |
H_PUT_WORD (abfd, src->st_value, dst->st_value); |
H_PUT_WORD (abfd, src->st_size, dst->st_size); |
H_PUT_8 (abfd, src->st_info, dst->st_info); |
H_PUT_8 (abfd, src->st_other, dst->st_other); |
tmp = src->st_shndx; |
if (tmp >= (SHN_LORESERVE & 0xffff) && tmp < SHN_LORESERVE) |
{ |
if (shndx == NULL) |
abort (); |
H_PUT_32 (abfd, tmp, shndx); |
tmp = SHN_XINDEX & 0xffff; |
} |
H_PUT_16 (abfd, tmp, dst->st_shndx); |
} |
/* Translate an ELF file header in external format into an ELF file header in |
internal format. */ |
static void |
elf_swap_ehdr_in (bfd *abfd, |
const Elf_External_Ehdr *src, |
Elf_Internal_Ehdr *dst) |
{ |
int signed_vma = get_elf_backend_data (abfd)->sign_extend_vma; |
memcpy (dst->e_ident, src->e_ident, EI_NIDENT); |
dst->e_type = H_GET_16 (abfd, src->e_type); |
dst->e_machine = H_GET_16 (abfd, src->e_machine); |
dst->e_version = H_GET_32 (abfd, src->e_version); |
if (signed_vma) |
dst->e_entry = H_GET_SIGNED_WORD (abfd, src->e_entry); |
else |
dst->e_entry = H_GET_WORD (abfd, src->e_entry); |
dst->e_phoff = H_GET_WORD (abfd, src->e_phoff); |
dst->e_shoff = H_GET_WORD (abfd, src->e_shoff); |
dst->e_flags = H_GET_32 (abfd, src->e_flags); |
dst->e_ehsize = H_GET_16 (abfd, src->e_ehsize); |
dst->e_phentsize = H_GET_16 (abfd, src->e_phentsize); |
dst->e_phnum = H_GET_16 (abfd, src->e_phnum); |
dst->e_shentsize = H_GET_16 (abfd, src->e_shentsize); |
dst->e_shnum = H_GET_16 (abfd, src->e_shnum); |
dst->e_shstrndx = H_GET_16 (abfd, src->e_shstrndx); |
} |
/* Translate an ELF file header in internal format into an ELF file header in |
external format. */ |
static void |
elf_swap_ehdr_out (bfd *abfd, |
const Elf_Internal_Ehdr *src, |
Elf_External_Ehdr *dst) |
{ |
unsigned int tmp; |
int signed_vma = get_elf_backend_data (abfd)->sign_extend_vma; |
memcpy (dst->e_ident, src->e_ident, EI_NIDENT); |
/* note that all elements of dst are *arrays of unsigned char* already... */ |
H_PUT_16 (abfd, src->e_type, dst->e_type); |
H_PUT_16 (abfd, src->e_machine, dst->e_machine); |
H_PUT_32 (abfd, src->e_version, dst->e_version); |
if (signed_vma) |
H_PUT_SIGNED_WORD (abfd, src->e_entry, dst->e_entry); |
else |
H_PUT_WORD (abfd, src->e_entry, dst->e_entry); |
H_PUT_WORD (abfd, src->e_phoff, dst->e_phoff); |
H_PUT_WORD (abfd, src->e_shoff, dst->e_shoff); |
H_PUT_32 (abfd, src->e_flags, dst->e_flags); |
H_PUT_16 (abfd, src->e_ehsize, dst->e_ehsize); |
H_PUT_16 (abfd, src->e_phentsize, dst->e_phentsize); |
tmp = src->e_phnum; |
if (tmp > PN_XNUM) |
tmp = PN_XNUM; |
H_PUT_16 (abfd, tmp, dst->e_phnum); |
H_PUT_16 (abfd, src->e_shentsize, dst->e_shentsize); |
tmp = src->e_shnum; |
if (tmp >= (SHN_LORESERVE & 0xffff)) |
tmp = SHN_UNDEF; |
H_PUT_16 (abfd, tmp, dst->e_shnum); |
tmp = src->e_shstrndx; |
if (tmp >= (SHN_LORESERVE & 0xffff)) |
tmp = SHN_XINDEX & 0xffff; |
H_PUT_16 (abfd, tmp, dst->e_shstrndx); |
} |
/* Translate an ELF section header table entry in external format into an |
ELF section header table entry in internal format. */ |
static void |
elf_swap_shdr_in (bfd *abfd, |
const Elf_External_Shdr *src, |
Elf_Internal_Shdr *dst) |
{ |
int signed_vma = get_elf_backend_data (abfd)->sign_extend_vma; |
dst->sh_name = H_GET_32 (abfd, src->sh_name); |
dst->sh_type = H_GET_32 (abfd, src->sh_type); |
dst->sh_flags = H_GET_WORD (abfd, src->sh_flags); |
if (signed_vma) |
dst->sh_addr = H_GET_SIGNED_WORD (abfd, src->sh_addr); |
else |
dst->sh_addr = H_GET_WORD (abfd, src->sh_addr); |
dst->sh_offset = H_GET_WORD (abfd, src->sh_offset); |
dst->sh_size = H_GET_WORD (abfd, src->sh_size); |
dst->sh_link = H_GET_32 (abfd, src->sh_link); |
dst->sh_info = H_GET_32 (abfd, src->sh_info); |
dst->sh_addralign = H_GET_WORD (abfd, src->sh_addralign); |
dst->sh_entsize = H_GET_WORD (abfd, src->sh_entsize); |
dst->bfd_section = NULL; |
dst->contents = NULL; |
} |
/* Translate an ELF section header table entry in internal format into an |
ELF section header table entry in external format. */ |
static void |
elf_swap_shdr_out (bfd *abfd, |
const Elf_Internal_Shdr *src, |
Elf_External_Shdr *dst) |
{ |
/* note that all elements of dst are *arrays of unsigned char* already... */ |
H_PUT_32 (abfd, src->sh_name, dst->sh_name); |
H_PUT_32 (abfd, src->sh_type, dst->sh_type); |
H_PUT_WORD (abfd, src->sh_flags, dst->sh_flags); |
H_PUT_WORD (abfd, src->sh_addr, dst->sh_addr); |
H_PUT_WORD (abfd, src->sh_offset, dst->sh_offset); |
H_PUT_WORD (abfd, src->sh_size, dst->sh_size); |
H_PUT_32 (abfd, src->sh_link, dst->sh_link); |
H_PUT_32 (abfd, src->sh_info, dst->sh_info); |
H_PUT_WORD (abfd, src->sh_addralign, dst->sh_addralign); |
H_PUT_WORD (abfd, src->sh_entsize, dst->sh_entsize); |
} |
/* Translate an ELF program header table entry in external format into an |
ELF program header table entry in internal format. */ |
void |
elf_swap_phdr_in (bfd *abfd, |
const Elf_External_Phdr *src, |
Elf_Internal_Phdr *dst) |
{ |
int signed_vma = get_elf_backend_data (abfd)->sign_extend_vma; |
dst->p_type = H_GET_32 (abfd, src->p_type); |
dst->p_flags = H_GET_32 (abfd, src->p_flags); |
dst->p_offset = H_GET_WORD (abfd, src->p_offset); |
if (signed_vma) |
{ |
dst->p_vaddr = H_GET_SIGNED_WORD (abfd, src->p_vaddr); |
dst->p_paddr = H_GET_SIGNED_WORD (abfd, src->p_paddr); |
} |
else |
{ |
dst->p_vaddr = H_GET_WORD (abfd, src->p_vaddr); |
dst->p_paddr = H_GET_WORD (abfd, src->p_paddr); |
} |
dst->p_filesz = H_GET_WORD (abfd, src->p_filesz); |
dst->p_memsz = H_GET_WORD (abfd, src->p_memsz); |
dst->p_align = H_GET_WORD (abfd, src->p_align); |
} |
void |
elf_swap_phdr_out (bfd *abfd, |
const Elf_Internal_Phdr *src, |
Elf_External_Phdr *dst) |
{ |
const struct elf_backend_data *bed; |
bfd_vma p_paddr; |
bed = get_elf_backend_data (abfd); |
p_paddr = bed->want_p_paddr_set_to_zero ? 0 : src->p_paddr; |
/* note that all elements of dst are *arrays of unsigned char* already... */ |
H_PUT_32 (abfd, src->p_type, dst->p_type); |
H_PUT_WORD (abfd, src->p_offset, dst->p_offset); |
H_PUT_WORD (abfd, src->p_vaddr, dst->p_vaddr); |
H_PUT_WORD (abfd, p_paddr, dst->p_paddr); |
H_PUT_WORD (abfd, src->p_filesz, dst->p_filesz); |
H_PUT_WORD (abfd, src->p_memsz, dst->p_memsz); |
H_PUT_32 (abfd, src->p_flags, dst->p_flags); |
H_PUT_WORD (abfd, src->p_align, dst->p_align); |
} |
/* Translate an ELF reloc from external format to internal format. */ |
void |
elf_swap_reloc_in (bfd *abfd, |
const bfd_byte *s, |
Elf_Internal_Rela *dst) |
{ |
const Elf_External_Rel *src = (const Elf_External_Rel *) s; |
dst->r_offset = H_GET_WORD (abfd, src->r_offset); |
dst->r_info = H_GET_WORD (abfd, src->r_info); |
dst->r_addend = 0; |
} |
void |
elf_swap_reloca_in (bfd *abfd, |
const bfd_byte *s, |
Elf_Internal_Rela *dst) |
{ |
const Elf_External_Rela *src = (const Elf_External_Rela *) s; |
dst->r_offset = H_GET_WORD (abfd, src->r_offset); |
dst->r_info = H_GET_WORD (abfd, src->r_info); |
dst->r_addend = H_GET_SIGNED_WORD (abfd, src->r_addend); |
} |
/* Translate an ELF reloc from internal format to external format. */ |
void |
elf_swap_reloc_out (bfd *abfd, |
const Elf_Internal_Rela *src, |
bfd_byte *d) |
{ |
Elf_External_Rel *dst = (Elf_External_Rel *) d; |
H_PUT_WORD (abfd, src->r_offset, dst->r_offset); |
H_PUT_WORD (abfd, src->r_info, dst->r_info); |
} |
void |
elf_swap_reloca_out (bfd *abfd, |
const Elf_Internal_Rela *src, |
bfd_byte *d) |
{ |
Elf_External_Rela *dst = (Elf_External_Rela *) d; |
H_PUT_WORD (abfd, src->r_offset, dst->r_offset); |
H_PUT_WORD (abfd, src->r_info, dst->r_info); |
H_PUT_SIGNED_WORD (abfd, src->r_addend, dst->r_addend); |
} |
void |
elf_swap_dyn_in (bfd *abfd, |
const void *p, |
Elf_Internal_Dyn *dst) |
{ |
const Elf_External_Dyn *src = (const Elf_External_Dyn *) p; |
dst->d_tag = H_GET_WORD (abfd, src->d_tag); |
dst->d_un.d_val = H_GET_WORD (abfd, src->d_un.d_val); |
} |
void |
elf_swap_dyn_out (bfd *abfd, |
const Elf_Internal_Dyn *src, |
void *p) |
{ |
Elf_External_Dyn *dst = (Elf_External_Dyn *) p; |
H_PUT_WORD (abfd, src->d_tag, dst->d_tag); |
H_PUT_WORD (abfd, src->d_un.d_val, dst->d_un.d_val); |
} |
/* ELF .o/exec file reading */ |
/* Begin processing a given object. |
First we validate the file by reading in the ELF header and checking |
the magic number. */ |
static inline bfd_boolean |
elf_file_p (Elf_External_Ehdr *x_ehdrp) |
{ |
return ((x_ehdrp->e_ident[EI_MAG0] == ELFMAG0) |
&& (x_ehdrp->e_ident[EI_MAG1] == ELFMAG1) |
&& (x_ehdrp->e_ident[EI_MAG2] == ELFMAG2) |
&& (x_ehdrp->e_ident[EI_MAG3] == ELFMAG3)); |
} |
/* Check to see if the file associated with ABFD matches the target vector |
that ABFD points to. |
Note that we may be called several times with the same ABFD, but different |
target vectors, most of which will not match. We have to avoid leaving |
any side effects in ABFD, or any data it points to (like tdata), if the |
file does not match the target vector. */ |
const bfd_target * |
elf_object_p (bfd *abfd) |
{ |
Elf_External_Ehdr x_ehdr; /* Elf file header, external form */ |
Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */ |
Elf_External_Shdr x_shdr; /* Section header table entry, external form */ |
Elf_Internal_Shdr i_shdr; |
Elf_Internal_Shdr *i_shdrp; /* Section header table, internal form */ |
unsigned int shindex; |
const struct elf_backend_data *ebd; |
asection *s; |
bfd_size_type amt; |
const bfd_target *target; |
/* Read in the ELF header in external format. */ |
if (bfd_bread (&x_ehdr, sizeof (x_ehdr), abfd) != sizeof (x_ehdr)) |
{ |
if (bfd_get_error () != bfd_error_system_call) |
goto got_wrong_format_error; |
else |
goto got_no_match; |
} |
/* Now check to see if we have a valid ELF file, and one that BFD can |
make use of. The magic number must match, the address size ('class') |
and byte-swapping must match our XVEC entry, and it must have a |
section header table (FIXME: See comments re sections at top of this |
file). */ |
if (! elf_file_p (&x_ehdr) |
|| x_ehdr.e_ident[EI_VERSION] != EV_CURRENT |
|| x_ehdr.e_ident[EI_CLASS] != ELFCLASS) |
goto got_wrong_format_error; |
/* Check that file's byte order matches xvec's */ |
switch (x_ehdr.e_ident[EI_DATA]) |
{ |
case ELFDATA2MSB: /* Big-endian */ |
if (! bfd_header_big_endian (abfd)) |
goto got_wrong_format_error; |
break; |
case ELFDATA2LSB: /* Little-endian */ |
if (! bfd_header_little_endian (abfd)) |
goto got_wrong_format_error; |
break; |
case ELFDATANONE: /* No data encoding specified */ |
default: /* Unknown data encoding specified */ |
goto got_wrong_format_error; |
} |
target = abfd->xvec; |
/* Allocate an instance of the elf_obj_tdata structure and hook it up to |
the tdata pointer in the bfd. */ |
if (! (*target->_bfd_set_format[bfd_object]) (abfd)) |
goto got_no_match; |
/* Now that we know the byte order, swap in the rest of the header */ |
i_ehdrp = elf_elfheader (abfd); |
elf_swap_ehdr_in (abfd, &x_ehdr, i_ehdrp); |
#if DEBUG & 1 |
elf_debug_file (i_ehdrp); |
#endif |
/* Reject ET_CORE (header indicates core file, not object file) */ |
if (i_ehdrp->e_type == ET_CORE) |
goto got_wrong_format_error; |
/* If this is a relocatable file and there is no section header |
table, then we're hosed. */ |
if (i_ehdrp->e_shoff == 0 && i_ehdrp->e_type == ET_REL) |
goto got_wrong_format_error; |
/* As a simple sanity check, verify that what BFD thinks is the |
size of each section header table entry actually matches the size |
recorded in the file, but only if there are any sections. */ |
if (i_ehdrp->e_shentsize != sizeof (x_shdr) && i_ehdrp->e_shnum != 0) |
goto got_wrong_format_error; |
/* Further sanity check. */ |
if (i_ehdrp->e_shoff == 0 && i_ehdrp->e_shnum != 0) |
goto got_wrong_format_error; |
ebd = get_elf_backend_data (abfd); |
if (ebd->s->arch_size != ARCH_SIZE) |
goto got_wrong_format_error; |
/* Check that the ELF e_machine field matches what this particular |
BFD format expects. */ |
if (ebd->elf_machine_code != i_ehdrp->e_machine |
&& (ebd->elf_machine_alt1 == 0 |
|| i_ehdrp->e_machine != ebd->elf_machine_alt1) |
&& (ebd->elf_machine_alt2 == 0 |
|| i_ehdrp->e_machine != ebd->elf_machine_alt2) |
&& ebd->elf_machine_code != EM_NONE) |
goto got_wrong_format_error; |
if (i_ehdrp->e_type == ET_EXEC) |
abfd->flags |= EXEC_P; |
else if (i_ehdrp->e_type == ET_DYN) |
abfd->flags |= DYNAMIC; |
if (i_ehdrp->e_phnum > 0) |
abfd->flags |= D_PAGED; |
if (! bfd_default_set_arch_mach (abfd, ebd->arch, 0)) |
{ |
/* It's OK if this fails for the generic target. */ |
if (ebd->elf_machine_code != EM_NONE) |
goto got_no_match; |
} |
if (ebd->elf_machine_code != EM_NONE |
&& i_ehdrp->e_ident[EI_OSABI] != ebd->elf_osabi |
&& ebd->elf_osabi != ELFOSABI_NONE) |
goto got_wrong_format_error; |
if (i_ehdrp->e_shoff != 0) |
{ |
bfd_signed_vma where = i_ehdrp->e_shoff; |
if (where != (file_ptr) where) |
goto got_wrong_format_error; |
/* Seek to the section header table in the file. */ |
if (bfd_seek (abfd, (file_ptr) where, SEEK_SET) != 0) |
goto got_no_match; |
/* Read the first section header at index 0, and convert to internal |
form. */ |
if (bfd_bread (&x_shdr, sizeof x_shdr, abfd) != sizeof (x_shdr)) |
goto got_no_match; |
elf_swap_shdr_in (abfd, &x_shdr, &i_shdr); |
/* If the section count is zero, the actual count is in the first |
section header. */ |
if (i_ehdrp->e_shnum == SHN_UNDEF) |
{ |
i_ehdrp->e_shnum = i_shdr.sh_size; |
if (i_ehdrp->e_shnum >= SHN_LORESERVE |
|| i_ehdrp->e_shnum != i_shdr.sh_size |
|| i_ehdrp->e_shnum == 0) |
goto got_wrong_format_error; |
} |
/* And similarly for the string table index. */ |
if (i_ehdrp->e_shstrndx == (SHN_XINDEX & 0xffff)) |
{ |
i_ehdrp->e_shstrndx = i_shdr.sh_link; |
if (i_ehdrp->e_shstrndx != i_shdr.sh_link) |
goto got_wrong_format_error; |
} |
/* And program headers. */ |
if (i_ehdrp->e_phnum == PN_XNUM && i_shdr.sh_info != 0) |
{ |
i_ehdrp->e_phnum = i_shdr.sh_info; |
if (i_ehdrp->e_phnum != i_shdr.sh_info) |
goto got_wrong_format_error; |
} |
/* Sanity check that we can read all of the section headers. |
It ought to be good enough to just read the last one. */ |
if (i_ehdrp->e_shnum != 1) |
{ |
/* Check that we don't have a totally silly number of sections. */ |
if (i_ehdrp->e_shnum > (unsigned int) -1 / sizeof (x_shdr) |
|| i_ehdrp->e_shnum > (unsigned int) -1 / sizeof (i_shdr)) |
goto got_wrong_format_error; |
where += (i_ehdrp->e_shnum - 1) * sizeof (x_shdr); |
if (where != (file_ptr) where) |
goto got_wrong_format_error; |
if ((bfd_size_type) where <= i_ehdrp->e_shoff) |
goto got_wrong_format_error; |
if (bfd_seek (abfd, (file_ptr) where, SEEK_SET) != 0) |
goto got_no_match; |
if (bfd_bread (&x_shdr, sizeof x_shdr, abfd) != sizeof (x_shdr)) |
goto got_no_match; |
/* Back to where we were. */ |
where = i_ehdrp->e_shoff + sizeof (x_shdr); |
if (bfd_seek (abfd, (file_ptr) where, SEEK_SET) != 0) |
goto got_no_match; |
} |
} |
/* Allocate space for a copy of the section header table in |
internal form. */ |
if (i_ehdrp->e_shnum != 0) |
{ |
Elf_Internal_Shdr *shdrp; |
unsigned int num_sec; |
amt = sizeof (*i_shdrp) * i_ehdrp->e_shnum; |
i_shdrp = (Elf_Internal_Shdr *) bfd_alloc (abfd, amt); |
if (!i_shdrp) |
goto got_no_match; |
num_sec = i_ehdrp->e_shnum; |
elf_numsections (abfd) = num_sec; |
amt = sizeof (i_shdrp) * num_sec; |
elf_elfsections (abfd) = (Elf_Internal_Shdr **) bfd_alloc (abfd, amt); |
if (!elf_elfsections (abfd)) |
goto got_no_match; |
memcpy (i_shdrp, &i_shdr, sizeof (*i_shdrp)); |
for (shdrp = i_shdrp, shindex = 0; shindex < num_sec; shindex++) |
elf_elfsections (abfd)[shindex] = shdrp++; |
/* Read in the rest of the section header table and convert it |
to internal form. */ |
for (shindex = 1; shindex < i_ehdrp->e_shnum; shindex++) |
{ |
if (bfd_bread (&x_shdr, sizeof x_shdr, abfd) != sizeof (x_shdr)) |
goto got_no_match; |
elf_swap_shdr_in (abfd, &x_shdr, i_shdrp + shindex); |
/* Sanity check sh_link and sh_info. */ |
if (i_shdrp[shindex].sh_link >= num_sec) |
{ |
/* PR 10478: Accept Solaris binaries with a sh_link |
field set to SHN_BEFORE or SHN_AFTER. */ |
switch (ebd->elf_machine_code) |
{ |
case EM_386: |
case EM_486: |
case EM_X86_64: |
case EM_OLD_SPARCV9: |
case EM_SPARC32PLUS: |
case EM_SPARCV9: |
case EM_SPARC: |
if (i_shdrp[shindex].sh_link == (SHN_LORESERVE & 0xffff) /* SHN_BEFORE */ |
|| i_shdrp[shindex].sh_link == ((SHN_LORESERVE + 1) & 0xffff) /* SHN_AFTER */) |
break; |
/* Otherwise fall through. */ |
default: |
goto got_wrong_format_error; |
} |
} |
if (((i_shdrp[shindex].sh_flags & SHF_INFO_LINK) |
|| i_shdrp[shindex].sh_type == SHT_RELA |
|| i_shdrp[shindex].sh_type == SHT_REL) |
&& i_shdrp[shindex].sh_info >= num_sec) |
goto got_wrong_format_error; |
/* If the section is loaded, but not page aligned, clear |
D_PAGED. */ |
if (i_shdrp[shindex].sh_size != 0 |
&& (i_shdrp[shindex].sh_flags & SHF_ALLOC) != 0 |
&& i_shdrp[shindex].sh_type != SHT_NOBITS |
&& (((i_shdrp[shindex].sh_addr - i_shdrp[shindex].sh_offset) |
% ebd->minpagesize) |
!= 0)) |
abfd->flags &= ~D_PAGED; |
} |
} |
/* A further sanity check. */ |
if (i_ehdrp->e_shnum != 0) |
{ |
if (i_ehdrp->e_shstrndx >= elf_numsections (abfd)) |
{ |
/* PR 2257: |
We used to just goto got_wrong_format_error here |
but there are binaries in existance for which this test |
will prevent the binutils from working with them at all. |
So we are kind, and reset the string index value to 0 |
so that at least some processing can be done. */ |
i_ehdrp->e_shstrndx = SHN_UNDEF; |
_bfd_error_handler (_("warning: %s has a corrupt string table index - ignoring"), abfd->filename); |
} |
} |
else if (i_ehdrp->e_shstrndx != SHN_UNDEF) |
goto got_wrong_format_error; |
/* Read in the program headers. */ |
if (i_ehdrp->e_phnum == 0) |
elf_tdata (abfd)->phdr = NULL; |
else |
{ |
Elf_Internal_Phdr *i_phdr; |
unsigned int i; |
amt = i_ehdrp->e_phnum * sizeof (Elf_Internal_Phdr); |
elf_tdata (abfd)->phdr = (Elf_Internal_Phdr *) bfd_alloc (abfd, amt); |
if (elf_tdata (abfd)->phdr == NULL) |
goto got_no_match; |
if (bfd_seek (abfd, (file_ptr) i_ehdrp->e_phoff, SEEK_SET) != 0) |
goto got_no_match; |
i_phdr = elf_tdata (abfd)->phdr; |
for (i = 0; i < i_ehdrp->e_phnum; i++, i_phdr++) |
{ |
Elf_External_Phdr x_phdr; |
if (bfd_bread (&x_phdr, sizeof x_phdr, abfd) != sizeof x_phdr) |
goto got_no_match; |
elf_swap_phdr_in (abfd, &x_phdr, i_phdr); |
} |
} |
if (i_ehdrp->e_shstrndx != 0 && i_ehdrp->e_shoff != 0) |
{ |
unsigned int num_sec; |
/* Once all of the section headers have been read and converted, we |
can start processing them. Note that the first section header is |
a dummy placeholder entry, so we ignore it. */ |
num_sec = elf_numsections (abfd); |
for (shindex = 1; shindex < num_sec; shindex++) |
if (!bfd_section_from_shdr (abfd, shindex)) |
goto got_no_match; |
/* Set up ELF sections for SHF_GROUP and SHF_LINK_ORDER. */ |
if (! _bfd_elf_setup_sections (abfd)) |
goto got_wrong_format_error; |
} |
/* Let the backend double check the format and override global |
information. */ |
if (ebd->elf_backend_object_p) |
{ |
if (! (*ebd->elf_backend_object_p) (abfd)) |
goto got_wrong_format_error; |
} |
/* Remember the entry point specified in the ELF file header. */ |
bfd_set_start_address (abfd, i_ehdrp->e_entry); |
/* If we have created any reloc sections that are associated with |
debugging sections, mark the reloc sections as debugging as well. */ |
for (s = abfd->sections; s != NULL; s = s->next) |
{ |
if ((elf_section_data (s)->this_hdr.sh_type == SHT_REL |
|| elf_section_data (s)->this_hdr.sh_type == SHT_RELA) |
&& elf_section_data (s)->this_hdr.sh_info > 0) |
{ |
unsigned long targ_index; |
asection *targ_sec; |
targ_index = elf_section_data (s)->this_hdr.sh_info; |
targ_sec = bfd_section_from_elf_index (abfd, targ_index); |
if (targ_sec != NULL |
&& (targ_sec->flags & SEC_DEBUGGING) != 0) |
s->flags |= SEC_DEBUGGING; |
} |
} |
return target; |
got_wrong_format_error: |
bfd_set_error (bfd_error_wrong_format); |
got_no_match: |
return NULL; |
} |
/* ELF .o/exec file writing */ |
/* Write out the relocs. */ |
void |
elf_write_relocs (bfd *abfd, asection *sec, void *data) |
{ |
bfd_boolean *failedp = (bfd_boolean *) data; |
Elf_Internal_Shdr *rela_hdr; |
bfd_vma addr_offset; |
void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *); |
size_t extsize; |
bfd_byte *dst_rela; |
unsigned int idx; |
asymbol *last_sym; |
int last_sym_idx; |
/* If we have already failed, don't do anything. */ |
if (*failedp) |
return; |
if ((sec->flags & SEC_RELOC) == 0) |
return; |
/* The linker backend writes the relocs out itself, and sets the |
reloc_count field to zero to inhibit writing them here. Also, |
sometimes the SEC_RELOC flag gets set even when there aren't any |
relocs. */ |
if (sec->reloc_count == 0) |
return; |
/* If we have opened an existing file for update, reloc_count may be |
set even though we are not linking. In that case we have nothing |
to do. */ |
if (sec->orelocation == NULL) |
return; |
rela_hdr = elf_section_data (sec)->rela.hdr; |
if (rela_hdr == NULL) |
rela_hdr = elf_section_data (sec)->rel.hdr; |
rela_hdr->sh_size = rela_hdr->sh_entsize * sec->reloc_count; |
rela_hdr->contents = (unsigned char *) bfd_alloc (abfd, rela_hdr->sh_size); |
if (rela_hdr->contents == NULL) |
{ |
*failedp = TRUE; |
return; |
} |
/* Figure out whether the relocations are RELA or REL relocations. */ |
if (rela_hdr->sh_type == SHT_RELA) |
{ |
swap_out = elf_swap_reloca_out; |
extsize = sizeof (Elf_External_Rela); |
} |
else if (rela_hdr->sh_type == SHT_REL) |
{ |
swap_out = elf_swap_reloc_out; |
extsize = sizeof (Elf_External_Rel); |
} |
else |
/* Every relocation section should be either an SHT_RELA or an |
SHT_REL section. */ |
abort (); |
/* The address of an ELF reloc is section relative for an object |
file, and absolute for an executable file or shared library. |
The address of a BFD reloc is always section relative. */ |
addr_offset = 0; |
if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0) |
addr_offset = sec->vma; |
/* orelocation has the data, reloc_count has the count... */ |
last_sym = 0; |
last_sym_idx = 0; |
dst_rela = rela_hdr->contents; |
for (idx = 0; idx < sec->reloc_count; idx++, dst_rela += extsize) |
{ |
Elf_Internal_Rela src_rela; |
arelent *ptr; |
asymbol *sym; |
int n; |
ptr = sec->orelocation[idx]; |
sym = *ptr->sym_ptr_ptr; |
if (sym == last_sym) |
n = last_sym_idx; |
else if (bfd_is_abs_section (sym->section) && sym->value == 0) |
n = STN_UNDEF; |
else |
{ |
last_sym = sym; |
n = _bfd_elf_symbol_from_bfd_symbol (abfd, &sym); |
if (n < 0) |
{ |
*failedp = TRUE; |
return; |
} |
last_sym_idx = n; |
} |
if ((*ptr->sym_ptr_ptr)->the_bfd != NULL |
&& (*ptr->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec |
&& ! _bfd_elf_validate_reloc (abfd, ptr)) |
{ |
*failedp = TRUE; |
return; |
} |
src_rela.r_offset = ptr->address + addr_offset; |
src_rela.r_info = ELF_R_INFO (n, ptr->howto->type); |
src_rela.r_addend = ptr->addend; |
(*swap_out) (abfd, &src_rela, dst_rela); |
} |
} |
/* Write out the program headers. */ |
int |
elf_write_out_phdrs (bfd *abfd, |
const Elf_Internal_Phdr *phdr, |
unsigned int count) |
{ |
while (count--) |
{ |
Elf_External_Phdr extphdr; |
elf_swap_phdr_out (abfd, phdr, &extphdr); |
if (bfd_bwrite (&extphdr, sizeof (Elf_External_Phdr), abfd) |
!= sizeof (Elf_External_Phdr)) |
return -1; |
phdr++; |
} |
return 0; |
} |
/* Write out the section headers and the ELF file header. */ |
bfd_boolean |
elf_write_shdrs_and_ehdr (bfd *abfd) |
{ |
Elf_External_Ehdr x_ehdr; /* Elf file header, external form */ |
Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */ |
Elf_External_Shdr *x_shdrp; /* Section header table, external form */ |
Elf_Internal_Shdr **i_shdrp; /* Section header table, internal form */ |
unsigned int count; |
bfd_size_type amt; |
i_ehdrp = elf_elfheader (abfd); |
i_shdrp = elf_elfsections (abfd); |
/* swap the header before spitting it out... */ |
#if DEBUG & 1 |
elf_debug_file (i_ehdrp); |
#endif |
elf_swap_ehdr_out (abfd, i_ehdrp, &x_ehdr); |
amt = sizeof (x_ehdr); |
if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 |
|| bfd_bwrite (&x_ehdr, amt, abfd) != amt) |
return FALSE; |
/* Some fields in the first section header handle overflow of ehdr |
fields. */ |
if (i_ehdrp->e_phnum >= PN_XNUM) |
i_shdrp[0]->sh_info = i_ehdrp->e_phnum; |
if (i_ehdrp->e_shnum >= (SHN_LORESERVE & 0xffff)) |
i_shdrp[0]->sh_size = i_ehdrp->e_shnum; |
if (i_ehdrp->e_shstrndx >= (SHN_LORESERVE & 0xffff)) |
i_shdrp[0]->sh_link = i_ehdrp->e_shstrndx; |
/* at this point we've concocted all the ELF sections... */ |
amt = i_ehdrp->e_shnum; |
amt *= sizeof (*x_shdrp); |
x_shdrp = (Elf_External_Shdr *) bfd_alloc (abfd, amt); |
if (!x_shdrp) |
return FALSE; |
for (count = 0; count < i_ehdrp->e_shnum; i_shdrp++, count++) |
{ |
#if DEBUG & 2 |
elf_debug_section (count, *i_shdrp); |
#endif |
elf_swap_shdr_out (abfd, *i_shdrp, x_shdrp + count); |
} |
if (bfd_seek (abfd, (file_ptr) i_ehdrp->e_shoff, SEEK_SET) != 0 |
|| bfd_bwrite (x_shdrp, amt, abfd) != amt) |
return FALSE; |
/* need to dump the string table too... */ |
return TRUE; |
} |
bfd_boolean |
elf_checksum_contents (bfd *abfd, |
void (*process) (const void *, size_t, void *), |
void *arg) |
{ |
Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd); |
Elf_Internal_Shdr **i_shdrp = elf_elfsections (abfd); |
Elf_Internal_Phdr *i_phdrp = elf_tdata (abfd)->phdr; |
unsigned int count, num; |
{ |
Elf_External_Ehdr x_ehdr; |
Elf_Internal_Ehdr i_ehdr; |
i_ehdr = *i_ehdrp; |
i_ehdr.e_phoff = i_ehdr.e_shoff = 0; |
elf_swap_ehdr_out (abfd, &i_ehdr, &x_ehdr); |
(*process) (&x_ehdr, sizeof x_ehdr, arg); |
} |
num = i_ehdrp->e_phnum; |
for (count = 0; count < num; count++) |
{ |
Elf_External_Phdr x_phdr; |
elf_swap_phdr_out (abfd, &i_phdrp[count], &x_phdr); |
(*process) (&x_phdr, sizeof x_phdr, arg); |
} |
num = elf_numsections (abfd); |
for (count = 0; count < num; count++) |
{ |
Elf_Internal_Shdr i_shdr; |
Elf_External_Shdr x_shdr; |
bfd_byte *contents, *free_contents; |
i_shdr = *i_shdrp[count]; |
i_shdr.sh_offset = 0; |
elf_swap_shdr_out (abfd, &i_shdr, &x_shdr); |
(*process) (&x_shdr, sizeof x_shdr, arg); |
/* Process the section's contents, if it has some. |
PR ld/12451: Read them in if necessary. */ |
if (i_shdr.sh_type == SHT_NOBITS) |
continue; |
free_contents = NULL; |
contents = i_shdr.contents; |
if (contents == NULL) |
{ |
asection *sec; |
sec = bfd_section_from_elf_index (abfd, count); |
if (sec != NULL) |
{ |
contents = sec->contents; |
if (contents == NULL) |
{ |
/* Force rereading from file. */ |
sec->flags &= ~SEC_IN_MEMORY; |
if (!bfd_malloc_and_get_section (abfd, sec, &free_contents)) |
continue; |
contents = free_contents; |
} |
} |
} |
if (contents != NULL) |
{ |
(*process) (contents, i_shdr.sh_size, arg); |
if (free_contents != NULL) |
free (free_contents); |
} |
} |
return TRUE; |
} |
long |
elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, bfd_boolean dynamic) |
{ |
Elf_Internal_Shdr *hdr; |
Elf_Internal_Shdr *verhdr; |
unsigned long symcount; /* Number of external ELF symbols */ |
elf_symbol_type *sym; /* Pointer to current bfd symbol */ |
elf_symbol_type *symbase; /* Buffer for generated bfd symbols */ |
Elf_Internal_Sym *isym; |
Elf_Internal_Sym *isymend; |
Elf_Internal_Sym *isymbuf = NULL; |
Elf_External_Versym *xver; |
Elf_External_Versym *xverbuf = NULL; |
const struct elf_backend_data *ebd; |
bfd_size_type amt; |
/* Read each raw ELF symbol, converting from external ELF form to |
internal ELF form, and then using the information to create a |
canonical bfd symbol table entry. |
Note that we allocate the initial bfd canonical symbol buffer |
based on a one-to-one mapping of the ELF symbols to canonical |
symbols. We actually use all the ELF symbols, so there will be no |
space left over at the end. When we have all the symbols, we |
build the caller's pointer vector. */ |
if (! dynamic) |
{ |
hdr = &elf_tdata (abfd)->symtab_hdr; |
verhdr = NULL; |
} |
else |
{ |
hdr = &elf_tdata (abfd)->dynsymtab_hdr; |
if (elf_dynversym (abfd) == 0) |
verhdr = NULL; |
else |
verhdr = &elf_tdata (abfd)->dynversym_hdr; |
if ((elf_dynverdef (abfd) != 0 |
&& elf_tdata (abfd)->verdef == NULL) |
|| (elf_dynverref (abfd) != 0 |
&& elf_tdata (abfd)->verref == NULL)) |
{ |
if (!_bfd_elf_slurp_version_tables (abfd, FALSE)) |
return -1; |
} |
} |
ebd = get_elf_backend_data (abfd); |
symcount = hdr->sh_size / sizeof (Elf_External_Sym); |
if (symcount == 0) |
sym = symbase = NULL; |
else |
{ |
isymbuf = bfd_elf_get_elf_syms (abfd, hdr, symcount, 0, |
NULL, NULL, NULL); |
if (isymbuf == NULL) |
return -1; |
amt = symcount; |
amt *= sizeof (elf_symbol_type); |
symbase = (elf_symbol_type *) bfd_zalloc (abfd, amt); |
if (symbase == (elf_symbol_type *) NULL) |
goto error_return; |
/* Read the raw ELF version symbol information. */ |
if (verhdr != NULL |
&& verhdr->sh_size / sizeof (Elf_External_Versym) != symcount) |
{ |
(*_bfd_error_handler) |
(_("%s: version count (%ld) does not match symbol count (%ld)"), |
abfd->filename, |
(long) (verhdr->sh_size / sizeof (Elf_External_Versym)), |
symcount); |
/* Slurp in the symbols without the version information, |
since that is more helpful than just quitting. */ |
verhdr = NULL; |
} |
if (verhdr != NULL) |
{ |
if (bfd_seek (abfd, verhdr->sh_offset, SEEK_SET) != 0) |
goto error_return; |
xverbuf = (Elf_External_Versym *) bfd_malloc (verhdr->sh_size); |
if (xverbuf == NULL && verhdr->sh_size != 0) |
goto error_return; |
if (bfd_bread (xverbuf, verhdr->sh_size, abfd) != verhdr->sh_size) |
goto error_return; |
} |
/* Skip first symbol, which is a null dummy. */ |
xver = xverbuf; |
if (xver != NULL) |
++xver; |
isymend = isymbuf + symcount; |
for (isym = isymbuf + 1, sym = symbase; isym < isymend; isym++, sym++) |
{ |
memcpy (&sym->internal_elf_sym, isym, sizeof (Elf_Internal_Sym)); |
sym->symbol.the_bfd = abfd; |
sym->symbol.name = bfd_elf_sym_name (abfd, hdr, isym, NULL); |
sym->symbol.value = isym->st_value; |
if (isym->st_shndx == SHN_UNDEF) |
{ |
sym->symbol.section = bfd_und_section_ptr; |
} |
else if (isym->st_shndx == SHN_ABS) |
{ |
sym->symbol.section = bfd_abs_section_ptr; |
} |
else if (isym->st_shndx == SHN_COMMON) |
{ |
sym->symbol.section = bfd_com_section_ptr; |
if ((abfd->flags & BFD_PLUGIN) != 0) |
{ |
asection *xc = bfd_get_section_by_name (abfd, "COMMON"); |
if (xc == NULL) |
{ |
flagword flags = (SEC_ALLOC | SEC_IS_COMMON | SEC_KEEP |
| SEC_EXCLUDE); |
xc = bfd_make_section_with_flags (abfd, "COMMON", flags); |
if (xc == NULL) |
goto error_return; |
} |
sym->symbol.section = xc; |
} |
/* Elf puts the alignment into the `value' field, and |
the size into the `size' field. BFD wants to see the |
size in the value field, and doesn't care (at the |
moment) about the alignment. */ |
sym->symbol.value = isym->st_size; |
} |
else |
{ |
sym->symbol.section |
= bfd_section_from_elf_index (abfd, isym->st_shndx); |
if (sym->symbol.section == NULL) |
{ |
/* This symbol is in a section for which we did not |
create a BFD section. Just use bfd_abs_section, |
although it is wrong. FIXME. */ |
sym->symbol.section = bfd_abs_section_ptr; |
} |
} |
/* If this is a relocatable file, then the symbol value is |
already section relative. */ |
if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0) |
sym->symbol.value -= sym->symbol.section->vma; |
switch (ELF_ST_BIND (isym->st_info)) |
{ |
case STB_LOCAL: |
sym->symbol.flags |= BSF_LOCAL; |
break; |
case STB_GLOBAL: |
if (isym->st_shndx != SHN_UNDEF && isym->st_shndx != SHN_COMMON) |
sym->symbol.flags |= BSF_GLOBAL; |
break; |
case STB_WEAK: |
sym->symbol.flags |= BSF_WEAK; |
break; |
case STB_GNU_UNIQUE: |
sym->symbol.flags |= BSF_GNU_UNIQUE; |
break; |
} |
switch (ELF_ST_TYPE (isym->st_info)) |
{ |
case STT_SECTION: |
sym->symbol.flags |= BSF_SECTION_SYM | BSF_DEBUGGING; |
break; |
case STT_FILE: |
sym->symbol.flags |= BSF_FILE | BSF_DEBUGGING; |
break; |
case STT_FUNC: |
sym->symbol.flags |= BSF_FUNCTION; |
break; |
case STT_COMMON: |
/* FIXME: Do we have to put the size field into the value field |
as we do with symbols in SHN_COMMON sections (see above) ? */ |
/* Fall through. */ |
case STT_OBJECT: |
sym->symbol.flags |= BSF_OBJECT; |
break; |
case STT_TLS: |
sym->symbol.flags |= BSF_THREAD_LOCAL; |
break; |
case STT_RELC: |
sym->symbol.flags |= BSF_RELC; |
break; |
case STT_SRELC: |
sym->symbol.flags |= BSF_SRELC; |
break; |
case STT_GNU_IFUNC: |
sym->symbol.flags |= BSF_GNU_INDIRECT_FUNCTION; |
break; |
} |
if (dynamic) |
sym->symbol.flags |= BSF_DYNAMIC; |
if (xver != NULL) |
{ |
Elf_Internal_Versym iversym; |
_bfd_elf_swap_versym_in (abfd, xver, &iversym); |
sym->version = iversym.vs_vers; |
xver++; |
} |
/* Do some backend-specific processing on this symbol. */ |
if (ebd->elf_backend_symbol_processing) |
(*ebd->elf_backend_symbol_processing) (abfd, &sym->symbol); |
} |
} |
/* Do some backend-specific processing on this symbol table. */ |
if (ebd->elf_backend_symbol_table_processing) |
(*ebd->elf_backend_symbol_table_processing) (abfd, symbase, symcount); |
/* We rely on the zalloc to clear out the final symbol entry. */ |
symcount = sym - symbase; |
/* Fill in the user's symbol pointer vector if needed. */ |
if (symptrs) |
{ |
long l = symcount; |
sym = symbase; |
while (l-- > 0) |
{ |
*symptrs++ = &sym->symbol; |
sym++; |
} |
*symptrs = 0; /* Final null pointer */ |
} |
if (xverbuf != NULL) |
free (xverbuf); |
if (isymbuf != NULL && hdr->contents != (unsigned char *) isymbuf) |
free (isymbuf); |
return symcount; |
error_return: |
if (xverbuf != NULL) |
free (xverbuf); |
if (isymbuf != NULL && hdr->contents != (unsigned char *) isymbuf) |
free (isymbuf); |
return -1; |
} |
/* Read relocations for ASECT from REL_HDR. There are RELOC_COUNT of |
them. */ |
static bfd_boolean |
elf_slurp_reloc_table_from_section (bfd *abfd, |
asection *asect, |
Elf_Internal_Shdr *rel_hdr, |
bfd_size_type reloc_count, |
arelent *relents, |
asymbol **symbols, |
bfd_boolean dynamic) |
{ |
const struct elf_backend_data * const ebd = get_elf_backend_data (abfd); |
void *allocated = NULL; |
bfd_byte *native_relocs; |
arelent *relent; |
unsigned int i; |
int entsize; |
unsigned int symcount; |
allocated = bfd_malloc (rel_hdr->sh_size); |
if (allocated == NULL) |
goto error_return; |
if (bfd_seek (abfd, rel_hdr->sh_offset, SEEK_SET) != 0 |
|| (bfd_bread (allocated, rel_hdr->sh_size, abfd) |
!= rel_hdr->sh_size)) |
goto error_return; |
native_relocs = (bfd_byte *) allocated; |
entsize = rel_hdr->sh_entsize; |
BFD_ASSERT (entsize == sizeof (Elf_External_Rel) |
|| entsize == sizeof (Elf_External_Rela)); |
if (dynamic) |
symcount = bfd_get_dynamic_symcount (abfd); |
else |
symcount = bfd_get_symcount (abfd); |
for (i = 0, relent = relents; |
i < reloc_count; |
i++, relent++, native_relocs += entsize) |
{ |
Elf_Internal_Rela rela; |
if (entsize == sizeof (Elf_External_Rela)) |
elf_swap_reloca_in (abfd, native_relocs, &rela); |
else |
elf_swap_reloc_in (abfd, native_relocs, &rela); |
/* The address of an ELF reloc is section relative for an object |
file, and absolute for an executable file or shared library. |
The address of a normal BFD reloc is always section relative, |
and the address of a dynamic reloc is absolute.. */ |
if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0 || dynamic) |
relent->address = rela.r_offset; |
else |
relent->address = rela.r_offset - asect->vma; |
if (ELF_R_SYM (rela.r_info) == STN_UNDEF) |
relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; |
else if (ELF_R_SYM (rela.r_info) > symcount) |
{ |
(*_bfd_error_handler) |
(_("%s(%s): relocation %d has invalid symbol index %ld"), |
abfd->filename, asect->name, i, ELF_R_SYM (rela.r_info)); |
relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; |
} |
else |
{ |
asymbol **ps; |
ps = symbols + ELF_R_SYM (rela.r_info) - 1; |
relent->sym_ptr_ptr = ps; |
} |
relent->addend = rela.r_addend; |
if ((entsize == sizeof (Elf_External_Rela) |
&& ebd->elf_info_to_howto != NULL) |
|| ebd->elf_info_to_howto_rel == NULL) |
(*ebd->elf_info_to_howto) (abfd, relent, &rela); |
else |
(*ebd->elf_info_to_howto_rel) (abfd, relent, &rela); |
} |
if (allocated != NULL) |
free (allocated); |
return TRUE; |
error_return: |
if (allocated != NULL) |
free (allocated); |
return FALSE; |
} |
/* Read in and swap the external relocs. */ |
bfd_boolean |
elf_slurp_reloc_table (bfd *abfd, |
asection *asect, |
asymbol **symbols, |
bfd_boolean dynamic) |
{ |
struct bfd_elf_section_data * const d = elf_section_data (asect); |
Elf_Internal_Shdr *rel_hdr; |
Elf_Internal_Shdr *rel_hdr2; |
bfd_size_type reloc_count; |
bfd_size_type reloc_count2; |
arelent *relents; |
bfd_size_type amt; |
if (asect->relocation != NULL) |
return TRUE; |
if (! dynamic) |
{ |
if ((asect->flags & SEC_RELOC) == 0 |
|| asect->reloc_count == 0) |
return TRUE; |
rel_hdr = d->rel.hdr; |
reloc_count = rel_hdr ? NUM_SHDR_ENTRIES (rel_hdr) : 0; |
rel_hdr2 = d->rela.hdr; |
reloc_count2 = rel_hdr2 ? NUM_SHDR_ENTRIES (rel_hdr2) : 0; |
BFD_ASSERT (asect->reloc_count == reloc_count + reloc_count2); |
BFD_ASSERT ((rel_hdr && asect->rel_filepos == rel_hdr->sh_offset) |
|| (rel_hdr2 && asect->rel_filepos == rel_hdr2->sh_offset)); |
} |
else |
{ |
/* Note that ASECT->RELOC_COUNT tends not to be accurate in this |
case because relocations against this section may use the |
dynamic symbol table, and in that case bfd_section_from_shdr |
in elf.c does not update the RELOC_COUNT. */ |
if (asect->size == 0) |
return TRUE; |
rel_hdr = &d->this_hdr; |
reloc_count = NUM_SHDR_ENTRIES (rel_hdr); |
rel_hdr2 = NULL; |
reloc_count2 = 0; |
} |
amt = (reloc_count + reloc_count2) * sizeof (arelent); |
relents = (arelent *) bfd_alloc (abfd, amt); |
if (relents == NULL) |
return FALSE; |
if (rel_hdr |
&& !elf_slurp_reloc_table_from_section (abfd, asect, |
rel_hdr, reloc_count, |
relents, |
symbols, dynamic)) |
return FALSE; |
if (rel_hdr2 |
&& !elf_slurp_reloc_table_from_section (abfd, asect, |
rel_hdr2, reloc_count2, |
relents + reloc_count, |
symbols, dynamic)) |
return FALSE; |
asect->relocation = relents; |
return TRUE; |
} |
#if DEBUG & 2 |
static void |
elf_debug_section (int num, Elf_Internal_Shdr *hdr) |
{ |
fprintf (stderr, "\nSection#%d '%s' 0x%.8lx\n", num, |
hdr->bfd_section != NULL ? hdr->bfd_section->name : "", |
(long) hdr); |
fprintf (stderr, |
"sh_name = %ld\tsh_type = %ld\tsh_flags = %ld\n", |
(long) hdr->sh_name, |
(long) hdr->sh_type, |
(long) hdr->sh_flags); |
fprintf (stderr, |
"sh_addr = %ld\tsh_offset = %ld\tsh_size = %ld\n", |
(long) hdr->sh_addr, |
(long) hdr->sh_offset, |
(long) hdr->sh_size); |
fprintf (stderr, |
"sh_link = %ld\tsh_info = %ld\tsh_addralign = %ld\n", |
(long) hdr->sh_link, |
(long) hdr->sh_info, |
(long) hdr->sh_addralign); |
fprintf (stderr, "sh_entsize = %ld\n", |
(long) hdr->sh_entsize); |
fflush (stderr); |
} |
#endif |
#if DEBUG & 1 |
static void |
elf_debug_file (Elf_Internal_Ehdr *ehdrp) |
{ |
fprintf (stderr, "e_entry = 0x%.8lx\n", (long) ehdrp->e_entry); |
fprintf (stderr, "e_phoff = %ld\n", (long) ehdrp->e_phoff); |
fprintf (stderr, "e_phnum = %ld\n", (long) ehdrp->e_phnum); |
fprintf (stderr, "e_phentsize = %ld\n", (long) ehdrp->e_phentsize); |
fprintf (stderr, "e_shoff = %ld\n", (long) ehdrp->e_shoff); |
fprintf (stderr, "e_shnum = %ld\n", (long) ehdrp->e_shnum); |
fprintf (stderr, "e_shentsize = %ld\n", (long) ehdrp->e_shentsize); |
} |
#endif |
/* Create a new BFD as if by bfd_openr. Rather than opening a file, |
reconstruct an ELF file by reading the segments out of remote memory |
based on the ELF file header at EHDR_VMA and the ELF program headers it |
points to. If not null, *LOADBASEP is filled in with the difference |
between the VMAs from which the segments were read, and the VMAs the |
file headers (and hence BFD's idea of each section's VMA) put them at. |
The function TARGET_READ_MEMORY is called to copy LEN bytes from the |
remote memory at target address VMA into the local buffer at MYADDR; it |
should return zero on success or an `errno' code on failure. TEMPL must |
be a BFD for a target with the word size and byte order found in the |
remote memory. */ |
bfd * |
NAME(_bfd_elf,bfd_from_remote_memory) |
(bfd *templ, |
bfd_vma ehdr_vma, |
bfd_vma *loadbasep, |
int (*target_read_memory) (bfd_vma, bfd_byte *, bfd_size_type)) |
{ |
Elf_External_Ehdr x_ehdr; /* Elf file header, external form */ |
Elf_Internal_Ehdr i_ehdr; /* Elf file header, internal form */ |
Elf_External_Phdr *x_phdrs; |
Elf_Internal_Phdr *i_phdrs, *last_phdr; |
bfd *nbfd; |
struct bfd_in_memory *bim; |
int contents_size; |
bfd_byte *contents; |
int err; |
unsigned int i; |
bfd_vma loadbase; |
bfd_boolean loadbase_set; |
/* Read in the ELF header in external format. */ |
err = target_read_memory (ehdr_vma, (bfd_byte *) &x_ehdr, sizeof x_ehdr); |
if (err) |
{ |
bfd_set_error (bfd_error_system_call); |
errno = err; |
return NULL; |
} |
/* Now check to see if we have a valid ELF file, and one that BFD can |
make use of. The magic number must match, the address size ('class') |
and byte-swapping must match our XVEC entry. */ |
if (! elf_file_p (&x_ehdr) |
|| x_ehdr.e_ident[EI_VERSION] != EV_CURRENT |
|| x_ehdr.e_ident[EI_CLASS] != ELFCLASS) |
{ |
bfd_set_error (bfd_error_wrong_format); |
return NULL; |
} |
/* Check that file's byte order matches xvec's */ |
switch (x_ehdr.e_ident[EI_DATA]) |
{ |
case ELFDATA2MSB: /* Big-endian */ |
if (! bfd_header_big_endian (templ)) |
{ |
bfd_set_error (bfd_error_wrong_format); |
return NULL; |
} |
break; |
case ELFDATA2LSB: /* Little-endian */ |
if (! bfd_header_little_endian (templ)) |
{ |
bfd_set_error (bfd_error_wrong_format); |
return NULL; |
} |
break; |
case ELFDATANONE: /* No data encoding specified */ |
default: /* Unknown data encoding specified */ |
bfd_set_error (bfd_error_wrong_format); |
return NULL; |
} |
elf_swap_ehdr_in (templ, &x_ehdr, &i_ehdr); |
/* The file header tells where to find the program headers. |
These are what we use to actually choose what to read. */ |
if (i_ehdr.e_phentsize != sizeof (Elf_External_Phdr) || i_ehdr.e_phnum == 0) |
{ |
bfd_set_error (bfd_error_wrong_format); |
return NULL; |
} |
x_phdrs = (Elf_External_Phdr *) |
bfd_malloc (i_ehdr.e_phnum * (sizeof *x_phdrs + sizeof *i_phdrs)); |
if (x_phdrs == NULL) |
{ |
bfd_set_error (bfd_error_no_memory); |
return NULL; |
} |
err = target_read_memory (ehdr_vma + i_ehdr.e_phoff, (bfd_byte *) x_phdrs, |
i_ehdr.e_phnum * sizeof x_phdrs[0]); |
if (err) |
{ |
free (x_phdrs); |
bfd_set_error (bfd_error_system_call); |
errno = err; |
return NULL; |
} |
i_phdrs = (Elf_Internal_Phdr *) &x_phdrs[i_ehdr.e_phnum]; |
contents_size = 0; |
last_phdr = NULL; |
loadbase = ehdr_vma; |
loadbase_set = FALSE; |
for (i = 0; i < i_ehdr.e_phnum; ++i) |
{ |
elf_swap_phdr_in (templ, &x_phdrs[i], &i_phdrs[i]); |
if (i_phdrs[i].p_type == PT_LOAD) |
{ |
bfd_vma segment_end; |
segment_end = (i_phdrs[i].p_offset + i_phdrs[i].p_filesz |
+ i_phdrs[i].p_align - 1) & -i_phdrs[i].p_align; |
if (segment_end > (bfd_vma) contents_size) |
contents_size = segment_end; |
/* LOADADDR is the `Base address' from the gELF specification: |
`lowest p_vaddr value for a PT_LOAD segment' is P_VADDR from the |
first PT_LOAD as PT_LOADs are ordered by P_VADDR. */ |
if (!loadbase_set && (i_phdrs[i].p_offset & -i_phdrs[i].p_align) == 0) |
{ |
loadbase = ehdr_vma - (i_phdrs[i].p_vaddr & -i_phdrs[i].p_align); |
loadbase_set = TRUE; |
} |
last_phdr = &i_phdrs[i]; |
} |
} |
if (last_phdr == NULL) |
{ |
/* There were no PT_LOAD segments, so we don't have anything to read. */ |
free (x_phdrs); |
bfd_set_error (bfd_error_wrong_format); |
return NULL; |
} |
/* Trim the last segment so we don't bother with zeros in the last page |
that are off the end of the file. However, if the extra bit in that |
page includes the section headers, keep them. */ |
if ((bfd_vma) contents_size > last_phdr->p_offset + last_phdr->p_filesz |
&& (bfd_vma) contents_size >= (i_ehdr.e_shoff |
+ i_ehdr.e_shnum * i_ehdr.e_shentsize)) |
{ |
contents_size = last_phdr->p_offset + last_phdr->p_filesz; |
if ((bfd_vma) contents_size < (i_ehdr.e_shoff |
+ i_ehdr.e_shnum * i_ehdr.e_shentsize)) |
contents_size = i_ehdr.e_shoff + i_ehdr.e_shnum * i_ehdr.e_shentsize; |
} |
else |
contents_size = last_phdr->p_offset + last_phdr->p_filesz; |
/* Now we know the size of the whole image we want read in. */ |
contents = (bfd_byte *) bfd_zmalloc (contents_size); |
if (contents == NULL) |
{ |
free (x_phdrs); |
bfd_set_error (bfd_error_no_memory); |
return NULL; |
} |
for (i = 0; i < i_ehdr.e_phnum; ++i) |
if (i_phdrs[i].p_type == PT_LOAD) |
{ |
bfd_vma start = i_phdrs[i].p_offset & -i_phdrs[i].p_align; |
bfd_vma end = (i_phdrs[i].p_offset + i_phdrs[i].p_filesz |
+ i_phdrs[i].p_align - 1) & -i_phdrs[i].p_align; |
if (end > (bfd_vma) contents_size) |
end = contents_size; |
err = target_read_memory ((loadbase + i_phdrs[i].p_vaddr) |
& -i_phdrs[i].p_align, |
contents + start, end - start); |
if (err) |
{ |
free (x_phdrs); |
free (contents); |
bfd_set_error (bfd_error_system_call); |
errno = err; |
return NULL; |
} |
} |
free (x_phdrs); |
/* If the segments visible in memory didn't include the section headers, |
then clear them from the file header. */ |
if ((bfd_vma) contents_size < (i_ehdr.e_shoff |
+ i_ehdr.e_shnum * i_ehdr.e_shentsize)) |
{ |
memset (&x_ehdr.e_shoff, 0, sizeof x_ehdr.e_shoff); |
memset (&x_ehdr.e_shnum, 0, sizeof x_ehdr.e_shnum); |
memset (&x_ehdr.e_shstrndx, 0, sizeof x_ehdr.e_shstrndx); |
} |
/* This will normally have been in the first PT_LOAD segment. But it |
conceivably could be missing, and we might have just changed it. */ |
memcpy (contents, &x_ehdr, sizeof x_ehdr); |
/* Now we have a memory image of the ELF file contents. Make a BFD. */ |
bim = (struct bfd_in_memory *) bfd_malloc (sizeof (struct bfd_in_memory)); |
if (bim == NULL) |
{ |
free (contents); |
bfd_set_error (bfd_error_no_memory); |
return NULL; |
} |
nbfd = _bfd_new_bfd (); |
if (nbfd == NULL) |
{ |
free (bim); |
free (contents); |
bfd_set_error (bfd_error_no_memory); |
return NULL; |
} |
nbfd->filename = "<in-memory>"; |
nbfd->xvec = templ->xvec; |
bim->size = contents_size; |
bim->buffer = contents; |
nbfd->iostream = bim; |
nbfd->flags = BFD_IN_MEMORY; |
nbfd->iovec = &_bfd_memory_iovec; |
nbfd->origin = 0; |
nbfd->direction = read_direction; |
nbfd->mtime = time (NULL); |
nbfd->mtime_set = TRUE; |
if (loadbasep) |
*loadbasep = loadbase; |
return nbfd; |
} |
/* Function for ELF_R_INFO. */ |
bfd_vma |
NAME(elf,r_info) (bfd_vma sym, bfd_vma type) |
{ |
return ELF_R_INFO (sym, type); |
} |
/* Function for ELF_R_SYM. */ |
bfd_vma |
NAME(elf,r_sym) (bfd_vma r_info) |
{ |
return ELF_R_SYM (r_info); |
} |
#include "elfcore.h" |
/* Size-dependent data and functions. */ |
const struct elf_size_info NAME(_bfd_elf,size_info) = { |
sizeof (Elf_External_Ehdr), |
sizeof (Elf_External_Phdr), |
sizeof (Elf_External_Shdr), |
sizeof (Elf_External_Rel), |
sizeof (Elf_External_Rela), |
sizeof (Elf_External_Sym), |
sizeof (Elf_External_Dyn), |
sizeof (Elf_External_Note), |
4, |
1, |
ARCH_SIZE, LOG_FILE_ALIGN, |
ELFCLASS, EV_CURRENT, |
elf_write_out_phdrs, |
elf_write_shdrs_and_ehdr, |
elf_checksum_contents, |
elf_write_relocs, |
elf_swap_symbol_in, |
elf_swap_symbol_out, |
elf_slurp_reloc_table, |
elf_slurp_symbol_table, |
elf_swap_dyn_in, |
elf_swap_dyn_out, |
elf_swap_reloc_in, |
elf_swap_reloc_out, |
elf_swap_reloca_in, |
elf_swap_reloca_out |
}; |
/contrib/toolchain/binutils/bfd/elfcore.h |
---|
0,0 → 1,320 |
/* ELF core file support for BFD. |
Copyright 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2005, 2007, |
2008, 2010 Free Software Foundation, Inc. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
char* |
elf_core_file_failing_command (bfd *abfd) |
{ |
return elf_tdata (abfd)->core->command; |
} |
int |
elf_core_file_failing_signal (bfd *abfd) |
{ |
return elf_tdata (abfd)->core->signal; |
} |
int |
elf_core_file_pid (bfd *abfd) |
{ |
return elf_tdata (abfd)->core->pid; |
} |
bfd_boolean |
elf_core_file_matches_executable_p (bfd *core_bfd, bfd *exec_bfd) |
{ |
char* corename; |
/* xvecs must match if both are ELF files for the same target. */ |
if (core_bfd->xvec != exec_bfd->xvec) |
{ |
bfd_set_error (bfd_error_system_call); |
return FALSE; |
} |
/* See if the name in the corefile matches the executable name. */ |
corename = elf_tdata (core_bfd)->core->program; |
if (corename != NULL) |
{ |
const char* execname = strrchr (exec_bfd->filename, '/'); |
execname = execname ? execname + 1 : exec_bfd->filename; |
if (strcmp (execname, corename) != 0) |
return FALSE; |
} |
return TRUE; |
} |
/* Core files are simply standard ELF formatted files that partition |
the file using the execution view of the file (program header table) |
rather than the linking view. In fact, there is no section header |
table in a core file. |
The process status information (including the contents of the general |
register set) and the floating point register set are stored in a |
segment of type PT_NOTE. We handcraft a couple of extra bfd sections |
that allow standard bfd access to the general registers (.reg) and the |
floating point registers (.reg2). */ |
const bfd_target * |
elf_core_file_p (bfd *abfd) |
{ |
Elf_External_Ehdr x_ehdr; /* Elf file header, external form. */ |
Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form. */ |
Elf_Internal_Phdr *i_phdrp; /* Elf program header, internal form. */ |
unsigned int phindex; |
const struct elf_backend_data *ebd; |
bfd_size_type amt; |
/* Read in the ELF header in external format. */ |
if (bfd_bread (&x_ehdr, sizeof (x_ehdr), abfd) != sizeof (x_ehdr)) |
{ |
if (bfd_get_error () != bfd_error_system_call) |
goto wrong; |
else |
goto fail; |
} |
/* Check the magic number. */ |
if (! elf_file_p (&x_ehdr)) |
goto wrong; |
/* FIXME: Check EI_VERSION here ! */ |
/* Check the address size ("class"). */ |
if (x_ehdr.e_ident[EI_CLASS] != ELFCLASS) |
goto wrong; |
/* Check the byteorder. */ |
switch (x_ehdr.e_ident[EI_DATA]) |
{ |
case ELFDATA2MSB: /* Big-endian. */ |
if (! bfd_big_endian (abfd)) |
goto wrong; |
break; |
case ELFDATA2LSB: /* Little-endian. */ |
if (! bfd_little_endian (abfd)) |
goto wrong; |
break; |
default: |
goto wrong; |
} |
/* Give abfd an elf_obj_tdata. */ |
if (! (*abfd->xvec->_bfd_set_format[bfd_core]) (abfd)) |
goto fail; |
/* Swap in the rest of the header, now that we have the byte order. */ |
i_ehdrp = elf_elfheader (abfd); |
elf_swap_ehdr_in (abfd, &x_ehdr, i_ehdrp); |
#if DEBUG & 1 |
elf_debug_file (i_ehdrp); |
#endif |
ebd = get_elf_backend_data (abfd); |
/* Check that the ELF e_machine field matches what this particular |
BFD format expects. */ |
if (ebd->elf_machine_code != i_ehdrp->e_machine |
&& (ebd->elf_machine_alt1 == 0 |
|| i_ehdrp->e_machine != ebd->elf_machine_alt1) |
&& (ebd->elf_machine_alt2 == 0 |
|| i_ehdrp->e_machine != ebd->elf_machine_alt2)) |
{ |
const bfd_target * const *target_ptr; |
if (ebd->elf_machine_code != EM_NONE) |
goto wrong; |
/* This is the generic ELF target. Let it match any ELF target |
for which we do not have a specific backend. */ |
for (target_ptr = bfd_target_vector; *target_ptr != NULL; target_ptr++) |
{ |
const struct elf_backend_data *back; |
if ((*target_ptr)->flavour != bfd_target_elf_flavour) |
continue; |
back = xvec_get_elf_backend_data (*target_ptr); |
if (back->s->arch_size != ARCH_SIZE) |
continue; |
if (back->elf_machine_code == i_ehdrp->e_machine |
|| (back->elf_machine_alt1 != 0 |
&& i_ehdrp->e_machine == back->elf_machine_alt1) |
|| (back->elf_machine_alt2 != 0 |
&& i_ehdrp->e_machine == back->elf_machine_alt2)) |
{ |
/* target_ptr is an ELF backend which matches this |
object file, so reject the generic ELF target. */ |
goto wrong; |
} |
} |
} |
/* If there is no program header, or the type is not a core file, then |
we are hosed. */ |
if (i_ehdrp->e_phoff == 0 || i_ehdrp->e_type != ET_CORE) |
goto wrong; |
/* Does BFD's idea of the phdr size match the size |
recorded in the file? */ |
if (i_ehdrp->e_phentsize != sizeof (Elf_External_Phdr)) |
goto wrong; |
/* If the program header count is PN_XNUM(0xffff), the actual |
count is in the first section header. */ |
if (i_ehdrp->e_shoff != 0 && i_ehdrp->e_phnum == PN_XNUM) |
{ |
Elf_External_Shdr x_shdr; |
Elf_Internal_Shdr i_shdr; |
bfd_signed_vma where = i_ehdrp->e_shoff; |
if (where != (file_ptr) where) |
goto wrong; |
/* Seek to the section header table in the file. */ |
if (bfd_seek (abfd, (file_ptr) where, SEEK_SET) != 0) |
goto fail; |
/* Read the first section header at index 0, and convert to internal |
form. */ |
if (bfd_bread (&x_shdr, sizeof (x_shdr), abfd) != sizeof (x_shdr)) |
goto fail; |
elf_swap_shdr_in (abfd, &x_shdr, &i_shdr); |
if (i_shdr.sh_info != 0) |
{ |
i_ehdrp->e_phnum = i_shdr.sh_info; |
if (i_ehdrp->e_phnum != i_shdr.sh_info) |
goto wrong; |
} |
} |
/* Sanity check that we can read all of the program headers. |
It ought to be good enough to just read the last one. */ |
if (i_ehdrp->e_phnum > 1) |
{ |
Elf_External_Phdr x_phdr; |
Elf_Internal_Phdr i_phdr; |
bfd_signed_vma where; |
/* Check that we don't have a totally silly number of |
program headers. */ |
if (i_ehdrp->e_phnum > (unsigned int) -1 / sizeof (x_phdr) |
|| i_ehdrp->e_phnum > (unsigned int) -1 / sizeof (i_phdr)) |
goto wrong; |
where = i_ehdrp->e_phoff + (i_ehdrp->e_phnum - 1) * sizeof (x_phdr); |
if (where != (file_ptr) where) |
goto wrong; |
if ((bfd_size_type) where <= i_ehdrp->e_phoff) |
goto wrong; |
if (bfd_seek (abfd, (file_ptr) where, SEEK_SET) != 0) |
goto fail; |
if (bfd_bread (&x_phdr, sizeof (x_phdr), abfd) != sizeof (x_phdr)) |
goto fail; |
} |
/* Move to the start of the program headers. */ |
if (bfd_seek (abfd, (file_ptr) i_ehdrp->e_phoff, SEEK_SET) != 0) |
goto wrong; |
/* Allocate space for the program headers. */ |
amt = sizeof (*i_phdrp) * i_ehdrp->e_phnum; |
i_phdrp = (Elf_Internal_Phdr *) bfd_alloc (abfd, amt); |
if (!i_phdrp) |
goto fail; |
elf_tdata (abfd)->phdr = i_phdrp; |
/* Read and convert to internal form. */ |
for (phindex = 0; phindex < i_ehdrp->e_phnum; ++phindex) |
{ |
Elf_External_Phdr x_phdr; |
if (bfd_bread (&x_phdr, sizeof (x_phdr), abfd) != sizeof (x_phdr)) |
goto fail; |
elf_swap_phdr_in (abfd, &x_phdr, i_phdrp + phindex); |
} |
/* Set the machine architecture. Do this before processing the |
program headers since we need to know the architecture type |
when processing the notes of some systems' core files. */ |
if (! bfd_default_set_arch_mach (abfd, ebd->arch, 0) |
/* It's OK if this fails for the generic target. */ |
&& ebd->elf_machine_code != EM_NONE) |
goto fail; |
/* Let the backend double check the format and override global |
information. We do this before processing the program headers |
to allow the correct machine (as opposed to just the default |
machine) to be set, making it possible for grok_prstatus and |
grok_psinfo to rely on the mach setting. */ |
if (ebd->elf_backend_object_p != NULL |
&& ! ebd->elf_backend_object_p (abfd)) |
goto wrong; |
/* Process each program header. */ |
for (phindex = 0; phindex < i_ehdrp->e_phnum; ++phindex) |
if (! bfd_section_from_phdr (abfd, i_phdrp + phindex, (int) phindex)) |
goto fail; |
/* Check for core truncation. */ |
{ |
bfd_size_type high = 0; |
struct stat statbuf; |
for (phindex = 0; phindex < i_ehdrp->e_phnum; ++phindex) |
{ |
Elf_Internal_Phdr *p = i_phdrp + phindex; |
if (p->p_filesz) |
{ |
bfd_size_type current = p->p_offset + p->p_filesz; |
if (high < current) |
high = current; |
} |
} |
if (bfd_stat (abfd, &statbuf) == 0) |
{ |
if ((bfd_size_type) statbuf.st_size < high) |
{ |
(*_bfd_error_handler) |
(_("Warning: %B is truncated: expected core file " |
"size >= %lu, found: %lu."), |
abfd, (unsigned long) high, (unsigned long) statbuf.st_size); |
} |
} |
} |
/* Save the entry point from the ELF header. */ |
bfd_get_start_address (abfd) = i_ehdrp->e_entry; |
return abfd->xvec; |
wrong: |
bfd_set_error (bfd_error_wrong_format); |
fail: |
return NULL; |
} |
/contrib/toolchain/binutils/bfd/elflink.c |
---|
0,0 → 1,13047 |
/* ELF linking support for BFD. |
Copyright 1995-2013 Free Software Foundation, Inc. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "bfdlink.h" |
#include "libbfd.h" |
#define ARCH_SIZE 0 |
#include "elf-bfd.h" |
#include "safe-ctype.h" |
#include "libiberty.h" |
#include "objalloc.h" |
/* This struct is used to pass information to routines called via |
elf_link_hash_traverse which must return failure. */ |
struct elf_info_failed |
{ |
struct bfd_link_info *info; |
bfd_boolean failed; |
}; |
/* This structure is used to pass information to |
_bfd_elf_link_find_version_dependencies. */ |
struct elf_find_verdep_info |
{ |
/* General link information. */ |
struct bfd_link_info *info; |
/* The number of dependencies. */ |
unsigned int vers; |
/* Whether we had a failure. */ |
bfd_boolean failed; |
}; |
static bfd_boolean _bfd_elf_fix_symbol_flags |
(struct elf_link_hash_entry *, struct elf_info_failed *); |
/* Define a symbol in a dynamic linkage section. */ |
struct elf_link_hash_entry * |
_bfd_elf_define_linkage_sym (bfd *abfd, |
struct bfd_link_info *info, |
asection *sec, |
const char *name) |
{ |
struct elf_link_hash_entry *h; |
struct bfd_link_hash_entry *bh; |
const struct elf_backend_data *bed; |
h = elf_link_hash_lookup (elf_hash_table (info), name, FALSE, FALSE, FALSE); |
if (h != NULL) |
{ |
/* Zap symbol defined in an as-needed lib that wasn't linked. |
This is a symptom of a larger problem: Absolute symbols |
defined in shared libraries can't be overridden, because we |
lose the link to the bfd which is via the symbol section. */ |
h->root.type = bfd_link_hash_new; |
} |
bh = &h->root; |
if (!_bfd_generic_link_add_one_symbol (info, abfd, name, BSF_GLOBAL, |
sec, 0, NULL, FALSE, |
get_elf_backend_data (abfd)->collect, |
&bh)) |
return NULL; |
h = (struct elf_link_hash_entry *) bh; |
h->def_regular = 1; |
h->non_elf = 0; |
h->type = STT_OBJECT; |
if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL) |
h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN; |
bed = get_elf_backend_data (abfd); |
(*bed->elf_backend_hide_symbol) (info, h, TRUE); |
return h; |
} |
bfd_boolean |
_bfd_elf_create_got_section (bfd *abfd, struct bfd_link_info *info) |
{ |
flagword flags; |
asection *s; |
struct elf_link_hash_entry *h; |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
struct elf_link_hash_table *htab = elf_hash_table (info); |
/* This function may be called more than once. */ |
s = bfd_get_linker_section (abfd, ".got"); |
if (s != NULL) |
return TRUE; |
flags = bed->dynamic_sec_flags; |
s = bfd_make_section_anyway_with_flags (abfd, |
(bed->rela_plts_and_copies_p |
? ".rela.got" : ".rel.got"), |
(bed->dynamic_sec_flags |
| SEC_READONLY)); |
if (s == NULL |
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) |
return FALSE; |
htab->srelgot = s; |
s = bfd_make_section_anyway_with_flags (abfd, ".got", flags); |
if (s == NULL |
|| !bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) |
return FALSE; |
htab->sgot = s; |
if (bed->want_got_plt) |
{ |
s = bfd_make_section_anyway_with_flags (abfd, ".got.plt", flags); |
if (s == NULL |
|| !bfd_set_section_alignment (abfd, s, |
bed->s->log_file_align)) |
return FALSE; |
htab->sgotplt = s; |
} |
/* The first bit of the global offset table is the header. */ |
s->size += bed->got_header_size; |
if (bed->want_got_sym) |
{ |
/* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the .got |
(or .got.plt) section. We don't do this in the linker script |
because we don't want to define the symbol if we are not creating |
a global offset table. */ |
h = _bfd_elf_define_linkage_sym (abfd, info, s, |
"_GLOBAL_OFFSET_TABLE_"); |
elf_hash_table (info)->hgot = h; |
if (h == NULL) |
return FALSE; |
} |
return TRUE; |
} |
/* Create a strtab to hold the dynamic symbol names. */ |
static bfd_boolean |
_bfd_elf_link_create_dynstrtab (bfd *abfd, struct bfd_link_info *info) |
{ |
struct elf_link_hash_table *hash_table; |
hash_table = elf_hash_table (info); |
if (hash_table->dynobj == NULL) |
hash_table->dynobj = abfd; |
if (hash_table->dynstr == NULL) |
{ |
hash_table->dynstr = _bfd_elf_strtab_init (); |
if (hash_table->dynstr == NULL) |
return FALSE; |
} |
return TRUE; |
} |
/* Create some sections which will be filled in with dynamic linking |
information. ABFD is an input file which requires dynamic sections |
to be created. The dynamic sections take up virtual memory space |
when the final executable is run, so we need to create them before |
addresses are assigned to the output sections. We work out the |
actual contents and size of these sections later. */ |
bfd_boolean |
_bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) |
{ |
flagword flags; |
asection *s; |
const struct elf_backend_data *bed; |
struct elf_link_hash_entry *h; |
if (! is_elf_hash_table (info->hash)) |
return FALSE; |
if (elf_hash_table (info)->dynamic_sections_created) |
return TRUE; |
if (!_bfd_elf_link_create_dynstrtab (abfd, info)) |
return FALSE; |
abfd = elf_hash_table (info)->dynobj; |
bed = get_elf_backend_data (abfd); |
flags = bed->dynamic_sec_flags; |
/* A dynamically linked executable has a .interp section, but a |
shared library does not. */ |
if (info->executable) |
{ |
s = bfd_make_section_anyway_with_flags (abfd, ".interp", |
flags | SEC_READONLY); |
if (s == NULL) |
return FALSE; |
} |
/* Create sections to hold version informations. These are removed |
if they are not needed. */ |
s = bfd_make_section_anyway_with_flags (abfd, ".gnu.version_d", |
flags | SEC_READONLY); |
if (s == NULL |
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) |
return FALSE; |
s = bfd_make_section_anyway_with_flags (abfd, ".gnu.version", |
flags | SEC_READONLY); |
if (s == NULL |
|| ! bfd_set_section_alignment (abfd, s, 1)) |
return FALSE; |
s = bfd_make_section_anyway_with_flags (abfd, ".gnu.version_r", |
flags | SEC_READONLY); |
if (s == NULL |
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) |
return FALSE; |
s = bfd_make_section_anyway_with_flags (abfd, ".dynsym", |
flags | SEC_READONLY); |
if (s == NULL |
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) |
return FALSE; |
s = bfd_make_section_anyway_with_flags (abfd, ".dynstr", |
flags | SEC_READONLY); |
if (s == NULL) |
return FALSE; |
s = bfd_make_section_anyway_with_flags (abfd, ".dynamic", flags); |
if (s == NULL |
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) |
return FALSE; |
/* The special symbol _DYNAMIC is always set to the start of the |
.dynamic section. We could set _DYNAMIC in a linker script, but we |
only want to define it if we are, in fact, creating a .dynamic |
section. We don't want to define it if there is no .dynamic |
section, since on some ELF platforms the start up code examines it |
to decide how to initialize the process. */ |
h = _bfd_elf_define_linkage_sym (abfd, info, s, "_DYNAMIC"); |
elf_hash_table (info)->hdynamic = h; |
if (h == NULL) |
return FALSE; |
if (info->emit_hash) |
{ |
s = bfd_make_section_anyway_with_flags (abfd, ".hash", |
flags | SEC_READONLY); |
if (s == NULL |
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) |
return FALSE; |
elf_section_data (s)->this_hdr.sh_entsize = bed->s->sizeof_hash_entry; |
} |
if (info->emit_gnu_hash) |
{ |
s = bfd_make_section_anyway_with_flags (abfd, ".gnu.hash", |
flags | SEC_READONLY); |
if (s == NULL |
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) |
return FALSE; |
/* For 64-bit ELF, .gnu.hash is a non-uniform entity size section: |
4 32-bit words followed by variable count of 64-bit words, then |
variable count of 32-bit words. */ |
if (bed->s->arch_size == 64) |
elf_section_data (s)->this_hdr.sh_entsize = 0; |
else |
elf_section_data (s)->this_hdr.sh_entsize = 4; |
} |
/* Let the backend create the rest of the sections. This lets the |
backend set the right flags. The backend will normally create |
the .got and .plt sections. */ |
if (bed->elf_backend_create_dynamic_sections == NULL |
|| ! (*bed->elf_backend_create_dynamic_sections) (abfd, info)) |
return FALSE; |
elf_hash_table (info)->dynamic_sections_created = TRUE; |
return TRUE; |
} |
/* Create dynamic sections when linking against a dynamic object. */ |
bfd_boolean |
_bfd_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) |
{ |
flagword flags, pltflags; |
struct elf_link_hash_entry *h; |
asection *s; |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
struct elf_link_hash_table *htab = elf_hash_table (info); |
/* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and |
.rel[a].bss sections. */ |
flags = bed->dynamic_sec_flags; |
pltflags = flags; |
if (bed->plt_not_loaded) |
/* We do not clear SEC_ALLOC here because we still want the OS to |
allocate space for the section; it's just that there's nothing |
to read in from the object file. */ |
pltflags &= ~ (SEC_CODE | SEC_LOAD | SEC_HAS_CONTENTS); |
else |
pltflags |= SEC_ALLOC | SEC_CODE | SEC_LOAD; |
if (bed->plt_readonly) |
pltflags |= SEC_READONLY; |
s = bfd_make_section_anyway_with_flags (abfd, ".plt", pltflags); |
if (s == NULL |
|| ! bfd_set_section_alignment (abfd, s, bed->plt_alignment)) |
return FALSE; |
htab->splt = s; |
/* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the |
.plt section. */ |
if (bed->want_plt_sym) |
{ |
h = _bfd_elf_define_linkage_sym (abfd, info, s, |
"_PROCEDURE_LINKAGE_TABLE_"); |
elf_hash_table (info)->hplt = h; |
if (h == NULL) |
return FALSE; |
} |
s = bfd_make_section_anyway_with_flags (abfd, |
(bed->rela_plts_and_copies_p |
? ".rela.plt" : ".rel.plt"), |
flags | SEC_READONLY); |
if (s == NULL |
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) |
return FALSE; |
htab->srelplt = s; |
if (! _bfd_elf_create_got_section (abfd, info)) |
return FALSE; |
if (bed->want_dynbss) |
{ |
/* The .dynbss section is a place to put symbols which are defined |
by dynamic objects, are referenced by regular objects, and are |
not functions. We must allocate space for them in the process |
image and use a R_*_COPY reloc to tell the dynamic linker to |
initialize them at run time. The linker script puts the .dynbss |
section into the .bss section of the final image. */ |
s = bfd_make_section_anyway_with_flags (abfd, ".dynbss", |
(SEC_ALLOC | SEC_LINKER_CREATED)); |
if (s == NULL) |
return FALSE; |
/* The .rel[a].bss section holds copy relocs. This section is not |
normally needed. We need to create it here, though, so that the |
linker will map it to an output section. We can't just create it |
only if we need it, because we will not know whether we need it |
until we have seen all the input files, and the first time the |
main linker code calls BFD after examining all the input files |
(size_dynamic_sections) the input sections have already been |
mapped to the output sections. If the section turns out not to |
be needed, we can discard it later. We will never need this |
section when generating a shared object, since they do not use |
copy relocs. */ |
if (! info->shared) |
{ |
s = bfd_make_section_anyway_with_flags (abfd, |
(bed->rela_plts_and_copies_p |
? ".rela.bss" : ".rel.bss"), |
flags | SEC_READONLY); |
if (s == NULL |
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) |
return FALSE; |
} |
} |
return TRUE; |
} |
/* Record a new dynamic symbol. We record the dynamic symbols as we |
read the input files, since we need to have a list of all of them |
before we can determine the final sizes of the output sections. |
Note that we may actually call this function even though we are not |
going to output any dynamic symbols; in some cases we know that a |
symbol should be in the dynamic symbol table, but only if there is |
one. */ |
bfd_boolean |
bfd_elf_link_record_dynamic_symbol (struct bfd_link_info *info, |
struct elf_link_hash_entry *h) |
{ |
if (h->dynindx == -1) |
{ |
struct elf_strtab_hash *dynstr; |
char *p; |
const char *name; |
bfd_size_type indx; |
/* XXX: The ABI draft says the linker must turn hidden and |
internal symbols into STB_LOCAL symbols when producing the |
DSO. However, if ld.so honors st_other in the dynamic table, |
this would not be necessary. */ |
switch (ELF_ST_VISIBILITY (h->other)) |
{ |
case STV_INTERNAL: |
case STV_HIDDEN: |
if (h->root.type != bfd_link_hash_undefined |
&& h->root.type != bfd_link_hash_undefweak) |
{ |
h->forced_local = 1; |
if (!elf_hash_table (info)->is_relocatable_executable) |
return TRUE; |
} |
default: |
break; |
} |
h->dynindx = elf_hash_table (info)->dynsymcount; |
++elf_hash_table (info)->dynsymcount; |
dynstr = elf_hash_table (info)->dynstr; |
if (dynstr == NULL) |
{ |
/* Create a strtab to hold the dynamic symbol names. */ |
elf_hash_table (info)->dynstr = dynstr = _bfd_elf_strtab_init (); |
if (dynstr == NULL) |
return FALSE; |
} |
/* We don't put any version information in the dynamic string |
table. */ |
name = h->root.root.string; |
p = strchr (name, ELF_VER_CHR); |
if (p != NULL) |
/* We know that the p points into writable memory. In fact, |
there are only a few symbols that have read-only names, being |
those like _GLOBAL_OFFSET_TABLE_ that are created specially |
by the backends. Most symbols will have names pointing into |
an ELF string table read from a file, or to objalloc memory. */ |
*p = 0; |
indx = _bfd_elf_strtab_add (dynstr, name, p != NULL); |
if (p != NULL) |
*p = ELF_VER_CHR; |
if (indx == (bfd_size_type) -1) |
return FALSE; |
h->dynstr_index = indx; |
} |
return TRUE; |
} |
/* Mark a symbol dynamic. */ |
static void |
bfd_elf_link_mark_dynamic_symbol (struct bfd_link_info *info, |
struct elf_link_hash_entry *h, |
Elf_Internal_Sym *sym) |
{ |
struct bfd_elf_dynamic_list *d = info->dynamic_list; |
/* It may be called more than once on the same H. */ |
if(h->dynamic || info->relocatable) |
return; |
if ((info->dynamic_data |
&& (h->type == STT_OBJECT |
|| (sym != NULL |
&& ELF_ST_TYPE (sym->st_info) == STT_OBJECT))) |
|| (d != NULL |
&& h->root.type == bfd_link_hash_new |
&& (*d->match) (&d->head, NULL, h->root.root.string))) |
h->dynamic = 1; |
} |
/* Record an assignment to a symbol made by a linker script. We need |
this in case some dynamic object refers to this symbol. */ |
bfd_boolean |
bfd_elf_record_link_assignment (bfd *output_bfd, |
struct bfd_link_info *info, |
const char *name, |
bfd_boolean provide, |
bfd_boolean hidden) |
{ |
struct elf_link_hash_entry *h, *hv; |
struct elf_link_hash_table *htab; |
const struct elf_backend_data *bed; |
if (!is_elf_hash_table (info->hash)) |
return TRUE; |
htab = elf_hash_table (info); |
h = elf_link_hash_lookup (htab, name, !provide, TRUE, FALSE); |
if (h == NULL) |
return provide; |
switch (h->root.type) |
{ |
case bfd_link_hash_defined: |
case bfd_link_hash_defweak: |
case bfd_link_hash_common: |
break; |
case bfd_link_hash_undefweak: |
case bfd_link_hash_undefined: |
/* Since we're defining the symbol, don't let it seem to have not |
been defined. record_dynamic_symbol and size_dynamic_sections |
may depend on this. */ |
h->root.type = bfd_link_hash_new; |
if (h->root.u.undef.next != NULL || htab->root.undefs_tail == &h->root) |
bfd_link_repair_undef_list (&htab->root); |
break; |
case bfd_link_hash_new: |
bfd_elf_link_mark_dynamic_symbol (info, h, NULL); |
h->non_elf = 0; |
break; |
case bfd_link_hash_indirect: |
/* We had a versioned symbol in a dynamic library. We make the |
the versioned symbol point to this one. */ |
bed = get_elf_backend_data (output_bfd); |
hv = h; |
while (hv->root.type == bfd_link_hash_indirect |
|| hv->root.type == bfd_link_hash_warning) |
hv = (struct elf_link_hash_entry *) hv->root.u.i.link; |
/* We don't need to update h->root.u since linker will set them |
later. */ |
h->root.type = bfd_link_hash_undefined; |
hv->root.type = bfd_link_hash_indirect; |
hv->root.u.i.link = (struct bfd_link_hash_entry *) h; |
(*bed->elf_backend_copy_indirect_symbol) (info, h, hv); |
break; |
case bfd_link_hash_warning: |
abort (); |
break; |
} |
/* If this symbol is being provided by the linker script, and it is |
currently defined by a dynamic object, but not by a regular |
object, then mark it as undefined so that the generic linker will |
force the correct value. */ |
if (provide |
&& h->def_dynamic |
&& !h->def_regular) |
h->root.type = bfd_link_hash_undefined; |
/* If this symbol is not being provided by the linker script, and it is |
currently defined by a dynamic object, but not by a regular object, |
then clear out any version information because the symbol will not be |
associated with the dynamic object any more. */ |
if (!provide |
&& h->def_dynamic |
&& !h->def_regular) |
h->verinfo.verdef = NULL; |
h->def_regular = 1; |
if (hidden) |
{ |
bed = get_elf_backend_data (output_bfd); |
if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL) |
h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN; |
(*bed->elf_backend_hide_symbol) (info, h, TRUE); |
} |
/* STV_HIDDEN and STV_INTERNAL symbols must be STB_LOCAL in shared objects |
and executables. */ |
if (!info->relocatable |
&& h->dynindx != -1 |
&& (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN |
|| ELF_ST_VISIBILITY (h->other) == STV_INTERNAL)) |
h->forced_local = 1; |
if ((h->def_dynamic |
|| h->ref_dynamic |
|| info->shared |
|| (info->executable && elf_hash_table (info)->is_relocatable_executable)) |
&& h->dynindx == -1) |
{ |
if (! bfd_elf_link_record_dynamic_symbol (info, h)) |
return FALSE; |
/* If this is a weak defined symbol, and we know a corresponding |
real symbol from the same dynamic object, make sure the real |
symbol is also made into a dynamic symbol. */ |
if (h->u.weakdef != NULL |
&& h->u.weakdef->dynindx == -1) |
{ |
if (! bfd_elf_link_record_dynamic_symbol (info, h->u.weakdef)) |
return FALSE; |
} |
} |
return TRUE; |
} |
/* Record a new local dynamic symbol. Returns 0 on failure, 1 on |
success, and 2 on a failure caused by attempting to record a symbol |
in a discarded section, eg. a discarded link-once section symbol. */ |
int |
bfd_elf_link_record_local_dynamic_symbol (struct bfd_link_info *info, |
bfd *input_bfd, |
long input_indx) |
{ |
bfd_size_type amt; |
struct elf_link_local_dynamic_entry *entry; |
struct elf_link_hash_table *eht; |
struct elf_strtab_hash *dynstr; |
unsigned long dynstr_index; |
char *name; |
Elf_External_Sym_Shndx eshndx; |
char esym[sizeof (Elf64_External_Sym)]; |
if (! is_elf_hash_table (info->hash)) |
return 0; |
/* See if the entry exists already. */ |
for (entry = elf_hash_table (info)->dynlocal; entry ; entry = entry->next) |
if (entry->input_bfd == input_bfd && entry->input_indx == input_indx) |
return 1; |
amt = sizeof (*entry); |
entry = (struct elf_link_local_dynamic_entry *) bfd_alloc (input_bfd, amt); |
if (entry == NULL) |
return 0; |
/* Go find the symbol, so that we can find it's name. */ |
if (!bfd_elf_get_elf_syms (input_bfd, &elf_tdata (input_bfd)->symtab_hdr, |
1, input_indx, &entry->isym, esym, &eshndx)) |
{ |
bfd_release (input_bfd, entry); |
return 0; |
} |
if (entry->isym.st_shndx != SHN_UNDEF |
&& entry->isym.st_shndx < SHN_LORESERVE) |
{ |
asection *s; |
s = bfd_section_from_elf_index (input_bfd, entry->isym.st_shndx); |
if (s == NULL || bfd_is_abs_section (s->output_section)) |
{ |
/* We can still bfd_release here as nothing has done another |
bfd_alloc. We can't do this later in this function. */ |
bfd_release (input_bfd, entry); |
return 2; |
} |
} |
name = (bfd_elf_string_from_elf_section |
(input_bfd, elf_tdata (input_bfd)->symtab_hdr.sh_link, |
entry->isym.st_name)); |
dynstr = elf_hash_table (info)->dynstr; |
if (dynstr == NULL) |
{ |
/* Create a strtab to hold the dynamic symbol names. */ |
elf_hash_table (info)->dynstr = dynstr = _bfd_elf_strtab_init (); |
if (dynstr == NULL) |
return 0; |
} |
dynstr_index = _bfd_elf_strtab_add (dynstr, name, FALSE); |
if (dynstr_index == (unsigned long) -1) |
return 0; |
entry->isym.st_name = dynstr_index; |
eht = elf_hash_table (info); |
entry->next = eht->dynlocal; |
eht->dynlocal = entry; |
entry->input_bfd = input_bfd; |
entry->input_indx = input_indx; |
eht->dynsymcount++; |
/* Whatever binding the symbol had before, it's now local. */ |
entry->isym.st_info |
= ELF_ST_INFO (STB_LOCAL, ELF_ST_TYPE (entry->isym.st_info)); |
/* The dynindx will be set at the end of size_dynamic_sections. */ |
return 1; |
} |
/* Return the dynindex of a local dynamic symbol. */ |
long |
_bfd_elf_link_lookup_local_dynindx (struct bfd_link_info *info, |
bfd *input_bfd, |
long input_indx) |
{ |
struct elf_link_local_dynamic_entry *e; |
for (e = elf_hash_table (info)->dynlocal; e ; e = e->next) |
if (e->input_bfd == input_bfd && e->input_indx == input_indx) |
return e->dynindx; |
return -1; |
} |
/* This function is used to renumber the dynamic symbols, if some of |
them are removed because they are marked as local. This is called |
via elf_link_hash_traverse. */ |
static bfd_boolean |
elf_link_renumber_hash_table_dynsyms (struct elf_link_hash_entry *h, |
void *data) |
{ |
size_t *count = (size_t *) data; |
if (h->forced_local) |
return TRUE; |
if (h->dynindx != -1) |
h->dynindx = ++(*count); |
return TRUE; |
} |
/* Like elf_link_renumber_hash_table_dynsyms, but just number symbols with |
STB_LOCAL binding. */ |
static bfd_boolean |
elf_link_renumber_local_hash_table_dynsyms (struct elf_link_hash_entry *h, |
void *data) |
{ |
size_t *count = (size_t *) data; |
if (!h->forced_local) |
return TRUE; |
if (h->dynindx != -1) |
h->dynindx = ++(*count); |
return TRUE; |
} |
/* Return true if the dynamic symbol for a given section should be |
omitted when creating a shared library. */ |
bfd_boolean |
_bfd_elf_link_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED, |
struct bfd_link_info *info, |
asection *p) |
{ |
struct elf_link_hash_table *htab; |
switch (elf_section_data (p)->this_hdr.sh_type) |
{ |
case SHT_PROGBITS: |
case SHT_NOBITS: |
/* If sh_type is yet undecided, assume it could be |
SHT_PROGBITS/SHT_NOBITS. */ |
case SHT_NULL: |
htab = elf_hash_table (info); |
if (p == htab->tls_sec) |
return FALSE; |
if (htab->text_index_section != NULL) |
return p != htab->text_index_section && p != htab->data_index_section; |
if (strcmp (p->name, ".got") == 0 |
|| strcmp (p->name, ".got.plt") == 0 |
|| strcmp (p->name, ".plt") == 0) |
{ |
asection *ip; |
if (htab->dynobj != NULL |
&& (ip = bfd_get_linker_section (htab->dynobj, p->name)) != NULL |
&& ip->output_section == p) |
return TRUE; |
} |
return FALSE; |
/* There shouldn't be section relative relocations |
against any other section. */ |
default: |
return TRUE; |
} |
} |
/* Assign dynsym indices. In a shared library we generate a section |
symbol for each output section, which come first. Next come symbols |
which have been forced to local binding. Then all of the back-end |
allocated local dynamic syms, followed by the rest of the global |
symbols. */ |
static unsigned long |
_bfd_elf_link_renumber_dynsyms (bfd *output_bfd, |
struct bfd_link_info *info, |
unsigned long *section_sym_count) |
{ |
unsigned long dynsymcount = 0; |
if (info->shared || elf_hash_table (info)->is_relocatable_executable) |
{ |
const struct elf_backend_data *bed = get_elf_backend_data (output_bfd); |
asection *p; |
for (p = output_bfd->sections; p ; p = p->next) |
if ((p->flags & SEC_EXCLUDE) == 0 |
&& (p->flags & SEC_ALLOC) != 0 |
&& !(*bed->elf_backend_omit_section_dynsym) (output_bfd, info, p)) |
elf_section_data (p)->dynindx = ++dynsymcount; |
else |
elf_section_data (p)->dynindx = 0; |
} |
*section_sym_count = dynsymcount; |
elf_link_hash_traverse (elf_hash_table (info), |
elf_link_renumber_local_hash_table_dynsyms, |
&dynsymcount); |
if (elf_hash_table (info)->dynlocal) |
{ |
struct elf_link_local_dynamic_entry *p; |
for (p = elf_hash_table (info)->dynlocal; p ; p = p->next) |
p->dynindx = ++dynsymcount; |
} |
elf_link_hash_traverse (elf_hash_table (info), |
elf_link_renumber_hash_table_dynsyms, |
&dynsymcount); |
/* There is an unused NULL entry at the head of the table which |
we must account for in our count. Unless there weren't any |
symbols, which means we'll have no table at all. */ |
if (dynsymcount != 0) |
++dynsymcount; |
elf_hash_table (info)->dynsymcount = dynsymcount; |
return dynsymcount; |
} |
/* Merge st_other field. */ |
static void |
elf_merge_st_other (bfd *abfd, struct elf_link_hash_entry *h, |
Elf_Internal_Sym *isym, bfd_boolean definition, |
bfd_boolean dynamic) |
{ |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
/* If st_other has a processor-specific meaning, specific |
code might be needed here. We never merge the visibility |
attribute with the one from a dynamic object. */ |
if (bed->elf_backend_merge_symbol_attribute) |
(*bed->elf_backend_merge_symbol_attribute) (h, isym, definition, |
dynamic); |
/* If this symbol has default visibility and the user has requested |
we not re-export it, then mark it as hidden. */ |
if (definition |
&& !dynamic |
&& (abfd->no_export |
|| (abfd->my_archive && abfd->my_archive->no_export)) |
&& ELF_ST_VISIBILITY (isym->st_other) != STV_INTERNAL) |
isym->st_other = (STV_HIDDEN |
| (isym->st_other & ~ELF_ST_VISIBILITY (-1))); |
if (!dynamic && ELF_ST_VISIBILITY (isym->st_other) != 0) |
{ |
unsigned char hvis, symvis, other, nvis; |
/* Only merge the visibility. Leave the remainder of the |
st_other field to elf_backend_merge_symbol_attribute. */ |
other = h->other & ~ELF_ST_VISIBILITY (-1); |
/* Combine visibilities, using the most constraining one. */ |
hvis = ELF_ST_VISIBILITY (h->other); |
symvis = ELF_ST_VISIBILITY (isym->st_other); |
if (! hvis) |
nvis = symvis; |
else if (! symvis) |
nvis = hvis; |
else |
nvis = hvis < symvis ? hvis : symvis; |
h->other = other | nvis; |
} |
} |
/* This function is called when we want to merge a new symbol with an |
existing symbol. It handles the various cases which arise when we |
find a definition in a dynamic object, or when there is already a |
definition in a dynamic object. The new symbol is described by |
NAME, SYM, PSEC, and PVALUE. We set SYM_HASH to the hash table |
entry. We set POLDBFD to the old symbol's BFD. We set POLD_WEAK |
if the old symbol was weak. We set POLD_ALIGNMENT to the alignment |
of an old common symbol. We set OVERRIDE if the old symbol is |
overriding a new definition. We set TYPE_CHANGE_OK if it is OK for |
the type to change. We set SIZE_CHANGE_OK if it is OK for the size |
to change. By OK to change, we mean that we shouldn't warn if the |
type or size does change. */ |
static bfd_boolean |
_bfd_elf_merge_symbol (bfd *abfd, |
struct bfd_link_info *info, |
const char *name, |
Elf_Internal_Sym *sym, |
asection **psec, |
bfd_vma *pvalue, |
struct elf_link_hash_entry **sym_hash, |
bfd **poldbfd, |
bfd_boolean *pold_weak, |
unsigned int *pold_alignment, |
bfd_boolean *skip, |
bfd_boolean *override, |
bfd_boolean *type_change_ok, |
bfd_boolean *size_change_ok) |
{ |
asection *sec, *oldsec; |
struct elf_link_hash_entry *h; |
struct elf_link_hash_entry *hi; |
struct elf_link_hash_entry *flip; |
int bind; |
bfd *oldbfd; |
bfd_boolean newdyn, olddyn, olddef, newdef, newdyncommon, olddyncommon; |
bfd_boolean newweak, oldweak, newfunc, oldfunc; |
const struct elf_backend_data *bed; |
*skip = FALSE; |
*override = FALSE; |
sec = *psec; |
bind = ELF_ST_BIND (sym->st_info); |
if (! bfd_is_und_section (sec)) |
h = elf_link_hash_lookup (elf_hash_table (info), name, TRUE, FALSE, FALSE); |
else |
h = ((struct elf_link_hash_entry *) |
bfd_wrapped_link_hash_lookup (abfd, info, name, TRUE, FALSE, FALSE)); |
if (h == NULL) |
return FALSE; |
*sym_hash = h; |
bed = get_elf_backend_data (abfd); |
/* For merging, we only care about real symbols. But we need to make |
sure that indirect symbol dynamic flags are updated. */ |
hi = h; |
while (h->root.type == bfd_link_hash_indirect |
|| h->root.type == bfd_link_hash_warning) |
h = (struct elf_link_hash_entry *) h->root.u.i.link; |
/* OLDBFD and OLDSEC are a BFD and an ASECTION associated with the |
existing symbol. */ |
oldbfd = NULL; |
oldsec = NULL; |
switch (h->root.type) |
{ |
default: |
break; |
case bfd_link_hash_undefined: |
case bfd_link_hash_undefweak: |
oldbfd = h->root.u.undef.abfd; |
break; |
case bfd_link_hash_defined: |
case bfd_link_hash_defweak: |
oldbfd = h->root.u.def.section->owner; |
oldsec = h->root.u.def.section; |
break; |
case bfd_link_hash_common: |
oldbfd = h->root.u.c.p->section->owner; |
oldsec = h->root.u.c.p->section; |
if (pold_alignment) |
*pold_alignment = h->root.u.c.p->alignment_power; |
break; |
} |
if (poldbfd && *poldbfd == NULL) |
*poldbfd = oldbfd; |
/* Differentiate strong and weak symbols. */ |
newweak = bind == STB_WEAK; |
oldweak = (h->root.type == bfd_link_hash_defweak |
|| h->root.type == bfd_link_hash_undefweak); |
if (pold_weak) |
*pold_weak = oldweak; |
/* This code is for coping with dynamic objects, and is only useful |
if we are doing an ELF link. */ |
if (!(*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec)) |
return TRUE; |
/* We have to check it for every instance since the first few may be |
references and not all compilers emit symbol type for undefined |
symbols. */ |
bfd_elf_link_mark_dynamic_symbol (info, h, sym); |
/* NEWDYN and OLDDYN indicate whether the new or old symbol, |
respectively, is from a dynamic object. */ |
newdyn = (abfd->flags & DYNAMIC) != 0; |
/* ref_dynamic_nonweak and dynamic_def flags track actual undefined |
syms and defined syms in dynamic libraries respectively. |
ref_dynamic on the other hand can be set for a symbol defined in |
a dynamic library, and def_dynamic may not be set; When the |
definition in a dynamic lib is overridden by a definition in the |
executable use of the symbol in the dynamic lib becomes a |
reference to the executable symbol. */ |
if (newdyn) |
{ |
if (bfd_is_und_section (sec)) |
{ |
if (bind != STB_WEAK) |
{ |
h->ref_dynamic_nonweak = 1; |
hi->ref_dynamic_nonweak = 1; |
} |
} |
else |
{ |
h->dynamic_def = 1; |
hi->dynamic_def = 1; |
} |
} |
/* If we just created the symbol, mark it as being an ELF symbol. |
Other than that, there is nothing to do--there is no merge issue |
with a newly defined symbol--so we just return. */ |
if (h->root.type == bfd_link_hash_new) |
{ |
h->non_elf = 0; |
return TRUE; |
} |
/* In cases involving weak versioned symbols, we may wind up trying |
to merge a symbol with itself. Catch that here, to avoid the |
confusion that results if we try to override a symbol with |
itself. The additional tests catch cases like |
_GLOBAL_OFFSET_TABLE_, which are regular symbols defined in a |
dynamic object, which we do want to handle here. */ |
if (abfd == oldbfd |
&& (newweak || oldweak) |
&& ((abfd->flags & DYNAMIC) == 0 |
|| !h->def_regular)) |
return TRUE; |
olddyn = FALSE; |
if (oldbfd != NULL) |
olddyn = (oldbfd->flags & DYNAMIC) != 0; |
else if (oldsec != NULL) |
{ |
/* This handles the special SHN_MIPS_{TEXT,DATA} section |
indices used by MIPS ELF. */ |
olddyn = (oldsec->symbol->flags & BSF_DYNAMIC) != 0; |
} |
/* NEWDEF and OLDDEF indicate whether the new or old symbol, |
respectively, appear to be a definition rather than reference. */ |
newdef = !bfd_is_und_section (sec) && !bfd_is_com_section (sec); |
olddef = (h->root.type != bfd_link_hash_undefined |
&& h->root.type != bfd_link_hash_undefweak |
&& h->root.type != bfd_link_hash_common); |
/* NEWFUNC and OLDFUNC indicate whether the new or old symbol, |
respectively, appear to be a function. */ |
newfunc = (ELF_ST_TYPE (sym->st_info) != STT_NOTYPE |
&& bed->is_function_type (ELF_ST_TYPE (sym->st_info))); |
oldfunc = (h->type != STT_NOTYPE |
&& bed->is_function_type (h->type)); |
/* When we try to create a default indirect symbol from the dynamic |
definition with the default version, we skip it if its type and |
the type of existing regular definition mismatch. We only do it |
if the existing regular definition won't be dynamic. */ |
if (pold_alignment == NULL |
&& !info->shared |
&& !info->export_dynamic |
&& !h->ref_dynamic |
&& newdyn |
&& newdef |
&& !olddyn |
&& (olddef || h->root.type == bfd_link_hash_common) |
&& ELF_ST_TYPE (sym->st_info) != h->type |
&& ELF_ST_TYPE (sym->st_info) != STT_NOTYPE |
&& h->type != STT_NOTYPE |
&& !(newfunc && oldfunc)) |
{ |
*skip = TRUE; |
return TRUE; |
} |
/* Plugin symbol type isn't currently set. Stop bogus errors. */ |
if (oldbfd != NULL && (oldbfd->flags & BFD_PLUGIN) != 0) |
*type_change_ok = TRUE; |
/* Check TLS symbol. We don't check undefined symbol introduced by |
"ld -u". */ |
else if (oldbfd != NULL |
&& ELF_ST_TYPE (sym->st_info) != h->type |
&& (ELF_ST_TYPE (sym->st_info) == STT_TLS || h->type == STT_TLS)) |
{ |
bfd *ntbfd, *tbfd; |
bfd_boolean ntdef, tdef; |
asection *ntsec, *tsec; |
if (h->type == STT_TLS) |
{ |
ntbfd = abfd; |
ntsec = sec; |
ntdef = newdef; |
tbfd = oldbfd; |
tsec = oldsec; |
tdef = olddef; |
} |
else |
{ |
ntbfd = oldbfd; |
ntsec = oldsec; |
ntdef = olddef; |
tbfd = abfd; |
tsec = sec; |
tdef = newdef; |
} |
if (tdef && ntdef) |
(*_bfd_error_handler) |
(_("%s: TLS definition in %B section %A " |
"mismatches non-TLS definition in %B section %A"), |
tbfd, tsec, ntbfd, ntsec, h->root.root.string); |
else if (!tdef && !ntdef) |
(*_bfd_error_handler) |
(_("%s: TLS reference in %B " |
"mismatches non-TLS reference in %B"), |
tbfd, ntbfd, h->root.root.string); |
else if (tdef) |
(*_bfd_error_handler) |
(_("%s: TLS definition in %B section %A " |
"mismatches non-TLS reference in %B"), |
tbfd, tsec, ntbfd, h->root.root.string); |
else |
(*_bfd_error_handler) |
(_("%s: TLS reference in %B " |
"mismatches non-TLS definition in %B section %A"), |
tbfd, ntbfd, ntsec, h->root.root.string); |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
/* If the old symbol has non-default visibility, we ignore the new |
definition from a dynamic object. */ |
if (newdyn |
&& ELF_ST_VISIBILITY (h->other) != STV_DEFAULT |
&& !bfd_is_und_section (sec)) |
{ |
*skip = TRUE; |
/* Make sure this symbol is dynamic. */ |
h->ref_dynamic = 1; |
hi->ref_dynamic = 1; |
/* A protected symbol has external availability. Make sure it is |
recorded as dynamic. |
FIXME: Should we check type and size for protected symbol? */ |
if (ELF_ST_VISIBILITY (h->other) == STV_PROTECTED) |
return bfd_elf_link_record_dynamic_symbol (info, h); |
else |
return TRUE; |
} |
else if (!newdyn |
&& ELF_ST_VISIBILITY (sym->st_other) != STV_DEFAULT |
&& h->def_dynamic) |
{ |
/* If the new symbol with non-default visibility comes from a |
relocatable file and the old definition comes from a dynamic |
object, we remove the old definition. */ |
if (hi->root.type == bfd_link_hash_indirect) |
{ |
/* Handle the case where the old dynamic definition is |
default versioned. We need to copy the symbol info from |
the symbol with default version to the normal one if it |
was referenced before. */ |
if (h->ref_regular) |
{ |
hi->root.type = h->root.type; |
h->root.type = bfd_link_hash_indirect; |
(*bed->elf_backend_copy_indirect_symbol) (info, hi, h); |
h->root.u.i.link = (struct bfd_link_hash_entry *) hi; |
if (ELF_ST_VISIBILITY (sym->st_other) != STV_PROTECTED) |
{ |
/* If the new symbol is hidden or internal, completely undo |
any dynamic link state. */ |
(*bed->elf_backend_hide_symbol) (info, h, TRUE); |
h->forced_local = 0; |
h->ref_dynamic = 0; |
} |
else |
h->ref_dynamic = 1; |
h->def_dynamic = 0; |
/* FIXME: Should we check type and size for protected symbol? */ |
h->size = 0; |
h->type = 0; |
h = hi; |
} |
else |
h = hi; |
} |
/* If the old symbol was undefined before, then it will still be |
on the undefs list. If the new symbol is undefined or |
common, we can't make it bfd_link_hash_new here, because new |
undefined or common symbols will be added to the undefs list |
by _bfd_generic_link_add_one_symbol. Symbols may not be |
added twice to the undefs list. Also, if the new symbol is |
undefweak then we don't want to lose the strong undef. */ |
if (h->root.u.undef.next || info->hash->undefs_tail == &h->root) |
{ |
h->root.type = bfd_link_hash_undefined; |
h->root.u.undef.abfd = abfd; |
} |
else |
{ |
h->root.type = bfd_link_hash_new; |
h->root.u.undef.abfd = NULL; |
} |
if (ELF_ST_VISIBILITY (sym->st_other) != STV_PROTECTED) |
{ |
/* If the new symbol is hidden or internal, completely undo |
any dynamic link state. */ |
(*bed->elf_backend_hide_symbol) (info, h, TRUE); |
h->forced_local = 0; |
h->ref_dynamic = 0; |
} |
else |
h->ref_dynamic = 1; |
h->def_dynamic = 0; |
/* FIXME: Should we check type and size for protected symbol? */ |
h->size = 0; |
h->type = 0; |
return TRUE; |
} |
/* If a new weak symbol definition comes from a regular file and the |
old symbol comes from a dynamic library, we treat the new one as |
strong. Similarly, an old weak symbol definition from a regular |
file is treated as strong when the new symbol comes from a dynamic |
library. Further, an old weak symbol from a dynamic library is |
treated as strong if the new symbol is from a dynamic library. |
This reflects the way glibc's ld.so works. |
Do this before setting *type_change_ok or *size_change_ok so that |
we warn properly when dynamic library symbols are overridden. */ |
if (newdef && !newdyn && olddyn) |
newweak = FALSE; |
if (olddef && newdyn) |
oldweak = FALSE; |
/* Allow changes between different types of function symbol. */ |
if (newfunc && oldfunc) |
*type_change_ok = TRUE; |
/* It's OK to change the type if either the existing symbol or the |
new symbol is weak. A type change is also OK if the old symbol |
is undefined and the new symbol is defined. */ |
if (oldweak |
|| newweak |
|| (newdef |
&& h->root.type == bfd_link_hash_undefined)) |
*type_change_ok = TRUE; |
/* It's OK to change the size if either the existing symbol or the |
new symbol is weak, or if the old symbol is undefined. */ |
if (*type_change_ok |
|| h->root.type == bfd_link_hash_undefined) |
*size_change_ok = TRUE; |
/* NEWDYNCOMMON and OLDDYNCOMMON indicate whether the new or old |
symbol, respectively, appears to be a common symbol in a dynamic |
object. If a symbol appears in an uninitialized section, and is |
not weak, and is not a function, then it may be a common symbol |
which was resolved when the dynamic object was created. We want |
to treat such symbols specially, because they raise special |
considerations when setting the symbol size: if the symbol |
appears as a common symbol in a regular object, and the size in |
the regular object is larger, we must make sure that we use the |
larger size. This problematic case can always be avoided in C, |
but it must be handled correctly when using Fortran shared |
libraries. |
Note that if NEWDYNCOMMON is set, NEWDEF will be set, and |
likewise for OLDDYNCOMMON and OLDDEF. |
Note that this test is just a heuristic, and that it is quite |
possible to have an uninitialized symbol in a shared object which |
is really a definition, rather than a common symbol. This could |
lead to some minor confusion when the symbol really is a common |
symbol in some regular object. However, I think it will be |
harmless. */ |
if (newdyn |
&& newdef |
&& !newweak |
&& (sec->flags & SEC_ALLOC) != 0 |
&& (sec->flags & SEC_LOAD) == 0 |
&& sym->st_size > 0 |
&& !newfunc) |
newdyncommon = TRUE; |
else |
newdyncommon = FALSE; |
if (olddyn |
&& olddef |
&& h->root.type == bfd_link_hash_defined |
&& h->def_dynamic |
&& (h->root.u.def.section->flags & SEC_ALLOC) != 0 |
&& (h->root.u.def.section->flags & SEC_LOAD) == 0 |
&& h->size > 0 |
&& !oldfunc) |
olddyncommon = TRUE; |
else |
olddyncommon = FALSE; |
/* We now know everything about the old and new symbols. We ask the |
backend to check if we can merge them. */ |
if (bed->merge_symbol != NULL) |
{ |
if (!bed->merge_symbol (h, sym, psec, newdef, olddef, oldbfd, oldsec)) |
return FALSE; |
sec = *psec; |
} |
/* If both the old and the new symbols look like common symbols in a |
dynamic object, set the size of the symbol to the larger of the |
two. */ |
if (olddyncommon |
&& newdyncommon |
&& sym->st_size != h->size) |
{ |
/* Since we think we have two common symbols, issue a multiple |
common warning if desired. Note that we only warn if the |
size is different. If the size is the same, we simply let |
the old symbol override the new one as normally happens with |
symbols defined in dynamic objects. */ |
if (! ((*info->callbacks->multiple_common) |
(info, &h->root, abfd, bfd_link_hash_common, sym->st_size))) |
return FALSE; |
if (sym->st_size > h->size) |
h->size = sym->st_size; |
*size_change_ok = TRUE; |
} |
/* If we are looking at a dynamic object, and we have found a |
definition, we need to see if the symbol was already defined by |
some other object. If so, we want to use the existing |
definition, and we do not want to report a multiple symbol |
definition error; we do this by clobbering *PSEC to be |
bfd_und_section_ptr. |
We treat a common symbol as a definition if the symbol in the |
shared library is a function, since common symbols always |
represent variables; this can cause confusion in principle, but |
any such confusion would seem to indicate an erroneous program or |
shared library. We also permit a common symbol in a regular |
object to override a weak symbol in a shared object. */ |
if (newdyn |
&& newdef |
&& (olddef |
|| (h->root.type == bfd_link_hash_common |
&& (newweak || newfunc)))) |
{ |
*override = TRUE; |
newdef = FALSE; |
newdyncommon = FALSE; |
*psec = sec = bfd_und_section_ptr; |
*size_change_ok = TRUE; |
/* If we get here when the old symbol is a common symbol, then |
we are explicitly letting it override a weak symbol or |
function in a dynamic object, and we don't want to warn about |
a type change. If the old symbol is a defined symbol, a type |
change warning may still be appropriate. */ |
if (h->root.type == bfd_link_hash_common) |
*type_change_ok = TRUE; |
} |
/* Handle the special case of an old common symbol merging with a |
new symbol which looks like a common symbol in a shared object. |
We change *PSEC and *PVALUE to make the new symbol look like a |
common symbol, and let _bfd_generic_link_add_one_symbol do the |
right thing. */ |
if (newdyncommon |
&& h->root.type == bfd_link_hash_common) |
{ |
*override = TRUE; |
newdef = FALSE; |
newdyncommon = FALSE; |
*pvalue = sym->st_size; |
*psec = sec = bed->common_section (oldsec); |
*size_change_ok = TRUE; |
} |
/* Skip weak definitions of symbols that are already defined. */ |
if (newdef && olddef && newweak) |
{ |
/* Don't skip new non-IR weak syms. */ |
if (!(oldbfd != NULL |
&& (oldbfd->flags & BFD_PLUGIN) != 0 |
&& (abfd->flags & BFD_PLUGIN) == 0)) |
*skip = TRUE; |
/* Merge st_other. If the symbol already has a dynamic index, |
but visibility says it should not be visible, turn it into a |
local symbol. */ |
elf_merge_st_other (abfd, h, sym, newdef, newdyn); |
if (h->dynindx != -1) |
switch (ELF_ST_VISIBILITY (h->other)) |
{ |
case STV_INTERNAL: |
case STV_HIDDEN: |
(*bed->elf_backend_hide_symbol) (info, h, TRUE); |
break; |
} |
} |
/* If the old symbol is from a dynamic object, and the new symbol is |
a definition which is not from a dynamic object, then the new |
symbol overrides the old symbol. Symbols from regular files |
always take precedence over symbols from dynamic objects, even if |
they are defined after the dynamic object in the link. |
As above, we again permit a common symbol in a regular object to |
override a definition in a shared object if the shared object |
symbol is a function or is weak. */ |
flip = NULL; |
if (!newdyn |
&& (newdef |
|| (bfd_is_com_section (sec) |
&& (oldweak || oldfunc))) |
&& olddyn |
&& olddef |
&& h->def_dynamic) |
{ |
/* Change the hash table entry to undefined, and let |
_bfd_generic_link_add_one_symbol do the right thing with the |
new definition. */ |
h->root.type = bfd_link_hash_undefined; |
h->root.u.undef.abfd = h->root.u.def.section->owner; |
*size_change_ok = TRUE; |
olddef = FALSE; |
olddyncommon = FALSE; |
/* We again permit a type change when a common symbol may be |
overriding a function. */ |
if (bfd_is_com_section (sec)) |
{ |
if (oldfunc) |
{ |
/* If a common symbol overrides a function, make sure |
that it isn't defined dynamically nor has type |
function. */ |
h->def_dynamic = 0; |
h->type = STT_NOTYPE; |
} |
*type_change_ok = TRUE; |
} |
if (hi->root.type == bfd_link_hash_indirect) |
flip = hi; |
else |
/* This union may have been set to be non-NULL when this symbol |
was seen in a dynamic object. We must force the union to be |
NULL, so that it is correct for a regular symbol. */ |
h->verinfo.vertree = NULL; |
} |
/* Handle the special case of a new common symbol merging with an |
old symbol that looks like it might be a common symbol defined in |
a shared object. Note that we have already handled the case in |
which a new common symbol should simply override the definition |
in the shared library. */ |
if (! newdyn |
&& bfd_is_com_section (sec) |
&& olddyncommon) |
{ |
/* It would be best if we could set the hash table entry to a |
common symbol, but we don't know what to use for the section |
or the alignment. */ |
if (! ((*info->callbacks->multiple_common) |
(info, &h->root, abfd, bfd_link_hash_common, sym->st_size))) |
return FALSE; |
/* If the presumed common symbol in the dynamic object is |
larger, pretend that the new symbol has its size. */ |
if (h->size > *pvalue) |
*pvalue = h->size; |
/* We need to remember the alignment required by the symbol |
in the dynamic object. */ |
BFD_ASSERT (pold_alignment); |
*pold_alignment = h->root.u.def.section->alignment_power; |
olddef = FALSE; |
olddyncommon = FALSE; |
h->root.type = bfd_link_hash_undefined; |
h->root.u.undef.abfd = h->root.u.def.section->owner; |
*size_change_ok = TRUE; |
*type_change_ok = TRUE; |
if (hi->root.type == bfd_link_hash_indirect) |
flip = hi; |
else |
h->verinfo.vertree = NULL; |
} |
if (flip != NULL) |
{ |
/* Handle the case where we had a versioned symbol in a dynamic |
library and now find a definition in a normal object. In this |
case, we make the versioned symbol point to the normal one. */ |
flip->root.type = h->root.type; |
flip->root.u.undef.abfd = h->root.u.undef.abfd; |
h->root.type = bfd_link_hash_indirect; |
h->root.u.i.link = (struct bfd_link_hash_entry *) flip; |
(*bed->elf_backend_copy_indirect_symbol) (info, flip, h); |
if (h->def_dynamic) |
{ |
h->def_dynamic = 0; |
flip->ref_dynamic = 1; |
} |
} |
return TRUE; |
} |
/* This function is called to create an indirect symbol from the |
default for the symbol with the default version if needed. The |
symbol is described by H, NAME, SYM, SEC, and VALUE. We |
set DYNSYM if the new indirect symbol is dynamic. */ |
static bfd_boolean |
_bfd_elf_add_default_symbol (bfd *abfd, |
struct bfd_link_info *info, |
struct elf_link_hash_entry *h, |
const char *name, |
Elf_Internal_Sym *sym, |
asection *sec, |
bfd_vma value, |
bfd **poldbfd, |
bfd_boolean *dynsym) |
{ |
bfd_boolean type_change_ok; |
bfd_boolean size_change_ok; |
bfd_boolean skip; |
char *shortname; |
struct elf_link_hash_entry *hi; |
struct bfd_link_hash_entry *bh; |
const struct elf_backend_data *bed; |
bfd_boolean collect; |
bfd_boolean dynamic; |
bfd_boolean override; |
char *p; |
size_t len, shortlen; |
asection *tmp_sec; |
/* If this symbol has a version, and it is the default version, we |
create an indirect symbol from the default name to the fully |
decorated name. This will cause external references which do not |
specify a version to be bound to this version of the symbol. */ |
p = strchr (name, ELF_VER_CHR); |
if (p == NULL || p[1] != ELF_VER_CHR) |
return TRUE; |
bed = get_elf_backend_data (abfd); |
collect = bed->collect; |
dynamic = (abfd->flags & DYNAMIC) != 0; |
shortlen = p - name; |
shortname = (char *) bfd_hash_allocate (&info->hash->table, shortlen + 1); |
if (shortname == NULL) |
return FALSE; |
memcpy (shortname, name, shortlen); |
shortname[shortlen] = '\0'; |
/* We are going to create a new symbol. Merge it with any existing |
symbol with this name. For the purposes of the merge, act as |
though we were defining the symbol we just defined, although we |
actually going to define an indirect symbol. */ |
type_change_ok = FALSE; |
size_change_ok = FALSE; |
tmp_sec = sec; |
if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &tmp_sec, &value, |
&hi, poldbfd, NULL, NULL, &skip, &override, |
&type_change_ok, &size_change_ok)) |
return FALSE; |
if (skip) |
goto nondefault; |
if (! override) |
{ |
bh = &hi->root; |
if (! (_bfd_generic_link_add_one_symbol |
(info, abfd, shortname, BSF_INDIRECT, bfd_ind_section_ptr, |
0, name, FALSE, collect, &bh))) |
return FALSE; |
hi = (struct elf_link_hash_entry *) bh; |
} |
else |
{ |
/* In this case the symbol named SHORTNAME is overriding the |
indirect symbol we want to add. We were planning on making |
SHORTNAME an indirect symbol referring to NAME. SHORTNAME |
is the name without a version. NAME is the fully versioned |
name, and it is the default version. |
Overriding means that we already saw a definition for the |
symbol SHORTNAME in a regular object, and it is overriding |
the symbol defined in the dynamic object. |
When this happens, we actually want to change NAME, the |
symbol we just added, to refer to SHORTNAME. This will cause |
references to NAME in the shared object to become references |
to SHORTNAME in the regular object. This is what we expect |
when we override a function in a shared object: that the |
references in the shared object will be mapped to the |
definition in the regular object. */ |
while (hi->root.type == bfd_link_hash_indirect |
|| hi->root.type == bfd_link_hash_warning) |
hi = (struct elf_link_hash_entry *) hi->root.u.i.link; |
h->root.type = bfd_link_hash_indirect; |
h->root.u.i.link = (struct bfd_link_hash_entry *) hi; |
if (h->def_dynamic) |
{ |
h->def_dynamic = 0; |
hi->ref_dynamic = 1; |
if (hi->ref_regular |
|| hi->def_regular) |
{ |
if (! bfd_elf_link_record_dynamic_symbol (info, hi)) |
return FALSE; |
} |
} |
/* Now set HI to H, so that the following code will set the |
other fields correctly. */ |
hi = h; |
} |
/* Check if HI is a warning symbol. */ |
if (hi->root.type == bfd_link_hash_warning) |
hi = (struct elf_link_hash_entry *) hi->root.u.i.link; |
/* If there is a duplicate definition somewhere, then HI may not |
point to an indirect symbol. We will have reported an error to |
the user in that case. */ |
if (hi->root.type == bfd_link_hash_indirect) |
{ |
struct elf_link_hash_entry *ht; |
ht = (struct elf_link_hash_entry *) hi->root.u.i.link; |
(*bed->elf_backend_copy_indirect_symbol) (info, ht, hi); |
/* See if the new flags lead us to realize that the symbol must |
be dynamic. */ |
if (! *dynsym) |
{ |
if (! dynamic) |
{ |
if (! info->executable |
|| hi->def_dynamic |
|| hi->ref_dynamic) |
*dynsym = TRUE; |
} |
else |
{ |
if (hi->ref_regular) |
*dynsym = TRUE; |
} |
} |
} |
/* We also need to define an indirection from the nondefault version |
of the symbol. */ |
nondefault: |
len = strlen (name); |
shortname = (char *) bfd_hash_allocate (&info->hash->table, len); |
if (shortname == NULL) |
return FALSE; |
memcpy (shortname, name, shortlen); |
memcpy (shortname + shortlen, p + 1, len - shortlen); |
/* Once again, merge with any existing symbol. */ |
type_change_ok = FALSE; |
size_change_ok = FALSE; |
tmp_sec = sec; |
if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &tmp_sec, &value, |
&hi, NULL, NULL, NULL, &skip, &override, |
&type_change_ok, &size_change_ok)) |
return FALSE; |
if (skip) |
return TRUE; |
if (override) |
{ |
/* Here SHORTNAME is a versioned name, so we don't expect to see |
the type of override we do in the case above unless it is |
overridden by a versioned definition. */ |
if (hi->root.type != bfd_link_hash_defined |
&& hi->root.type != bfd_link_hash_defweak) |
(*_bfd_error_handler) |
(_("%B: unexpected redefinition of indirect versioned symbol `%s'"), |
abfd, shortname); |
} |
else |
{ |
bh = &hi->root; |
if (! (_bfd_generic_link_add_one_symbol |
(info, abfd, shortname, BSF_INDIRECT, |
bfd_ind_section_ptr, 0, name, FALSE, collect, &bh))) |
return FALSE; |
hi = (struct elf_link_hash_entry *) bh; |
/* If there is a duplicate definition somewhere, then HI may not |
point to an indirect symbol. We will have reported an error |
to the user in that case. */ |
if (hi->root.type == bfd_link_hash_indirect) |
{ |
(*bed->elf_backend_copy_indirect_symbol) (info, h, hi); |
/* See if the new flags lead us to realize that the symbol |
must be dynamic. */ |
if (! *dynsym) |
{ |
if (! dynamic) |
{ |
if (! info->executable |
|| hi->ref_dynamic) |
*dynsym = TRUE; |
} |
else |
{ |
if (hi->ref_regular) |
*dynsym = TRUE; |
} |
} |
} |
} |
return TRUE; |
} |
/* This routine is used to export all defined symbols into the dynamic |
symbol table. It is called via elf_link_hash_traverse. */ |
static bfd_boolean |
_bfd_elf_export_symbol (struct elf_link_hash_entry *h, void *data) |
{ |
struct elf_info_failed *eif = (struct elf_info_failed *) data; |
/* Ignore indirect symbols. These are added by the versioning code. */ |
if (h->root.type == bfd_link_hash_indirect) |
return TRUE; |
/* Ignore this if we won't export it. */ |
if (!eif->info->export_dynamic && !h->dynamic) |
return TRUE; |
if (h->dynindx == -1 |
&& (h->def_regular || h->ref_regular) |
&& ! bfd_hide_sym_by_version (eif->info->version_info, |
h->root.root.string)) |
{ |
if (! bfd_elf_link_record_dynamic_symbol (eif->info, h)) |
{ |
eif->failed = TRUE; |
return FALSE; |
} |
} |
return TRUE; |
} |
/* Look through the symbols which are defined in other shared |
libraries and referenced here. Update the list of version |
dependencies. This will be put into the .gnu.version_r section. |
This function is called via elf_link_hash_traverse. */ |
static bfd_boolean |
_bfd_elf_link_find_version_dependencies (struct elf_link_hash_entry *h, |
void *data) |
{ |
struct elf_find_verdep_info *rinfo = (struct elf_find_verdep_info *) data; |
Elf_Internal_Verneed *t; |
Elf_Internal_Vernaux *a; |
bfd_size_type amt; |
/* We only care about symbols defined in shared objects with version |
information. */ |
if (!h->def_dynamic |
|| h->def_regular |
|| h->dynindx == -1 |
|| h->verinfo.verdef == NULL) |
return TRUE; |
/* See if we already know about this version. */ |
for (t = elf_tdata (rinfo->info->output_bfd)->verref; |
t != NULL; |
t = t->vn_nextref) |
{ |
if (t->vn_bfd != h->verinfo.verdef->vd_bfd) |
continue; |
for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr) |
if (a->vna_nodename == h->verinfo.verdef->vd_nodename) |
return TRUE; |
break; |
} |
/* This is a new version. Add it to tree we are building. */ |
if (t == NULL) |
{ |
amt = sizeof *t; |
t = (Elf_Internal_Verneed *) bfd_zalloc (rinfo->info->output_bfd, amt); |
if (t == NULL) |
{ |
rinfo->failed = TRUE; |
return FALSE; |
} |
t->vn_bfd = h->verinfo.verdef->vd_bfd; |
t->vn_nextref = elf_tdata (rinfo->info->output_bfd)->verref; |
elf_tdata (rinfo->info->output_bfd)->verref = t; |
} |
amt = sizeof *a; |
a = (Elf_Internal_Vernaux *) bfd_zalloc (rinfo->info->output_bfd, amt); |
if (a == NULL) |
{ |
rinfo->failed = TRUE; |
return FALSE; |
} |
/* Note that we are copying a string pointer here, and testing it |
above. If bfd_elf_string_from_elf_section is ever changed to |
discard the string data when low in memory, this will have to be |
fixed. */ |
a->vna_nodename = h->verinfo.verdef->vd_nodename; |
a->vna_flags = h->verinfo.verdef->vd_flags; |
a->vna_nextptr = t->vn_auxptr; |
h->verinfo.verdef->vd_exp_refno = rinfo->vers; |
++rinfo->vers; |
a->vna_other = h->verinfo.verdef->vd_exp_refno + 1; |
t->vn_auxptr = a; |
return TRUE; |
} |
/* Figure out appropriate versions for all the symbols. We may not |
have the version number script until we have read all of the input |
files, so until that point we don't know which symbols should be |
local. This function is called via elf_link_hash_traverse. */ |
static bfd_boolean |
_bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data) |
{ |
struct elf_info_failed *sinfo; |
struct bfd_link_info *info; |
const struct elf_backend_data *bed; |
struct elf_info_failed eif; |
char *p; |
bfd_size_type amt; |
sinfo = (struct elf_info_failed *) data; |
info = sinfo->info; |
/* Fix the symbol flags. */ |
eif.failed = FALSE; |
eif.info = info; |
if (! _bfd_elf_fix_symbol_flags (h, &eif)) |
{ |
if (eif.failed) |
sinfo->failed = TRUE; |
return FALSE; |
} |
/* We only need version numbers for symbols defined in regular |
objects. */ |
if (!h->def_regular) |
return TRUE; |
bed = get_elf_backend_data (info->output_bfd); |
p = strchr (h->root.root.string, ELF_VER_CHR); |
if (p != NULL && h->verinfo.vertree == NULL) |
{ |
struct bfd_elf_version_tree *t; |
bfd_boolean hidden; |
hidden = TRUE; |
/* There are two consecutive ELF_VER_CHR characters if this is |
not a hidden symbol. */ |
++p; |
if (*p == ELF_VER_CHR) |
{ |
hidden = FALSE; |
++p; |
} |
/* If there is no version string, we can just return out. */ |
if (*p == '\0') |
{ |
if (hidden) |
h->hidden = 1; |
return TRUE; |
} |
/* Look for the version. If we find it, it is no longer weak. */ |
for (t = sinfo->info->version_info; t != NULL; t = t->next) |
{ |
if (strcmp (t->name, p) == 0) |
{ |
size_t len; |
char *alc; |
struct bfd_elf_version_expr *d; |
len = p - h->root.root.string; |
alc = (char *) bfd_malloc (len); |
if (alc == NULL) |
{ |
sinfo->failed = TRUE; |
return FALSE; |
} |
memcpy (alc, h->root.root.string, len - 1); |
alc[len - 1] = '\0'; |
if (alc[len - 2] == ELF_VER_CHR) |
alc[len - 2] = '\0'; |
h->verinfo.vertree = t; |
t->used = TRUE; |
d = NULL; |
if (t->globals.list != NULL) |
d = (*t->match) (&t->globals, NULL, alc); |
/* See if there is anything to force this symbol to |
local scope. */ |
if (d == NULL && t->locals.list != NULL) |
{ |
d = (*t->match) (&t->locals, NULL, alc); |
if (d != NULL |
&& h->dynindx != -1 |
&& ! info->export_dynamic) |
(*bed->elf_backend_hide_symbol) (info, h, TRUE); |
} |
free (alc); |
break; |
} |
} |
/* If we are building an application, we need to create a |
version node for this version. */ |
if (t == NULL && info->executable) |
{ |
struct bfd_elf_version_tree **pp; |
int version_index; |
/* If we aren't going to export this symbol, we don't need |
to worry about it. */ |
if (h->dynindx == -1) |
return TRUE; |
amt = sizeof *t; |
t = (struct bfd_elf_version_tree *) bfd_zalloc (info->output_bfd, amt); |
if (t == NULL) |
{ |
sinfo->failed = TRUE; |
return FALSE; |
} |
t->name = p; |
t->name_indx = (unsigned int) -1; |
t->used = TRUE; |
version_index = 1; |
/* Don't count anonymous version tag. */ |
if (sinfo->info->version_info != NULL |
&& sinfo->info->version_info->vernum == 0) |
version_index = 0; |
for (pp = &sinfo->info->version_info; |
*pp != NULL; |
pp = &(*pp)->next) |
++version_index; |
t->vernum = version_index; |
*pp = t; |
h->verinfo.vertree = t; |
} |
else if (t == NULL) |
{ |
/* We could not find the version for a symbol when |
generating a shared archive. Return an error. */ |
(*_bfd_error_handler) |
(_("%B: version node not found for symbol %s"), |
info->output_bfd, h->root.root.string); |
bfd_set_error (bfd_error_bad_value); |
sinfo->failed = TRUE; |
return FALSE; |
} |
if (hidden) |
h->hidden = 1; |
} |
/* If we don't have a version for this symbol, see if we can find |
something. */ |
if (h->verinfo.vertree == NULL && sinfo->info->version_info != NULL) |
{ |
bfd_boolean hide; |
h->verinfo.vertree |
= bfd_find_version_for_sym (sinfo->info->version_info, |
h->root.root.string, &hide); |
if (h->verinfo.vertree != NULL && hide) |
(*bed->elf_backend_hide_symbol) (info, h, TRUE); |
} |
return TRUE; |
} |
/* Read and swap the relocs from the section indicated by SHDR. This |
may be either a REL or a RELA section. The relocations are |
translated into RELA relocations and stored in INTERNAL_RELOCS, |
which should have already been allocated to contain enough space. |
The EXTERNAL_RELOCS are a buffer where the external form of the |
relocations should be stored. |
Returns FALSE if something goes wrong. */ |
static bfd_boolean |
elf_link_read_relocs_from_section (bfd *abfd, |
asection *sec, |
Elf_Internal_Shdr *shdr, |
void *external_relocs, |
Elf_Internal_Rela *internal_relocs) |
{ |
const struct elf_backend_data *bed; |
void (*swap_in) (bfd *, const bfd_byte *, Elf_Internal_Rela *); |
const bfd_byte *erela; |
const bfd_byte *erelaend; |
Elf_Internal_Rela *irela; |
Elf_Internal_Shdr *symtab_hdr; |
size_t nsyms; |
/* Position ourselves at the start of the section. */ |
if (bfd_seek (abfd, shdr->sh_offset, SEEK_SET) != 0) |
return FALSE; |
/* Read the relocations. */ |
if (bfd_bread (external_relocs, shdr->sh_size, abfd) != shdr->sh_size) |
return FALSE; |
symtab_hdr = &elf_tdata (abfd)->symtab_hdr; |
nsyms = NUM_SHDR_ENTRIES (symtab_hdr); |
bed = get_elf_backend_data (abfd); |
/* Convert the external relocations to the internal format. */ |
if (shdr->sh_entsize == bed->s->sizeof_rel) |
swap_in = bed->s->swap_reloc_in; |
else if (shdr->sh_entsize == bed->s->sizeof_rela) |
swap_in = bed->s->swap_reloca_in; |
else |
{ |
bfd_set_error (bfd_error_wrong_format); |
return FALSE; |
} |
erela = (const bfd_byte *) external_relocs; |
erelaend = erela + shdr->sh_size; |
irela = internal_relocs; |
while (erela < erelaend) |
{ |
bfd_vma r_symndx; |
(*swap_in) (abfd, erela, irela); |
r_symndx = ELF32_R_SYM (irela->r_info); |
if (bed->s->arch_size == 64) |
r_symndx >>= 24; |
if (nsyms > 0) |
{ |
if ((size_t) r_symndx >= nsyms) |
{ |
(*_bfd_error_handler) |
(_("%B: bad reloc symbol index (0x%lx >= 0x%lx)" |
" for offset 0x%lx in section `%A'"), |
abfd, sec, |
(unsigned long) r_symndx, (unsigned long) nsyms, irela->r_offset); |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
} |
else if (r_symndx != STN_UNDEF) |
{ |
(*_bfd_error_handler) |
(_("%B: non-zero symbol index (0x%lx) for offset 0x%lx in section `%A'" |
" when the object file has no symbol table"), |
abfd, sec, |
(unsigned long) r_symndx, (unsigned long) nsyms, irela->r_offset); |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
irela += bed->s->int_rels_per_ext_rel; |
erela += shdr->sh_entsize; |
} |
return TRUE; |
} |
/* Read and swap the relocs for a section O. They may have been |
cached. If the EXTERNAL_RELOCS and INTERNAL_RELOCS arguments are |
not NULL, they are used as buffers to read into. They are known to |
be large enough. If the INTERNAL_RELOCS relocs argument is NULL, |
the return value is allocated using either malloc or bfd_alloc, |
according to the KEEP_MEMORY argument. If O has two relocation |
sections (both REL and RELA relocations), then the REL_HDR |
relocations will appear first in INTERNAL_RELOCS, followed by the |
RELA_HDR relocations. */ |
Elf_Internal_Rela * |
_bfd_elf_link_read_relocs (bfd *abfd, |
asection *o, |
void *external_relocs, |
Elf_Internal_Rela *internal_relocs, |
bfd_boolean keep_memory) |
{ |
void *alloc1 = NULL; |
Elf_Internal_Rela *alloc2 = NULL; |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
struct bfd_elf_section_data *esdo = elf_section_data (o); |
Elf_Internal_Rela *internal_rela_relocs; |
if (esdo->relocs != NULL) |
return esdo->relocs; |
if (o->reloc_count == 0) |
return NULL; |
if (internal_relocs == NULL) |
{ |
bfd_size_type size; |
size = o->reloc_count; |
size *= bed->s->int_rels_per_ext_rel * sizeof (Elf_Internal_Rela); |
if (keep_memory) |
internal_relocs = alloc2 = (Elf_Internal_Rela *) bfd_alloc (abfd, size); |
else |
internal_relocs = alloc2 = (Elf_Internal_Rela *) bfd_malloc (size); |
if (internal_relocs == NULL) |
goto error_return; |
} |
if (external_relocs == NULL) |
{ |
bfd_size_type size = 0; |
if (esdo->rel.hdr) |
size += esdo->rel.hdr->sh_size; |
if (esdo->rela.hdr) |
size += esdo->rela.hdr->sh_size; |
alloc1 = bfd_malloc (size); |
if (alloc1 == NULL) |
goto error_return; |
external_relocs = alloc1; |
} |
internal_rela_relocs = internal_relocs; |
if (esdo->rel.hdr) |
{ |
if (!elf_link_read_relocs_from_section (abfd, o, esdo->rel.hdr, |
external_relocs, |
internal_relocs)) |
goto error_return; |
external_relocs = (((bfd_byte *) external_relocs) |
+ esdo->rel.hdr->sh_size); |
internal_rela_relocs += (NUM_SHDR_ENTRIES (esdo->rel.hdr) |
* bed->s->int_rels_per_ext_rel); |
} |
if (esdo->rela.hdr |
&& (!elf_link_read_relocs_from_section (abfd, o, esdo->rela.hdr, |
external_relocs, |
internal_rela_relocs))) |
goto error_return; |
/* Cache the results for next time, if we can. */ |
if (keep_memory) |
esdo->relocs = internal_relocs; |
if (alloc1 != NULL) |
free (alloc1); |
/* Don't free alloc2, since if it was allocated we are passing it |
back (under the name of internal_relocs). */ |
return internal_relocs; |
error_return: |
if (alloc1 != NULL) |
free (alloc1); |
if (alloc2 != NULL) |
{ |
if (keep_memory) |
bfd_release (abfd, alloc2); |
else |
free (alloc2); |
} |
return NULL; |
} |
/* Compute the size of, and allocate space for, REL_HDR which is the |
section header for a section containing relocations for O. */ |
static bfd_boolean |
_bfd_elf_link_size_reloc_section (bfd *abfd, |
struct bfd_elf_section_reloc_data *reldata) |
{ |
Elf_Internal_Shdr *rel_hdr = reldata->hdr; |
/* That allows us to calculate the size of the section. */ |
rel_hdr->sh_size = rel_hdr->sh_entsize * reldata->count; |
/* The contents field must last into write_object_contents, so we |
allocate it with bfd_alloc rather than malloc. Also since we |
cannot be sure that the contents will actually be filled in, |
we zero the allocated space. */ |
rel_hdr->contents = (unsigned char *) bfd_zalloc (abfd, rel_hdr->sh_size); |
if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0) |
return FALSE; |
if (reldata->hashes == NULL && reldata->count) |
{ |
struct elf_link_hash_entry **p; |
p = (struct elf_link_hash_entry **) |
bfd_zmalloc (reldata->count * sizeof (struct elf_link_hash_entry *)); |
if (p == NULL) |
return FALSE; |
reldata->hashes = p; |
} |
return TRUE; |
} |
/* Copy the relocations indicated by the INTERNAL_RELOCS (which |
originated from the section given by INPUT_REL_HDR) to the |
OUTPUT_BFD. */ |
bfd_boolean |
_bfd_elf_link_output_relocs (bfd *output_bfd, |
asection *input_section, |
Elf_Internal_Shdr *input_rel_hdr, |
Elf_Internal_Rela *internal_relocs, |
struct elf_link_hash_entry **rel_hash |
ATTRIBUTE_UNUSED) |
{ |
Elf_Internal_Rela *irela; |
Elf_Internal_Rela *irelaend; |
bfd_byte *erel; |
struct bfd_elf_section_reloc_data *output_reldata; |
asection *output_section; |
const struct elf_backend_data *bed; |
void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *); |
struct bfd_elf_section_data *esdo; |
output_section = input_section->output_section; |
bed = get_elf_backend_data (output_bfd); |
esdo = elf_section_data (output_section); |
if (esdo->rel.hdr && esdo->rel.hdr->sh_entsize == input_rel_hdr->sh_entsize) |
{ |
output_reldata = &esdo->rel; |
swap_out = bed->s->swap_reloc_out; |
} |
else if (esdo->rela.hdr |
&& esdo->rela.hdr->sh_entsize == input_rel_hdr->sh_entsize) |
{ |
output_reldata = &esdo->rela; |
swap_out = bed->s->swap_reloca_out; |
} |
else |
{ |
(*_bfd_error_handler) |
(_("%B: relocation size mismatch in %B section %A"), |
output_bfd, input_section->owner, input_section); |
bfd_set_error (bfd_error_wrong_format); |
return FALSE; |
} |
erel = output_reldata->hdr->contents; |
erel += output_reldata->count * input_rel_hdr->sh_entsize; |
irela = internal_relocs; |
irelaend = irela + (NUM_SHDR_ENTRIES (input_rel_hdr) |
* bed->s->int_rels_per_ext_rel); |
while (irela < irelaend) |
{ |
(*swap_out) (output_bfd, irela, erel); |
irela += bed->s->int_rels_per_ext_rel; |
erel += input_rel_hdr->sh_entsize; |
} |
/* Bump the counter, so that we know where to add the next set of |
relocations. */ |
output_reldata->count += NUM_SHDR_ENTRIES (input_rel_hdr); |
return TRUE; |
} |
/* Make weak undefined symbols in PIE dynamic. */ |
bfd_boolean |
_bfd_elf_link_hash_fixup_symbol (struct bfd_link_info *info, |
struct elf_link_hash_entry *h) |
{ |
if (info->pie |
&& h->dynindx == -1 |
&& h->root.type == bfd_link_hash_undefweak) |
return bfd_elf_link_record_dynamic_symbol (info, h); |
return TRUE; |
} |
/* Fix up the flags for a symbol. This handles various cases which |
can only be fixed after all the input files are seen. This is |
currently called by both adjust_dynamic_symbol and |
assign_sym_version, which is unnecessary but perhaps more robust in |
the face of future changes. */ |
static bfd_boolean |
_bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h, |
struct elf_info_failed *eif) |
{ |
const struct elf_backend_data *bed; |
/* If this symbol was mentioned in a non-ELF file, try to set |
DEF_REGULAR and REF_REGULAR correctly. This is the only way to |
permit a non-ELF file to correctly refer to a symbol defined in |
an ELF dynamic object. */ |
if (h->non_elf) |
{ |
while (h->root.type == bfd_link_hash_indirect) |
h = (struct elf_link_hash_entry *) h->root.u.i.link; |
if (h->root.type != bfd_link_hash_defined |
&& h->root.type != bfd_link_hash_defweak) |
{ |
h->ref_regular = 1; |
h->ref_regular_nonweak = 1; |
} |
else |
{ |
if (h->root.u.def.section->owner != NULL |
&& (bfd_get_flavour (h->root.u.def.section->owner) |
== bfd_target_elf_flavour)) |
{ |
h->ref_regular = 1; |
h->ref_regular_nonweak = 1; |
} |
else |
h->def_regular = 1; |
} |
if (h->dynindx == -1 |
&& (h->def_dynamic |
|| h->ref_dynamic)) |
{ |
if (! bfd_elf_link_record_dynamic_symbol (eif->info, h)) |
{ |
eif->failed = TRUE; |
return FALSE; |
} |
} |
} |
else |
{ |
/* Unfortunately, NON_ELF is only correct if the symbol |
was first seen in a non-ELF file. Fortunately, if the symbol |
was first seen in an ELF file, we're probably OK unless the |
symbol was defined in a non-ELF file. Catch that case here. |
FIXME: We're still in trouble if the symbol was first seen in |
a dynamic object, and then later in a non-ELF regular object. */ |
if ((h->root.type == bfd_link_hash_defined |
|| h->root.type == bfd_link_hash_defweak) |
&& !h->def_regular |
&& (h->root.u.def.section->owner != NULL |
? (bfd_get_flavour (h->root.u.def.section->owner) |
!= bfd_target_elf_flavour) |
: (bfd_is_abs_section (h->root.u.def.section) |
&& !h->def_dynamic))) |
h->def_regular = 1; |
} |
/* Backend specific symbol fixup. */ |
bed = get_elf_backend_data (elf_hash_table (eif->info)->dynobj); |
if (bed->elf_backend_fixup_symbol |
&& !(*bed->elf_backend_fixup_symbol) (eif->info, h)) |
return FALSE; |
/* If this is a final link, and the symbol was defined as a common |
symbol in a regular object file, and there was no definition in |
any dynamic object, then the linker will have allocated space for |
the symbol in a common section but the DEF_REGULAR |
flag will not have been set. */ |
if (h->root.type == bfd_link_hash_defined |
&& !h->def_regular |
&& h->ref_regular |
&& !h->def_dynamic |
&& (h->root.u.def.section->owner->flags & (DYNAMIC | BFD_PLUGIN)) == 0) |
h->def_regular = 1; |
/* If -Bsymbolic was used (which means to bind references to global |
symbols to the definition within the shared object), and this |
symbol was defined in a regular object, then it actually doesn't |
need a PLT entry. Likewise, if the symbol has non-default |
visibility. If the symbol has hidden or internal visibility, we |
will force it local. */ |
if (h->needs_plt |
&& eif->info->shared |
&& is_elf_hash_table (eif->info->hash) |
&& (SYMBOLIC_BIND (eif->info, h) |
|| ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) |
&& h->def_regular) |
{ |
bfd_boolean force_local; |
force_local = (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL |
|| ELF_ST_VISIBILITY (h->other) == STV_HIDDEN); |
(*bed->elf_backend_hide_symbol) (eif->info, h, force_local); |
} |
/* If a weak undefined symbol has non-default visibility, we also |
hide it from the dynamic linker. */ |
if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT |
&& h->root.type == bfd_link_hash_undefweak) |
(*bed->elf_backend_hide_symbol) (eif->info, h, TRUE); |
/* If this is a weak defined symbol in a dynamic object, and we know |
the real definition in the dynamic object, copy interesting flags |
over to the real definition. */ |
if (h->u.weakdef != NULL) |
{ |
/* If the real definition is defined by a regular object file, |
don't do anything special. See the longer description in |
_bfd_elf_adjust_dynamic_symbol, below. */ |
if (h->u.weakdef->def_regular) |
h->u.weakdef = NULL; |
else |
{ |
struct elf_link_hash_entry *weakdef = h->u.weakdef; |
while (h->root.type == bfd_link_hash_indirect) |
h = (struct elf_link_hash_entry *) h->root.u.i.link; |
BFD_ASSERT (h->root.type == bfd_link_hash_defined |
|| h->root.type == bfd_link_hash_defweak); |
BFD_ASSERT (weakdef->def_dynamic); |
BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined |
|| weakdef->root.type == bfd_link_hash_defweak); |
(*bed->elf_backend_copy_indirect_symbol) (eif->info, weakdef, h); |
} |
} |
return TRUE; |
} |
/* Make the backend pick a good value for a dynamic symbol. This is |
called via elf_link_hash_traverse, and also calls itself |
recursively. */ |
static bfd_boolean |
_bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data) |
{ |
struct elf_info_failed *eif = (struct elf_info_failed *) data; |
bfd *dynobj; |
const struct elf_backend_data *bed; |
if (! is_elf_hash_table (eif->info->hash)) |
return FALSE; |
/* Ignore indirect symbols. These are added by the versioning code. */ |
if (h->root.type == bfd_link_hash_indirect) |
return TRUE; |
/* Fix the symbol flags. */ |
if (! _bfd_elf_fix_symbol_flags (h, eif)) |
return FALSE; |
/* If this symbol does not require a PLT entry, and it is not |
defined by a dynamic object, or is not referenced by a regular |
object, ignore it. We do have to handle a weak defined symbol, |
even if no regular object refers to it, if we decided to add it |
to the dynamic symbol table. FIXME: Do we normally need to worry |
about symbols which are defined by one dynamic object and |
referenced by another one? */ |
if (!h->needs_plt |
&& h->type != STT_GNU_IFUNC |
&& (h->def_regular |
|| !h->def_dynamic |
|| (!h->ref_regular |
&& (h->u.weakdef == NULL || h->u.weakdef->dynindx == -1)))) |
{ |
h->plt = elf_hash_table (eif->info)->init_plt_offset; |
return TRUE; |
} |
/* If we've already adjusted this symbol, don't do it again. This |
can happen via a recursive call. */ |
if (h->dynamic_adjusted) |
return TRUE; |
/* Don't look at this symbol again. Note that we must set this |
after checking the above conditions, because we may look at a |
symbol once, decide not to do anything, and then get called |
recursively later after REF_REGULAR is set below. */ |
h->dynamic_adjusted = 1; |
/* If this is a weak definition, and we know a real definition, and |
the real symbol is not itself defined by a regular object file, |
then get a good value for the real definition. We handle the |
real symbol first, for the convenience of the backend routine. |
Note that there is a confusing case here. If the real definition |
is defined by a regular object file, we don't get the real symbol |
from the dynamic object, but we do get the weak symbol. If the |
processor backend uses a COPY reloc, then if some routine in the |
dynamic object changes the real symbol, we will not see that |
change in the corresponding weak symbol. This is the way other |
ELF linkers work as well, and seems to be a result of the shared |
library model. |
I will clarify this issue. Most SVR4 shared libraries define the |
variable _timezone and define timezone as a weak synonym. The |
tzset call changes _timezone. If you write |
extern int timezone; |
int _timezone = 5; |
int main () { tzset (); printf ("%d %d\n", timezone, _timezone); } |
you might expect that, since timezone is a synonym for _timezone, |
the same number will print both times. However, if the processor |
backend uses a COPY reloc, then actually timezone will be copied |
into your process image, and, since you define _timezone |
yourself, _timezone will not. Thus timezone and _timezone will |
wind up at different memory locations. The tzset call will set |
_timezone, leaving timezone unchanged. */ |
if (h->u.weakdef != NULL) |
{ |
/* If we get to this point, there is an implicit reference to |
H->U.WEAKDEF by a regular object file via the weak symbol H. */ |
h->u.weakdef->ref_regular = 1; |
/* Ensure that the backend adjust_dynamic_symbol function sees |
H->U.WEAKDEF before H by recursively calling ourselves. */ |
if (! _bfd_elf_adjust_dynamic_symbol (h->u.weakdef, eif)) |
return FALSE; |
} |
/* If a symbol has no type and no size and does not require a PLT |
entry, then we are probably about to do the wrong thing here: we |
are probably going to create a COPY reloc for an empty object. |
This case can arise when a shared object is built with assembly |
code, and the assembly code fails to set the symbol type. */ |
if (h->size == 0 |
&& h->type == STT_NOTYPE |
&& !h->needs_plt) |
(*_bfd_error_handler) |
(_("warning: type and size of dynamic symbol `%s' are not defined"), |
h->root.root.string); |
dynobj = elf_hash_table (eif->info)->dynobj; |
bed = get_elf_backend_data (dynobj); |
if (! (*bed->elf_backend_adjust_dynamic_symbol) (eif->info, h)) |
{ |
eif->failed = TRUE; |
return FALSE; |
} |
return TRUE; |
} |
/* Adjust the dynamic symbol, H, for copy in the dynamic bss section, |
DYNBSS. */ |
bfd_boolean |
_bfd_elf_adjust_dynamic_copy (struct elf_link_hash_entry *h, |
asection *dynbss) |
{ |
unsigned int power_of_two; |
bfd_vma mask; |
asection *sec = h->root.u.def.section; |
/* The section aligment of definition is the maximum alignment |
requirement of symbols defined in the section. Since we don't |
know the symbol alignment requirement, we start with the |
maximum alignment and check low bits of the symbol address |
for the minimum alignment. */ |
power_of_two = bfd_get_section_alignment (sec->owner, sec); |
mask = ((bfd_vma) 1 << power_of_two) - 1; |
while ((h->root.u.def.value & mask) != 0) |
{ |
mask >>= 1; |
--power_of_two; |
} |
if (power_of_two > bfd_get_section_alignment (dynbss->owner, |
dynbss)) |
{ |
/* Adjust the section alignment if needed. */ |
if (! bfd_set_section_alignment (dynbss->owner, dynbss, |
power_of_two)) |
return FALSE; |
} |
/* We make sure that the symbol will be aligned properly. */ |
dynbss->size = BFD_ALIGN (dynbss->size, mask + 1); |
/* Define the symbol as being at this point in DYNBSS. */ |
h->root.u.def.section = dynbss; |
h->root.u.def.value = dynbss->size; |
/* Increment the size of DYNBSS to make room for the symbol. */ |
dynbss->size += h->size; |
return TRUE; |
} |
/* Adjust all external symbols pointing into SEC_MERGE sections |
to reflect the object merging within the sections. */ |
static bfd_boolean |
_bfd_elf_link_sec_merge_syms (struct elf_link_hash_entry *h, void *data) |
{ |
asection *sec; |
if ((h->root.type == bfd_link_hash_defined |
|| h->root.type == bfd_link_hash_defweak) |
&& ((sec = h->root.u.def.section)->flags & SEC_MERGE) |
&& sec->sec_info_type == SEC_INFO_TYPE_MERGE) |
{ |
bfd *output_bfd = (bfd *) data; |
h->root.u.def.value = |
_bfd_merged_section_offset (output_bfd, |
&h->root.u.def.section, |
elf_section_data (sec)->sec_info, |
h->root.u.def.value); |
} |
return TRUE; |
} |
/* Returns false if the symbol referred to by H should be considered |
to resolve local to the current module, and true if it should be |
considered to bind dynamically. */ |
bfd_boolean |
_bfd_elf_dynamic_symbol_p (struct elf_link_hash_entry *h, |
struct bfd_link_info *info, |
bfd_boolean not_local_protected) |
{ |
bfd_boolean binding_stays_local_p; |
const struct elf_backend_data *bed; |
struct elf_link_hash_table *hash_table; |
if (h == NULL) |
return FALSE; |
while (h->root.type == bfd_link_hash_indirect |
|| h->root.type == bfd_link_hash_warning) |
h = (struct elf_link_hash_entry *) h->root.u.i.link; |
/* If it was forced local, then clearly it's not dynamic. */ |
if (h->dynindx == -1) |
return FALSE; |
if (h->forced_local) |
return FALSE; |
/* Identify the cases where name binding rules say that a |
visible symbol resolves locally. */ |
binding_stays_local_p = info->executable || SYMBOLIC_BIND (info, h); |
switch (ELF_ST_VISIBILITY (h->other)) |
{ |
case STV_INTERNAL: |
case STV_HIDDEN: |
return FALSE; |
case STV_PROTECTED: |
hash_table = elf_hash_table (info); |
if (!is_elf_hash_table (hash_table)) |
return FALSE; |
bed = get_elf_backend_data (hash_table->dynobj); |
/* Proper resolution for function pointer equality may require |
that these symbols perhaps be resolved dynamically, even though |
we should be resolving them to the current module. */ |
if (!not_local_protected || !bed->is_function_type (h->type)) |
binding_stays_local_p = TRUE; |
break; |
default: |
break; |
} |
/* If it isn't defined locally, then clearly it's dynamic. */ |
if (!h->def_regular && !ELF_COMMON_DEF_P (h)) |
return TRUE; |
/* Otherwise, the symbol is dynamic if binding rules don't tell |
us that it remains local. */ |
return !binding_stays_local_p; |
} |
/* Return true if the symbol referred to by H should be considered |
to resolve local to the current module, and false otherwise. Differs |
from (the inverse of) _bfd_elf_dynamic_symbol_p in the treatment of |
undefined symbols. The two functions are virtually identical except |
for the place where forced_local and dynindx == -1 are tested. If |
either of those tests are true, _bfd_elf_dynamic_symbol_p will say |
the symbol is local, while _bfd_elf_symbol_refs_local_p will say |
the symbol is local only for defined symbols. |
It might seem that _bfd_elf_dynamic_symbol_p could be rewritten as |
!_bfd_elf_symbol_refs_local_p, except that targets differ in their |
treatment of undefined weak symbols. For those that do not make |
undefined weak symbols dynamic, both functions may return false. */ |
bfd_boolean |
_bfd_elf_symbol_refs_local_p (struct elf_link_hash_entry *h, |
struct bfd_link_info *info, |
bfd_boolean local_protected) |
{ |
const struct elf_backend_data *bed; |
struct elf_link_hash_table *hash_table; |
/* If it's a local sym, of course we resolve locally. */ |
if (h == NULL) |
return TRUE; |
/* STV_HIDDEN or STV_INTERNAL ones must be local. */ |
if (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN |
|| ELF_ST_VISIBILITY (h->other) == STV_INTERNAL) |
return TRUE; |
/* Common symbols that become definitions don't get the DEF_REGULAR |
flag set, so test it first, and don't bail out. */ |
if (ELF_COMMON_DEF_P (h)) |
/* Do nothing. */; |
/* If we don't have a definition in a regular file, then we can't |
resolve locally. The sym is either undefined or dynamic. */ |
else if (!h->def_regular) |
return FALSE; |
/* Forced local symbols resolve locally. */ |
if (h->forced_local) |
return TRUE; |
/* As do non-dynamic symbols. */ |
if (h->dynindx == -1) |
return TRUE; |
/* At this point, we know the symbol is defined and dynamic. In an |
executable it must resolve locally, likewise when building symbolic |
shared libraries. */ |
if (info->executable || SYMBOLIC_BIND (info, h)) |
return TRUE; |
/* Now deal with defined dynamic symbols in shared libraries. Ones |
with default visibility might not resolve locally. */ |
if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) |
return FALSE; |
hash_table = elf_hash_table (info); |
if (!is_elf_hash_table (hash_table)) |
return TRUE; |
bed = get_elf_backend_data (hash_table->dynobj); |
/* STV_PROTECTED non-function symbols are local. */ |
if (!bed->is_function_type (h->type)) |
return TRUE; |
/* Function pointer equality tests may require that STV_PROTECTED |
symbols be treated as dynamic symbols. If the address of a |
function not defined in an executable is set to that function's |
plt entry in the executable, then the address of the function in |
a shared library must also be the plt entry in the executable. */ |
return local_protected; |
} |
/* Caches some TLS segment info, and ensures that the TLS segment vma is |
aligned. Returns the first TLS output section. */ |
struct bfd_section * |
_bfd_elf_tls_setup (bfd *obfd, struct bfd_link_info *info) |
{ |
struct bfd_section *sec, *tls; |
unsigned int align = 0; |
for (sec = obfd->sections; sec != NULL; sec = sec->next) |
if ((sec->flags & SEC_THREAD_LOCAL) != 0) |
break; |
tls = sec; |
for (; sec != NULL && (sec->flags & SEC_THREAD_LOCAL) != 0; sec = sec->next) |
if (sec->alignment_power > align) |
align = sec->alignment_power; |
elf_hash_table (info)->tls_sec = tls; |
/* Ensure the alignment of the first section is the largest alignment, |
so that the tls segment starts aligned. */ |
if (tls != NULL) |
tls->alignment_power = align; |
return tls; |
} |
/* Return TRUE iff this is a non-common, definition of a non-function symbol. */ |
static bfd_boolean |
is_global_data_symbol_definition (bfd *abfd ATTRIBUTE_UNUSED, |
Elf_Internal_Sym *sym) |
{ |
const struct elf_backend_data *bed; |
/* Local symbols do not count, but target specific ones might. */ |
if (ELF_ST_BIND (sym->st_info) != STB_GLOBAL |
&& ELF_ST_BIND (sym->st_info) < STB_LOOS) |
return FALSE; |
bed = get_elf_backend_data (abfd); |
/* Function symbols do not count. */ |
if (bed->is_function_type (ELF_ST_TYPE (sym->st_info))) |
return FALSE; |
/* If the section is undefined, then so is the symbol. */ |
if (sym->st_shndx == SHN_UNDEF) |
return FALSE; |
/* If the symbol is defined in the common section, then |
it is a common definition and so does not count. */ |
if (bed->common_definition (sym)) |
return FALSE; |
/* If the symbol is in a target specific section then we |
must rely upon the backend to tell us what it is. */ |
if (sym->st_shndx >= SHN_LORESERVE && sym->st_shndx < SHN_ABS) |
/* FIXME - this function is not coded yet: |
return _bfd_is_global_symbol_definition (abfd, sym); |
Instead for now assume that the definition is not global, |
Even if this is wrong, at least the linker will behave |
in the same way that it used to do. */ |
return FALSE; |
return TRUE; |
} |
/* Search the symbol table of the archive element of the archive ABFD |
whose archive map contains a mention of SYMDEF, and determine if |
the symbol is defined in this element. */ |
static bfd_boolean |
elf_link_is_defined_archive_symbol (bfd * abfd, carsym * symdef) |
{ |
Elf_Internal_Shdr * hdr; |
bfd_size_type symcount; |
bfd_size_type extsymcount; |
bfd_size_type extsymoff; |
Elf_Internal_Sym *isymbuf; |
Elf_Internal_Sym *isym; |
Elf_Internal_Sym *isymend; |
bfd_boolean result; |
abfd = _bfd_get_elt_at_filepos (abfd, symdef->file_offset); |
if (abfd == NULL) |
return FALSE; |
if (! bfd_check_format (abfd, bfd_object)) |
return FALSE; |
/* If we have already included the element containing this symbol in the |
link then we do not need to include it again. Just claim that any symbol |
it contains is not a definition, so that our caller will not decide to |
(re)include this element. */ |
if (abfd->archive_pass) |
return FALSE; |
/* Select the appropriate symbol table. */ |
if ((abfd->flags & DYNAMIC) == 0 || elf_dynsymtab (abfd) == 0) |
hdr = &elf_tdata (abfd)->symtab_hdr; |
else |
hdr = &elf_tdata (abfd)->dynsymtab_hdr; |
symcount = hdr->sh_size / get_elf_backend_data (abfd)->s->sizeof_sym; |
/* The sh_info field of the symtab header tells us where the |
external symbols start. We don't care about the local symbols. */ |
if (elf_bad_symtab (abfd)) |
{ |
extsymcount = symcount; |
extsymoff = 0; |
} |
else |
{ |
extsymcount = symcount - hdr->sh_info; |
extsymoff = hdr->sh_info; |
} |
if (extsymcount == 0) |
return FALSE; |
/* Read in the symbol table. */ |
isymbuf = bfd_elf_get_elf_syms (abfd, hdr, extsymcount, extsymoff, |
NULL, NULL, NULL); |
if (isymbuf == NULL) |
return FALSE; |
/* Scan the symbol table looking for SYMDEF. */ |
result = FALSE; |
for (isym = isymbuf, isymend = isymbuf + extsymcount; isym < isymend; isym++) |
{ |
const char *name; |
name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link, |
isym->st_name); |
if (name == NULL) |
break; |
if (strcmp (name, symdef->name) == 0) |
{ |
result = is_global_data_symbol_definition (abfd, isym); |
break; |
} |
} |
free (isymbuf); |
return result; |
} |
/* Add an entry to the .dynamic table. */ |
bfd_boolean |
_bfd_elf_add_dynamic_entry (struct bfd_link_info *info, |
bfd_vma tag, |
bfd_vma val) |
{ |
struct elf_link_hash_table *hash_table; |
const struct elf_backend_data *bed; |
asection *s; |
bfd_size_type newsize; |
bfd_byte *newcontents; |
Elf_Internal_Dyn dyn; |
hash_table = elf_hash_table (info); |
if (! is_elf_hash_table (hash_table)) |
return FALSE; |
bed = get_elf_backend_data (hash_table->dynobj); |
s = bfd_get_linker_section (hash_table->dynobj, ".dynamic"); |
BFD_ASSERT (s != NULL); |
newsize = s->size + bed->s->sizeof_dyn; |
newcontents = (bfd_byte *) bfd_realloc (s->contents, newsize); |
if (newcontents == NULL) |
return FALSE; |
dyn.d_tag = tag; |
dyn.d_un.d_val = val; |
bed->s->swap_dyn_out (hash_table->dynobj, &dyn, newcontents + s->size); |
s->size = newsize; |
s->contents = newcontents; |
return TRUE; |
} |
/* Add a DT_NEEDED entry for this dynamic object if DO_IT is true, |
otherwise just check whether one already exists. Returns -1 on error, |
1 if a DT_NEEDED tag already exists, and 0 on success. */ |
static int |
elf_add_dt_needed_tag (bfd *abfd, |
struct bfd_link_info *info, |
const char *soname, |
bfd_boolean do_it) |
{ |
struct elf_link_hash_table *hash_table; |
bfd_size_type strindex; |
if (!_bfd_elf_link_create_dynstrtab (abfd, info)) |
return -1; |
hash_table = elf_hash_table (info); |
strindex = _bfd_elf_strtab_add (hash_table->dynstr, soname, FALSE); |
if (strindex == (bfd_size_type) -1) |
return -1; |
if (_bfd_elf_strtab_refcount (hash_table->dynstr, strindex) != 1) |
{ |
asection *sdyn; |
const struct elf_backend_data *bed; |
bfd_byte *extdyn; |
bed = get_elf_backend_data (hash_table->dynobj); |
sdyn = bfd_get_linker_section (hash_table->dynobj, ".dynamic"); |
if (sdyn != NULL) |
for (extdyn = sdyn->contents; |
extdyn < sdyn->contents + sdyn->size; |
extdyn += bed->s->sizeof_dyn) |
{ |
Elf_Internal_Dyn dyn; |
bed->s->swap_dyn_in (hash_table->dynobj, extdyn, &dyn); |
if (dyn.d_tag == DT_NEEDED |
&& dyn.d_un.d_val == strindex) |
{ |
_bfd_elf_strtab_delref (hash_table->dynstr, strindex); |
return 1; |
} |
} |
} |
if (do_it) |
{ |
if (!_bfd_elf_link_create_dynamic_sections (hash_table->dynobj, info)) |
return -1; |
if (!_bfd_elf_add_dynamic_entry (info, DT_NEEDED, strindex)) |
return -1; |
} |
else |
/* We were just checking for existence of the tag. */ |
_bfd_elf_strtab_delref (hash_table->dynstr, strindex); |
return 0; |
} |
static bfd_boolean |
on_needed_list (const char *soname, struct bfd_link_needed_list *needed) |
{ |
for (; needed != NULL; needed = needed->next) |
if (strcmp (soname, needed->name) == 0) |
return TRUE; |
return FALSE; |
} |
/* Sort symbol by value, section, and size. */ |
static int |
elf_sort_symbol (const void *arg1, const void *arg2) |
{ |
const struct elf_link_hash_entry *h1; |
const struct elf_link_hash_entry *h2; |
bfd_signed_vma vdiff; |
h1 = *(const struct elf_link_hash_entry **) arg1; |
h2 = *(const struct elf_link_hash_entry **) arg2; |
vdiff = h1->root.u.def.value - h2->root.u.def.value; |
if (vdiff != 0) |
return vdiff > 0 ? 1 : -1; |
else |
{ |
long sdiff = h1->root.u.def.section->id - h2->root.u.def.section->id; |
if (sdiff != 0) |
return sdiff > 0 ? 1 : -1; |
} |
vdiff = h1->size - h2->size; |
return vdiff == 0 ? 0 : vdiff > 0 ? 1 : -1; |
} |
/* This function is used to adjust offsets into .dynstr for |
dynamic symbols. This is called via elf_link_hash_traverse. */ |
static bfd_boolean |
elf_adjust_dynstr_offsets (struct elf_link_hash_entry *h, void *data) |
{ |
struct elf_strtab_hash *dynstr = (struct elf_strtab_hash *) data; |
if (h->dynindx != -1) |
h->dynstr_index = _bfd_elf_strtab_offset (dynstr, h->dynstr_index); |
return TRUE; |
} |
/* Assign string offsets in .dynstr, update all structures referencing |
them. */ |
static bfd_boolean |
elf_finalize_dynstr (bfd *output_bfd, struct bfd_link_info *info) |
{ |
struct elf_link_hash_table *hash_table = elf_hash_table (info); |
struct elf_link_local_dynamic_entry *entry; |
struct elf_strtab_hash *dynstr = hash_table->dynstr; |
bfd *dynobj = hash_table->dynobj; |
asection *sdyn; |
bfd_size_type size; |
const struct elf_backend_data *bed; |
bfd_byte *extdyn; |
_bfd_elf_strtab_finalize (dynstr); |
size = _bfd_elf_strtab_size (dynstr); |
bed = get_elf_backend_data (dynobj); |
sdyn = bfd_get_linker_section (dynobj, ".dynamic"); |
BFD_ASSERT (sdyn != NULL); |
/* Update all .dynamic entries referencing .dynstr strings. */ |
for (extdyn = sdyn->contents; |
extdyn < sdyn->contents + sdyn->size; |
extdyn += bed->s->sizeof_dyn) |
{ |
Elf_Internal_Dyn dyn; |
bed->s->swap_dyn_in (dynobj, extdyn, &dyn); |
switch (dyn.d_tag) |
{ |
case DT_STRSZ: |
dyn.d_un.d_val = size; |
break; |
case DT_NEEDED: |
case DT_SONAME: |
case DT_RPATH: |
case DT_RUNPATH: |
case DT_FILTER: |
case DT_AUXILIARY: |
case DT_AUDIT: |
case DT_DEPAUDIT: |
dyn.d_un.d_val = _bfd_elf_strtab_offset (dynstr, dyn.d_un.d_val); |
break; |
default: |
continue; |
} |
bed->s->swap_dyn_out (dynobj, &dyn, extdyn); |
} |
/* Now update local dynamic symbols. */ |
for (entry = hash_table->dynlocal; entry ; entry = entry->next) |
entry->isym.st_name = _bfd_elf_strtab_offset (dynstr, |
entry->isym.st_name); |
/* And the rest of dynamic symbols. */ |
elf_link_hash_traverse (hash_table, elf_adjust_dynstr_offsets, dynstr); |
/* Adjust version definitions. */ |
if (elf_tdata (output_bfd)->cverdefs) |
{ |
asection *s; |
bfd_byte *p; |
bfd_size_type i; |
Elf_Internal_Verdef def; |
Elf_Internal_Verdaux defaux; |
s = bfd_get_linker_section (dynobj, ".gnu.version_d"); |
p = s->contents; |
do |
{ |
_bfd_elf_swap_verdef_in (output_bfd, (Elf_External_Verdef *) p, |
&def); |
p += sizeof (Elf_External_Verdef); |
if (def.vd_aux != sizeof (Elf_External_Verdef)) |
continue; |
for (i = 0; i < def.vd_cnt; ++i) |
{ |
_bfd_elf_swap_verdaux_in (output_bfd, |
(Elf_External_Verdaux *) p, &defaux); |
defaux.vda_name = _bfd_elf_strtab_offset (dynstr, |
defaux.vda_name); |
_bfd_elf_swap_verdaux_out (output_bfd, |
&defaux, (Elf_External_Verdaux *) p); |
p += sizeof (Elf_External_Verdaux); |
} |
} |
while (def.vd_next); |
} |
/* Adjust version references. */ |
if (elf_tdata (output_bfd)->verref) |
{ |
asection *s; |
bfd_byte *p; |
bfd_size_type i; |
Elf_Internal_Verneed need; |
Elf_Internal_Vernaux needaux; |
s = bfd_get_linker_section (dynobj, ".gnu.version_r"); |
p = s->contents; |
do |
{ |
_bfd_elf_swap_verneed_in (output_bfd, (Elf_External_Verneed *) p, |
&need); |
need.vn_file = _bfd_elf_strtab_offset (dynstr, need.vn_file); |
_bfd_elf_swap_verneed_out (output_bfd, &need, |
(Elf_External_Verneed *) p); |
p += sizeof (Elf_External_Verneed); |
for (i = 0; i < need.vn_cnt; ++i) |
{ |
_bfd_elf_swap_vernaux_in (output_bfd, |
(Elf_External_Vernaux *) p, &needaux); |
needaux.vna_name = _bfd_elf_strtab_offset (dynstr, |
needaux.vna_name); |
_bfd_elf_swap_vernaux_out (output_bfd, |
&needaux, |
(Elf_External_Vernaux *) p); |
p += sizeof (Elf_External_Vernaux); |
} |
} |
while (need.vn_next); |
} |
return TRUE; |
} |
/* Return TRUE iff relocations for INPUT are compatible with OUTPUT. |
The default is to only match when the INPUT and OUTPUT are exactly |
the same target. */ |
bfd_boolean |
_bfd_elf_default_relocs_compatible (const bfd_target *input, |
const bfd_target *output) |
{ |
return input == output; |
} |
/* Return TRUE iff relocations for INPUT are compatible with OUTPUT. |
This version is used when different targets for the same architecture |
are virtually identical. */ |
bfd_boolean |
_bfd_elf_relocs_compatible (const bfd_target *input, |
const bfd_target *output) |
{ |
const struct elf_backend_data *obed, *ibed; |
if (input == output) |
return TRUE; |
ibed = xvec_get_elf_backend_data (input); |
obed = xvec_get_elf_backend_data (output); |
if (ibed->arch != obed->arch) |
return FALSE; |
/* If both backends are using this function, deem them compatible. */ |
return ibed->relocs_compatible == obed->relocs_compatible; |
} |
/* Make a special call to the linker "notice" function to tell it that |
we are about to handle an as-needed lib, or have finished |
processing the lib. */ |
bfd_boolean |
_bfd_elf_notice_as_needed (bfd *ibfd, |
struct bfd_link_info *info, |
enum notice_asneeded_action act) |
{ |
return (*info->callbacks->notice) (info, NULL, ibfd, NULL, act, 0, NULL); |
} |
/* Add symbols from an ELF object file to the linker hash table. */ |
static bfd_boolean |
elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) |
{ |
Elf_Internal_Ehdr *ehdr; |
Elf_Internal_Shdr *hdr; |
bfd_size_type symcount; |
bfd_size_type extsymcount; |
bfd_size_type extsymoff; |
struct elf_link_hash_entry **sym_hash; |
bfd_boolean dynamic; |
Elf_External_Versym *extversym = NULL; |
Elf_External_Versym *ever; |
struct elf_link_hash_entry *weaks; |
struct elf_link_hash_entry **nondeflt_vers = NULL; |
bfd_size_type nondeflt_vers_cnt = 0; |
Elf_Internal_Sym *isymbuf = NULL; |
Elf_Internal_Sym *isym; |
Elf_Internal_Sym *isymend; |
const struct elf_backend_data *bed; |
bfd_boolean add_needed; |
struct elf_link_hash_table *htab; |
bfd_size_type amt; |
void *alloc_mark = NULL; |
struct bfd_hash_entry **old_table = NULL; |
unsigned int old_size = 0; |
unsigned int old_count = 0; |
void *old_tab = NULL; |
void *old_ent; |
struct bfd_link_hash_entry *old_undefs = NULL; |
struct bfd_link_hash_entry *old_undefs_tail = NULL; |
long old_dynsymcount = 0; |
bfd_size_type old_dynstr_size = 0; |
size_t tabsize = 0; |
asection *s; |
htab = elf_hash_table (info); |
bed = get_elf_backend_data (abfd); |
if ((abfd->flags & DYNAMIC) == 0) |
dynamic = FALSE; |
else |
{ |
dynamic = TRUE; |
/* You can't use -r against a dynamic object. Also, there's no |
hope of using a dynamic object which does not exactly match |
the format of the output file. */ |
if (info->relocatable |
|| !is_elf_hash_table (htab) |
|| info->output_bfd->xvec != abfd->xvec) |
{ |
if (info->relocatable) |
bfd_set_error (bfd_error_invalid_operation); |
else |
bfd_set_error (bfd_error_wrong_format); |
goto error_return; |
} |
} |
ehdr = elf_elfheader (abfd); |
if (info->warn_alternate_em |
&& bed->elf_machine_code != ehdr->e_machine |
&& ((bed->elf_machine_alt1 != 0 |
&& ehdr->e_machine == bed->elf_machine_alt1) |
|| (bed->elf_machine_alt2 != 0 |
&& ehdr->e_machine == bed->elf_machine_alt2))) |
info->callbacks->einfo |
(_("%P: alternate ELF machine code found (%d) in %B, expecting %d\n"), |
ehdr->e_machine, abfd, bed->elf_machine_code); |
/* As a GNU extension, any input sections which are named |
.gnu.warning.SYMBOL are treated as warning symbols for the given |
symbol. This differs from .gnu.warning sections, which generate |
warnings when they are included in an output file. */ |
/* PR 12761: Also generate this warning when building shared libraries. */ |
for (s = abfd->sections; s != NULL; s = s->next) |
{ |
const char *name; |
name = bfd_get_section_name (abfd, s); |
if (CONST_STRNEQ (name, ".gnu.warning.")) |
{ |
char *msg; |
bfd_size_type sz; |
name += sizeof ".gnu.warning." - 1; |
/* If this is a shared object, then look up the symbol |
in the hash table. If it is there, and it is already |
been defined, then we will not be using the entry |
from this shared object, so we don't need to warn. |
FIXME: If we see the definition in a regular object |
later on, we will warn, but we shouldn't. The only |
fix is to keep track of what warnings we are supposed |
to emit, and then handle them all at the end of the |
link. */ |
if (dynamic) |
{ |
struct elf_link_hash_entry *h; |
h = elf_link_hash_lookup (htab, name, FALSE, FALSE, TRUE); |
/* FIXME: What about bfd_link_hash_common? */ |
if (h != NULL |
&& (h->root.type == bfd_link_hash_defined |
|| h->root.type == bfd_link_hash_defweak)) |
continue; |
} |
sz = s->size; |
msg = (char *) bfd_alloc (abfd, sz + 1); |
if (msg == NULL) |
goto error_return; |
if (! bfd_get_section_contents (abfd, s, msg, 0, sz)) |
goto error_return; |
msg[sz] = '\0'; |
if (! (_bfd_generic_link_add_one_symbol |
(info, abfd, name, BSF_WARNING, s, 0, msg, |
FALSE, bed->collect, NULL))) |
goto error_return; |
if (!info->relocatable && info->executable) |
{ |
/* Clobber the section size so that the warning does |
not get copied into the output file. */ |
s->size = 0; |
/* Also set SEC_EXCLUDE, so that symbols defined in |
the warning section don't get copied to the output. */ |
s->flags |= SEC_EXCLUDE; |
} |
} |
} |
add_needed = TRUE; |
if (! dynamic) |
{ |
/* If we are creating a shared library, create all the dynamic |
sections immediately. We need to attach them to something, |
so we attach them to this BFD, provided it is the right |
format. FIXME: If there are no input BFD's of the same |
format as the output, we can't make a shared library. */ |
if (info->shared |
&& is_elf_hash_table (htab) |
&& info->output_bfd->xvec == abfd->xvec |
&& !htab->dynamic_sections_created) |
{ |
if (! _bfd_elf_link_create_dynamic_sections (abfd, info)) |
goto error_return; |
} |
} |
else if (!is_elf_hash_table (htab)) |
goto error_return; |
else |
{ |
const char *soname = NULL; |
char *audit = NULL; |
struct bfd_link_needed_list *rpath = NULL, *runpath = NULL; |
int ret; |
/* ld --just-symbols and dynamic objects don't mix very well. |
ld shouldn't allow it. */ |
if ((s = abfd->sections) != NULL |
&& s->sec_info_type == SEC_INFO_TYPE_JUST_SYMS) |
abort (); |
/* If this dynamic lib was specified on the command line with |
--as-needed in effect, then we don't want to add a DT_NEEDED |
tag unless the lib is actually used. Similary for libs brought |
in by another lib's DT_NEEDED. When --no-add-needed is used |
on a dynamic lib, we don't want to add a DT_NEEDED entry for |
any dynamic library in DT_NEEDED tags in the dynamic lib at |
all. */ |
add_needed = (elf_dyn_lib_class (abfd) |
& (DYN_AS_NEEDED | DYN_DT_NEEDED |
| DYN_NO_NEEDED)) == 0; |
s = bfd_get_section_by_name (abfd, ".dynamic"); |
if (s != NULL) |
{ |
bfd_byte *dynbuf; |
bfd_byte *extdyn; |
unsigned int elfsec; |
unsigned long shlink; |
if (!bfd_malloc_and_get_section (abfd, s, &dynbuf)) |
{ |
error_free_dyn: |
free (dynbuf); |
goto error_return; |
} |
elfsec = _bfd_elf_section_from_bfd_section (abfd, s); |
if (elfsec == SHN_BAD) |
goto error_free_dyn; |
shlink = elf_elfsections (abfd)[elfsec]->sh_link; |
for (extdyn = dynbuf; |
extdyn < dynbuf + s->size; |
extdyn += bed->s->sizeof_dyn) |
{ |
Elf_Internal_Dyn dyn; |
bed->s->swap_dyn_in (abfd, extdyn, &dyn); |
if (dyn.d_tag == DT_SONAME) |
{ |
unsigned int tagv = dyn.d_un.d_val; |
soname = bfd_elf_string_from_elf_section (abfd, shlink, tagv); |
if (soname == NULL) |
goto error_free_dyn; |
} |
if (dyn.d_tag == DT_NEEDED) |
{ |
struct bfd_link_needed_list *n, **pn; |
char *fnm, *anm; |
unsigned int tagv = dyn.d_un.d_val; |
amt = sizeof (struct bfd_link_needed_list); |
n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt); |
fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv); |
if (n == NULL || fnm == NULL) |
goto error_free_dyn; |
amt = strlen (fnm) + 1; |
anm = (char *) bfd_alloc (abfd, amt); |
if (anm == NULL) |
goto error_free_dyn; |
memcpy (anm, fnm, amt); |
n->name = anm; |
n->by = abfd; |
n->next = NULL; |
for (pn = &htab->needed; *pn != NULL; pn = &(*pn)->next) |
; |
*pn = n; |
} |
if (dyn.d_tag == DT_RUNPATH) |
{ |
struct bfd_link_needed_list *n, **pn; |
char *fnm, *anm; |
unsigned int tagv = dyn.d_un.d_val; |
amt = sizeof (struct bfd_link_needed_list); |
n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt); |
fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv); |
if (n == NULL || fnm == NULL) |
goto error_free_dyn; |
amt = strlen (fnm) + 1; |
anm = (char *) bfd_alloc (abfd, amt); |
if (anm == NULL) |
goto error_free_dyn; |
memcpy (anm, fnm, amt); |
n->name = anm; |
n->by = abfd; |
n->next = NULL; |
for (pn = & runpath; |
*pn != NULL; |
pn = &(*pn)->next) |
; |
*pn = n; |
} |
/* Ignore DT_RPATH if we have seen DT_RUNPATH. */ |
if (!runpath && dyn.d_tag == DT_RPATH) |
{ |
struct bfd_link_needed_list *n, **pn; |
char *fnm, *anm; |
unsigned int tagv = dyn.d_un.d_val; |
amt = sizeof (struct bfd_link_needed_list); |
n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt); |
fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv); |
if (n == NULL || fnm == NULL) |
goto error_free_dyn; |
amt = strlen (fnm) + 1; |
anm = (char *) bfd_alloc (abfd, amt); |
if (anm == NULL) |
goto error_free_dyn; |
memcpy (anm, fnm, amt); |
n->name = anm; |
n->by = abfd; |
n->next = NULL; |
for (pn = & rpath; |
*pn != NULL; |
pn = &(*pn)->next) |
; |
*pn = n; |
} |
if (dyn.d_tag == DT_AUDIT) |
{ |
unsigned int tagv = dyn.d_un.d_val; |
audit = bfd_elf_string_from_elf_section (abfd, shlink, tagv); |
} |
} |
free (dynbuf); |
} |
/* DT_RUNPATH overrides DT_RPATH. Do _NOT_ bfd_release, as that |
frees all more recently bfd_alloc'd blocks as well. */ |
if (runpath) |
rpath = runpath; |
if (rpath) |
{ |
struct bfd_link_needed_list **pn; |
for (pn = &htab->runpath; *pn != NULL; pn = &(*pn)->next) |
; |
*pn = rpath; |
} |
/* We do not want to include any of the sections in a dynamic |
object in the output file. We hack by simply clobbering the |
list of sections in the BFD. This could be handled more |
cleanly by, say, a new section flag; the existing |
SEC_NEVER_LOAD flag is not the one we want, because that one |
still implies that the section takes up space in the output |
file. */ |
bfd_section_list_clear (abfd); |
/* Find the name to use in a DT_NEEDED entry that refers to this |
object. If the object has a DT_SONAME entry, we use it. |
Otherwise, if the generic linker stuck something in |
elf_dt_name, we use that. Otherwise, we just use the file |
name. */ |
if (soname == NULL || *soname == '\0') |
{ |
soname = elf_dt_name (abfd); |
if (soname == NULL || *soname == '\0') |
soname = bfd_get_filename (abfd); |
} |
/* Save the SONAME because sometimes the linker emulation code |
will need to know it. */ |
elf_dt_name (abfd) = soname; |
ret = elf_add_dt_needed_tag (abfd, info, soname, add_needed); |
if (ret < 0) |
goto error_return; |
/* If we have already included this dynamic object in the |
link, just ignore it. There is no reason to include a |
particular dynamic object more than once. */ |
if (ret > 0) |
return TRUE; |
/* Save the DT_AUDIT entry for the linker emulation code. */ |
elf_dt_audit (abfd) = audit; |
} |
/* If this is a dynamic object, we always link against the .dynsym |
symbol table, not the .symtab symbol table. The dynamic linker |
will only see the .dynsym symbol table, so there is no reason to |
look at .symtab for a dynamic object. */ |
if (! dynamic || elf_dynsymtab (abfd) == 0) |
hdr = &elf_tdata (abfd)->symtab_hdr; |
else |
hdr = &elf_tdata (abfd)->dynsymtab_hdr; |
symcount = hdr->sh_size / bed->s->sizeof_sym; |
/* The sh_info field of the symtab header tells us where the |
external symbols start. We don't care about the local symbols at |
this point. */ |
if (elf_bad_symtab (abfd)) |
{ |
extsymcount = symcount; |
extsymoff = 0; |
} |
else |
{ |
extsymcount = symcount - hdr->sh_info; |
extsymoff = hdr->sh_info; |
} |
sym_hash = elf_sym_hashes (abfd); |
if (extsymcount != 0) |
{ |
isymbuf = bfd_elf_get_elf_syms (abfd, hdr, extsymcount, extsymoff, |
NULL, NULL, NULL); |
if (isymbuf == NULL) |
goto error_return; |
if (sym_hash == NULL) |
{ |
/* We store a pointer to the hash table entry for each |
external symbol. */ |
amt = extsymcount * sizeof (struct elf_link_hash_entry *); |
sym_hash = (struct elf_link_hash_entry **) bfd_zalloc (abfd, amt); |
if (sym_hash == NULL) |
goto error_free_sym; |
elf_sym_hashes (abfd) = sym_hash; |
} |
} |
if (dynamic) |
{ |
/* Read in any version definitions. */ |
if (!_bfd_elf_slurp_version_tables (abfd, |
info->default_imported_symver)) |
goto error_free_sym; |
/* Read in the symbol versions, but don't bother to convert them |
to internal format. */ |
if (elf_dynversym (abfd) != 0) |
{ |
Elf_Internal_Shdr *versymhdr; |
versymhdr = &elf_tdata (abfd)->dynversym_hdr; |
extversym = (Elf_External_Versym *) bfd_malloc (versymhdr->sh_size); |
if (extversym == NULL) |
goto error_free_sym; |
amt = versymhdr->sh_size; |
if (bfd_seek (abfd, versymhdr->sh_offset, SEEK_SET) != 0 |
|| bfd_bread (extversym, amt, abfd) != amt) |
goto error_free_vers; |
} |
} |
/* If we are loading an as-needed shared lib, save the symbol table |
state before we start adding symbols. If the lib turns out |
to be unneeded, restore the state. */ |
if ((elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0) |
{ |
unsigned int i; |
size_t entsize; |
for (entsize = 0, i = 0; i < htab->root.table.size; i++) |
{ |
struct bfd_hash_entry *p; |
struct elf_link_hash_entry *h; |
for (p = htab->root.table.table[i]; p != NULL; p = p->next) |
{ |
h = (struct elf_link_hash_entry *) p; |
entsize += htab->root.table.entsize; |
if (h->root.type == bfd_link_hash_warning) |
entsize += htab->root.table.entsize; |
} |
} |
tabsize = htab->root.table.size * sizeof (struct bfd_hash_entry *); |
old_tab = bfd_malloc (tabsize + entsize); |
if (old_tab == NULL) |
goto error_free_vers; |
/* Remember the current objalloc pointer, so that all mem for |
symbols added can later be reclaimed. */ |
alloc_mark = bfd_hash_allocate (&htab->root.table, 1); |
if (alloc_mark == NULL) |
goto error_free_vers; |
/* Make a special call to the linker "notice" function to |
tell it that we are about to handle an as-needed lib. */ |
if (!(*bed->notice_as_needed) (abfd, info, notice_as_needed)) |
goto error_free_vers; |
/* Clone the symbol table. Remember some pointers into the |
symbol table, and dynamic symbol count. */ |
old_ent = (char *) old_tab + tabsize; |
memcpy (old_tab, htab->root.table.table, tabsize); |
old_undefs = htab->root.undefs; |
old_undefs_tail = htab->root.undefs_tail; |
old_table = htab->root.table.table; |
old_size = htab->root.table.size; |
old_count = htab->root.table.count; |
old_dynsymcount = htab->dynsymcount; |
old_dynstr_size = _bfd_elf_strtab_size (htab->dynstr); |
for (i = 0; i < htab->root.table.size; i++) |
{ |
struct bfd_hash_entry *p; |
struct elf_link_hash_entry *h; |
for (p = htab->root.table.table[i]; p != NULL; p = p->next) |
{ |
memcpy (old_ent, p, htab->root.table.entsize); |
old_ent = (char *) old_ent + htab->root.table.entsize; |
h = (struct elf_link_hash_entry *) p; |
if (h->root.type == bfd_link_hash_warning) |
{ |
memcpy (old_ent, h->root.u.i.link, htab->root.table.entsize); |
old_ent = (char *) old_ent + htab->root.table.entsize; |
} |
} |
} |
} |
weaks = NULL; |
ever = extversym != NULL ? extversym + extsymoff : NULL; |
for (isym = isymbuf, isymend = isymbuf + extsymcount; |
isym < isymend; |
isym++, sym_hash++, ever = (ever != NULL ? ever + 1 : NULL)) |
{ |
int bind; |
bfd_vma value; |
asection *sec, *new_sec; |
flagword flags; |
const char *name; |
struct elf_link_hash_entry *h; |
struct elf_link_hash_entry *hi; |
bfd_boolean definition; |
bfd_boolean size_change_ok; |
bfd_boolean type_change_ok; |
bfd_boolean new_weakdef; |
bfd_boolean new_weak; |
bfd_boolean old_weak; |
bfd_boolean override; |
bfd_boolean common; |
unsigned int old_alignment; |
bfd *old_bfd; |
override = FALSE; |
flags = BSF_NO_FLAGS; |
sec = NULL; |
value = isym->st_value; |
common = bed->common_definition (isym); |
bind = ELF_ST_BIND (isym->st_info); |
switch (bind) |
{ |
case STB_LOCAL: |
/* This should be impossible, since ELF requires that all |
global symbols follow all local symbols, and that sh_info |
point to the first global symbol. Unfortunately, Irix 5 |
screws this up. */ |
continue; |
case STB_GLOBAL: |
if (isym->st_shndx != SHN_UNDEF && !common) |
flags = BSF_GLOBAL; |
break; |
case STB_WEAK: |
flags = BSF_WEAK; |
break; |
case STB_GNU_UNIQUE: |
flags = BSF_GNU_UNIQUE; |
break; |
default: |
/* Leave it up to the processor backend. */ |
break; |
} |
if (isym->st_shndx == SHN_UNDEF) |
sec = bfd_und_section_ptr; |
else if (isym->st_shndx == SHN_ABS) |
sec = bfd_abs_section_ptr; |
else if (isym->st_shndx == SHN_COMMON) |
{ |
sec = bfd_com_section_ptr; |
/* What ELF calls the size we call the value. What ELF |
calls the value we call the alignment. */ |
value = isym->st_size; |
} |
else |
{ |
sec = bfd_section_from_elf_index (abfd, isym->st_shndx); |
if (sec == NULL) |
sec = bfd_abs_section_ptr; |
else if (discarded_section (sec)) |
{ |
/* Symbols from discarded section are undefined. We keep |
its visibility. */ |
sec = bfd_und_section_ptr; |
isym->st_shndx = SHN_UNDEF; |
} |
else if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0) |
value -= sec->vma; |
} |
name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link, |
isym->st_name); |
if (name == NULL) |
goto error_free_vers; |
if (isym->st_shndx == SHN_COMMON |
&& (abfd->flags & BFD_PLUGIN) != 0) |
{ |
asection *xc = bfd_get_section_by_name (abfd, "COMMON"); |
if (xc == NULL) |
{ |
flagword sflags = (SEC_ALLOC | SEC_IS_COMMON | SEC_KEEP |
| SEC_EXCLUDE); |
xc = bfd_make_section_with_flags (abfd, "COMMON", sflags); |
if (xc == NULL) |
goto error_free_vers; |
} |
sec = xc; |
} |
else if (isym->st_shndx == SHN_COMMON |
&& ELF_ST_TYPE (isym->st_info) == STT_TLS |
&& !info->relocatable) |
{ |
asection *tcomm = bfd_get_section_by_name (abfd, ".tcommon"); |
if (tcomm == NULL) |
{ |
flagword sflags = (SEC_ALLOC | SEC_THREAD_LOCAL | SEC_IS_COMMON |
| SEC_LINKER_CREATED); |
tcomm = bfd_make_section_with_flags (abfd, ".tcommon", sflags); |
if (tcomm == NULL) |
goto error_free_vers; |
} |
sec = tcomm; |
} |
else if (bed->elf_add_symbol_hook) |
{ |
if (! (*bed->elf_add_symbol_hook) (abfd, info, isym, &name, &flags, |
&sec, &value)) |
goto error_free_vers; |
/* The hook function sets the name to NULL if this symbol |
should be skipped for some reason. */ |
if (name == NULL) |
continue; |
} |
/* Sanity check that all possibilities were handled. */ |
if (sec == NULL) |
{ |
bfd_set_error (bfd_error_bad_value); |
goto error_free_vers; |
} |
/* Silently discard TLS symbols from --just-syms. There's |
no way to combine a static TLS block with a new TLS block |
for this executable. */ |
if (ELF_ST_TYPE (isym->st_info) == STT_TLS |
&& sec->sec_info_type == SEC_INFO_TYPE_JUST_SYMS) |
continue; |
if (bfd_is_und_section (sec) |
|| bfd_is_com_section (sec)) |
definition = FALSE; |
else |
definition = TRUE; |
size_change_ok = FALSE; |
type_change_ok = bed->type_change_ok; |
old_weak = FALSE; |
old_alignment = 0; |
old_bfd = NULL; |
new_sec = sec; |
if (is_elf_hash_table (htab)) |
{ |
Elf_Internal_Versym iver; |
unsigned int vernum = 0; |
bfd_boolean skip; |
if (ever == NULL) |
{ |
if (info->default_imported_symver) |
/* Use the default symbol version created earlier. */ |
iver.vs_vers = elf_tdata (abfd)->cverdefs; |
else |
iver.vs_vers = 0; |
} |
else |
_bfd_elf_swap_versym_in (abfd, ever, &iver); |
vernum = iver.vs_vers & VERSYM_VERSION; |
/* If this is a hidden symbol, or if it is not version |
1, we append the version name to the symbol name. |
However, we do not modify a non-hidden absolute symbol |
if it is not a function, because it might be the version |
symbol itself. FIXME: What if it isn't? */ |
if ((iver.vs_vers & VERSYM_HIDDEN) != 0 |
|| (vernum > 1 |
&& (!bfd_is_abs_section (sec) |
|| bed->is_function_type (ELF_ST_TYPE (isym->st_info))))) |
{ |
const char *verstr; |
size_t namelen, verlen, newlen; |
char *newname, *p; |
if (isym->st_shndx != SHN_UNDEF) |
{ |
if (vernum > elf_tdata (abfd)->cverdefs) |
verstr = NULL; |
else if (vernum > 1) |
verstr = |
elf_tdata (abfd)->verdef[vernum - 1].vd_nodename; |
else |
verstr = ""; |
if (verstr == NULL) |
{ |
(*_bfd_error_handler) |
(_("%B: %s: invalid version %u (max %d)"), |
abfd, name, vernum, |
elf_tdata (abfd)->cverdefs); |
bfd_set_error (bfd_error_bad_value); |
goto error_free_vers; |
} |
} |
else |
{ |
/* We cannot simply test for the number of |
entries in the VERNEED section since the |
numbers for the needed versions do not start |
at 0. */ |
Elf_Internal_Verneed *t; |
verstr = NULL; |
for (t = elf_tdata (abfd)->verref; |
t != NULL; |
t = t->vn_nextref) |
{ |
Elf_Internal_Vernaux *a; |
for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr) |
{ |
if (a->vna_other == vernum) |
{ |
verstr = a->vna_nodename; |
break; |
} |
} |
if (a != NULL) |
break; |
} |
if (verstr == NULL) |
{ |
(*_bfd_error_handler) |
(_("%B: %s: invalid needed version %d"), |
abfd, name, vernum); |
bfd_set_error (bfd_error_bad_value); |
goto error_free_vers; |
} |
} |
namelen = strlen (name); |
verlen = strlen (verstr); |
newlen = namelen + verlen + 2; |
if ((iver.vs_vers & VERSYM_HIDDEN) == 0 |
&& isym->st_shndx != SHN_UNDEF) |
++newlen; |
newname = (char *) bfd_hash_allocate (&htab->root.table, newlen); |
if (newname == NULL) |
goto error_free_vers; |
memcpy (newname, name, namelen); |
p = newname + namelen; |
*p++ = ELF_VER_CHR; |
/* If this is a defined non-hidden version symbol, |
we add another @ to the name. This indicates the |
default version of the symbol. */ |
if ((iver.vs_vers & VERSYM_HIDDEN) == 0 |
&& isym->st_shndx != SHN_UNDEF) |
*p++ = ELF_VER_CHR; |
memcpy (p, verstr, verlen + 1); |
name = newname; |
} |
if (!_bfd_elf_merge_symbol (abfd, info, name, isym, &sec, &value, |
sym_hash, &old_bfd, &old_weak, |
&old_alignment, &skip, &override, |
&type_change_ok, &size_change_ok)) |
goto error_free_vers; |
if (skip) |
continue; |
if (override) |
definition = FALSE; |
h = *sym_hash; |
while (h->root.type == bfd_link_hash_indirect |
|| h->root.type == bfd_link_hash_warning) |
h = (struct elf_link_hash_entry *) h->root.u.i.link; |
if (elf_tdata (abfd)->verdef != NULL |
&& vernum > 1 |
&& definition) |
h->verinfo.verdef = &elf_tdata (abfd)->verdef[vernum - 1]; |
} |
if (! (_bfd_generic_link_add_one_symbol |
(info, abfd, name, flags, sec, value, NULL, FALSE, bed->collect, |
(struct bfd_link_hash_entry **) sym_hash))) |
goto error_free_vers; |
h = *sym_hash; |
/* We need to make sure that indirect symbol dynamic flags are |
updated. */ |
hi = h; |
while (h->root.type == bfd_link_hash_indirect |
|| h->root.type == bfd_link_hash_warning) |
h = (struct elf_link_hash_entry *) h->root.u.i.link; |
*sym_hash = h; |
new_weak = (flags & BSF_WEAK) != 0; |
new_weakdef = FALSE; |
if (dynamic |
&& definition |
&& new_weak |
&& !bed->is_function_type (ELF_ST_TYPE (isym->st_info)) |
&& is_elf_hash_table (htab) |
&& h->u.weakdef == NULL) |
{ |
/* Keep a list of all weak defined non function symbols from |
a dynamic object, using the weakdef field. Later in this |
function we will set the weakdef field to the correct |
value. We only put non-function symbols from dynamic |
objects on this list, because that happens to be the only |
time we need to know the normal symbol corresponding to a |
weak symbol, and the information is time consuming to |
figure out. If the weakdef field is not already NULL, |
then this symbol was already defined by some previous |
dynamic object, and we will be using that previous |
definition anyhow. */ |
h->u.weakdef = weaks; |
weaks = h; |
new_weakdef = TRUE; |
} |
/* Set the alignment of a common symbol. */ |
if ((common || bfd_is_com_section (sec)) |
&& h->root.type == bfd_link_hash_common) |
{ |
unsigned int align; |
if (common) |
align = bfd_log2 (isym->st_value); |
else |
{ |
/* The new symbol is a common symbol in a shared object. |
We need to get the alignment from the section. */ |
align = new_sec->alignment_power; |
} |
if (align > old_alignment) |
h->root.u.c.p->alignment_power = align; |
else |
h->root.u.c.p->alignment_power = old_alignment; |
} |
if (is_elf_hash_table (htab)) |
{ |
/* Set a flag in the hash table entry indicating the type of |
reference or definition we just found. A dynamic symbol |
is one which is referenced or defined by both a regular |
object and a shared object. */ |
bfd_boolean dynsym = FALSE; |
/* Plugin symbols aren't normal. Don't set def_regular or |
ref_regular for them, or make them dynamic. */ |
if ((abfd->flags & BFD_PLUGIN) != 0) |
; |
else if (! dynamic) |
{ |
if (! definition) |
{ |
h->ref_regular = 1; |
if (bind != STB_WEAK) |
h->ref_regular_nonweak = 1; |
} |
else |
{ |
h->def_regular = 1; |
if (h->def_dynamic) |
{ |
h->def_dynamic = 0; |
h->ref_dynamic = 1; |
} |
} |
/* If the indirect symbol has been forced local, don't |
make the real symbol dynamic. */ |
if ((h == hi || !hi->forced_local) |
&& (! info->executable |
|| h->def_dynamic |
|| h->ref_dynamic)) |
dynsym = TRUE; |
} |
else |
{ |
if (! definition) |
{ |
h->ref_dynamic = 1; |
hi->ref_dynamic = 1; |
} |
else |
{ |
h->def_dynamic = 1; |
hi->def_dynamic = 1; |
} |
/* If the indirect symbol has been forced local, don't |
make the real symbol dynamic. */ |
if ((h == hi || !hi->forced_local) |
&& (h->def_regular |
|| h->ref_regular |
|| (h->u.weakdef != NULL |
&& ! new_weakdef |
&& h->u.weakdef->dynindx != -1))) |
dynsym = TRUE; |
} |
/* Check to see if we need to add an indirect symbol for |
the default name. */ |
if (definition |
|| (!override && h->root.type == bfd_link_hash_common)) |
if (!_bfd_elf_add_default_symbol (abfd, info, h, name, isym, |
sec, value, &old_bfd, &dynsym)) |
goto error_free_vers; |
/* Check the alignment when a common symbol is involved. This |
can change when a common symbol is overridden by a normal |
definition or a common symbol is ignored due to the old |
normal definition. We need to make sure the maximum |
alignment is maintained. */ |
if ((old_alignment || common) |
&& h->root.type != bfd_link_hash_common) |
{ |
unsigned int common_align; |
unsigned int normal_align; |
unsigned int symbol_align; |
bfd *normal_bfd; |
bfd *common_bfd; |
BFD_ASSERT (h->root.type == bfd_link_hash_defined |
|| h->root.type == bfd_link_hash_defweak); |
symbol_align = ffs (h->root.u.def.value) - 1; |
if (h->root.u.def.section->owner != NULL |
&& (h->root.u.def.section->owner->flags & DYNAMIC) == 0) |
{ |
normal_align = h->root.u.def.section->alignment_power; |
if (normal_align > symbol_align) |
normal_align = symbol_align; |
} |
else |
normal_align = symbol_align; |
if (old_alignment) |
{ |
common_align = old_alignment; |
common_bfd = old_bfd; |
normal_bfd = abfd; |
} |
else |
{ |
common_align = bfd_log2 (isym->st_value); |
common_bfd = abfd; |
normal_bfd = old_bfd; |
} |
if (normal_align < common_align) |
{ |
/* PR binutils/2735 */ |
if (normal_bfd == NULL) |
(*_bfd_error_handler) |
(_("Warning: alignment %u of common symbol `%s' in %B is" |
" greater than the alignment (%u) of its section %A"), |
common_bfd, h->root.u.def.section, |
1 << common_align, name, 1 << normal_align); |
else |
(*_bfd_error_handler) |
(_("Warning: alignment %u of symbol `%s' in %B" |
" is smaller than %u in %B"), |
normal_bfd, common_bfd, |
1 << normal_align, name, 1 << common_align); |
} |
} |
/* Remember the symbol size if it isn't undefined. */ |
if (isym->st_size != 0 |
&& isym->st_shndx != SHN_UNDEF |
&& (definition || h->size == 0)) |
{ |
if (h->size != 0 |
&& h->size != isym->st_size |
&& ! size_change_ok) |
(*_bfd_error_handler) |
(_("Warning: size of symbol `%s' changed" |
" from %lu in %B to %lu in %B"), |
old_bfd, abfd, |
name, (unsigned long) h->size, |
(unsigned long) isym->st_size); |
h->size = isym->st_size; |
} |
/* If this is a common symbol, then we always want H->SIZE |
to be the size of the common symbol. The code just above |
won't fix the size if a common symbol becomes larger. We |
don't warn about a size change here, because that is |
covered by --warn-common. Allow changes between different |
function types. */ |
if (h->root.type == bfd_link_hash_common) |
h->size = h->root.u.c.size; |
if (ELF_ST_TYPE (isym->st_info) != STT_NOTYPE |
&& ((definition && !new_weak) |
|| (old_weak && h->root.type == bfd_link_hash_common) |
|| h->type == STT_NOTYPE)) |
{ |
unsigned int type = ELF_ST_TYPE (isym->st_info); |
/* Turn an IFUNC symbol from a DSO into a normal FUNC |
symbol. */ |
if (type == STT_GNU_IFUNC |
&& (abfd->flags & DYNAMIC) != 0) |
type = STT_FUNC; |
if (h->type != type) |
{ |
if (h->type != STT_NOTYPE && ! type_change_ok) |
(*_bfd_error_handler) |
(_("Warning: type of symbol `%s' changed" |
" from %d to %d in %B"), |
abfd, name, h->type, type); |
h->type = type; |
} |
} |
/* Merge st_other field. */ |
elf_merge_st_other (abfd, h, isym, definition, dynamic); |
/* We don't want to make debug symbol dynamic. */ |
if (definition && (sec->flags & SEC_DEBUGGING) && !info->relocatable) |
dynsym = FALSE; |
/* Nor should we make plugin symbols dynamic. */ |
if ((abfd->flags & BFD_PLUGIN) != 0) |
dynsym = FALSE; |
if (definition) |
{ |
h->target_internal = isym->st_target_internal; |
h->unique_global = (flags & BSF_GNU_UNIQUE) != 0; |
} |
if (definition && !dynamic) |
{ |
char *p = strchr (name, ELF_VER_CHR); |
if (p != NULL && p[1] != ELF_VER_CHR) |
{ |
/* Queue non-default versions so that .symver x, x@FOO |
aliases can be checked. */ |
if (!nondeflt_vers) |
{ |
amt = ((isymend - isym + 1) |
* sizeof (struct elf_link_hash_entry *)); |
nondeflt_vers = |
(struct elf_link_hash_entry **) bfd_malloc (amt); |
if (!nondeflt_vers) |
goto error_free_vers; |
} |
nondeflt_vers[nondeflt_vers_cnt++] = h; |
} |
} |
if (dynsym && h->dynindx == -1) |
{ |
if (! bfd_elf_link_record_dynamic_symbol (info, h)) |
goto error_free_vers; |
if (h->u.weakdef != NULL |
&& ! new_weakdef |
&& h->u.weakdef->dynindx == -1) |
{ |
if (!bfd_elf_link_record_dynamic_symbol (info, h->u.weakdef)) |
goto error_free_vers; |
} |
} |
else if (dynsym && h->dynindx != -1) |
/* If the symbol already has a dynamic index, but |
visibility says it should not be visible, turn it into |
a local symbol. */ |
switch (ELF_ST_VISIBILITY (h->other)) |
{ |
case STV_INTERNAL: |
case STV_HIDDEN: |
(*bed->elf_backend_hide_symbol) (info, h, TRUE); |
dynsym = FALSE; |
break; |
} |
/* Don't add DT_NEEDED for references from the dummy bfd. */ |
if (!add_needed |
&& definition |
&& ((dynsym |
&& h->ref_regular_nonweak |
&& (old_bfd == NULL |
|| (old_bfd->flags & BFD_PLUGIN) == 0)) |
|| (h->ref_dynamic_nonweak |
&& (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0 |
&& !on_needed_list (elf_dt_name (abfd), htab->needed)))) |
{ |
int ret; |
const char *soname = elf_dt_name (abfd); |
/* A symbol from a library loaded via DT_NEEDED of some |
other library is referenced by a regular object. |
Add a DT_NEEDED entry for it. Issue an error if |
--no-add-needed is used and the reference was not |
a weak one. */ |
if (old_bfd != NULL |
&& (elf_dyn_lib_class (abfd) & DYN_NO_NEEDED) != 0) |
{ |
(*_bfd_error_handler) |
(_("%B: undefined reference to symbol '%s'"), |
old_bfd, name); |
bfd_set_error (bfd_error_missing_dso); |
goto error_free_vers; |
} |
elf_dyn_lib_class (abfd) = (enum dynamic_lib_link_class) |
(elf_dyn_lib_class (abfd) & ~DYN_AS_NEEDED); |
add_needed = TRUE; |
ret = elf_add_dt_needed_tag (abfd, info, soname, add_needed); |
if (ret < 0) |
goto error_free_vers; |
BFD_ASSERT (ret == 0); |
} |
} |
} |
if (extversym != NULL) |
{ |
free (extversym); |
extversym = NULL; |
} |
if (isymbuf != NULL) |
{ |
free (isymbuf); |
isymbuf = NULL; |
} |
if ((elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0) |
{ |
unsigned int i; |
/* Restore the symbol table. */ |
old_ent = (char *) old_tab + tabsize; |
memset (elf_sym_hashes (abfd), 0, |
extsymcount * sizeof (struct elf_link_hash_entry *)); |
htab->root.table.table = old_table; |
htab->root.table.size = old_size; |
htab->root.table.count = old_count; |
memcpy (htab->root.table.table, old_tab, tabsize); |
htab->root.undefs = old_undefs; |
htab->root.undefs_tail = old_undefs_tail; |
_bfd_elf_strtab_restore_size (htab->dynstr, old_dynstr_size); |
for (i = 0; i < htab->root.table.size; i++) |
{ |
struct bfd_hash_entry *p; |
struct elf_link_hash_entry *h; |
bfd_size_type size; |
unsigned int alignment_power; |
for (p = htab->root.table.table[i]; p != NULL; p = p->next) |
{ |
h = (struct elf_link_hash_entry *) p; |
if (h->root.type == bfd_link_hash_warning) |
h = (struct elf_link_hash_entry *) h->root.u.i.link; |
if (h->dynindx >= old_dynsymcount |
&& h->dynstr_index < old_dynstr_size) |
_bfd_elf_strtab_delref (htab->dynstr, h->dynstr_index); |
/* Preserve the maximum alignment and size for common |
symbols even if this dynamic lib isn't on DT_NEEDED |
since it can still be loaded at run time by another |
dynamic lib. */ |
if (h->root.type == bfd_link_hash_common) |
{ |
size = h->root.u.c.size; |
alignment_power = h->root.u.c.p->alignment_power; |
} |
else |
{ |
size = 0; |
alignment_power = 0; |
} |
memcpy (p, old_ent, htab->root.table.entsize); |
old_ent = (char *) old_ent + htab->root.table.entsize; |
h = (struct elf_link_hash_entry *) p; |
if (h->root.type == bfd_link_hash_warning) |
{ |
memcpy (h->root.u.i.link, old_ent, htab->root.table.entsize); |
old_ent = (char *) old_ent + htab->root.table.entsize; |
h = (struct elf_link_hash_entry *) h->root.u.i.link; |
} |
if (h->root.type == bfd_link_hash_common) |
{ |
if (size > h->root.u.c.size) |
h->root.u.c.size = size; |
if (alignment_power > h->root.u.c.p->alignment_power) |
h->root.u.c.p->alignment_power = alignment_power; |
} |
} |
} |
/* Make a special call to the linker "notice" function to |
tell it that symbols added for crefs may need to be removed. */ |
if (!(*bed->notice_as_needed) (abfd, info, notice_not_needed)) |
goto error_free_vers; |
free (old_tab); |
objalloc_free_block ((struct objalloc *) htab->root.table.memory, |
alloc_mark); |
if (nondeflt_vers != NULL) |
free (nondeflt_vers); |
return TRUE; |
} |
if (old_tab != NULL) |
{ |
if (!(*bed->notice_as_needed) (abfd, info, notice_needed)) |
goto error_free_vers; |
free (old_tab); |
old_tab = NULL; |
} |
/* Now that all the symbols from this input file are created, handle |
.symver foo, foo@BAR such that any relocs against foo become foo@BAR. */ |
if (nondeflt_vers != NULL) |
{ |
bfd_size_type cnt, symidx; |
for (cnt = 0; cnt < nondeflt_vers_cnt; ++cnt) |
{ |
struct elf_link_hash_entry *h = nondeflt_vers[cnt], *hi; |
char *shortname, *p; |
p = strchr (h->root.root.string, ELF_VER_CHR); |
if (p == NULL |
|| (h->root.type != bfd_link_hash_defined |
&& h->root.type != bfd_link_hash_defweak)) |
continue; |
amt = p - h->root.root.string; |
shortname = (char *) bfd_malloc (amt + 1); |
if (!shortname) |
goto error_free_vers; |
memcpy (shortname, h->root.root.string, amt); |
shortname[amt] = '\0'; |
hi = (struct elf_link_hash_entry *) |
bfd_link_hash_lookup (&htab->root, shortname, |
FALSE, FALSE, FALSE); |
if (hi != NULL |
&& hi->root.type == h->root.type |
&& hi->root.u.def.value == h->root.u.def.value |
&& hi->root.u.def.section == h->root.u.def.section) |
{ |
(*bed->elf_backend_hide_symbol) (info, hi, TRUE); |
hi->root.type = bfd_link_hash_indirect; |
hi->root.u.i.link = (struct bfd_link_hash_entry *) h; |
(*bed->elf_backend_copy_indirect_symbol) (info, h, hi); |
sym_hash = elf_sym_hashes (abfd); |
if (sym_hash) |
for (symidx = 0; symidx < extsymcount; ++symidx) |
if (sym_hash[symidx] == hi) |
{ |
sym_hash[symidx] = h; |
break; |
} |
} |
free (shortname); |
} |
free (nondeflt_vers); |
nondeflt_vers = NULL; |
} |
/* Now set the weakdefs field correctly for all the weak defined |
symbols we found. The only way to do this is to search all the |
symbols. Since we only need the information for non functions in |
dynamic objects, that's the only time we actually put anything on |
the list WEAKS. We need this information so that if a regular |
object refers to a symbol defined weakly in a dynamic object, the |
real symbol in the dynamic object is also put in the dynamic |
symbols; we also must arrange for both symbols to point to the |
same memory location. We could handle the general case of symbol |
aliasing, but a general symbol alias can only be generated in |
assembler code, handling it correctly would be very time |
consuming, and other ELF linkers don't handle general aliasing |
either. */ |
if (weaks != NULL) |
{ |
struct elf_link_hash_entry **hpp; |
struct elf_link_hash_entry **hppend; |
struct elf_link_hash_entry **sorted_sym_hash; |
struct elf_link_hash_entry *h; |
size_t sym_count; |
/* Since we have to search the whole symbol list for each weak |
defined symbol, search time for N weak defined symbols will be |
O(N^2). Binary search will cut it down to O(NlogN). */ |
amt = extsymcount * sizeof (struct elf_link_hash_entry *); |
sorted_sym_hash = (struct elf_link_hash_entry **) bfd_malloc (amt); |
if (sorted_sym_hash == NULL) |
goto error_return; |
sym_hash = sorted_sym_hash; |
hpp = elf_sym_hashes (abfd); |
hppend = hpp + extsymcount; |
sym_count = 0; |
for (; hpp < hppend; hpp++) |
{ |
h = *hpp; |
if (h != NULL |
&& h->root.type == bfd_link_hash_defined |
&& !bed->is_function_type (h->type)) |
{ |
*sym_hash = h; |
sym_hash++; |
sym_count++; |
} |
} |
qsort (sorted_sym_hash, sym_count, |
sizeof (struct elf_link_hash_entry *), |
elf_sort_symbol); |
while (weaks != NULL) |
{ |
struct elf_link_hash_entry *hlook; |
asection *slook; |
bfd_vma vlook; |
size_t i, j, idx = 0; |
hlook = weaks; |
weaks = hlook->u.weakdef; |
hlook->u.weakdef = NULL; |
BFD_ASSERT (hlook->root.type == bfd_link_hash_defined |
|| hlook->root.type == bfd_link_hash_defweak |
|| hlook->root.type == bfd_link_hash_common |
|| hlook->root.type == bfd_link_hash_indirect); |
slook = hlook->root.u.def.section; |
vlook = hlook->root.u.def.value; |
i = 0; |
j = sym_count; |
while (i != j) |
{ |
bfd_signed_vma vdiff; |
idx = (i + j) / 2; |
h = sorted_sym_hash[idx]; |
vdiff = vlook - h->root.u.def.value; |
if (vdiff < 0) |
j = idx; |
else if (vdiff > 0) |
i = idx + 1; |
else |
{ |
long sdiff = slook->id - h->root.u.def.section->id; |
if (sdiff < 0) |
j = idx; |
else if (sdiff > 0) |
i = idx + 1; |
else |
break; |
} |
} |
/* We didn't find a value/section match. */ |
if (i == j) |
continue; |
/* With multiple aliases, or when the weak symbol is already |
strongly defined, we have multiple matching symbols and |
the binary search above may land on any of them. Step |
one past the matching symbol(s). */ |
while (++idx != j) |
{ |
h = sorted_sym_hash[idx]; |
if (h->root.u.def.section != slook |
|| h->root.u.def.value != vlook) |
break; |
} |
/* Now look back over the aliases. Since we sorted by size |
as well as value and section, we'll choose the one with |
the largest size. */ |
while (idx-- != i) |
{ |
h = sorted_sym_hash[idx]; |
/* Stop if value or section doesn't match. */ |
if (h->root.u.def.section != slook |
|| h->root.u.def.value != vlook) |
break; |
else if (h != hlook) |
{ |
hlook->u.weakdef = h; |
/* If the weak definition is in the list of dynamic |
symbols, make sure the real definition is put |
there as well. */ |
if (hlook->dynindx != -1 && h->dynindx == -1) |
{ |
if (! bfd_elf_link_record_dynamic_symbol (info, h)) |
{ |
err_free_sym_hash: |
free (sorted_sym_hash); |
goto error_return; |
} |
} |
/* If the real definition is in the list of dynamic |
symbols, make sure the weak definition is put |
there as well. If we don't do this, then the |
dynamic loader might not merge the entries for the |
real definition and the weak definition. */ |
if (h->dynindx != -1 && hlook->dynindx == -1) |
{ |
if (! bfd_elf_link_record_dynamic_symbol (info, hlook)) |
goto err_free_sym_hash; |
} |
break; |
} |
} |
} |
free (sorted_sym_hash); |
} |
if (bed->check_directives |
&& !(*bed->check_directives) (abfd, info)) |
return FALSE; |
/* If this object is the same format as the output object, and it is |
not a shared library, then let the backend look through the |
relocs. |
This is required to build global offset table entries and to |
arrange for dynamic relocs. It is not required for the |
particular common case of linking non PIC code, even when linking |
against shared libraries, but unfortunately there is no way of |
knowing whether an object file has been compiled PIC or not. |
Looking through the relocs is not particularly time consuming. |
The problem is that we must either (1) keep the relocs in memory, |
which causes the linker to require additional runtime memory or |
(2) read the relocs twice from the input file, which wastes time. |
This would be a good case for using mmap. |
I have no idea how to handle linking PIC code into a file of a |
different format. It probably can't be done. */ |
if (! dynamic |
&& is_elf_hash_table (htab) |
&& bed->check_relocs != NULL |
&& elf_object_id (abfd) == elf_hash_table_id (htab) |
&& (*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec)) |
{ |
asection *o; |
for (o = abfd->sections; o != NULL; o = o->next) |
{ |
Elf_Internal_Rela *internal_relocs; |
bfd_boolean ok; |
if ((o->flags & SEC_RELOC) == 0 |
|| o->reloc_count == 0 |
|| ((info->strip == strip_all || info->strip == strip_debugger) |
&& (o->flags & SEC_DEBUGGING) != 0) |
|| bfd_is_abs_section (o->output_section)) |
continue; |
internal_relocs = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL, |
info->keep_memory); |
if (internal_relocs == NULL) |
goto error_return; |
ok = (*bed->check_relocs) (abfd, info, o, internal_relocs); |
if (elf_section_data (o)->relocs != internal_relocs) |
free (internal_relocs); |
if (! ok) |
goto error_return; |
} |
} |
/* If this is a non-traditional link, try to optimize the handling |
of the .stab/.stabstr sections. */ |
if (! dynamic |
&& ! info->traditional_format |
&& is_elf_hash_table (htab) |
&& (info->strip != strip_all && info->strip != strip_debugger)) |
{ |
asection *stabstr; |
stabstr = bfd_get_section_by_name (abfd, ".stabstr"); |
if (stabstr != NULL) |
{ |
bfd_size_type string_offset = 0; |
asection *stab; |
for (stab = abfd->sections; stab; stab = stab->next) |
if (CONST_STRNEQ (stab->name, ".stab") |
&& (!stab->name[5] || |
(stab->name[5] == '.' && ISDIGIT (stab->name[6]))) |
&& (stab->flags & SEC_MERGE) == 0 |
&& !bfd_is_abs_section (stab->output_section)) |
{ |
struct bfd_elf_section_data *secdata; |
secdata = elf_section_data (stab); |
if (! _bfd_link_section_stabs (abfd, &htab->stab_info, stab, |
stabstr, &secdata->sec_info, |
&string_offset)) |
goto error_return; |
if (secdata->sec_info) |
stab->sec_info_type = SEC_INFO_TYPE_STABS; |
} |
} |
} |
if (is_elf_hash_table (htab) && add_needed) |
{ |
/* Add this bfd to the loaded list. */ |
struct elf_link_loaded_list *n; |
n = (struct elf_link_loaded_list *) |
bfd_alloc (abfd, sizeof (struct elf_link_loaded_list)); |
if (n == NULL) |
goto error_return; |
n->abfd = abfd; |
n->next = htab->loaded; |
htab->loaded = n; |
} |
return TRUE; |
error_free_vers: |
if (old_tab != NULL) |
free (old_tab); |
if (nondeflt_vers != NULL) |
free (nondeflt_vers); |
if (extversym != NULL) |
free (extversym); |
error_free_sym: |
if (isymbuf != NULL) |
free (isymbuf); |
error_return: |
return FALSE; |
} |
/* Return the linker hash table entry of a symbol that might be |
satisfied by an archive symbol. Return -1 on error. */ |
struct elf_link_hash_entry * |
_bfd_elf_archive_symbol_lookup (bfd *abfd, |
struct bfd_link_info *info, |
const char *name) |
{ |
struct elf_link_hash_entry *h; |
char *p, *copy; |
size_t len, first; |
h = elf_link_hash_lookup (elf_hash_table (info), name, FALSE, FALSE, TRUE); |
if (h != NULL) |
return h; |
/* If this is a default version (the name contains @@), look up the |
symbol again with only one `@' as well as without the version. |
The effect is that references to the symbol with and without the |
version will be matched by the default symbol in the archive. */ |
p = strchr (name, ELF_VER_CHR); |
if (p == NULL || p[1] != ELF_VER_CHR) |
return h; |
/* First check with only one `@'. */ |
len = strlen (name); |
copy = (char *) bfd_alloc (abfd, len); |
if (copy == NULL) |
return (struct elf_link_hash_entry *) 0 - 1; |
first = p - name + 1; |
memcpy (copy, name, first); |
memcpy (copy + first, name + first + 1, len - first); |
h = elf_link_hash_lookup (elf_hash_table (info), copy, FALSE, FALSE, TRUE); |
if (h == NULL) |
{ |
/* We also need to check references to the symbol without the |
version. */ |
copy[first - 1] = '\0'; |
h = elf_link_hash_lookup (elf_hash_table (info), copy, |
FALSE, FALSE, TRUE); |
} |
bfd_release (abfd, copy); |
return h; |
} |
/* Add symbols from an ELF archive file to the linker hash table. We |
don't use _bfd_generic_link_add_archive_symbols because of a |
problem which arises on UnixWare. The UnixWare libc.so is an |
archive which includes an entry libc.so.1 which defines a bunch of |
symbols. The libc.so archive also includes a number of other |
object files, which also define symbols, some of which are the same |
as those defined in libc.so.1. Correct linking requires that we |
consider each object file in turn, and include it if it defines any |
symbols we need. _bfd_generic_link_add_archive_symbols does not do |
this; it looks through the list of undefined symbols, and includes |
any object file which defines them. When this algorithm is used on |
UnixWare, it winds up pulling in libc.so.1 early and defining a |
bunch of symbols. This means that some of the other objects in the |
archive are not included in the link, which is incorrect since they |
precede libc.so.1 in the archive. |
Fortunately, ELF archive handling is simpler than that done by |
_bfd_generic_link_add_archive_symbols, which has to allow for a.out |
oddities. In ELF, if we find a symbol in the archive map, and the |
symbol is currently undefined, we know that we must pull in that |
object file. |
Unfortunately, we do have to make multiple passes over the symbol |
table until nothing further is resolved. */ |
static bfd_boolean |
elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info) |
{ |
symindex c; |
bfd_boolean *defined = NULL; |
bfd_boolean *included = NULL; |
carsym *symdefs; |
bfd_boolean loop; |
bfd_size_type amt; |
const struct elf_backend_data *bed; |
struct elf_link_hash_entry * (*archive_symbol_lookup) |
(bfd *, struct bfd_link_info *, const char *); |
if (! bfd_has_map (abfd)) |
{ |
/* An empty archive is a special case. */ |
if (bfd_openr_next_archived_file (abfd, NULL) == NULL) |
return TRUE; |
bfd_set_error (bfd_error_no_armap); |
return FALSE; |
} |
/* Keep track of all symbols we know to be already defined, and all |
files we know to be already included. This is to speed up the |
second and subsequent passes. */ |
c = bfd_ardata (abfd)->symdef_count; |
if (c == 0) |
return TRUE; |
amt = c; |
amt *= sizeof (bfd_boolean); |
defined = (bfd_boolean *) bfd_zmalloc (amt); |
included = (bfd_boolean *) bfd_zmalloc (amt); |
if (defined == NULL || included == NULL) |
goto error_return; |
symdefs = bfd_ardata (abfd)->symdefs; |
bed = get_elf_backend_data (abfd); |
archive_symbol_lookup = bed->elf_backend_archive_symbol_lookup; |
do |
{ |
file_ptr last; |
symindex i; |
carsym *symdef; |
carsym *symdefend; |
loop = FALSE; |
last = -1; |
symdef = symdefs; |
symdefend = symdef + c; |
for (i = 0; symdef < symdefend; symdef++, i++) |
{ |
struct elf_link_hash_entry *h; |
bfd *element; |
struct bfd_link_hash_entry *undefs_tail; |
symindex mark; |
if (defined[i] || included[i]) |
continue; |
if (symdef->file_offset == last) |
{ |
included[i] = TRUE; |
continue; |
} |
h = archive_symbol_lookup (abfd, info, symdef->name); |
if (h == (struct elf_link_hash_entry *) 0 - 1) |
goto error_return; |
if (h == NULL) |
continue; |
if (h->root.type == bfd_link_hash_common) |
{ |
/* We currently have a common symbol. The archive map contains |
a reference to this symbol, so we may want to include it. We |
only want to include it however, if this archive element |
contains a definition of the symbol, not just another common |
declaration of it. |
Unfortunately some archivers (including GNU ar) will put |
declarations of common symbols into their archive maps, as |
well as real definitions, so we cannot just go by the archive |
map alone. Instead we must read in the element's symbol |
table and check that to see what kind of symbol definition |
this is. */ |
if (! elf_link_is_defined_archive_symbol (abfd, symdef)) |
continue; |
} |
else if (h->root.type != bfd_link_hash_undefined) |
{ |
if (h->root.type != bfd_link_hash_undefweak) |
defined[i] = TRUE; |
continue; |
} |
/* We need to include this archive member. */ |
element = _bfd_get_elt_at_filepos (abfd, symdef->file_offset); |
if (element == NULL) |
goto error_return; |
if (! bfd_check_format (element, bfd_object)) |
goto error_return; |
/* Doublecheck that we have not included this object |
already--it should be impossible, but there may be |
something wrong with the archive. */ |
if (element->archive_pass != 0) |
{ |
bfd_set_error (bfd_error_bad_value); |
goto error_return; |
} |
element->archive_pass = 1; |
undefs_tail = info->hash->undefs_tail; |
if (!(*info->callbacks |
->add_archive_element) (info, element, symdef->name, &element)) |
goto error_return; |
if (!bfd_link_add_symbols (element, info)) |
goto error_return; |
/* If there are any new undefined symbols, we need to make |
another pass through the archive in order to see whether |
they can be defined. FIXME: This isn't perfect, because |
common symbols wind up on undefs_tail and because an |
undefined symbol which is defined later on in this pass |
does not require another pass. This isn't a bug, but it |
does make the code less efficient than it could be. */ |
if (undefs_tail != info->hash->undefs_tail) |
loop = TRUE; |
/* Look backward to mark all symbols from this object file |
which we have already seen in this pass. */ |
mark = i; |
do |
{ |
included[mark] = TRUE; |
if (mark == 0) |
break; |
--mark; |
} |
while (symdefs[mark].file_offset == symdef->file_offset); |
/* We mark subsequent symbols from this object file as we go |
on through the loop. */ |
last = symdef->file_offset; |
} |
} |
while (loop); |
free (defined); |
free (included); |
return TRUE; |
error_return: |
if (defined != NULL) |
free (defined); |
if (included != NULL) |
free (included); |
return FALSE; |
} |
/* Given an ELF BFD, add symbols to the global hash table as |
appropriate. */ |
bfd_boolean |
bfd_elf_link_add_symbols (bfd *abfd, struct bfd_link_info *info) |
{ |
switch (bfd_get_format (abfd)) |
{ |
case bfd_object: |
return elf_link_add_object_symbols (abfd, info); |
case bfd_archive: |
return elf_link_add_archive_symbols (abfd, info); |
default: |
bfd_set_error (bfd_error_wrong_format); |
return FALSE; |
} |
} |
struct hash_codes_info |
{ |
unsigned long *hashcodes; |
bfd_boolean error; |
}; |
/* This function will be called though elf_link_hash_traverse to store |
all hash value of the exported symbols in an array. */ |
static bfd_boolean |
elf_collect_hash_codes (struct elf_link_hash_entry *h, void *data) |
{ |
struct hash_codes_info *inf = (struct hash_codes_info *) data; |
const char *name; |
char *p; |
unsigned long ha; |
char *alc = NULL; |
/* Ignore indirect symbols. These are added by the versioning code. */ |
if (h->dynindx == -1) |
return TRUE; |
name = h->root.root.string; |
p = strchr (name, ELF_VER_CHR); |
if (p != NULL) |
{ |
alc = (char *) bfd_malloc (p - name + 1); |
if (alc == NULL) |
{ |
inf->error = TRUE; |
return FALSE; |
} |
memcpy (alc, name, p - name); |
alc[p - name] = '\0'; |
name = alc; |
} |
/* Compute the hash value. */ |
ha = bfd_elf_hash (name); |
/* Store the found hash value in the array given as the argument. */ |
*(inf->hashcodes)++ = ha; |
/* And store it in the struct so that we can put it in the hash table |
later. */ |
h->u.elf_hash_value = ha; |
if (alc != NULL) |
free (alc); |
return TRUE; |
} |
struct collect_gnu_hash_codes |
{ |
bfd *output_bfd; |
const struct elf_backend_data *bed; |
unsigned long int nsyms; |
unsigned long int maskbits; |
unsigned long int *hashcodes; |
unsigned long int *hashval; |
unsigned long int *indx; |
unsigned long int *counts; |
bfd_vma *bitmask; |
bfd_byte *contents; |
long int min_dynindx; |
unsigned long int bucketcount; |
unsigned long int symindx; |
long int local_indx; |
long int shift1, shift2; |
unsigned long int mask; |
bfd_boolean error; |
}; |
/* This function will be called though elf_link_hash_traverse to store |
all hash value of the exported symbols in an array. */ |
static bfd_boolean |
elf_collect_gnu_hash_codes (struct elf_link_hash_entry *h, void *data) |
{ |
struct collect_gnu_hash_codes *s = (struct collect_gnu_hash_codes *) data; |
const char *name; |
char *p; |
unsigned long ha; |
char *alc = NULL; |
/* Ignore indirect symbols. These are added by the versioning code. */ |
if (h->dynindx == -1) |
return TRUE; |
/* Ignore also local symbols and undefined symbols. */ |
if (! (*s->bed->elf_hash_symbol) (h)) |
return TRUE; |
name = h->root.root.string; |
p = strchr (name, ELF_VER_CHR); |
if (p != NULL) |
{ |
alc = (char *) bfd_malloc (p - name + 1); |
if (alc == NULL) |
{ |
s->error = TRUE; |
return FALSE; |
} |
memcpy (alc, name, p - name); |
alc[p - name] = '\0'; |
name = alc; |
} |
/* Compute the hash value. */ |
ha = bfd_elf_gnu_hash (name); |
/* Store the found hash value in the array for compute_bucket_count, |
and also for .dynsym reordering purposes. */ |
s->hashcodes[s->nsyms] = ha; |
s->hashval[h->dynindx] = ha; |
++s->nsyms; |
if (s->min_dynindx < 0 || s->min_dynindx > h->dynindx) |
s->min_dynindx = h->dynindx; |
if (alc != NULL) |
free (alc); |
return TRUE; |
} |
/* This function will be called though elf_link_hash_traverse to do |
final dynaminc symbol renumbering. */ |
static bfd_boolean |
elf_renumber_gnu_hash_syms (struct elf_link_hash_entry *h, void *data) |
{ |
struct collect_gnu_hash_codes *s = (struct collect_gnu_hash_codes *) data; |
unsigned long int bucket; |
unsigned long int val; |
/* Ignore indirect symbols. */ |
if (h->dynindx == -1) |
return TRUE; |
/* Ignore also local symbols and undefined symbols. */ |
if (! (*s->bed->elf_hash_symbol) (h)) |
{ |
if (h->dynindx >= s->min_dynindx) |
h->dynindx = s->local_indx++; |
return TRUE; |
} |
bucket = s->hashval[h->dynindx] % s->bucketcount; |
val = (s->hashval[h->dynindx] >> s->shift1) |
& ((s->maskbits >> s->shift1) - 1); |
s->bitmask[val] |= ((bfd_vma) 1) << (s->hashval[h->dynindx] & s->mask); |
s->bitmask[val] |
|= ((bfd_vma) 1) << ((s->hashval[h->dynindx] >> s->shift2) & s->mask); |
val = s->hashval[h->dynindx] & ~(unsigned long int) 1; |
if (s->counts[bucket] == 1) |
/* Last element terminates the chain. */ |
val |= 1; |
bfd_put_32 (s->output_bfd, val, |
s->contents + (s->indx[bucket] - s->symindx) * 4); |
--s->counts[bucket]; |
h->dynindx = s->indx[bucket]++; |
return TRUE; |
} |
/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ |
bfd_boolean |
_bfd_elf_hash_symbol (struct elf_link_hash_entry *h) |
{ |
return !(h->forced_local |
|| h->root.type == bfd_link_hash_undefined |
|| h->root.type == bfd_link_hash_undefweak |
|| ((h->root.type == bfd_link_hash_defined |
|| h->root.type == bfd_link_hash_defweak) |
&& h->root.u.def.section->output_section == NULL)); |
} |
/* Array used to determine the number of hash table buckets to use |
based on the number of symbols there are. If there are fewer than |
3 symbols we use 1 bucket, fewer than 17 symbols we use 3 buckets, |
fewer than 37 we use 17 buckets, and so forth. We never use more |
than 32771 buckets. */ |
static const size_t elf_buckets[] = |
{ |
1, 3, 17, 37, 67, 97, 131, 197, 263, 521, 1031, 2053, 4099, 8209, |
16411, 32771, 0 |
}; |
/* Compute bucket count for hashing table. We do not use a static set |
of possible tables sizes anymore. Instead we determine for all |
possible reasonable sizes of the table the outcome (i.e., the |
number of collisions etc) and choose the best solution. The |
weighting functions are not too simple to allow the table to grow |
without bounds. Instead one of the weighting factors is the size. |
Therefore the result is always a good payoff between few collisions |
(= short chain lengths) and table size. */ |
static size_t |
compute_bucket_count (struct bfd_link_info *info ATTRIBUTE_UNUSED, |
unsigned long int *hashcodes ATTRIBUTE_UNUSED, |
unsigned long int nsyms, |
int gnu_hash) |
{ |
size_t best_size = 0; |
unsigned long int i; |
/* We have a problem here. The following code to optimize the table |
size requires an integer type with more the 32 bits. If |
BFD_HOST_U_64_BIT is set we know about such a type. */ |
#ifdef BFD_HOST_U_64_BIT |
if (info->optimize) |
{ |
size_t minsize; |
size_t maxsize; |
BFD_HOST_U_64_BIT best_chlen = ~((BFD_HOST_U_64_BIT) 0); |
bfd *dynobj = elf_hash_table (info)->dynobj; |
size_t dynsymcount = elf_hash_table (info)->dynsymcount; |
const struct elf_backend_data *bed = get_elf_backend_data (dynobj); |
unsigned long int *counts; |
bfd_size_type amt; |
unsigned int no_improvement_count = 0; |
/* Possible optimization parameters: if we have NSYMS symbols we say |
that the hashing table must at least have NSYMS/4 and at most |
2*NSYMS buckets. */ |
minsize = nsyms / 4; |
if (minsize == 0) |
minsize = 1; |
best_size = maxsize = nsyms * 2; |
if (gnu_hash) |
{ |
if (minsize < 2) |
minsize = 2; |
if ((best_size & 31) == 0) |
++best_size; |
} |
/* Create array where we count the collisions in. We must use bfd_malloc |
since the size could be large. */ |
amt = maxsize; |
amt *= sizeof (unsigned long int); |
counts = (unsigned long int *) bfd_malloc (amt); |
if (counts == NULL) |
return 0; |
/* Compute the "optimal" size for the hash table. The criteria is a |
minimal chain length. The minor criteria is (of course) the size |
of the table. */ |
for (i = minsize; i < maxsize; ++i) |
{ |
/* Walk through the array of hashcodes and count the collisions. */ |
BFD_HOST_U_64_BIT max; |
unsigned long int j; |
unsigned long int fact; |
if (gnu_hash && (i & 31) == 0) |
continue; |
memset (counts, '\0', i * sizeof (unsigned long int)); |
/* Determine how often each hash bucket is used. */ |
for (j = 0; j < nsyms; ++j) |
++counts[hashcodes[j] % i]; |
/* For the weight function we need some information about the |
pagesize on the target. This is information need not be 100% |
accurate. Since this information is not available (so far) we |
define it here to a reasonable default value. If it is crucial |
to have a better value some day simply define this value. */ |
# ifndef BFD_TARGET_PAGESIZE |
# define BFD_TARGET_PAGESIZE (4096) |
# endif |
/* We in any case need 2 + DYNSYMCOUNT entries for the size values |
and the chains. */ |
max = (2 + dynsymcount) * bed->s->sizeof_hash_entry; |
# if 1 |
/* Variant 1: optimize for short chains. We add the squares |
of all the chain lengths (which favors many small chain |
over a few long chains). */ |
for (j = 0; j < i; ++j) |
max += counts[j] * counts[j]; |
/* This adds penalties for the overall size of the table. */ |
fact = i / (BFD_TARGET_PAGESIZE / bed->s->sizeof_hash_entry) + 1; |
max *= fact * fact; |
# else |
/* Variant 2: Optimize a lot more for small table. Here we |
also add squares of the size but we also add penalties for |
empty slots (the +1 term). */ |
for (j = 0; j < i; ++j) |
max += (1 + counts[j]) * (1 + counts[j]); |
/* The overall size of the table is considered, but not as |
strong as in variant 1, where it is squared. */ |
fact = i / (BFD_TARGET_PAGESIZE / bed->s->sizeof_hash_entry) + 1; |
max *= fact; |
# endif |
/* Compare with current best results. */ |
if (max < best_chlen) |
{ |
best_chlen = max; |
best_size = i; |
no_improvement_count = 0; |
} |
/* PR 11843: Avoid futile long searches for the best bucket size |
when there are a large number of symbols. */ |
else if (++no_improvement_count == 100) |
break; |
} |
free (counts); |
} |
else |
#endif /* defined (BFD_HOST_U_64_BIT) */ |
{ |
/* This is the fallback solution if no 64bit type is available or if we |
are not supposed to spend much time on optimizations. We select the |
bucket count using a fixed set of numbers. */ |
for (i = 0; elf_buckets[i] != 0; i++) |
{ |
best_size = elf_buckets[i]; |
if (nsyms < elf_buckets[i + 1]) |
break; |
} |
if (gnu_hash && best_size < 2) |
best_size = 2; |
} |
return best_size; |
} |
/* Size any SHT_GROUP section for ld -r. */ |
bfd_boolean |
_bfd_elf_size_group_sections (struct bfd_link_info *info) |
{ |
bfd *ibfd; |
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) |
if (bfd_get_flavour (ibfd) == bfd_target_elf_flavour |
&& !_bfd_elf_fixup_group_sections (ibfd, bfd_abs_section_ptr)) |
return FALSE; |
return TRUE; |
} |
/* Set a default stack segment size. The value in INFO wins. If it |
is unset, LEGACY_SYMBOL's value is used, and if that symbol is |
undefined it is initialized. */ |
bfd_boolean |
bfd_elf_stack_segment_size (bfd *output_bfd, |
struct bfd_link_info *info, |
const char *legacy_symbol, |
bfd_vma default_size) |
{ |
struct elf_link_hash_entry *h = NULL; |
/* Look for legacy symbol. */ |
if (legacy_symbol) |
h = elf_link_hash_lookup (elf_hash_table (info), legacy_symbol, |
FALSE, FALSE, FALSE); |
if (h && (h->root.type == bfd_link_hash_defined |
|| h->root.type == bfd_link_hash_defweak) |
&& h->def_regular |
&& (h->type == STT_NOTYPE || h->type == STT_OBJECT)) |
{ |
/* The symbol has no type if specified on the command line. */ |
h->type = STT_OBJECT; |
if (info->stacksize) |
(*_bfd_error_handler) (_("%B: stack size specified and %s set"), |
output_bfd, legacy_symbol); |
else if (h->root.u.def.section != bfd_abs_section_ptr) |
(*_bfd_error_handler) (_("%B: %s not absolute"), |
output_bfd, legacy_symbol); |
else |
info->stacksize = h->root.u.def.value; |
} |
if (!info->stacksize) |
/* If the user didn't set a size, or explicitly inhibit the |
size, set it now. */ |
info->stacksize = default_size; |
/* Provide the legacy symbol, if it is referenced. */ |
if (h && (h->root.type == bfd_link_hash_undefined |
|| h->root.type == bfd_link_hash_undefweak)) |
{ |
struct bfd_link_hash_entry *bh = NULL; |
if (!(_bfd_generic_link_add_one_symbol |
(info, output_bfd, legacy_symbol, |
BSF_GLOBAL, bfd_abs_section_ptr, |
info->stacksize >= 0 ? info->stacksize : 0, |
NULL, FALSE, get_elf_backend_data (output_bfd)->collect, &bh))) |
return FALSE; |
h = (struct elf_link_hash_entry *) bh; |
h->def_regular = 1; |
h->type = STT_OBJECT; |
} |
return TRUE; |
} |
/* Set up the sizes and contents of the ELF dynamic sections. This is |
called by the ELF linker emulation before_allocation routine. We |
must set the sizes of the sections before the linker sets the |
addresses of the various sections. */ |
bfd_boolean |
bfd_elf_size_dynamic_sections (bfd *output_bfd, |
const char *soname, |
const char *rpath, |
const char *filter_shlib, |
const char *audit, |
const char *depaudit, |
const char * const *auxiliary_filters, |
struct bfd_link_info *info, |
asection **sinterpptr) |
{ |
bfd_size_type soname_indx; |
bfd *dynobj; |
const struct elf_backend_data *bed; |
struct elf_info_failed asvinfo; |
*sinterpptr = NULL; |
soname_indx = (bfd_size_type) -1; |
if (!is_elf_hash_table (info->hash)) |
return TRUE; |
bed = get_elf_backend_data (output_bfd); |
/* Any syms created from now on start with -1 in |
got.refcount/offset and plt.refcount/offset. */ |
elf_hash_table (info)->init_got_refcount |
= elf_hash_table (info)->init_got_offset; |
elf_hash_table (info)->init_plt_refcount |
= elf_hash_table (info)->init_plt_offset; |
if (info->relocatable |
&& !_bfd_elf_size_group_sections (info)) |
return FALSE; |
/* The backend may have to create some sections regardless of whether |
we're dynamic or not. */ |
if (bed->elf_backend_always_size_sections |
&& ! (*bed->elf_backend_always_size_sections) (output_bfd, info)) |
return FALSE; |
/* Determine any GNU_STACK segment requirements, after the backend |
has had a chance to set a default segment size. */ |
if (info->execstack) |
elf_stack_flags (output_bfd) = PF_R | PF_W | PF_X; |
else if (info->noexecstack) |
elf_stack_flags (output_bfd) = PF_R | PF_W; |
else |
{ |
bfd *inputobj; |
asection *notesec = NULL; |
int exec = 0; |
for (inputobj = info->input_bfds; |
inputobj; |
inputobj = inputobj->link_next) |
{ |
asection *s; |
if (inputobj->flags |
& (DYNAMIC | EXEC_P | BFD_PLUGIN | BFD_LINKER_CREATED)) |
continue; |
s = bfd_get_section_by_name (inputobj, ".note.GNU-stack"); |
if (s) |
{ |
if (s->flags & SEC_CODE) |
exec = PF_X; |
notesec = s; |
} |
else if (bed->default_execstack) |
exec = PF_X; |
} |
if (notesec || info->stacksize > 0) |
elf_stack_flags (output_bfd) = PF_R | PF_W | exec; |
if (notesec && exec && info->relocatable |
&& notesec->output_section != bfd_abs_section_ptr) |
notesec->output_section->flags |= SEC_CODE; |
} |
dynobj = elf_hash_table (info)->dynobj; |
if (dynobj != NULL && elf_hash_table (info)->dynamic_sections_created) |
{ |
struct elf_info_failed eif; |
struct elf_link_hash_entry *h; |
asection *dynstr; |
struct bfd_elf_version_tree *t; |
struct bfd_elf_version_expr *d; |
asection *s; |
bfd_boolean all_defined; |
*sinterpptr = bfd_get_linker_section (dynobj, ".interp"); |
BFD_ASSERT (*sinterpptr != NULL || !info->executable); |
if (soname != NULL) |
{ |
soname_indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, |
soname, TRUE); |
if (soname_indx == (bfd_size_type) -1 |
|| !_bfd_elf_add_dynamic_entry (info, DT_SONAME, soname_indx)) |
return FALSE; |
} |
if (info->symbolic) |
{ |
if (!_bfd_elf_add_dynamic_entry (info, DT_SYMBOLIC, 0)) |
return FALSE; |
info->flags |= DF_SYMBOLIC; |
} |
if (rpath != NULL) |
{ |
bfd_size_type indx; |
bfd_vma tag; |
indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, rpath, |
TRUE); |
if (indx == (bfd_size_type) -1) |
return FALSE; |
tag = info->new_dtags ? DT_RUNPATH : DT_RPATH; |
if (!_bfd_elf_add_dynamic_entry (info, tag, indx)) |
return FALSE; |
} |
if (filter_shlib != NULL) |
{ |
bfd_size_type indx; |
indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, |
filter_shlib, TRUE); |
if (indx == (bfd_size_type) -1 |
|| !_bfd_elf_add_dynamic_entry (info, DT_FILTER, indx)) |
return FALSE; |
} |
if (auxiliary_filters != NULL) |
{ |
const char * const *p; |
for (p = auxiliary_filters; *p != NULL; p++) |
{ |
bfd_size_type indx; |
indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, |
*p, TRUE); |
if (indx == (bfd_size_type) -1 |
|| !_bfd_elf_add_dynamic_entry (info, DT_AUXILIARY, indx)) |
return FALSE; |
} |
} |
if (audit != NULL) |
{ |
bfd_size_type indx; |
indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, audit, |
TRUE); |
if (indx == (bfd_size_type) -1 |
|| !_bfd_elf_add_dynamic_entry (info, DT_AUDIT, indx)) |
return FALSE; |
} |
if (depaudit != NULL) |
{ |
bfd_size_type indx; |
indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, depaudit, |
TRUE); |
if (indx == (bfd_size_type) -1 |
|| !_bfd_elf_add_dynamic_entry (info, DT_DEPAUDIT, indx)) |
return FALSE; |
} |
eif.info = info; |
eif.failed = FALSE; |
/* If we are supposed to export all symbols into the dynamic symbol |
table (this is not the normal case), then do so. */ |
if (info->export_dynamic |
|| (info->executable && info->dynamic)) |
{ |
elf_link_hash_traverse (elf_hash_table (info), |
_bfd_elf_export_symbol, |
&eif); |
if (eif.failed) |
return FALSE; |
} |
/* Make all global versions with definition. */ |
for (t = info->version_info; t != NULL; t = t->next) |
for (d = t->globals.list; d != NULL; d = d->next) |
if (!d->symver && d->literal) |
{ |
const char *verstr, *name; |
size_t namelen, verlen, newlen; |
char *newname, *p, leading_char; |
struct elf_link_hash_entry *newh; |
leading_char = bfd_get_symbol_leading_char (output_bfd); |
name = d->pattern; |
namelen = strlen (name) + (leading_char != '\0'); |
verstr = t->name; |
verlen = strlen (verstr); |
newlen = namelen + verlen + 3; |
newname = (char *) bfd_malloc (newlen); |
if (newname == NULL) |
return FALSE; |
newname[0] = leading_char; |
memcpy (newname + (leading_char != '\0'), name, namelen); |
/* Check the hidden versioned definition. */ |
p = newname + namelen; |
*p++ = ELF_VER_CHR; |
memcpy (p, verstr, verlen + 1); |
newh = elf_link_hash_lookup (elf_hash_table (info), |
newname, FALSE, FALSE, |
FALSE); |
if (newh == NULL |
|| (newh->root.type != bfd_link_hash_defined |
&& newh->root.type != bfd_link_hash_defweak)) |
{ |
/* Check the default versioned definition. */ |
*p++ = ELF_VER_CHR; |
memcpy (p, verstr, verlen + 1); |
newh = elf_link_hash_lookup (elf_hash_table (info), |
newname, FALSE, FALSE, |
FALSE); |
} |
free (newname); |
/* Mark this version if there is a definition and it is |
not defined in a shared object. */ |
if (newh != NULL |
&& !newh->def_dynamic |
&& (newh->root.type == bfd_link_hash_defined |
|| newh->root.type == bfd_link_hash_defweak)) |
d->symver = 1; |
} |
/* Attach all the symbols to their version information. */ |
asvinfo.info = info; |
asvinfo.failed = FALSE; |
elf_link_hash_traverse (elf_hash_table (info), |
_bfd_elf_link_assign_sym_version, |
&asvinfo); |
if (asvinfo.failed) |
return FALSE; |
if (!info->allow_undefined_version) |
{ |
/* Check if all global versions have a definition. */ |
all_defined = TRUE; |
for (t = info->version_info; t != NULL; t = t->next) |
for (d = t->globals.list; d != NULL; d = d->next) |
if (d->literal && !d->symver && !d->script) |
{ |
(*_bfd_error_handler) |
(_("%s: undefined version: %s"), |
d->pattern, t->name); |
all_defined = FALSE; |
} |
if (!all_defined) |
{ |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
} |
/* Find all symbols which were defined in a dynamic object and make |
the backend pick a reasonable value for them. */ |
elf_link_hash_traverse (elf_hash_table (info), |
_bfd_elf_adjust_dynamic_symbol, |
&eif); |
if (eif.failed) |
return FALSE; |
/* Add some entries to the .dynamic section. We fill in some of the |
values later, in bfd_elf_final_link, but we must add the entries |
now so that we know the final size of the .dynamic section. */ |
/* If there are initialization and/or finalization functions to |
call then add the corresponding DT_INIT/DT_FINI entries. */ |
h = (info->init_function |
? elf_link_hash_lookup (elf_hash_table (info), |
info->init_function, FALSE, |
FALSE, FALSE) |
: NULL); |
if (h != NULL |
&& (h->ref_regular |
|| h->def_regular)) |
{ |
if (!_bfd_elf_add_dynamic_entry (info, DT_INIT, 0)) |
return FALSE; |
} |
h = (info->fini_function |
? elf_link_hash_lookup (elf_hash_table (info), |
info->fini_function, FALSE, |
FALSE, FALSE) |
: NULL); |
if (h != NULL |
&& (h->ref_regular |
|| h->def_regular)) |
{ |
if (!_bfd_elf_add_dynamic_entry (info, DT_FINI, 0)) |
return FALSE; |
} |
s = bfd_get_section_by_name (output_bfd, ".preinit_array"); |
if (s != NULL && s->linker_has_input) |
{ |
/* DT_PREINIT_ARRAY is not allowed in shared library. */ |
if (! info->executable) |
{ |
bfd *sub; |
asection *o; |
for (sub = info->input_bfds; sub != NULL; |
sub = sub->link_next) |
if (bfd_get_flavour (sub) == bfd_target_elf_flavour) |
for (o = sub->sections; o != NULL; o = o->next) |
if (elf_section_data (o)->this_hdr.sh_type |
== SHT_PREINIT_ARRAY) |
{ |
(*_bfd_error_handler) |
(_("%B: .preinit_array section is not allowed in DSO"), |
sub); |
break; |
} |
bfd_set_error (bfd_error_nonrepresentable_section); |
return FALSE; |
} |
if (!_bfd_elf_add_dynamic_entry (info, DT_PREINIT_ARRAY, 0) |
|| !_bfd_elf_add_dynamic_entry (info, DT_PREINIT_ARRAYSZ, 0)) |
return FALSE; |
} |
s = bfd_get_section_by_name (output_bfd, ".init_array"); |
if (s != NULL && s->linker_has_input) |
{ |
if (!_bfd_elf_add_dynamic_entry (info, DT_INIT_ARRAY, 0) |
|| !_bfd_elf_add_dynamic_entry (info, DT_INIT_ARRAYSZ, 0)) |
return FALSE; |
} |
s = bfd_get_section_by_name (output_bfd, ".fini_array"); |
if (s != NULL && s->linker_has_input) |
{ |
if (!_bfd_elf_add_dynamic_entry (info, DT_FINI_ARRAY, 0) |
|| !_bfd_elf_add_dynamic_entry (info, DT_FINI_ARRAYSZ, 0)) |
return FALSE; |
} |
dynstr = bfd_get_linker_section (dynobj, ".dynstr"); |
/* If .dynstr is excluded from the link, we don't want any of |
these tags. Strictly, we should be checking each section |
individually; This quick check covers for the case where |
someone does a /DISCARD/ : { *(*) }. */ |
if (dynstr != NULL && dynstr->output_section != bfd_abs_section_ptr) |
{ |
bfd_size_type strsize; |
strsize = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr); |
if ((info->emit_hash |
&& !_bfd_elf_add_dynamic_entry (info, DT_HASH, 0)) |
|| (info->emit_gnu_hash |
&& !_bfd_elf_add_dynamic_entry (info, DT_GNU_HASH, 0)) |
|| !_bfd_elf_add_dynamic_entry (info, DT_STRTAB, 0) |
|| !_bfd_elf_add_dynamic_entry (info, DT_SYMTAB, 0) |
|| !_bfd_elf_add_dynamic_entry (info, DT_STRSZ, strsize) |
|| !_bfd_elf_add_dynamic_entry (info, DT_SYMENT, |
bed->s->sizeof_sym)) |
return FALSE; |
} |
} |
/* The backend must work out the sizes of all the other dynamic |
sections. */ |
if (dynobj != NULL |
&& bed->elf_backend_size_dynamic_sections != NULL |
&& ! (*bed->elf_backend_size_dynamic_sections) (output_bfd, info)) |
return FALSE; |
if (! _bfd_elf_maybe_strip_eh_frame_hdr (info)) |
return FALSE; |
if (dynobj != NULL && elf_hash_table (info)->dynamic_sections_created) |
{ |
unsigned long section_sym_count; |
struct bfd_elf_version_tree *verdefs; |
asection *s; |
/* Set up the version definition section. */ |
s = bfd_get_linker_section (dynobj, ".gnu.version_d"); |
BFD_ASSERT (s != NULL); |
/* We may have created additional version definitions if we are |
just linking a regular application. */ |
verdefs = info->version_info; |
/* Skip anonymous version tag. */ |
if (verdefs != NULL && verdefs->vernum == 0) |
verdefs = verdefs->next; |
if (verdefs == NULL && !info->create_default_symver) |
s->flags |= SEC_EXCLUDE; |
else |
{ |
unsigned int cdefs; |
bfd_size_type size; |
struct bfd_elf_version_tree *t; |
bfd_byte *p; |
Elf_Internal_Verdef def; |
Elf_Internal_Verdaux defaux; |
struct bfd_link_hash_entry *bh; |
struct elf_link_hash_entry *h; |
const char *name; |
cdefs = 0; |
size = 0; |
/* Make space for the base version. */ |
size += sizeof (Elf_External_Verdef); |
size += sizeof (Elf_External_Verdaux); |
++cdefs; |
/* Make space for the default version. */ |
if (info->create_default_symver) |
{ |
size += sizeof (Elf_External_Verdef); |
++cdefs; |
} |
for (t = verdefs; t != NULL; t = t->next) |
{ |
struct bfd_elf_version_deps *n; |
/* Don't emit base version twice. */ |
if (t->vernum == 0) |
continue; |
size += sizeof (Elf_External_Verdef); |
size += sizeof (Elf_External_Verdaux); |
++cdefs; |
for (n = t->deps; n != NULL; n = n->next) |
size += sizeof (Elf_External_Verdaux); |
} |
s->size = size; |
s->contents = (unsigned char *) bfd_alloc (output_bfd, s->size); |
if (s->contents == NULL && s->size != 0) |
return FALSE; |
/* Fill in the version definition section. */ |
p = s->contents; |
def.vd_version = VER_DEF_CURRENT; |
def.vd_flags = VER_FLG_BASE; |
def.vd_ndx = 1; |
def.vd_cnt = 1; |
if (info->create_default_symver) |
{ |
def.vd_aux = 2 * sizeof (Elf_External_Verdef); |
def.vd_next = sizeof (Elf_External_Verdef); |
} |
else |
{ |
def.vd_aux = sizeof (Elf_External_Verdef); |
def.vd_next = (sizeof (Elf_External_Verdef) |
+ sizeof (Elf_External_Verdaux)); |
} |
if (soname_indx != (bfd_size_type) -1) |
{ |
_bfd_elf_strtab_addref (elf_hash_table (info)->dynstr, |
soname_indx); |
def.vd_hash = bfd_elf_hash (soname); |
defaux.vda_name = soname_indx; |
name = soname; |
} |
else |
{ |
bfd_size_type indx; |
name = lbasename (output_bfd->filename); |
def.vd_hash = bfd_elf_hash (name); |
indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, |
name, FALSE); |
if (indx == (bfd_size_type) -1) |
return FALSE; |
defaux.vda_name = indx; |
} |
defaux.vda_next = 0; |
_bfd_elf_swap_verdef_out (output_bfd, &def, |
(Elf_External_Verdef *) p); |
p += sizeof (Elf_External_Verdef); |
if (info->create_default_symver) |
{ |
/* Add a symbol representing this version. */ |
bh = NULL; |
if (! (_bfd_generic_link_add_one_symbol |
(info, dynobj, name, BSF_GLOBAL, bfd_abs_section_ptr, |
0, NULL, FALSE, |
get_elf_backend_data (dynobj)->collect, &bh))) |
return FALSE; |
h = (struct elf_link_hash_entry *) bh; |
h->non_elf = 0; |
h->def_regular = 1; |
h->type = STT_OBJECT; |
h->verinfo.vertree = NULL; |
if (! bfd_elf_link_record_dynamic_symbol (info, h)) |
return FALSE; |
/* Create a duplicate of the base version with the same |
aux block, but different flags. */ |
def.vd_flags = 0; |
def.vd_ndx = 2; |
def.vd_aux = sizeof (Elf_External_Verdef); |
if (verdefs) |
def.vd_next = (sizeof (Elf_External_Verdef) |
+ sizeof (Elf_External_Verdaux)); |
else |
def.vd_next = 0; |
_bfd_elf_swap_verdef_out (output_bfd, &def, |
(Elf_External_Verdef *) p); |
p += sizeof (Elf_External_Verdef); |
} |
_bfd_elf_swap_verdaux_out (output_bfd, &defaux, |
(Elf_External_Verdaux *) p); |
p += sizeof (Elf_External_Verdaux); |
for (t = verdefs; t != NULL; t = t->next) |
{ |
unsigned int cdeps; |
struct bfd_elf_version_deps *n; |
/* Don't emit the base version twice. */ |
if (t->vernum == 0) |
continue; |
cdeps = 0; |
for (n = t->deps; n != NULL; n = n->next) |
++cdeps; |
/* Add a symbol representing this version. */ |
bh = NULL; |
if (! (_bfd_generic_link_add_one_symbol |
(info, dynobj, t->name, BSF_GLOBAL, bfd_abs_section_ptr, |
0, NULL, FALSE, |
get_elf_backend_data (dynobj)->collect, &bh))) |
return FALSE; |
h = (struct elf_link_hash_entry *) bh; |
h->non_elf = 0; |
h->def_regular = 1; |
h->type = STT_OBJECT; |
h->verinfo.vertree = t; |
if (! bfd_elf_link_record_dynamic_symbol (info, h)) |
return FALSE; |
def.vd_version = VER_DEF_CURRENT; |
def.vd_flags = 0; |
if (t->globals.list == NULL |
&& t->locals.list == NULL |
&& ! t->used) |
def.vd_flags |= VER_FLG_WEAK; |
def.vd_ndx = t->vernum + (info->create_default_symver ? 2 : 1); |
def.vd_cnt = cdeps + 1; |
def.vd_hash = bfd_elf_hash (t->name); |
def.vd_aux = sizeof (Elf_External_Verdef); |
def.vd_next = 0; |
/* If a basever node is next, it *must* be the last node in |
the chain, otherwise Verdef construction breaks. */ |
if (t->next != NULL && t->next->vernum == 0) |
BFD_ASSERT (t->next->next == NULL); |
if (t->next != NULL && t->next->vernum != 0) |
def.vd_next = (sizeof (Elf_External_Verdef) |
+ (cdeps + 1) * sizeof (Elf_External_Verdaux)); |
_bfd_elf_swap_verdef_out (output_bfd, &def, |
(Elf_External_Verdef *) p); |
p += sizeof (Elf_External_Verdef); |
defaux.vda_name = h->dynstr_index; |
_bfd_elf_strtab_addref (elf_hash_table (info)->dynstr, |
h->dynstr_index); |
defaux.vda_next = 0; |
if (t->deps != NULL) |
defaux.vda_next = sizeof (Elf_External_Verdaux); |
t->name_indx = defaux.vda_name; |
_bfd_elf_swap_verdaux_out (output_bfd, &defaux, |
(Elf_External_Verdaux *) p); |
p += sizeof (Elf_External_Verdaux); |
for (n = t->deps; n != NULL; n = n->next) |
{ |
if (n->version_needed == NULL) |
{ |
/* This can happen if there was an error in the |
version script. */ |
defaux.vda_name = 0; |
} |
else |
{ |
defaux.vda_name = n->version_needed->name_indx; |
_bfd_elf_strtab_addref (elf_hash_table (info)->dynstr, |
defaux.vda_name); |
} |
if (n->next == NULL) |
defaux.vda_next = 0; |
else |
defaux.vda_next = sizeof (Elf_External_Verdaux); |
_bfd_elf_swap_verdaux_out (output_bfd, &defaux, |
(Elf_External_Verdaux *) p); |
p += sizeof (Elf_External_Verdaux); |
} |
} |
if (!_bfd_elf_add_dynamic_entry (info, DT_VERDEF, 0) |
|| !_bfd_elf_add_dynamic_entry (info, DT_VERDEFNUM, cdefs)) |
return FALSE; |
elf_tdata (output_bfd)->cverdefs = cdefs; |
} |
if ((info->new_dtags && info->flags) || (info->flags & DF_STATIC_TLS)) |
{ |
if (!_bfd_elf_add_dynamic_entry (info, DT_FLAGS, info->flags)) |
return FALSE; |
} |
else if (info->flags & DF_BIND_NOW) |
{ |
if (!_bfd_elf_add_dynamic_entry (info, DT_BIND_NOW, 0)) |
return FALSE; |
} |
if (info->flags_1) |
{ |
if (info->executable) |
info->flags_1 &= ~ (DF_1_INITFIRST |
| DF_1_NODELETE |
| DF_1_NOOPEN); |
if (!_bfd_elf_add_dynamic_entry (info, DT_FLAGS_1, info->flags_1)) |
return FALSE; |
} |
/* Work out the size of the version reference section. */ |
s = bfd_get_linker_section (dynobj, ".gnu.version_r"); |
BFD_ASSERT (s != NULL); |
{ |
struct elf_find_verdep_info sinfo; |
sinfo.info = info; |
sinfo.vers = elf_tdata (output_bfd)->cverdefs; |
if (sinfo.vers == 0) |
sinfo.vers = 1; |
sinfo.failed = FALSE; |
elf_link_hash_traverse (elf_hash_table (info), |
_bfd_elf_link_find_version_dependencies, |
&sinfo); |
if (sinfo.failed) |
return FALSE; |
if (elf_tdata (output_bfd)->verref == NULL) |
s->flags |= SEC_EXCLUDE; |
else |
{ |
Elf_Internal_Verneed *t; |
unsigned int size; |
unsigned int crefs; |
bfd_byte *p; |
/* Build the version dependency section. */ |
size = 0; |
crefs = 0; |
for (t = elf_tdata (output_bfd)->verref; |
t != NULL; |
t = t->vn_nextref) |
{ |
Elf_Internal_Vernaux *a; |
size += sizeof (Elf_External_Verneed); |
++crefs; |
for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr) |
size += sizeof (Elf_External_Vernaux); |
} |
s->size = size; |
s->contents = (unsigned char *) bfd_alloc (output_bfd, s->size); |
if (s->contents == NULL) |
return FALSE; |
p = s->contents; |
for (t = elf_tdata (output_bfd)->verref; |
t != NULL; |
t = t->vn_nextref) |
{ |
unsigned int caux; |
Elf_Internal_Vernaux *a; |
bfd_size_type indx; |
caux = 0; |
for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr) |
++caux; |
t->vn_version = VER_NEED_CURRENT; |
t->vn_cnt = caux; |
indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, |
elf_dt_name (t->vn_bfd) != NULL |
? elf_dt_name (t->vn_bfd) |
: lbasename (t->vn_bfd->filename), |
FALSE); |
if (indx == (bfd_size_type) -1) |
return FALSE; |
t->vn_file = indx; |
t->vn_aux = sizeof (Elf_External_Verneed); |
if (t->vn_nextref == NULL) |
t->vn_next = 0; |
else |
t->vn_next = (sizeof (Elf_External_Verneed) |
+ caux * sizeof (Elf_External_Vernaux)); |
_bfd_elf_swap_verneed_out (output_bfd, t, |
(Elf_External_Verneed *) p); |
p += sizeof (Elf_External_Verneed); |
for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr) |
{ |
a->vna_hash = bfd_elf_hash (a->vna_nodename); |
indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, |
a->vna_nodename, FALSE); |
if (indx == (bfd_size_type) -1) |
return FALSE; |
a->vna_name = indx; |
if (a->vna_nextptr == NULL) |
a->vna_next = 0; |
else |
a->vna_next = sizeof (Elf_External_Vernaux); |
_bfd_elf_swap_vernaux_out (output_bfd, a, |
(Elf_External_Vernaux *) p); |
p += sizeof (Elf_External_Vernaux); |
} |
} |
if (!_bfd_elf_add_dynamic_entry (info, DT_VERNEED, 0) |
|| !_bfd_elf_add_dynamic_entry (info, DT_VERNEEDNUM, crefs)) |
return FALSE; |
elf_tdata (output_bfd)->cverrefs = crefs; |
} |
} |
if ((elf_tdata (output_bfd)->cverrefs == 0 |
&& elf_tdata (output_bfd)->cverdefs == 0) |
|| _bfd_elf_link_renumber_dynsyms (output_bfd, info, |
§ion_sym_count) == 0) |
{ |
s = bfd_get_linker_section (dynobj, ".gnu.version"); |
s->flags |= SEC_EXCLUDE; |
} |
} |
return TRUE; |
} |
/* Find the first non-excluded output section. We'll use its |
section symbol for some emitted relocs. */ |
void |
_bfd_elf_init_1_index_section (bfd *output_bfd, struct bfd_link_info *info) |
{ |
asection *s; |
for (s = output_bfd->sections; s != NULL; s = s->next) |
if ((s->flags & (SEC_EXCLUDE | SEC_ALLOC)) == SEC_ALLOC |
&& !_bfd_elf_link_omit_section_dynsym (output_bfd, info, s)) |
{ |
elf_hash_table (info)->text_index_section = s; |
break; |
} |
} |
/* Find two non-excluded output sections, one for code, one for data. |
We'll use their section symbols for some emitted relocs. */ |
void |
_bfd_elf_init_2_index_sections (bfd *output_bfd, struct bfd_link_info *info) |
{ |
asection *s; |
/* Data first, since setting text_index_section changes |
_bfd_elf_link_omit_section_dynsym. */ |
for (s = output_bfd->sections; s != NULL; s = s->next) |
if (((s->flags & (SEC_EXCLUDE | SEC_ALLOC | SEC_READONLY)) == SEC_ALLOC) |
&& !_bfd_elf_link_omit_section_dynsym (output_bfd, info, s)) |
{ |
elf_hash_table (info)->data_index_section = s; |
break; |
} |
for (s = output_bfd->sections; s != NULL; s = s->next) |
if (((s->flags & (SEC_EXCLUDE | SEC_ALLOC | SEC_READONLY)) |
== (SEC_ALLOC | SEC_READONLY)) |
&& !_bfd_elf_link_omit_section_dynsym (output_bfd, info, s)) |
{ |
elf_hash_table (info)->text_index_section = s; |
break; |
} |
if (elf_hash_table (info)->text_index_section == NULL) |
elf_hash_table (info)->text_index_section |
= elf_hash_table (info)->data_index_section; |
} |
bfd_boolean |
bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info) |
{ |
const struct elf_backend_data *bed; |
if (!is_elf_hash_table (info->hash)) |
return TRUE; |
bed = get_elf_backend_data (output_bfd); |
(*bed->elf_backend_init_index_section) (output_bfd, info); |
if (elf_hash_table (info)->dynamic_sections_created) |
{ |
bfd *dynobj; |
asection *s; |
bfd_size_type dynsymcount; |
unsigned long section_sym_count; |
unsigned int dtagcount; |
dynobj = elf_hash_table (info)->dynobj; |
/* Assign dynsym indicies. In a shared library we generate a |
section symbol for each output section, which come first. |
Next come all of the back-end allocated local dynamic syms, |
followed by the rest of the global symbols. */ |
dynsymcount = _bfd_elf_link_renumber_dynsyms (output_bfd, info, |
§ion_sym_count); |
/* Work out the size of the symbol version section. */ |
s = bfd_get_linker_section (dynobj, ".gnu.version"); |
BFD_ASSERT (s != NULL); |
if (dynsymcount != 0 |
&& (s->flags & SEC_EXCLUDE) == 0) |
{ |
s->size = dynsymcount * sizeof (Elf_External_Versym); |
s->contents = (unsigned char *) bfd_zalloc (output_bfd, s->size); |
if (s->contents == NULL) |
return FALSE; |
if (!_bfd_elf_add_dynamic_entry (info, DT_VERSYM, 0)) |
return FALSE; |
} |
/* Set the size of the .dynsym and .hash sections. We counted |
the number of dynamic symbols in elf_link_add_object_symbols. |
We will build the contents of .dynsym and .hash when we build |
the final symbol table, because until then we do not know the |
correct value to give the symbols. We built the .dynstr |
section as we went along in elf_link_add_object_symbols. */ |
s = bfd_get_linker_section (dynobj, ".dynsym"); |
BFD_ASSERT (s != NULL); |
s->size = dynsymcount * bed->s->sizeof_sym; |
if (dynsymcount != 0) |
{ |
s->contents = (unsigned char *) bfd_alloc (output_bfd, s->size); |
if (s->contents == NULL) |
return FALSE; |
/* The first entry in .dynsym is a dummy symbol. |
Clear all the section syms, in case we don't output them all. */ |
++section_sym_count; |
memset (s->contents, 0, section_sym_count * bed->s->sizeof_sym); |
} |
elf_hash_table (info)->bucketcount = 0; |
/* Compute the size of the hashing table. As a side effect this |
computes the hash values for all the names we export. */ |
if (info->emit_hash) |
{ |
unsigned long int *hashcodes; |
struct hash_codes_info hashinf; |
bfd_size_type amt; |
unsigned long int nsyms; |
size_t bucketcount; |
size_t hash_entry_size; |
/* Compute the hash values for all exported symbols. At the same |
time store the values in an array so that we could use them for |
optimizations. */ |
amt = dynsymcount * sizeof (unsigned long int); |
hashcodes = (unsigned long int *) bfd_malloc (amt); |
if (hashcodes == NULL) |
return FALSE; |
hashinf.hashcodes = hashcodes; |
hashinf.error = FALSE; |
/* Put all hash values in HASHCODES. */ |
elf_link_hash_traverse (elf_hash_table (info), |
elf_collect_hash_codes, &hashinf); |
if (hashinf.error) |
{ |
free (hashcodes); |
return FALSE; |
} |
nsyms = hashinf.hashcodes - hashcodes; |
bucketcount |
= compute_bucket_count (info, hashcodes, nsyms, 0); |
free (hashcodes); |
if (bucketcount == 0) |
return FALSE; |
elf_hash_table (info)->bucketcount = bucketcount; |
s = bfd_get_linker_section (dynobj, ".hash"); |
BFD_ASSERT (s != NULL); |
hash_entry_size = elf_section_data (s)->this_hdr.sh_entsize; |
s->size = ((2 + bucketcount + dynsymcount) * hash_entry_size); |
s->contents = (unsigned char *) bfd_zalloc (output_bfd, s->size); |
if (s->contents == NULL) |
return FALSE; |
bfd_put (8 * hash_entry_size, output_bfd, bucketcount, s->contents); |
bfd_put (8 * hash_entry_size, output_bfd, dynsymcount, |
s->contents + hash_entry_size); |
} |
if (info->emit_gnu_hash) |
{ |
size_t i, cnt; |
unsigned char *contents; |
struct collect_gnu_hash_codes cinfo; |
bfd_size_type amt; |
size_t bucketcount; |
memset (&cinfo, 0, sizeof (cinfo)); |
/* Compute the hash values for all exported symbols. At the same |
time store the values in an array so that we could use them for |
optimizations. */ |
amt = dynsymcount * 2 * sizeof (unsigned long int); |
cinfo.hashcodes = (long unsigned int *) bfd_malloc (amt); |
if (cinfo.hashcodes == NULL) |
return FALSE; |
cinfo.hashval = cinfo.hashcodes + dynsymcount; |
cinfo.min_dynindx = -1; |
cinfo.output_bfd = output_bfd; |
cinfo.bed = bed; |
/* Put all hash values in HASHCODES. */ |
elf_link_hash_traverse (elf_hash_table (info), |
elf_collect_gnu_hash_codes, &cinfo); |
if (cinfo.error) |
{ |
free (cinfo.hashcodes); |
return FALSE; |
} |
bucketcount |
= compute_bucket_count (info, cinfo.hashcodes, cinfo.nsyms, 1); |
if (bucketcount == 0) |
{ |
free (cinfo.hashcodes); |
return FALSE; |
} |
s = bfd_get_linker_section (dynobj, ".gnu.hash"); |
BFD_ASSERT (s != NULL); |
if (cinfo.nsyms == 0) |
{ |
/* Empty .gnu.hash section is special. */ |
BFD_ASSERT (cinfo.min_dynindx == -1); |
free (cinfo.hashcodes); |
s->size = 5 * 4 + bed->s->arch_size / 8; |
contents = (unsigned char *) bfd_zalloc (output_bfd, s->size); |
if (contents == NULL) |
return FALSE; |
s->contents = contents; |
/* 1 empty bucket. */ |
bfd_put_32 (output_bfd, 1, contents); |
/* SYMIDX above the special symbol 0. */ |
bfd_put_32 (output_bfd, 1, contents + 4); |
/* Just one word for bitmask. */ |
bfd_put_32 (output_bfd, 1, contents + 8); |
/* Only hash fn bloom filter. */ |
bfd_put_32 (output_bfd, 0, contents + 12); |
/* No hashes are valid - empty bitmask. */ |
bfd_put (bed->s->arch_size, output_bfd, 0, contents + 16); |
/* No hashes in the only bucket. */ |
bfd_put_32 (output_bfd, 0, |
contents + 16 + bed->s->arch_size / 8); |
} |
else |
{ |
unsigned long int maskwords, maskbitslog2, x; |
BFD_ASSERT (cinfo.min_dynindx != -1); |
x = cinfo.nsyms; |
maskbitslog2 = 1; |
while ((x >>= 1) != 0) |
++maskbitslog2; |
if (maskbitslog2 < 3) |
maskbitslog2 = 5; |
else if ((1 << (maskbitslog2 - 2)) & cinfo.nsyms) |
maskbitslog2 = maskbitslog2 + 3; |
else |
maskbitslog2 = maskbitslog2 + 2; |
if (bed->s->arch_size == 64) |
{ |
if (maskbitslog2 == 5) |
maskbitslog2 = 6; |
cinfo.shift1 = 6; |
} |
else |
cinfo.shift1 = 5; |
cinfo.mask = (1 << cinfo.shift1) - 1; |
cinfo.shift2 = maskbitslog2; |
cinfo.maskbits = 1 << maskbitslog2; |
maskwords = 1 << (maskbitslog2 - cinfo.shift1); |
amt = bucketcount * sizeof (unsigned long int) * 2; |
amt += maskwords * sizeof (bfd_vma); |
cinfo.bitmask = (bfd_vma *) bfd_malloc (amt); |
if (cinfo.bitmask == NULL) |
{ |
free (cinfo.hashcodes); |
return FALSE; |
} |
cinfo.counts = (long unsigned int *) (cinfo.bitmask + maskwords); |
cinfo.indx = cinfo.counts + bucketcount; |
cinfo.symindx = dynsymcount - cinfo.nsyms; |
memset (cinfo.bitmask, 0, maskwords * sizeof (bfd_vma)); |
/* Determine how often each hash bucket is used. */ |
memset (cinfo.counts, 0, bucketcount * sizeof (cinfo.counts[0])); |
for (i = 0; i < cinfo.nsyms; ++i) |
++cinfo.counts[cinfo.hashcodes[i] % bucketcount]; |
for (i = 0, cnt = cinfo.symindx; i < bucketcount; ++i) |
if (cinfo.counts[i] != 0) |
{ |
cinfo.indx[i] = cnt; |
cnt += cinfo.counts[i]; |
} |
BFD_ASSERT (cnt == dynsymcount); |
cinfo.bucketcount = bucketcount; |
cinfo.local_indx = cinfo.min_dynindx; |
s->size = (4 + bucketcount + cinfo.nsyms) * 4; |
s->size += cinfo.maskbits / 8; |
contents = (unsigned char *) bfd_zalloc (output_bfd, s->size); |
if (contents == NULL) |
{ |
free (cinfo.bitmask); |
free (cinfo.hashcodes); |
return FALSE; |
} |
s->contents = contents; |
bfd_put_32 (output_bfd, bucketcount, contents); |
bfd_put_32 (output_bfd, cinfo.symindx, contents + 4); |
bfd_put_32 (output_bfd, maskwords, contents + 8); |
bfd_put_32 (output_bfd, cinfo.shift2, contents + 12); |
contents += 16 + cinfo.maskbits / 8; |
for (i = 0; i < bucketcount; ++i) |
{ |
if (cinfo.counts[i] == 0) |
bfd_put_32 (output_bfd, 0, contents); |
else |
bfd_put_32 (output_bfd, cinfo.indx[i], contents); |
contents += 4; |
} |
cinfo.contents = contents; |
/* Renumber dynamic symbols, populate .gnu.hash section. */ |
elf_link_hash_traverse (elf_hash_table (info), |
elf_renumber_gnu_hash_syms, &cinfo); |
contents = s->contents + 16; |
for (i = 0; i < maskwords; ++i) |
{ |
bfd_put (bed->s->arch_size, output_bfd, cinfo.bitmask[i], |
contents); |
contents += bed->s->arch_size / 8; |
} |
free (cinfo.bitmask); |
free (cinfo.hashcodes); |
} |
} |
s = bfd_get_linker_section (dynobj, ".dynstr"); |
BFD_ASSERT (s != NULL); |
elf_finalize_dynstr (output_bfd, info); |
s->size = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr); |
for (dtagcount = 0; dtagcount <= info->spare_dynamic_tags; ++dtagcount) |
if (!_bfd_elf_add_dynamic_entry (info, DT_NULL, 0)) |
return FALSE; |
} |
return TRUE; |
} |
/* Make sure sec_info_type is cleared if sec_info is cleared too. */ |
static void |
merge_sections_remove_hook (bfd *abfd ATTRIBUTE_UNUSED, |
asection *sec) |
{ |
BFD_ASSERT (sec->sec_info_type == SEC_INFO_TYPE_MERGE); |
sec->sec_info_type = SEC_INFO_TYPE_NONE; |
} |
/* Finish SHF_MERGE section merging. */ |
bfd_boolean |
_bfd_elf_merge_sections (bfd *abfd, struct bfd_link_info *info) |
{ |
bfd *ibfd; |
asection *sec; |
if (!is_elf_hash_table (info->hash)) |
return FALSE; |
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) |
if ((ibfd->flags & DYNAMIC) == 0) |
for (sec = ibfd->sections; sec != NULL; sec = sec->next) |
if ((sec->flags & SEC_MERGE) != 0 |
&& !bfd_is_abs_section (sec->output_section)) |
{ |
struct bfd_elf_section_data *secdata; |
secdata = elf_section_data (sec); |
if (! _bfd_add_merge_section (abfd, |
&elf_hash_table (info)->merge_info, |
sec, &secdata->sec_info)) |
return FALSE; |
else if (secdata->sec_info) |
sec->sec_info_type = SEC_INFO_TYPE_MERGE; |
} |
if (elf_hash_table (info)->merge_info != NULL) |
_bfd_merge_sections (abfd, info, elf_hash_table (info)->merge_info, |
merge_sections_remove_hook); |
return TRUE; |
} |
/* Create an entry in an ELF linker hash table. */ |
struct bfd_hash_entry * |
_bfd_elf_link_hash_newfunc (struct bfd_hash_entry *entry, |
struct bfd_hash_table *table, |
const char *string) |
{ |
/* Allocate the structure if it has not already been allocated by a |
subclass. */ |
if (entry == NULL) |
{ |
entry = (struct bfd_hash_entry *) |
bfd_hash_allocate (table, sizeof (struct elf_link_hash_entry)); |
if (entry == NULL) |
return entry; |
} |
/* Call the allocation method of the superclass. */ |
entry = _bfd_link_hash_newfunc (entry, table, string); |
if (entry != NULL) |
{ |
struct elf_link_hash_entry *ret = (struct elf_link_hash_entry *) entry; |
struct elf_link_hash_table *htab = (struct elf_link_hash_table *) table; |
/* Set local fields. */ |
ret->indx = -1; |
ret->dynindx = -1; |
ret->got = htab->init_got_refcount; |
ret->plt = htab->init_plt_refcount; |
memset (&ret->size, 0, (sizeof (struct elf_link_hash_entry) |
- offsetof (struct elf_link_hash_entry, size))); |
/* Assume that we have been called by a non-ELF symbol reader. |
This flag is then reset by the code which reads an ELF input |
file. This ensures that a symbol created by a non-ELF symbol |
reader will have the flag set correctly. */ |
ret->non_elf = 1; |
} |
return entry; |
} |
/* Copy data from an indirect symbol to its direct symbol, hiding the |
old indirect symbol. Also used for copying flags to a weakdef. */ |
void |
_bfd_elf_link_hash_copy_indirect (struct bfd_link_info *info, |
struct elf_link_hash_entry *dir, |
struct elf_link_hash_entry *ind) |
{ |
struct elf_link_hash_table *htab; |
/* Copy down any references that we may have already seen to the |
symbol which just became indirect. */ |
dir->ref_dynamic |= ind->ref_dynamic; |
dir->ref_regular |= ind->ref_regular; |
dir->ref_regular_nonweak |= ind->ref_regular_nonweak; |
dir->non_got_ref |= ind->non_got_ref; |
dir->needs_plt |= ind->needs_plt; |
dir->pointer_equality_needed |= ind->pointer_equality_needed; |
if (ind->root.type != bfd_link_hash_indirect) |
return; |
/* Copy over the global and procedure linkage table refcount entries. |
These may have been already set up by a check_relocs routine. */ |
htab = elf_hash_table (info); |
if (ind->got.refcount > htab->init_got_refcount.refcount) |
{ |
if (dir->got.refcount < 0) |
dir->got.refcount = 0; |
dir->got.refcount += ind->got.refcount; |
ind->got.refcount = htab->init_got_refcount.refcount; |
} |
if (ind->plt.refcount > htab->init_plt_refcount.refcount) |
{ |
if (dir->plt.refcount < 0) |
dir->plt.refcount = 0; |
dir->plt.refcount += ind->plt.refcount; |
ind->plt.refcount = htab->init_plt_refcount.refcount; |
} |
if (ind->dynindx != -1) |
{ |
if (dir->dynindx != -1) |
_bfd_elf_strtab_delref (htab->dynstr, dir->dynstr_index); |
dir->dynindx = ind->dynindx; |
dir->dynstr_index = ind->dynstr_index; |
ind->dynindx = -1; |
ind->dynstr_index = 0; |
} |
} |
void |
_bfd_elf_link_hash_hide_symbol (struct bfd_link_info *info, |
struct elf_link_hash_entry *h, |
bfd_boolean force_local) |
{ |
/* STT_GNU_IFUNC symbol must go through PLT. */ |
if (h->type != STT_GNU_IFUNC) |
{ |
h->plt = elf_hash_table (info)->init_plt_offset; |
h->needs_plt = 0; |
} |
if (force_local) |
{ |
h->forced_local = 1; |
if (h->dynindx != -1) |
{ |
h->dynindx = -1; |
_bfd_elf_strtab_delref (elf_hash_table (info)->dynstr, |
h->dynstr_index); |
} |
} |
} |
/* Initialize an ELF linker hash table. *TABLE has been zeroed by our |
caller. */ |
bfd_boolean |
_bfd_elf_link_hash_table_init |
(struct elf_link_hash_table *table, |
bfd *abfd, |
struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *, |
struct bfd_hash_table *, |
const char *), |
unsigned int entsize, |
enum elf_target_id target_id) |
{ |
bfd_boolean ret; |
int can_refcount = get_elf_backend_data (abfd)->can_refcount; |
table->init_got_refcount.refcount = can_refcount - 1; |
table->init_plt_refcount.refcount = can_refcount - 1; |
table->init_got_offset.offset = -(bfd_vma) 1; |
table->init_plt_offset.offset = -(bfd_vma) 1; |
/* The first dynamic symbol is a dummy. */ |
table->dynsymcount = 1; |
ret = _bfd_link_hash_table_init (&table->root, abfd, newfunc, entsize); |
table->root.type = bfd_link_elf_hash_table; |
table->hash_table_id = target_id; |
return ret; |
} |
/* Create an ELF linker hash table. */ |
struct bfd_link_hash_table * |
_bfd_elf_link_hash_table_create (bfd *abfd) |
{ |
struct elf_link_hash_table *ret; |
bfd_size_type amt = sizeof (struct elf_link_hash_table); |
ret = (struct elf_link_hash_table *) bfd_zmalloc (amt); |
if (ret == NULL) |
return NULL; |
if (! _bfd_elf_link_hash_table_init (ret, abfd, _bfd_elf_link_hash_newfunc, |
sizeof (struct elf_link_hash_entry), |
GENERIC_ELF_DATA)) |
{ |
free (ret); |
return NULL; |
} |
return &ret->root; |
} |
/* Destroy an ELF linker hash table. */ |
void |
_bfd_elf_link_hash_table_free (struct bfd_link_hash_table *hash) |
{ |
struct elf_link_hash_table *htab = (struct elf_link_hash_table *) hash; |
if (htab->dynstr != NULL) |
_bfd_elf_strtab_free (htab->dynstr); |
_bfd_merge_sections_free (htab->merge_info); |
_bfd_generic_link_hash_table_free (hash); |
} |
/* This is a hook for the ELF emulation code in the generic linker to |
tell the backend linker what file name to use for the DT_NEEDED |
entry for a dynamic object. */ |
void |
bfd_elf_set_dt_needed_name (bfd *abfd, const char *name) |
{ |
if (bfd_get_flavour (abfd) == bfd_target_elf_flavour |
&& bfd_get_format (abfd) == bfd_object) |
elf_dt_name (abfd) = name; |
} |
int |
bfd_elf_get_dyn_lib_class (bfd *abfd) |
{ |
int lib_class; |
if (bfd_get_flavour (abfd) == bfd_target_elf_flavour |
&& bfd_get_format (abfd) == bfd_object) |
lib_class = elf_dyn_lib_class (abfd); |
else |
lib_class = 0; |
return lib_class; |
} |
void |
bfd_elf_set_dyn_lib_class (bfd *abfd, enum dynamic_lib_link_class lib_class) |
{ |
if (bfd_get_flavour (abfd) == bfd_target_elf_flavour |
&& bfd_get_format (abfd) == bfd_object) |
elf_dyn_lib_class (abfd) = lib_class; |
} |
/* Get the list of DT_NEEDED entries for a link. This is a hook for |
the linker ELF emulation code. */ |
struct bfd_link_needed_list * |
bfd_elf_get_needed_list (bfd *abfd ATTRIBUTE_UNUSED, |
struct bfd_link_info *info) |
{ |
if (! is_elf_hash_table (info->hash)) |
return NULL; |
return elf_hash_table (info)->needed; |
} |
/* Get the list of DT_RPATH/DT_RUNPATH entries for a link. This is a |
hook for the linker ELF emulation code. */ |
struct bfd_link_needed_list * |
bfd_elf_get_runpath_list (bfd *abfd ATTRIBUTE_UNUSED, |
struct bfd_link_info *info) |
{ |
if (! is_elf_hash_table (info->hash)) |
return NULL; |
return elf_hash_table (info)->runpath; |
} |
/* Get the name actually used for a dynamic object for a link. This |
is the SONAME entry if there is one. Otherwise, it is the string |
passed to bfd_elf_set_dt_needed_name, or it is the filename. */ |
const char * |
bfd_elf_get_dt_soname (bfd *abfd) |
{ |
if (bfd_get_flavour (abfd) == bfd_target_elf_flavour |
&& bfd_get_format (abfd) == bfd_object) |
return elf_dt_name (abfd); |
return NULL; |
} |
/* Get the list of DT_NEEDED entries from a BFD. This is a hook for |
the ELF linker emulation code. */ |
bfd_boolean |
bfd_elf_get_bfd_needed_list (bfd *abfd, |
struct bfd_link_needed_list **pneeded) |
{ |
asection *s; |
bfd_byte *dynbuf = NULL; |
unsigned int elfsec; |
unsigned long shlink; |
bfd_byte *extdyn, *extdynend; |
size_t extdynsize; |
void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *); |
*pneeded = NULL; |
if (bfd_get_flavour (abfd) != bfd_target_elf_flavour |
|| bfd_get_format (abfd) != bfd_object) |
return TRUE; |
s = bfd_get_section_by_name (abfd, ".dynamic"); |
if (s == NULL || s->size == 0) |
return TRUE; |
if (!bfd_malloc_and_get_section (abfd, s, &dynbuf)) |
goto error_return; |
elfsec = _bfd_elf_section_from_bfd_section (abfd, s); |
if (elfsec == SHN_BAD) |
goto error_return; |
shlink = elf_elfsections (abfd)[elfsec]->sh_link; |
extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn; |
swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in; |
extdyn = dynbuf; |
extdynend = extdyn + s->size; |
for (; extdyn < extdynend; extdyn += extdynsize) |
{ |
Elf_Internal_Dyn dyn; |
(*swap_dyn_in) (abfd, extdyn, &dyn); |
if (dyn.d_tag == DT_NULL) |
break; |
if (dyn.d_tag == DT_NEEDED) |
{ |
const char *string; |
struct bfd_link_needed_list *l; |
unsigned int tagv = dyn.d_un.d_val; |
bfd_size_type amt; |
string = bfd_elf_string_from_elf_section (abfd, shlink, tagv); |
if (string == NULL) |
goto error_return; |
amt = sizeof *l; |
l = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt); |
if (l == NULL) |
goto error_return; |
l->by = abfd; |
l->name = string; |
l->next = *pneeded; |
*pneeded = l; |
} |
} |
free (dynbuf); |
return TRUE; |
error_return: |
if (dynbuf != NULL) |
free (dynbuf); |
return FALSE; |
} |
struct elf_symbuf_symbol |
{ |
unsigned long st_name; /* Symbol name, index in string tbl */ |
unsigned char st_info; /* Type and binding attributes */ |
unsigned char st_other; /* Visibilty, and target specific */ |
}; |
struct elf_symbuf_head |
{ |
struct elf_symbuf_symbol *ssym; |
bfd_size_type count; |
unsigned int st_shndx; |
}; |
struct elf_symbol |
{ |
union |
{ |
Elf_Internal_Sym *isym; |
struct elf_symbuf_symbol *ssym; |
} u; |
const char *name; |
}; |
/* Sort references to symbols by ascending section number. */ |
static int |
elf_sort_elf_symbol (const void *arg1, const void *arg2) |
{ |
const Elf_Internal_Sym *s1 = *(const Elf_Internal_Sym **) arg1; |
const Elf_Internal_Sym *s2 = *(const Elf_Internal_Sym **) arg2; |
return s1->st_shndx - s2->st_shndx; |
} |
static int |
elf_sym_name_compare (const void *arg1, const void *arg2) |
{ |
const struct elf_symbol *s1 = (const struct elf_symbol *) arg1; |
const struct elf_symbol *s2 = (const struct elf_symbol *) arg2; |
return strcmp (s1->name, s2->name); |
} |
static struct elf_symbuf_head * |
elf_create_symbuf (bfd_size_type symcount, Elf_Internal_Sym *isymbuf) |
{ |
Elf_Internal_Sym **ind, **indbufend, **indbuf; |
struct elf_symbuf_symbol *ssym; |
struct elf_symbuf_head *ssymbuf, *ssymhead; |
bfd_size_type i, shndx_count, total_size; |
indbuf = (Elf_Internal_Sym **) bfd_malloc2 (symcount, sizeof (*indbuf)); |
if (indbuf == NULL) |
return NULL; |
for (ind = indbuf, i = 0; i < symcount; i++) |
if (isymbuf[i].st_shndx != SHN_UNDEF) |
*ind++ = &isymbuf[i]; |
indbufend = ind; |
qsort (indbuf, indbufend - indbuf, sizeof (Elf_Internal_Sym *), |
elf_sort_elf_symbol); |
shndx_count = 0; |
if (indbufend > indbuf) |
for (ind = indbuf, shndx_count++; ind < indbufend - 1; ind++) |
if (ind[0]->st_shndx != ind[1]->st_shndx) |
shndx_count++; |
total_size = ((shndx_count + 1) * sizeof (*ssymbuf) |
+ (indbufend - indbuf) * sizeof (*ssym)); |
ssymbuf = (struct elf_symbuf_head *) bfd_malloc (total_size); |
if (ssymbuf == NULL) |
{ |
free (indbuf); |
return NULL; |
} |
ssym = (struct elf_symbuf_symbol *) (ssymbuf + shndx_count + 1); |
ssymbuf->ssym = NULL; |
ssymbuf->count = shndx_count; |
ssymbuf->st_shndx = 0; |
for (ssymhead = ssymbuf, ind = indbuf; ind < indbufend; ssym++, ind++) |
{ |
if (ind == indbuf || ssymhead->st_shndx != (*ind)->st_shndx) |
{ |
ssymhead++; |
ssymhead->ssym = ssym; |
ssymhead->count = 0; |
ssymhead->st_shndx = (*ind)->st_shndx; |
} |
ssym->st_name = (*ind)->st_name; |
ssym->st_info = (*ind)->st_info; |
ssym->st_other = (*ind)->st_other; |
ssymhead->count++; |
} |
BFD_ASSERT ((bfd_size_type) (ssymhead - ssymbuf) == shndx_count |
&& (((bfd_hostptr_t) ssym - (bfd_hostptr_t) ssymbuf) |
== total_size)); |
free (indbuf); |
return ssymbuf; |
} |
/* Check if 2 sections define the same set of local and global |
symbols. */ |
static bfd_boolean |
bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2, |
struct bfd_link_info *info) |
{ |
bfd *bfd1, *bfd2; |
const struct elf_backend_data *bed1, *bed2; |
Elf_Internal_Shdr *hdr1, *hdr2; |
bfd_size_type symcount1, symcount2; |
Elf_Internal_Sym *isymbuf1, *isymbuf2; |
struct elf_symbuf_head *ssymbuf1, *ssymbuf2; |
Elf_Internal_Sym *isym, *isymend; |
struct elf_symbol *symtable1 = NULL, *symtable2 = NULL; |
bfd_size_type count1, count2, i; |
unsigned int shndx1, shndx2; |
bfd_boolean result; |
bfd1 = sec1->owner; |
bfd2 = sec2->owner; |
/* Both sections have to be in ELF. */ |
if (bfd_get_flavour (bfd1) != bfd_target_elf_flavour |
|| bfd_get_flavour (bfd2) != bfd_target_elf_flavour) |
return FALSE; |
if (elf_section_type (sec1) != elf_section_type (sec2)) |
return FALSE; |
shndx1 = _bfd_elf_section_from_bfd_section (bfd1, sec1); |
shndx2 = _bfd_elf_section_from_bfd_section (bfd2, sec2); |
if (shndx1 == SHN_BAD || shndx2 == SHN_BAD) |
return FALSE; |
bed1 = get_elf_backend_data (bfd1); |
bed2 = get_elf_backend_data (bfd2); |
hdr1 = &elf_tdata (bfd1)->symtab_hdr; |
symcount1 = hdr1->sh_size / bed1->s->sizeof_sym; |
hdr2 = &elf_tdata (bfd2)->symtab_hdr; |
symcount2 = hdr2->sh_size / bed2->s->sizeof_sym; |
if (symcount1 == 0 || symcount2 == 0) |
return FALSE; |
result = FALSE; |
isymbuf1 = NULL; |
isymbuf2 = NULL; |
ssymbuf1 = (struct elf_symbuf_head *) elf_tdata (bfd1)->symbuf; |
ssymbuf2 = (struct elf_symbuf_head *) elf_tdata (bfd2)->symbuf; |
if (ssymbuf1 == NULL) |
{ |
isymbuf1 = bfd_elf_get_elf_syms (bfd1, hdr1, symcount1, 0, |
NULL, NULL, NULL); |
if (isymbuf1 == NULL) |
goto done; |
if (!info->reduce_memory_overheads) |
elf_tdata (bfd1)->symbuf = ssymbuf1 |
= elf_create_symbuf (symcount1, isymbuf1); |
} |
if (ssymbuf1 == NULL || ssymbuf2 == NULL) |
{ |
isymbuf2 = bfd_elf_get_elf_syms (bfd2, hdr2, symcount2, 0, |
NULL, NULL, NULL); |
if (isymbuf2 == NULL) |
goto done; |
if (ssymbuf1 != NULL && !info->reduce_memory_overheads) |
elf_tdata (bfd2)->symbuf = ssymbuf2 |
= elf_create_symbuf (symcount2, isymbuf2); |
} |
if (ssymbuf1 != NULL && ssymbuf2 != NULL) |
{ |
/* Optimized faster version. */ |
bfd_size_type lo, hi, mid; |
struct elf_symbol *symp; |
struct elf_symbuf_symbol *ssym, *ssymend; |
lo = 0; |
hi = ssymbuf1->count; |
ssymbuf1++; |
count1 = 0; |
while (lo < hi) |
{ |
mid = (lo + hi) / 2; |
if (shndx1 < ssymbuf1[mid].st_shndx) |
hi = mid; |
else if (shndx1 > ssymbuf1[mid].st_shndx) |
lo = mid + 1; |
else |
{ |
count1 = ssymbuf1[mid].count; |
ssymbuf1 += mid; |
break; |
} |
} |
lo = 0; |
hi = ssymbuf2->count; |
ssymbuf2++; |
count2 = 0; |
while (lo < hi) |
{ |
mid = (lo + hi) / 2; |
if (shndx2 < ssymbuf2[mid].st_shndx) |
hi = mid; |
else if (shndx2 > ssymbuf2[mid].st_shndx) |
lo = mid + 1; |
else |
{ |
count2 = ssymbuf2[mid].count; |
ssymbuf2 += mid; |
break; |
} |
} |
if (count1 == 0 || count2 == 0 || count1 != count2) |
goto done; |
symtable1 = (struct elf_symbol *) |
bfd_malloc (count1 * sizeof (struct elf_symbol)); |
symtable2 = (struct elf_symbol *) |
bfd_malloc (count2 * sizeof (struct elf_symbol)); |
if (symtable1 == NULL || symtable2 == NULL) |
goto done; |
symp = symtable1; |
for (ssym = ssymbuf1->ssym, ssymend = ssym + count1; |
ssym < ssymend; ssym++, symp++) |
{ |
symp->u.ssym = ssym; |
symp->name = bfd_elf_string_from_elf_section (bfd1, |
hdr1->sh_link, |
ssym->st_name); |
} |
symp = symtable2; |
for (ssym = ssymbuf2->ssym, ssymend = ssym + count2; |
ssym < ssymend; ssym++, symp++) |
{ |
symp->u.ssym = ssym; |
symp->name = bfd_elf_string_from_elf_section (bfd2, |
hdr2->sh_link, |
ssym->st_name); |
} |
/* Sort symbol by name. */ |
qsort (symtable1, count1, sizeof (struct elf_symbol), |
elf_sym_name_compare); |
qsort (symtable2, count1, sizeof (struct elf_symbol), |
elf_sym_name_compare); |
for (i = 0; i < count1; i++) |
/* Two symbols must have the same binding, type and name. */ |
if (symtable1 [i].u.ssym->st_info != symtable2 [i].u.ssym->st_info |
|| symtable1 [i].u.ssym->st_other != symtable2 [i].u.ssym->st_other |
|| strcmp (symtable1 [i].name, symtable2 [i].name) != 0) |
goto done; |
result = TRUE; |
goto done; |
} |
symtable1 = (struct elf_symbol *) |
bfd_malloc (symcount1 * sizeof (struct elf_symbol)); |
symtable2 = (struct elf_symbol *) |
bfd_malloc (symcount2 * sizeof (struct elf_symbol)); |
if (symtable1 == NULL || symtable2 == NULL) |
goto done; |
/* Count definitions in the section. */ |
count1 = 0; |
for (isym = isymbuf1, isymend = isym + symcount1; isym < isymend; isym++) |
if (isym->st_shndx == shndx1) |
symtable1[count1++].u.isym = isym; |
count2 = 0; |
for (isym = isymbuf2, isymend = isym + symcount2; isym < isymend; isym++) |
if (isym->st_shndx == shndx2) |
symtable2[count2++].u.isym = isym; |
if (count1 == 0 || count2 == 0 || count1 != count2) |
goto done; |
for (i = 0; i < count1; i++) |
symtable1[i].name |
= bfd_elf_string_from_elf_section (bfd1, hdr1->sh_link, |
symtable1[i].u.isym->st_name); |
for (i = 0; i < count2; i++) |
symtable2[i].name |
= bfd_elf_string_from_elf_section (bfd2, hdr2->sh_link, |
symtable2[i].u.isym->st_name); |
/* Sort symbol by name. */ |
qsort (symtable1, count1, sizeof (struct elf_symbol), |
elf_sym_name_compare); |
qsort (symtable2, count1, sizeof (struct elf_symbol), |
elf_sym_name_compare); |
for (i = 0; i < count1; i++) |
/* Two symbols must have the same binding, type and name. */ |
if (symtable1 [i].u.isym->st_info != symtable2 [i].u.isym->st_info |
|| symtable1 [i].u.isym->st_other != symtable2 [i].u.isym->st_other |
|| strcmp (symtable1 [i].name, symtable2 [i].name) != 0) |
goto done; |
result = TRUE; |
done: |
if (symtable1) |
free (symtable1); |
if (symtable2) |
free (symtable2); |
if (isymbuf1) |
free (isymbuf1); |
if (isymbuf2) |
free (isymbuf2); |
return result; |
} |
/* Return TRUE if 2 section types are compatible. */ |
bfd_boolean |
_bfd_elf_match_sections_by_type (bfd *abfd, const asection *asec, |
bfd *bbfd, const asection *bsec) |
{ |
if (asec == NULL |
|| bsec == NULL |
|| abfd->xvec->flavour != bfd_target_elf_flavour |
|| bbfd->xvec->flavour != bfd_target_elf_flavour) |
return TRUE; |
return elf_section_type (asec) == elf_section_type (bsec); |
} |
/* Final phase of ELF linker. */ |
/* A structure we use to avoid passing large numbers of arguments. */ |
struct elf_final_link_info |
{ |
/* General link information. */ |
struct bfd_link_info *info; |
/* Output BFD. */ |
bfd *output_bfd; |
/* Symbol string table. */ |
struct bfd_strtab_hash *symstrtab; |
/* .dynsym section. */ |
asection *dynsym_sec; |
/* .hash section. */ |
asection *hash_sec; |
/* symbol version section (.gnu.version). */ |
asection *symver_sec; |
/* Buffer large enough to hold contents of any section. */ |
bfd_byte *contents; |
/* Buffer large enough to hold external relocs of any section. */ |
void *external_relocs; |
/* Buffer large enough to hold internal relocs of any section. */ |
Elf_Internal_Rela *internal_relocs; |
/* Buffer large enough to hold external local symbols of any input |
BFD. */ |
bfd_byte *external_syms; |
/* And a buffer for symbol section indices. */ |
Elf_External_Sym_Shndx *locsym_shndx; |
/* Buffer large enough to hold internal local symbols of any input |
BFD. */ |
Elf_Internal_Sym *internal_syms; |
/* Array large enough to hold a symbol index for each local symbol |
of any input BFD. */ |
long *indices; |
/* Array large enough to hold a section pointer for each local |
symbol of any input BFD. */ |
asection **sections; |
/* Buffer to hold swapped out symbols. */ |
bfd_byte *symbuf; |
/* And one for symbol section indices. */ |
Elf_External_Sym_Shndx *symshndxbuf; |
/* Number of swapped out symbols in buffer. */ |
size_t symbuf_count; |
/* Number of symbols which fit in symbuf. */ |
size_t symbuf_size; |
/* And same for symshndxbuf. */ |
size_t shndxbuf_size; |
/* Number of STT_FILE syms seen. */ |
size_t filesym_count; |
}; |
/* This struct is used to pass information to elf_link_output_extsym. */ |
struct elf_outext_info |
{ |
bfd_boolean failed; |
bfd_boolean localsyms; |
bfd_boolean need_second_pass; |
bfd_boolean second_pass; |
struct elf_final_link_info *flinfo; |
}; |
/* Support for evaluating a complex relocation. |
Complex relocations are generalized, self-describing relocations. The |
implementation of them consists of two parts: complex symbols, and the |
relocations themselves. |
The relocations are use a reserved elf-wide relocation type code (R_RELC |
external / BFD_RELOC_RELC internal) and an encoding of relocation field |
information (start bit, end bit, word width, etc) into the addend. This |
information is extracted from CGEN-generated operand tables within gas. |
Complex symbols are mangled symbols (BSF_RELC external / STT_RELC |
internal) representing prefix-notation expressions, including but not |
limited to those sorts of expressions normally encoded as addends in the |
addend field. The symbol mangling format is: |
<node> := <literal> |
| <unary-operator> ':' <node> |
| <binary-operator> ':' <node> ':' <node> |
; |
<literal> := 's' <digits=N> ':' <N character symbol name> |
| 'S' <digits=N> ':' <N character section name> |
| '#' <hexdigits> |
; |
<binary-operator> := as in C |
<unary-operator> := as in C, plus "0-" for unambiguous negation. */ |
static void |
set_symbol_value (bfd *bfd_with_globals, |
Elf_Internal_Sym *isymbuf, |
size_t locsymcount, |
size_t symidx, |
bfd_vma val) |
{ |
struct elf_link_hash_entry **sym_hashes; |
struct elf_link_hash_entry *h; |
size_t extsymoff = locsymcount; |
if (symidx < locsymcount) |
{ |
Elf_Internal_Sym *sym; |
sym = isymbuf + symidx; |
if (ELF_ST_BIND (sym->st_info) == STB_LOCAL) |
{ |
/* It is a local symbol: move it to the |
"absolute" section and give it a value. */ |
sym->st_shndx = SHN_ABS; |
sym->st_value = val; |
return; |
} |
BFD_ASSERT (elf_bad_symtab (bfd_with_globals)); |
extsymoff = 0; |
} |
/* It is a global symbol: set its link type |
to "defined" and give it a value. */ |
sym_hashes = elf_sym_hashes (bfd_with_globals); |
h = sym_hashes [symidx - extsymoff]; |
while (h->root.type == bfd_link_hash_indirect |
|| h->root.type == bfd_link_hash_warning) |
h = (struct elf_link_hash_entry *) h->root.u.i.link; |
h->root.type = bfd_link_hash_defined; |
h->root.u.def.value = val; |
h->root.u.def.section = bfd_abs_section_ptr; |
} |
static bfd_boolean |
resolve_symbol (const char *name, |
bfd *input_bfd, |
struct elf_final_link_info *flinfo, |
bfd_vma *result, |
Elf_Internal_Sym *isymbuf, |
size_t locsymcount) |
{ |
Elf_Internal_Sym *sym; |
struct bfd_link_hash_entry *global_entry; |
const char *candidate = NULL; |
Elf_Internal_Shdr *symtab_hdr; |
size_t i; |
symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; |
for (i = 0; i < locsymcount; ++ i) |
{ |
sym = isymbuf + i; |
if (ELF_ST_BIND (sym->st_info) != STB_LOCAL) |
continue; |
candidate = bfd_elf_string_from_elf_section (input_bfd, |
symtab_hdr->sh_link, |
sym->st_name); |
#ifdef DEBUG |
printf ("Comparing string: '%s' vs. '%s' = 0x%lx\n", |
name, candidate, (unsigned long) sym->st_value); |
#endif |
if (candidate && strcmp (candidate, name) == 0) |
{ |
asection *sec = flinfo->sections [i]; |
*result = _bfd_elf_rel_local_sym (input_bfd, sym, &sec, 0); |
*result += sec->output_offset + sec->output_section->vma; |
#ifdef DEBUG |
printf ("Found symbol with value %8.8lx\n", |
(unsigned long) *result); |
#endif |
return TRUE; |
} |
} |
/* Hmm, haven't found it yet. perhaps it is a global. */ |
global_entry = bfd_link_hash_lookup (flinfo->info->hash, name, |
FALSE, FALSE, TRUE); |
if (!global_entry) |
return FALSE; |
if (global_entry->type == bfd_link_hash_defined |
|| global_entry->type == bfd_link_hash_defweak) |
{ |
*result = (global_entry->u.def.value |
+ global_entry->u.def.section->output_section->vma |
+ global_entry->u.def.section->output_offset); |
#ifdef DEBUG |
printf ("Found GLOBAL symbol '%s' with value %8.8lx\n", |
global_entry->root.string, (unsigned long) *result); |
#endif |
return TRUE; |
} |
return FALSE; |
} |
static bfd_boolean |
resolve_section (const char *name, |
asection *sections, |
bfd_vma *result) |
{ |
asection *curr; |
unsigned int len; |
for (curr = sections; curr; curr = curr->next) |
if (strcmp (curr->name, name) == 0) |
{ |
*result = curr->vma; |
return TRUE; |
} |
/* Hmm. still haven't found it. try pseudo-section names. */ |
for (curr = sections; curr; curr = curr->next) |
{ |
len = strlen (curr->name); |
if (len > strlen (name)) |
continue; |
if (strncmp (curr->name, name, len) == 0) |
{ |
if (strncmp (".end", name + len, 4) == 0) |
{ |
*result = curr->vma + curr->size; |
return TRUE; |
} |
/* Insert more pseudo-section names here, if you like. */ |
} |
} |
return FALSE; |
} |
static void |
undefined_reference (const char *reftype, const char *name) |
{ |
_bfd_error_handler (_("undefined %s reference in complex symbol: %s"), |
reftype, name); |
} |
static bfd_boolean |
eval_symbol (bfd_vma *result, |
const char **symp, |
bfd *input_bfd, |
struct elf_final_link_info *flinfo, |
bfd_vma dot, |
Elf_Internal_Sym *isymbuf, |
size_t locsymcount, |
int signed_p) |
{ |
size_t len; |
size_t symlen; |
bfd_vma a; |
bfd_vma b; |
char symbuf[4096]; |
const char *sym = *symp; |
const char *symend; |
bfd_boolean symbol_is_section = FALSE; |
len = strlen (sym); |
symend = sym + len; |
if (len < 1 || len > sizeof (symbuf)) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
switch (* sym) |
{ |
case '.': |
*result = dot; |
*symp = sym + 1; |
return TRUE; |
case '#': |
++sym; |
*result = strtoul (sym, (char **) symp, 16); |
return TRUE; |
case 'S': |
symbol_is_section = TRUE; |
case 's': |
++sym; |
symlen = strtol (sym, (char **) symp, 10); |
sym = *symp + 1; /* Skip the trailing ':'. */ |
if (symend < sym || symlen + 1 > sizeof (symbuf)) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
memcpy (symbuf, sym, symlen); |
symbuf[symlen] = '\0'; |
*symp = sym + symlen; |
/* Is it always possible, with complex symbols, that gas "mis-guessed" |
the symbol as a section, or vice-versa. so we're pretty liberal in our |
interpretation here; section means "try section first", not "must be a |
section", and likewise with symbol. */ |
if (symbol_is_section) |
{ |
if (!resolve_section (symbuf, flinfo->output_bfd->sections, result) |
&& !resolve_symbol (symbuf, input_bfd, flinfo, result, |
isymbuf, locsymcount)) |
{ |
undefined_reference ("section", symbuf); |
return FALSE; |
} |
} |
else |
{ |
if (!resolve_symbol (symbuf, input_bfd, flinfo, result, |
isymbuf, locsymcount) |
&& !resolve_section (symbuf, flinfo->output_bfd->sections, |
result)) |
{ |
undefined_reference ("symbol", symbuf); |
return FALSE; |
} |
} |
return TRUE; |
/* All that remains are operators. */ |
#define UNARY_OP(op) \ |
if (strncmp (sym, #op, strlen (#op)) == 0) \ |
{ \ |
sym += strlen (#op); \ |
if (*sym == ':') \ |
++sym; \ |
*symp = sym; \ |
if (!eval_symbol (&a, symp, input_bfd, flinfo, dot, \ |
isymbuf, locsymcount, signed_p)) \ |
return FALSE; \ |
if (signed_p) \ |
*result = op ((bfd_signed_vma) a); \ |
else \ |
*result = op a; \ |
return TRUE; \ |
} |
#define BINARY_OP(op) \ |
if (strncmp (sym, #op, strlen (#op)) == 0) \ |
{ \ |
sym += strlen (#op); \ |
if (*sym == ':') \ |
++sym; \ |
*symp = sym; \ |
if (!eval_symbol (&a, symp, input_bfd, flinfo, dot, \ |
isymbuf, locsymcount, signed_p)) \ |
return FALSE; \ |
++*symp; \ |
if (!eval_symbol (&b, symp, input_bfd, flinfo, dot, \ |
isymbuf, locsymcount, signed_p)) \ |
return FALSE; \ |
if (signed_p) \ |
*result = ((bfd_signed_vma) a) op ((bfd_signed_vma) b); \ |
else \ |
*result = a op b; \ |
return TRUE; \ |
} |
default: |
UNARY_OP (0-); |
BINARY_OP (<<); |
BINARY_OP (>>); |
BINARY_OP (==); |
BINARY_OP (!=); |
BINARY_OP (<=); |
BINARY_OP (>=); |
BINARY_OP (&&); |
BINARY_OP (||); |
UNARY_OP (~); |
UNARY_OP (!); |
BINARY_OP (*); |
BINARY_OP (/); |
BINARY_OP (%); |
BINARY_OP (^); |
BINARY_OP (|); |
BINARY_OP (&); |
BINARY_OP (+); |
BINARY_OP (-); |
BINARY_OP (<); |
BINARY_OP (>); |
#undef UNARY_OP |
#undef BINARY_OP |
_bfd_error_handler (_("unknown operator '%c' in complex symbol"), * sym); |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
} |
static void |
put_value (bfd_vma size, |
unsigned long chunksz, |
bfd *input_bfd, |
bfd_vma x, |
bfd_byte *location) |
{ |
location += (size - chunksz); |
for (; size; size -= chunksz, location -= chunksz, x >>= (chunksz * 8)) |
{ |
switch (chunksz) |
{ |
default: |
case 0: |
abort (); |
case 1: |
bfd_put_8 (input_bfd, x, location); |
break; |
case 2: |
bfd_put_16 (input_bfd, x, location); |
break; |
case 4: |
bfd_put_32 (input_bfd, x, location); |
break; |
case 8: |
#ifdef BFD64 |
bfd_put_64 (input_bfd, x, location); |
#else |
abort (); |
#endif |
break; |
} |
} |
} |
static bfd_vma |
get_value (bfd_vma size, |
unsigned long chunksz, |
bfd *input_bfd, |
bfd_byte *location) |
{ |
int shift; |
bfd_vma x = 0; |
/* Sanity checks. */ |
BFD_ASSERT (chunksz <= sizeof (x) |
&& size >= chunksz |
&& chunksz != 0 |
&& (size % chunksz) == 0 |
&& input_bfd != NULL |
&& location != NULL); |
if (chunksz == sizeof (x)) |
{ |
BFD_ASSERT (size == chunksz); |
/* Make sure that we do not perform an undefined shift operation. |
We know that size == chunksz so there will only be one iteration |
of the loop below. */ |
shift = 0; |
} |
else |
shift = 8 * chunksz; |
for (; size; size -= chunksz, location += chunksz) |
{ |
switch (chunksz) |
{ |
case 1: |
x = (x << shift) | bfd_get_8 (input_bfd, location); |
break; |
case 2: |
x = (x << shift) | bfd_get_16 (input_bfd, location); |
break; |
case 4: |
x = (x << shift) | bfd_get_32 (input_bfd, location); |
break; |
#ifdef BFD64 |
case 8: |
x = (x << shift) | bfd_get_64 (input_bfd, location); |
break; |
#endif |
default: |
abort (); |
} |
} |
return x; |
} |
static void |
decode_complex_addend (unsigned long *start, /* in bits */ |
unsigned long *oplen, /* in bits */ |
unsigned long *len, /* in bits */ |
unsigned long *wordsz, /* in bytes */ |
unsigned long *chunksz, /* in bytes */ |
unsigned long *lsb0_p, |
unsigned long *signed_p, |
unsigned long *trunc_p, |
unsigned long encoded) |
{ |
* start = encoded & 0x3F; |
* len = (encoded >> 6) & 0x3F; |
* oplen = (encoded >> 12) & 0x3F; |
* wordsz = (encoded >> 18) & 0xF; |
* chunksz = (encoded >> 22) & 0xF; |
* lsb0_p = (encoded >> 27) & 1; |
* signed_p = (encoded >> 28) & 1; |
* trunc_p = (encoded >> 29) & 1; |
} |
bfd_reloc_status_type |
bfd_elf_perform_complex_relocation (bfd *input_bfd, |
asection *input_section ATTRIBUTE_UNUSED, |
bfd_byte *contents, |
Elf_Internal_Rela *rel, |
bfd_vma relocation) |
{ |
bfd_vma shift, x, mask; |
unsigned long start, oplen, len, wordsz, chunksz, lsb0_p, signed_p, trunc_p; |
bfd_reloc_status_type r; |
/* Perform this reloc, since it is complex. |
(this is not to say that it necessarily refers to a complex |
symbol; merely that it is a self-describing CGEN based reloc. |
i.e. the addend has the complete reloc information (bit start, end, |
word size, etc) encoded within it.). */ |
decode_complex_addend (&start, &oplen, &len, &wordsz, |
&chunksz, &lsb0_p, &signed_p, |
&trunc_p, rel->r_addend); |
mask = (((1L << (len - 1)) - 1) << 1) | 1; |
if (lsb0_p) |
shift = (start + 1) - len; |
else |
shift = (8 * wordsz) - (start + len); |
/* FIXME: octets_per_byte. */ |
x = get_value (wordsz, chunksz, input_bfd, contents + rel->r_offset); |
#ifdef DEBUG |
printf ("Doing complex reloc: " |
"lsb0? %ld, signed? %ld, trunc? %ld, wordsz %ld, " |
"chunksz %ld, start %ld, len %ld, oplen %ld\n" |
" dest: %8.8lx, mask: %8.8lx, reloc: %8.8lx\n", |
lsb0_p, signed_p, trunc_p, wordsz, chunksz, start, len, |
oplen, (unsigned long) x, (unsigned long) mask, |
(unsigned long) relocation); |
#endif |
r = bfd_reloc_ok; |
if (! trunc_p) |
/* Now do an overflow check. */ |
r = bfd_check_overflow ((signed_p |
? complain_overflow_signed |
: complain_overflow_unsigned), |
len, 0, (8 * wordsz), |
relocation); |
/* Do the deed. */ |
x = (x & ~(mask << shift)) | ((relocation & mask) << shift); |
#ifdef DEBUG |
printf (" relocation: %8.8lx\n" |
" shifted mask: %8.8lx\n" |
" shifted/masked reloc: %8.8lx\n" |
" result: %8.8lx\n", |
(unsigned long) relocation, (unsigned long) (mask << shift), |
(unsigned long) ((relocation & mask) << shift), (unsigned long) x); |
#endif |
/* FIXME: octets_per_byte. */ |
put_value (wordsz, chunksz, input_bfd, x, contents + rel->r_offset); |
return r; |
} |
/* When performing a relocatable link, the input relocations are |
preserved. But, if they reference global symbols, the indices |
referenced must be updated. Update all the relocations found in |
RELDATA. */ |
static void |
elf_link_adjust_relocs (bfd *abfd, |
struct bfd_elf_section_reloc_data *reldata) |
{ |
unsigned int i; |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
bfd_byte *erela; |
void (*swap_in) (bfd *, const bfd_byte *, Elf_Internal_Rela *); |
void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *); |
bfd_vma r_type_mask; |
int r_sym_shift; |
unsigned int count = reldata->count; |
struct elf_link_hash_entry **rel_hash = reldata->hashes; |
if (reldata->hdr->sh_entsize == bed->s->sizeof_rel) |
{ |
swap_in = bed->s->swap_reloc_in; |
swap_out = bed->s->swap_reloc_out; |
} |
else if (reldata->hdr->sh_entsize == bed->s->sizeof_rela) |
{ |
swap_in = bed->s->swap_reloca_in; |
swap_out = bed->s->swap_reloca_out; |
} |
else |
abort (); |
if (bed->s->int_rels_per_ext_rel > MAX_INT_RELS_PER_EXT_REL) |
abort (); |
if (bed->s->arch_size == 32) |
{ |
r_type_mask = 0xff; |
r_sym_shift = 8; |
} |
else |
{ |
r_type_mask = 0xffffffff; |
r_sym_shift = 32; |
} |
erela = reldata->hdr->contents; |
for (i = 0; i < count; i++, rel_hash++, erela += reldata->hdr->sh_entsize) |
{ |
Elf_Internal_Rela irela[MAX_INT_RELS_PER_EXT_REL]; |
unsigned int j; |
if (*rel_hash == NULL) |
continue; |
BFD_ASSERT ((*rel_hash)->indx >= 0); |
(*swap_in) (abfd, erela, irela); |
for (j = 0; j < bed->s->int_rels_per_ext_rel; j++) |
irela[j].r_info = ((bfd_vma) (*rel_hash)->indx << r_sym_shift |
| (irela[j].r_info & r_type_mask)); |
(*swap_out) (abfd, irela, erela); |
} |
} |
struct elf_link_sort_rela |
{ |
union { |
bfd_vma offset; |
bfd_vma sym_mask; |
} u; |
enum elf_reloc_type_class type; |
/* We use this as an array of size int_rels_per_ext_rel. */ |
Elf_Internal_Rela rela[1]; |
}; |
static int |
elf_link_sort_cmp1 (const void *A, const void *B) |
{ |
const struct elf_link_sort_rela *a = (const struct elf_link_sort_rela *) A; |
const struct elf_link_sort_rela *b = (const struct elf_link_sort_rela *) B; |
int relativea, relativeb; |
relativea = a->type == reloc_class_relative; |
relativeb = b->type == reloc_class_relative; |
if (relativea < relativeb) |
return 1; |
if (relativea > relativeb) |
return -1; |
if ((a->rela->r_info & a->u.sym_mask) < (b->rela->r_info & b->u.sym_mask)) |
return -1; |
if ((a->rela->r_info & a->u.sym_mask) > (b->rela->r_info & b->u.sym_mask)) |
return 1; |
if (a->rela->r_offset < b->rela->r_offset) |
return -1; |
if (a->rela->r_offset > b->rela->r_offset) |
return 1; |
return 0; |
} |
static int |
elf_link_sort_cmp2 (const void *A, const void *B) |
{ |
const struct elf_link_sort_rela *a = (const struct elf_link_sort_rela *) A; |
const struct elf_link_sort_rela *b = (const struct elf_link_sort_rela *) B; |
if (a->type < b->type) |
return -1; |
if (a->type > b->type) |
return 1; |
if (a->u.offset < b->u.offset) |
return -1; |
if (a->u.offset > b->u.offset) |
return 1; |
if (a->rela->r_offset < b->rela->r_offset) |
return -1; |
if (a->rela->r_offset > b->rela->r_offset) |
return 1; |
return 0; |
} |
static size_t |
elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec) |
{ |
asection *dynamic_relocs; |
asection *rela_dyn; |
asection *rel_dyn; |
bfd_size_type count, size; |
size_t i, ret, sort_elt, ext_size; |
bfd_byte *sort, *s_non_relative, *p; |
struct elf_link_sort_rela *sq; |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
int i2e = bed->s->int_rels_per_ext_rel; |
void (*swap_in) (bfd *, const bfd_byte *, Elf_Internal_Rela *); |
void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *); |
struct bfd_link_order *lo; |
bfd_vma r_sym_mask; |
bfd_boolean use_rela; |
/* Find a dynamic reloc section. */ |
rela_dyn = bfd_get_section_by_name (abfd, ".rela.dyn"); |
rel_dyn = bfd_get_section_by_name (abfd, ".rel.dyn"); |
if (rela_dyn != NULL && rela_dyn->size > 0 |
&& rel_dyn != NULL && rel_dyn->size > 0) |
{ |
bfd_boolean use_rela_initialised = FALSE; |
/* This is just here to stop gcc from complaining. |
It's initialization checking code is not perfect. */ |
use_rela = TRUE; |
/* Both sections are present. Examine the sizes |
of the indirect sections to help us choose. */ |
for (lo = rela_dyn->map_head.link_order; lo != NULL; lo = lo->next) |
if (lo->type == bfd_indirect_link_order) |
{ |
asection *o = lo->u.indirect.section; |
if ((o->size % bed->s->sizeof_rela) == 0) |
{ |
if ((o->size % bed->s->sizeof_rel) == 0) |
/* Section size is divisible by both rel and rela sizes. |
It is of no help to us. */ |
; |
else |
{ |
/* Section size is only divisible by rela. */ |
if (use_rela_initialised && (use_rela == FALSE)) |
{ |
_bfd_error_handler |
(_("%B: Unable to sort relocs - they are in more than one size"), abfd); |
bfd_set_error (bfd_error_invalid_operation); |
return 0; |
} |
else |
{ |
use_rela = TRUE; |
use_rela_initialised = TRUE; |
} |
} |
} |
else if ((o->size % bed->s->sizeof_rel) == 0) |
{ |
/* Section size is only divisible by rel. */ |
if (use_rela_initialised && (use_rela == TRUE)) |
{ |
_bfd_error_handler |
(_("%B: Unable to sort relocs - they are in more than one size"), abfd); |
bfd_set_error (bfd_error_invalid_operation); |
return 0; |
} |
else |
{ |
use_rela = FALSE; |
use_rela_initialised = TRUE; |
} |
} |
else |
{ |
/* The section size is not divisible by either - something is wrong. */ |
_bfd_error_handler |
(_("%B: Unable to sort relocs - they are of an unknown size"), abfd); |
bfd_set_error (bfd_error_invalid_operation); |
return 0; |
} |
} |
for (lo = rel_dyn->map_head.link_order; lo != NULL; lo = lo->next) |
if (lo->type == bfd_indirect_link_order) |
{ |
asection *o = lo->u.indirect.section; |
if ((o->size % bed->s->sizeof_rela) == 0) |
{ |
if ((o->size % bed->s->sizeof_rel) == 0) |
/* Section size is divisible by both rel and rela sizes. |
It is of no help to us. */ |
; |
else |
{ |
/* Section size is only divisible by rela. */ |
if (use_rela_initialised && (use_rela == FALSE)) |
{ |
_bfd_error_handler |
(_("%B: Unable to sort relocs - they are in more than one size"), abfd); |
bfd_set_error (bfd_error_invalid_operation); |
return 0; |
} |
else |
{ |
use_rela = TRUE; |
use_rela_initialised = TRUE; |
} |
} |
} |
else if ((o->size % bed->s->sizeof_rel) == 0) |
{ |
/* Section size is only divisible by rel. */ |
if (use_rela_initialised && (use_rela == TRUE)) |
{ |
_bfd_error_handler |
(_("%B: Unable to sort relocs - they are in more than one size"), abfd); |
bfd_set_error (bfd_error_invalid_operation); |
return 0; |
} |
else |
{ |
use_rela = FALSE; |
use_rela_initialised = TRUE; |
} |
} |
else |
{ |
/* The section size is not divisible by either - something is wrong. */ |
_bfd_error_handler |
(_("%B: Unable to sort relocs - they are of an unknown size"), abfd); |
bfd_set_error (bfd_error_invalid_operation); |
return 0; |
} |
} |
if (! use_rela_initialised) |
/* Make a guess. */ |
use_rela = TRUE; |
} |
else if (rela_dyn != NULL && rela_dyn->size > 0) |
use_rela = TRUE; |
else if (rel_dyn != NULL && rel_dyn->size > 0) |
use_rela = FALSE; |
else |
return 0; |
if (use_rela) |
{ |
dynamic_relocs = rela_dyn; |
ext_size = bed->s->sizeof_rela; |
swap_in = bed->s->swap_reloca_in; |
swap_out = bed->s->swap_reloca_out; |
} |
else |
{ |
dynamic_relocs = rel_dyn; |
ext_size = bed->s->sizeof_rel; |
swap_in = bed->s->swap_reloc_in; |
swap_out = bed->s->swap_reloc_out; |
} |
size = 0; |
for (lo = dynamic_relocs->map_head.link_order; lo != NULL; lo = lo->next) |
if (lo->type == bfd_indirect_link_order) |
size += lo->u.indirect.section->size; |
if (size != dynamic_relocs->size) |
return 0; |
sort_elt = (sizeof (struct elf_link_sort_rela) |
+ (i2e - 1) * sizeof (Elf_Internal_Rela)); |
count = dynamic_relocs->size / ext_size; |
if (count == 0) |
return 0; |
sort = (bfd_byte *) bfd_zmalloc (sort_elt * count); |
if (sort == NULL) |
{ |
(*info->callbacks->warning) |
(info, _("Not enough memory to sort relocations"), 0, abfd, 0, 0); |
return 0; |
} |
if (bed->s->arch_size == 32) |
r_sym_mask = ~(bfd_vma) 0xff; |
else |
r_sym_mask = ~(bfd_vma) 0xffffffff; |
for (lo = dynamic_relocs->map_head.link_order; lo != NULL; lo = lo->next) |
if (lo->type == bfd_indirect_link_order) |
{ |
bfd_byte *erel, *erelend; |
asection *o = lo->u.indirect.section; |
if (o->contents == NULL && o->size != 0) |
{ |
/* This is a reloc section that is being handled as a normal |
section. See bfd_section_from_shdr. We can't combine |
relocs in this case. */ |
free (sort); |
return 0; |
} |
erel = o->contents; |
erelend = o->contents + o->size; |
/* FIXME: octets_per_byte. */ |
p = sort + o->output_offset / ext_size * sort_elt; |
while (erel < erelend) |
{ |
struct elf_link_sort_rela *s = (struct elf_link_sort_rela *) p; |
(*swap_in) (abfd, erel, s->rela); |
s->type = (*bed->elf_backend_reloc_type_class) (info, o, s->rela); |
s->u.sym_mask = r_sym_mask; |
p += sort_elt; |
erel += ext_size; |
} |
} |
qsort (sort, count, sort_elt, elf_link_sort_cmp1); |
for (i = 0, p = sort; i < count; i++, p += sort_elt) |
{ |
struct elf_link_sort_rela *s = (struct elf_link_sort_rela *) p; |
if (s->type != reloc_class_relative) |
break; |
} |
ret = i; |
s_non_relative = p; |
sq = (struct elf_link_sort_rela *) s_non_relative; |
for (; i < count; i++, p += sort_elt) |
{ |
struct elf_link_sort_rela *sp = (struct elf_link_sort_rela *) p; |
if (((sp->rela->r_info ^ sq->rela->r_info) & r_sym_mask) != 0) |
sq = sp; |
sp->u.offset = sq->rela->r_offset; |
} |
qsort (s_non_relative, count - ret, sort_elt, elf_link_sort_cmp2); |
for (lo = dynamic_relocs->map_head.link_order; lo != NULL; lo = lo->next) |
if (lo->type == bfd_indirect_link_order) |
{ |
bfd_byte *erel, *erelend; |
asection *o = lo->u.indirect.section; |
erel = o->contents; |
erelend = o->contents + o->size; |
/* FIXME: octets_per_byte. */ |
p = sort + o->output_offset / ext_size * sort_elt; |
while (erel < erelend) |
{ |
struct elf_link_sort_rela *s = (struct elf_link_sort_rela *) p; |
(*swap_out) (abfd, s->rela, erel); |
p += sort_elt; |
erel += ext_size; |
} |
} |
free (sort); |
*psec = dynamic_relocs; |
return ret; |
} |
/* Flush the output symbols to the file. */ |
static bfd_boolean |
elf_link_flush_output_syms (struct elf_final_link_info *flinfo, |
const struct elf_backend_data *bed) |
{ |
if (flinfo->symbuf_count > 0) |
{ |
Elf_Internal_Shdr *hdr; |
file_ptr pos; |
bfd_size_type amt; |
hdr = &elf_tdata (flinfo->output_bfd)->symtab_hdr; |
pos = hdr->sh_offset + hdr->sh_size; |
amt = flinfo->symbuf_count * bed->s->sizeof_sym; |
if (bfd_seek (flinfo->output_bfd, pos, SEEK_SET) != 0 |
|| bfd_bwrite (flinfo->symbuf, amt, flinfo->output_bfd) != amt) |
return FALSE; |
hdr->sh_size += amt; |
flinfo->symbuf_count = 0; |
} |
return TRUE; |
} |
/* Add a symbol to the output symbol table. */ |
static int |
elf_link_output_sym (struct elf_final_link_info *flinfo, |
const char *name, |
Elf_Internal_Sym *elfsym, |
asection *input_sec, |
struct elf_link_hash_entry *h) |
{ |
bfd_byte *dest; |
Elf_External_Sym_Shndx *destshndx; |
int (*output_symbol_hook) |
(struct bfd_link_info *, const char *, Elf_Internal_Sym *, asection *, |
struct elf_link_hash_entry *); |
const struct elf_backend_data *bed; |
bed = get_elf_backend_data (flinfo->output_bfd); |
output_symbol_hook = bed->elf_backend_link_output_symbol_hook; |
if (output_symbol_hook != NULL) |
{ |
int ret = (*output_symbol_hook) (flinfo->info, name, elfsym, input_sec, h); |
if (ret != 1) |
return ret; |
} |
if (name == NULL || *name == '\0') |
elfsym->st_name = 0; |
else if (input_sec->flags & SEC_EXCLUDE) |
elfsym->st_name = 0; |
else |
{ |
elfsym->st_name = (unsigned long) _bfd_stringtab_add (flinfo->symstrtab, |
name, TRUE, FALSE); |
if (elfsym->st_name == (unsigned long) -1) |
return 0; |
} |
if (flinfo->symbuf_count >= flinfo->symbuf_size) |
{ |
if (! elf_link_flush_output_syms (flinfo, bed)) |
return 0; |
} |
dest = flinfo->symbuf + flinfo->symbuf_count * bed->s->sizeof_sym; |
destshndx = flinfo->symshndxbuf; |
if (destshndx != NULL) |
{ |
if (bfd_get_symcount (flinfo->output_bfd) >= flinfo->shndxbuf_size) |
{ |
bfd_size_type amt; |
amt = flinfo->shndxbuf_size * sizeof (Elf_External_Sym_Shndx); |
destshndx = (Elf_External_Sym_Shndx *) bfd_realloc (destshndx, |
amt * 2); |
if (destshndx == NULL) |
return 0; |
flinfo->symshndxbuf = destshndx; |
memset ((char *) destshndx + amt, 0, amt); |
flinfo->shndxbuf_size *= 2; |
} |
destshndx += bfd_get_symcount (flinfo->output_bfd); |
} |
bed->s->swap_symbol_out (flinfo->output_bfd, elfsym, dest, destshndx); |
flinfo->symbuf_count += 1; |
bfd_get_symcount (flinfo->output_bfd) += 1; |
return 1; |
} |
/* Return TRUE if the dynamic symbol SYM in ABFD is supported. */ |
static bfd_boolean |
check_dynsym (bfd *abfd, Elf_Internal_Sym *sym) |
{ |
if (sym->st_shndx >= (SHN_LORESERVE & 0xffff) |
&& sym->st_shndx < SHN_LORESERVE) |
{ |
/* The gABI doesn't support dynamic symbols in output sections |
beyond 64k. */ |
(*_bfd_error_handler) |
(_("%B: Too many sections: %d (>= %d)"), |
abfd, bfd_count_sections (abfd), SHN_LORESERVE & 0xffff); |
bfd_set_error (bfd_error_nonrepresentable_section); |
return FALSE; |
} |
return TRUE; |
} |
/* For DSOs loaded in via a DT_NEEDED entry, emulate ld.so in |
allowing an unsatisfied unversioned symbol in the DSO to match a |
versioned symbol that would normally require an explicit version. |
We also handle the case that a DSO references a hidden symbol |
which may be satisfied by a versioned symbol in another DSO. */ |
static bfd_boolean |
elf_link_check_versioned_symbol (struct bfd_link_info *info, |
const struct elf_backend_data *bed, |
struct elf_link_hash_entry *h) |
{ |
bfd *abfd; |
struct elf_link_loaded_list *loaded; |
if (!is_elf_hash_table (info->hash)) |
return FALSE; |
/* Check indirect symbol. */ |
while (h->root.type == bfd_link_hash_indirect) |
h = (struct elf_link_hash_entry *) h->root.u.i.link; |
switch (h->root.type) |
{ |
default: |
abfd = NULL; |
break; |
case bfd_link_hash_undefined: |
case bfd_link_hash_undefweak: |
abfd = h->root.u.undef.abfd; |
if ((abfd->flags & DYNAMIC) == 0 |
|| (elf_dyn_lib_class (abfd) & DYN_DT_NEEDED) == 0) |
return FALSE; |
break; |
case bfd_link_hash_defined: |
case bfd_link_hash_defweak: |
abfd = h->root.u.def.section->owner; |
break; |
case bfd_link_hash_common: |
abfd = h->root.u.c.p->section->owner; |
break; |
} |
BFD_ASSERT (abfd != NULL); |
for (loaded = elf_hash_table (info)->loaded; |
loaded != NULL; |
loaded = loaded->next) |
{ |
bfd *input; |
Elf_Internal_Shdr *hdr; |
bfd_size_type symcount; |
bfd_size_type extsymcount; |
bfd_size_type extsymoff; |
Elf_Internal_Shdr *versymhdr; |
Elf_Internal_Sym *isym; |
Elf_Internal_Sym *isymend; |
Elf_Internal_Sym *isymbuf; |
Elf_External_Versym *ever; |
Elf_External_Versym *extversym; |
input = loaded->abfd; |
/* We check each DSO for a possible hidden versioned definition. */ |
if (input == abfd |
|| (input->flags & DYNAMIC) == 0 |
|| elf_dynversym (input) == 0) |
continue; |
hdr = &elf_tdata (input)->dynsymtab_hdr; |
symcount = hdr->sh_size / bed->s->sizeof_sym; |
if (elf_bad_symtab (input)) |
{ |
extsymcount = symcount; |
extsymoff = 0; |
} |
else |
{ |
extsymcount = symcount - hdr->sh_info; |
extsymoff = hdr->sh_info; |
} |
if (extsymcount == 0) |
continue; |
isymbuf = bfd_elf_get_elf_syms (input, hdr, extsymcount, extsymoff, |
NULL, NULL, NULL); |
if (isymbuf == NULL) |
return FALSE; |
/* Read in any version definitions. */ |
versymhdr = &elf_tdata (input)->dynversym_hdr; |
extversym = (Elf_External_Versym *) bfd_malloc (versymhdr->sh_size); |
if (extversym == NULL) |
goto error_ret; |
if (bfd_seek (input, versymhdr->sh_offset, SEEK_SET) != 0 |
|| (bfd_bread (extversym, versymhdr->sh_size, input) |
!= versymhdr->sh_size)) |
{ |
free (extversym); |
error_ret: |
free (isymbuf); |
return FALSE; |
} |
ever = extversym + extsymoff; |
isymend = isymbuf + extsymcount; |
for (isym = isymbuf; isym < isymend; isym++, ever++) |
{ |
const char *name; |
Elf_Internal_Versym iver; |
unsigned short version_index; |
if (ELF_ST_BIND (isym->st_info) == STB_LOCAL |
|| isym->st_shndx == SHN_UNDEF) |
continue; |
name = bfd_elf_string_from_elf_section (input, |
hdr->sh_link, |
isym->st_name); |
if (strcmp (name, h->root.root.string) != 0) |
continue; |
_bfd_elf_swap_versym_in (input, ever, &iver); |
if ((iver.vs_vers & VERSYM_HIDDEN) == 0 |
&& !(h->def_regular |
&& h->forced_local)) |
{ |
/* If we have a non-hidden versioned sym, then it should |
have provided a definition for the undefined sym unless |
it is defined in a non-shared object and forced local. |
*/ |
abort (); |
} |
version_index = iver.vs_vers & VERSYM_VERSION; |
if (version_index == 1 || version_index == 2) |
{ |
/* This is the base or first version. We can use it. */ |
free (extversym); |
free (isymbuf); |
return TRUE; |
} |
} |
free (extversym); |
free (isymbuf); |
} |
return FALSE; |
} |
/* Add an external symbol to the symbol table. This is called from |
the hash table traversal routine. When generating a shared object, |
we go through the symbol table twice. The first time we output |
anything that might have been forced to local scope in a version |
script. The second time we output the symbols that are still |
global symbols. */ |
static bfd_boolean |
elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) |
{ |
struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) bh; |
struct elf_outext_info *eoinfo = (struct elf_outext_info *) data; |
struct elf_final_link_info *flinfo = eoinfo->flinfo; |
bfd_boolean strip; |
Elf_Internal_Sym sym; |
asection *input_sec; |
const struct elf_backend_data *bed; |
long indx; |
int ret; |
if (h->root.type == bfd_link_hash_warning) |
{ |
h = (struct elf_link_hash_entry *) h->root.u.i.link; |
if (h->root.type == bfd_link_hash_new) |
return TRUE; |
} |
/* Decide whether to output this symbol in this pass. */ |
if (eoinfo->localsyms) |
{ |
if (!h->forced_local) |
return TRUE; |
if (eoinfo->second_pass |
&& !((h->root.type == bfd_link_hash_defined |
|| h->root.type == bfd_link_hash_defweak) |
&& h->root.u.def.section->output_section != NULL)) |
return TRUE; |
} |
else |
{ |
if (h->forced_local) |
return TRUE; |
} |
bed = get_elf_backend_data (flinfo->output_bfd); |
if (h->root.type == bfd_link_hash_undefined) |
{ |
/* If we have an undefined symbol reference here then it must have |
come from a shared library that is being linked in. (Undefined |
references in regular files have already been handled unless |
they are in unreferenced sections which are removed by garbage |
collection). */ |
bfd_boolean ignore_undef = FALSE; |
/* Some symbols may be special in that the fact that they're |
undefined can be safely ignored - let backend determine that. */ |
if (bed->elf_backend_ignore_undef_symbol) |
ignore_undef = bed->elf_backend_ignore_undef_symbol (h); |
/* If we are reporting errors for this situation then do so now. */ |
if (!ignore_undef |
&& h->ref_dynamic |
&& (!h->ref_regular || flinfo->info->gc_sections) |
&& !elf_link_check_versioned_symbol (flinfo->info, bed, h) |
&& flinfo->info->unresolved_syms_in_shared_libs != RM_IGNORE) |
{ |
if (!(flinfo->info->callbacks->undefined_symbol |
(flinfo->info, h->root.root.string, |
h->ref_regular ? NULL : h->root.u.undef.abfd, |
NULL, 0, |
(flinfo->info->unresolved_syms_in_shared_libs |
== RM_GENERATE_ERROR)))) |
{ |
bfd_set_error (bfd_error_bad_value); |
eoinfo->failed = TRUE; |
return FALSE; |
} |
} |
} |
/* We should also warn if a forced local symbol is referenced from |
shared libraries. */ |
if (!flinfo->info->relocatable |
&& flinfo->info->executable |
&& h->forced_local |
&& h->ref_dynamic |
&& h->def_regular |
&& !h->dynamic_def |
&& h->ref_dynamic_nonweak |
&& !elf_link_check_versioned_symbol (flinfo->info, bed, h)) |
{ |
bfd *def_bfd; |
const char *msg; |
struct elf_link_hash_entry *hi = h; |
/* Check indirect symbol. */ |
while (hi->root.type == bfd_link_hash_indirect) |
hi = (struct elf_link_hash_entry *) hi->root.u.i.link; |
if (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL) |
msg = _("%B: internal symbol `%s' in %B is referenced by DSO"); |
else if (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN) |
msg = _("%B: hidden symbol `%s' in %B is referenced by DSO"); |
else |
msg = _("%B: local symbol `%s' in %B is referenced by DSO"); |
def_bfd = flinfo->output_bfd; |
if (hi->root.u.def.section != bfd_abs_section_ptr) |
def_bfd = hi->root.u.def.section->owner; |
(*_bfd_error_handler) (msg, flinfo->output_bfd, def_bfd, |
h->root.root.string); |
bfd_set_error (bfd_error_bad_value); |
eoinfo->failed = TRUE; |
return FALSE; |
} |
/* We don't want to output symbols that have never been mentioned by |
a regular file, or that we have been told to strip. However, if |
h->indx is set to -2, the symbol is used by a reloc and we must |
output it. */ |
if (h->indx == -2) |
strip = FALSE; |
else if ((h->def_dynamic |
|| h->ref_dynamic |
|| h->root.type == bfd_link_hash_new) |
&& !h->def_regular |
&& !h->ref_regular) |
strip = TRUE; |
else if (flinfo->info->strip == strip_all) |
strip = TRUE; |
else if (flinfo->info->strip == strip_some |
&& bfd_hash_lookup (flinfo->info->keep_hash, |
h->root.root.string, FALSE, FALSE) == NULL) |
strip = TRUE; |
else if ((h->root.type == bfd_link_hash_defined |
|| h->root.type == bfd_link_hash_defweak) |
&& ((flinfo->info->strip_discarded |
&& discarded_section (h->root.u.def.section)) |
|| (h->root.u.def.section->owner != NULL |
&& (h->root.u.def.section->owner->flags & BFD_PLUGIN) != 0))) |
strip = TRUE; |
else if ((h->root.type == bfd_link_hash_undefined |
|| h->root.type == bfd_link_hash_undefweak) |
&& h->root.u.undef.abfd != NULL |
&& (h->root.u.undef.abfd->flags & BFD_PLUGIN) != 0) |
strip = TRUE; |
else |
strip = FALSE; |
/* If we're stripping it, and it's not a dynamic symbol, there's |
nothing else to do unless it is a forced local symbol or a |
STT_GNU_IFUNC symbol. */ |
if (strip |
&& h->dynindx == -1 |
&& h->type != STT_GNU_IFUNC |
&& !h->forced_local) |
return TRUE; |
sym.st_value = 0; |
sym.st_size = h->size; |
sym.st_other = h->other; |
if (h->forced_local) |
{ |
sym.st_info = ELF_ST_INFO (STB_LOCAL, h->type); |
/* Turn off visibility on local symbol. */ |
sym.st_other &= ~ELF_ST_VISIBILITY (-1); |
} |
/* Set STB_GNU_UNIQUE only if symbol is defined in regular object. */ |
else if (h->unique_global && h->def_regular) |
sym.st_info = ELF_ST_INFO (STB_GNU_UNIQUE, h->type); |
else if (h->root.type == bfd_link_hash_undefweak |
|| h->root.type == bfd_link_hash_defweak) |
sym.st_info = ELF_ST_INFO (STB_WEAK, h->type); |
else |
sym.st_info = ELF_ST_INFO (STB_GLOBAL, h->type); |
sym.st_target_internal = h->target_internal; |
switch (h->root.type) |
{ |
default: |
case bfd_link_hash_new: |
case bfd_link_hash_warning: |
abort (); |
return FALSE; |
case bfd_link_hash_undefined: |
case bfd_link_hash_undefweak: |
input_sec = bfd_und_section_ptr; |
sym.st_shndx = SHN_UNDEF; |
break; |
case bfd_link_hash_defined: |
case bfd_link_hash_defweak: |
{ |
input_sec = h->root.u.def.section; |
if (input_sec->output_section != NULL) |
{ |
if (eoinfo->localsyms && flinfo->filesym_count == 1) |
{ |
bfd_boolean second_pass_sym |
= (input_sec->owner == flinfo->output_bfd |
|| input_sec->owner == NULL |
|| (input_sec->flags & SEC_LINKER_CREATED) != 0 |
|| (input_sec->owner->flags & BFD_LINKER_CREATED) != 0); |
eoinfo->need_second_pass |= second_pass_sym; |
if (eoinfo->second_pass != second_pass_sym) |
return TRUE; |
} |
sym.st_shndx = |
_bfd_elf_section_from_bfd_section (flinfo->output_bfd, |
input_sec->output_section); |
if (sym.st_shndx == SHN_BAD) |
{ |
(*_bfd_error_handler) |
(_("%B: could not find output section %A for input section %A"), |
flinfo->output_bfd, input_sec->output_section, input_sec); |
bfd_set_error (bfd_error_nonrepresentable_section); |
eoinfo->failed = TRUE; |
return FALSE; |
} |
/* ELF symbols in relocatable files are section relative, |
but in nonrelocatable files they are virtual |
addresses. */ |
sym.st_value = h->root.u.def.value + input_sec->output_offset; |
if (!flinfo->info->relocatable) |
{ |
sym.st_value += input_sec->output_section->vma; |
if (h->type == STT_TLS) |
{ |
asection *tls_sec = elf_hash_table (flinfo->info)->tls_sec; |
if (tls_sec != NULL) |
sym.st_value -= tls_sec->vma; |
else |
{ |
/* The TLS section may have been garbage collected. */ |
BFD_ASSERT (flinfo->info->gc_sections |
&& !input_sec->gc_mark); |
} |
} |
} |
} |
else |
{ |
BFD_ASSERT (input_sec->owner == NULL |
|| (input_sec->owner->flags & DYNAMIC) != 0); |
sym.st_shndx = SHN_UNDEF; |
input_sec = bfd_und_section_ptr; |
} |
} |
break; |
case bfd_link_hash_common: |
input_sec = h->root.u.c.p->section; |
sym.st_shndx = bed->common_section_index (input_sec); |
sym.st_value = 1 << h->root.u.c.p->alignment_power; |
break; |
case bfd_link_hash_indirect: |
/* These symbols are created by symbol versioning. They point |
to the decorated version of the name. For example, if the |
symbol foo@@GNU_1.2 is the default, which should be used when |
foo is used with no version, then we add an indirect symbol |
foo which points to foo@@GNU_1.2. We ignore these symbols, |
since the indirected symbol is already in the hash table. */ |
return TRUE; |
} |
/* Give the processor backend a chance to tweak the symbol value, |
and also to finish up anything that needs to be done for this |
symbol. FIXME: Not calling elf_backend_finish_dynamic_symbol for |
forced local syms when non-shared is due to a historical quirk. |
STT_GNU_IFUNC symbol must go through PLT. */ |
if ((h->type == STT_GNU_IFUNC |
&& h->def_regular |
&& !flinfo->info->relocatable) |
|| ((h->dynindx != -1 |
|| h->forced_local) |
&& ((flinfo->info->shared |
&& (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT |
|| h->root.type != bfd_link_hash_undefweak)) |
|| !h->forced_local) |
&& elf_hash_table (flinfo->info)->dynamic_sections_created)) |
{ |
if (! ((*bed->elf_backend_finish_dynamic_symbol) |
(flinfo->output_bfd, flinfo->info, h, &sym))) |
{ |
eoinfo->failed = TRUE; |
return FALSE; |
} |
} |
/* If we are marking the symbol as undefined, and there are no |
non-weak references to this symbol from a regular object, then |
mark the symbol as weak undefined; if there are non-weak |
references, mark the symbol as strong. We can't do this earlier, |
because it might not be marked as undefined until the |
finish_dynamic_symbol routine gets through with it. */ |
if (sym.st_shndx == SHN_UNDEF |
&& h->ref_regular |
&& (ELF_ST_BIND (sym.st_info) == STB_GLOBAL |
|| ELF_ST_BIND (sym.st_info) == STB_WEAK)) |
{ |
int bindtype; |
unsigned int type = ELF_ST_TYPE (sym.st_info); |
/* Turn an undefined IFUNC symbol into a normal FUNC symbol. */ |
if (type == STT_GNU_IFUNC) |
type = STT_FUNC; |
if (h->ref_regular_nonweak) |
bindtype = STB_GLOBAL; |
else |
bindtype = STB_WEAK; |
sym.st_info = ELF_ST_INFO (bindtype, type); |
} |
/* If this is a symbol defined in a dynamic library, don't use the |
symbol size from the dynamic library. Relinking an executable |
against a new library may introduce gratuitous changes in the |
executable's symbols if we keep the size. */ |
if (sym.st_shndx == SHN_UNDEF |
&& !h->def_regular |
&& h->def_dynamic) |
sym.st_size = 0; |
/* If a non-weak symbol with non-default visibility is not defined |
locally, it is a fatal error. */ |
if (!flinfo->info->relocatable |
&& ELF_ST_VISIBILITY (sym.st_other) != STV_DEFAULT |
&& ELF_ST_BIND (sym.st_info) != STB_WEAK |
&& h->root.type == bfd_link_hash_undefined |
&& !h->def_regular) |
{ |
const char *msg; |
if (ELF_ST_VISIBILITY (sym.st_other) == STV_PROTECTED) |
msg = _("%B: protected symbol `%s' isn't defined"); |
else if (ELF_ST_VISIBILITY (sym.st_other) == STV_INTERNAL) |
msg = _("%B: internal symbol `%s' isn't defined"); |
else |
msg = _("%B: hidden symbol `%s' isn't defined"); |
(*_bfd_error_handler) (msg, flinfo->output_bfd, h->root.root.string); |
bfd_set_error (bfd_error_bad_value); |
eoinfo->failed = TRUE; |
return FALSE; |
} |
/* If this symbol should be put in the .dynsym section, then put it |
there now. We already know the symbol index. We also fill in |
the entry in the .hash section. */ |
if (flinfo->dynsym_sec != NULL |
&& h->dynindx != -1 |
&& elf_hash_table (flinfo->info)->dynamic_sections_created) |
{ |
bfd_byte *esym; |
/* Since there is no version information in the dynamic string, |
if there is no version info in symbol version section, we will |
have a run-time problem. */ |
if (h->verinfo.verdef == NULL) |
{ |
char *p = strrchr (h->root.root.string, ELF_VER_CHR); |
if (p && p [1] != '\0') |
{ |
(*_bfd_error_handler) |
(_("%B: No symbol version section for versioned symbol `%s'"), |
flinfo->output_bfd, h->root.root.string); |
eoinfo->failed = TRUE; |
return FALSE; |
} |
} |
sym.st_name = h->dynstr_index; |
esym = flinfo->dynsym_sec->contents + h->dynindx * bed->s->sizeof_sym; |
if (!check_dynsym (flinfo->output_bfd, &sym)) |
{ |
eoinfo->failed = TRUE; |
return FALSE; |
} |
bed->s->swap_symbol_out (flinfo->output_bfd, &sym, esym, 0); |
if (flinfo->hash_sec != NULL) |
{ |
size_t hash_entry_size; |
bfd_byte *bucketpos; |
bfd_vma chain; |
size_t bucketcount; |
size_t bucket; |
bucketcount = elf_hash_table (flinfo->info)->bucketcount; |
bucket = h->u.elf_hash_value % bucketcount; |
hash_entry_size |
= elf_section_data (flinfo->hash_sec)->this_hdr.sh_entsize; |
bucketpos = ((bfd_byte *) flinfo->hash_sec->contents |
+ (bucket + 2) * hash_entry_size); |
chain = bfd_get (8 * hash_entry_size, flinfo->output_bfd, bucketpos); |
bfd_put (8 * hash_entry_size, flinfo->output_bfd, h->dynindx, |
bucketpos); |
bfd_put (8 * hash_entry_size, flinfo->output_bfd, chain, |
((bfd_byte *) flinfo->hash_sec->contents |
+ (bucketcount + 2 + h->dynindx) * hash_entry_size)); |
} |
if (flinfo->symver_sec != NULL && flinfo->symver_sec->contents != NULL) |
{ |
Elf_Internal_Versym iversym; |
Elf_External_Versym *eversym; |
if (!h->def_regular) |
{ |
if (h->verinfo.verdef == NULL) |
iversym.vs_vers = 0; |
else |
iversym.vs_vers = h->verinfo.verdef->vd_exp_refno + 1; |
} |
else |
{ |
if (h->verinfo.vertree == NULL) |
iversym.vs_vers = 1; |
else |
iversym.vs_vers = h->verinfo.vertree->vernum + 1; |
if (flinfo->info->create_default_symver) |
iversym.vs_vers++; |
} |
if (h->hidden) |
iversym.vs_vers |= VERSYM_HIDDEN; |
eversym = (Elf_External_Versym *) flinfo->symver_sec->contents; |
eversym += h->dynindx; |
_bfd_elf_swap_versym_out (flinfo->output_bfd, &iversym, eversym); |
} |
} |
/* If we're stripping it, then it was just a dynamic symbol, and |
there's nothing else to do. */ |
if (strip || (input_sec->flags & SEC_EXCLUDE) != 0) |
return TRUE; |
indx = bfd_get_symcount (flinfo->output_bfd); |
ret = elf_link_output_sym (flinfo, h->root.root.string, &sym, input_sec, h); |
if (ret == 0) |
{ |
eoinfo->failed = TRUE; |
return FALSE; |
} |
else if (ret == 1) |
h->indx = indx; |
else if (h->indx == -2) |
abort(); |
return TRUE; |
} |
/* Return TRUE if special handling is done for relocs in SEC against |
symbols defined in discarded sections. */ |
static bfd_boolean |
elf_section_ignore_discarded_relocs (asection *sec) |
{ |
const struct elf_backend_data *bed; |
switch (sec->sec_info_type) |
{ |
case SEC_INFO_TYPE_STABS: |
case SEC_INFO_TYPE_EH_FRAME: |
return TRUE; |
default: |
break; |
} |
bed = get_elf_backend_data (sec->owner); |
if (bed->elf_backend_ignore_discarded_relocs != NULL |
&& (*bed->elf_backend_ignore_discarded_relocs) (sec)) |
return TRUE; |
return FALSE; |
} |
/* Return a mask saying how ld should treat relocations in SEC against |
symbols defined in discarded sections. If this function returns |
COMPLAIN set, ld will issue a warning message. If this function |
returns PRETEND set, and the discarded section was link-once and the |
same size as the kept link-once section, ld will pretend that the |
symbol was actually defined in the kept section. Otherwise ld will |
zero the reloc (at least that is the intent, but some cooperation by |
the target dependent code is needed, particularly for REL targets). */ |
unsigned int |
_bfd_elf_default_action_discarded (asection *sec) |
{ |
if (sec->flags & SEC_DEBUGGING) |
return PRETEND; |
if (strcmp (".eh_frame", sec->name) == 0) |
return 0; |
if (strcmp (".gcc_except_table", sec->name) == 0) |
return 0; |
return COMPLAIN | PRETEND; |
} |
/* Find a match between a section and a member of a section group. */ |
static asection * |
match_group_member (asection *sec, asection *group, |
struct bfd_link_info *info) |
{ |
asection *first = elf_next_in_group (group); |
asection *s = first; |
while (s != NULL) |
{ |
if (bfd_elf_match_symbols_in_sections (s, sec, info)) |
return s; |
s = elf_next_in_group (s); |
if (s == first) |
break; |
} |
return NULL; |
} |
/* Check if the kept section of a discarded section SEC can be used |
to replace it. Return the replacement if it is OK. Otherwise return |
NULL. */ |
asection * |
_bfd_elf_check_kept_section (asection *sec, struct bfd_link_info *info) |
{ |
asection *kept; |
kept = sec->kept_section; |
if (kept != NULL) |
{ |
if ((kept->flags & SEC_GROUP) != 0) |
kept = match_group_member (sec, kept, info); |
if (kept != NULL |
&& ((sec->rawsize != 0 ? sec->rawsize : sec->size) |
!= (kept->rawsize != 0 ? kept->rawsize : kept->size))) |
kept = NULL; |
sec->kept_section = kept; |
} |
return kept; |
} |
/* Link an input file into the linker output file. This function |
handles all the sections and relocations of the input file at once. |
This is so that we only have to read the local symbols once, and |
don't have to keep them in memory. */ |
static bfd_boolean |
elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) |
{ |
int (*relocate_section) |
(bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, |
Elf_Internal_Rela *, Elf_Internal_Sym *, asection **); |
bfd *output_bfd; |
Elf_Internal_Shdr *symtab_hdr; |
size_t locsymcount; |
size_t extsymoff; |
Elf_Internal_Sym *isymbuf; |
Elf_Internal_Sym *isym; |
Elf_Internal_Sym *isymend; |
long *pindex; |
asection **ppsection; |
asection *o; |
const struct elf_backend_data *bed; |
struct elf_link_hash_entry **sym_hashes; |
bfd_size_type address_size; |
bfd_vma r_type_mask; |
int r_sym_shift; |
bfd_boolean have_file_sym = FALSE; |
output_bfd = flinfo->output_bfd; |
bed = get_elf_backend_data (output_bfd); |
relocate_section = bed->elf_backend_relocate_section; |
/* If this is a dynamic object, we don't want to do anything here: |
we don't want the local symbols, and we don't want the section |
contents. */ |
if ((input_bfd->flags & DYNAMIC) != 0) |
return TRUE; |
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; |
if (elf_bad_symtab (input_bfd)) |
{ |
locsymcount = symtab_hdr->sh_size / bed->s->sizeof_sym; |
extsymoff = 0; |
} |
else |
{ |
locsymcount = symtab_hdr->sh_info; |
extsymoff = symtab_hdr->sh_info; |
} |
/* Read the local symbols. */ |
isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; |
if (isymbuf == NULL && locsymcount != 0) |
{ |
isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, locsymcount, 0, |
flinfo->internal_syms, |
flinfo->external_syms, |
flinfo->locsym_shndx); |
if (isymbuf == NULL) |
return FALSE; |
} |
/* Find local symbol sections and adjust values of symbols in |
SEC_MERGE sections. Write out those local symbols we know are |
going into the output file. */ |
isymend = isymbuf + locsymcount; |
for (isym = isymbuf, pindex = flinfo->indices, ppsection = flinfo->sections; |
isym < isymend; |
isym++, pindex++, ppsection++) |
{ |
asection *isec; |
const char *name; |
Elf_Internal_Sym osym; |
long indx; |
int ret; |
*pindex = -1; |
if (elf_bad_symtab (input_bfd)) |
{ |
if (ELF_ST_BIND (isym->st_info) != STB_LOCAL) |
{ |
*ppsection = NULL; |
continue; |
} |
} |
if (isym->st_shndx == SHN_UNDEF) |
isec = bfd_und_section_ptr; |
else if (isym->st_shndx == SHN_ABS) |
isec = bfd_abs_section_ptr; |
else if (isym->st_shndx == SHN_COMMON) |
isec = bfd_com_section_ptr; |
else |
{ |
isec = bfd_section_from_elf_index (input_bfd, isym->st_shndx); |
if (isec == NULL) |
{ |
/* Don't attempt to output symbols with st_shnx in the |
reserved range other than SHN_ABS and SHN_COMMON. */ |
*ppsection = NULL; |
continue; |
} |
else if (isec->sec_info_type == SEC_INFO_TYPE_MERGE |
&& ELF_ST_TYPE (isym->st_info) != STT_SECTION) |
isym->st_value = |
_bfd_merged_section_offset (output_bfd, &isec, |
elf_section_data (isec)->sec_info, |
isym->st_value); |
} |
*ppsection = isec; |
/* Don't output the first, undefined, symbol. */ |
if (ppsection == flinfo->sections) |
continue; |
if (ELF_ST_TYPE (isym->st_info) == STT_SECTION) |
{ |
/* We never output section symbols. Instead, we use the |
section symbol of the corresponding section in the output |
file. */ |
continue; |
} |
/* If we are stripping all symbols, we don't want to output this |
one. */ |
if (flinfo->info->strip == strip_all) |
continue; |
/* If we are discarding all local symbols, we don't want to |
output this one. If we are generating a relocatable output |
file, then some of the local symbols may be required by |
relocs; we output them below as we discover that they are |
needed. */ |
if (flinfo->info->discard == discard_all) |
continue; |
/* If this symbol is defined in a section which we are |
discarding, we don't need to keep it. */ |
if (isym->st_shndx != SHN_UNDEF |
&& isym->st_shndx < SHN_LORESERVE |
&& bfd_section_removed_from_list (output_bfd, |
isec->output_section)) |
continue; |
/* Get the name of the symbol. */ |
name = bfd_elf_string_from_elf_section (input_bfd, symtab_hdr->sh_link, |
isym->st_name); |
if (name == NULL) |
return FALSE; |
/* See if we are discarding symbols with this name. */ |
if ((flinfo->info->strip == strip_some |
&& (bfd_hash_lookup (flinfo->info->keep_hash, name, FALSE, FALSE) |
== NULL)) |
|| (((flinfo->info->discard == discard_sec_merge |
&& (isec->flags & SEC_MERGE) && !flinfo->info->relocatable) |
|| flinfo->info->discard == discard_l) |
&& bfd_is_local_label_name (input_bfd, name))) |
continue; |
if (ELF_ST_TYPE (isym->st_info) == STT_FILE) |
{ |
have_file_sym = TRUE; |
flinfo->filesym_count += 1; |
} |
if (!have_file_sym) |
{ |
/* In the absence of debug info, bfd_find_nearest_line uses |
FILE symbols to determine the source file for local |
function symbols. Provide a FILE symbol here if input |
files lack such, so that their symbols won't be |
associated with a previous input file. It's not the |
source file, but the best we can do. */ |
have_file_sym = TRUE; |
flinfo->filesym_count += 1; |
memset (&osym, 0, sizeof (osym)); |
osym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE); |
osym.st_shndx = SHN_ABS; |
if (!elf_link_output_sym (flinfo, input_bfd->filename, &osym, |
bfd_abs_section_ptr, NULL)) |
return FALSE; |
} |
osym = *isym; |
/* Adjust the section index for the output file. */ |
osym.st_shndx = _bfd_elf_section_from_bfd_section (output_bfd, |
isec->output_section); |
if (osym.st_shndx == SHN_BAD) |
return FALSE; |
/* ELF symbols in relocatable files are section relative, but |
in executable files they are virtual addresses. Note that |
this code assumes that all ELF sections have an associated |
BFD section with a reasonable value for output_offset; below |
we assume that they also have a reasonable value for |
output_section. Any special sections must be set up to meet |
these requirements. */ |
osym.st_value += isec->output_offset; |
if (!flinfo->info->relocatable) |
{ |
osym.st_value += isec->output_section->vma; |
if (ELF_ST_TYPE (osym.st_info) == STT_TLS) |
{ |
/* STT_TLS symbols are relative to PT_TLS segment base. */ |
BFD_ASSERT (elf_hash_table (flinfo->info)->tls_sec != NULL); |
osym.st_value -= elf_hash_table (flinfo->info)->tls_sec->vma; |
} |
} |
indx = bfd_get_symcount (output_bfd); |
ret = elf_link_output_sym (flinfo, name, &osym, isec, NULL); |
if (ret == 0) |
return FALSE; |
else if (ret == 1) |
*pindex = indx; |
} |
if (bed->s->arch_size == 32) |
{ |
r_type_mask = 0xff; |
r_sym_shift = 8; |
address_size = 4; |
} |
else |
{ |
r_type_mask = 0xffffffff; |
r_sym_shift = 32; |
address_size = 8; |
} |
/* Relocate the contents of each section. */ |
sym_hashes = elf_sym_hashes (input_bfd); |
for (o = input_bfd->sections; o != NULL; o = o->next) |
{ |
bfd_byte *contents; |
if (! o->linker_mark) |
{ |
/* This section was omitted from the link. */ |
continue; |
} |
if (flinfo->info->relocatable |
&& (o->flags & (SEC_LINKER_CREATED | SEC_GROUP)) == SEC_GROUP) |
{ |
/* Deal with the group signature symbol. */ |
struct bfd_elf_section_data *sec_data = elf_section_data (o); |
unsigned long symndx = sec_data->this_hdr.sh_info; |
asection *osec = o->output_section; |
if (symndx >= locsymcount |
|| (elf_bad_symtab (input_bfd) |
&& flinfo->sections[symndx] == NULL)) |
{ |
struct elf_link_hash_entry *h = sym_hashes[symndx - extsymoff]; |
while (h->root.type == bfd_link_hash_indirect |
|| h->root.type == bfd_link_hash_warning) |
h = (struct elf_link_hash_entry *) h->root.u.i.link; |
/* Arrange for symbol to be output. */ |
h->indx = -2; |
elf_section_data (osec)->this_hdr.sh_info = -2; |
} |
else if (ELF_ST_TYPE (isymbuf[symndx].st_info) == STT_SECTION) |
{ |
/* We'll use the output section target_index. */ |
asection *sec = flinfo->sections[symndx]->output_section; |
elf_section_data (osec)->this_hdr.sh_info = sec->target_index; |
} |
else |
{ |
if (flinfo->indices[symndx] == -1) |
{ |
/* Otherwise output the local symbol now. */ |
Elf_Internal_Sym sym = isymbuf[symndx]; |
asection *sec = flinfo->sections[symndx]->output_section; |
const char *name; |
long indx; |
int ret; |
name = bfd_elf_string_from_elf_section (input_bfd, |
symtab_hdr->sh_link, |
sym.st_name); |
if (name == NULL) |
return FALSE; |
sym.st_shndx = _bfd_elf_section_from_bfd_section (output_bfd, |
sec); |
if (sym.st_shndx == SHN_BAD) |
return FALSE; |
sym.st_value += o->output_offset; |
indx = bfd_get_symcount (output_bfd); |
ret = elf_link_output_sym (flinfo, name, &sym, o, NULL); |
if (ret == 0) |
return FALSE; |
else if (ret == 1) |
flinfo->indices[symndx] = indx; |
else |
abort (); |
} |
elf_section_data (osec)->this_hdr.sh_info |
= flinfo->indices[symndx]; |
} |
} |
if ((o->flags & SEC_HAS_CONTENTS) == 0 |
|| (o->size == 0 && (o->flags & SEC_RELOC) == 0)) |
continue; |
if ((o->flags & SEC_LINKER_CREATED) != 0) |
{ |
/* Section was created by _bfd_elf_link_create_dynamic_sections |
or somesuch. */ |
continue; |
} |
/* Get the contents of the section. They have been cached by a |
relaxation routine. Note that o is a section in an input |
file, so the contents field will not have been set by any of |
the routines which work on output files. */ |
if (elf_section_data (o)->this_hdr.contents != NULL) |
contents = elf_section_data (o)->this_hdr.contents; |
else |
{ |
contents = flinfo->contents; |
if (! bfd_get_full_section_contents (input_bfd, o, &contents)) |
return FALSE; |
} |
if ((o->flags & SEC_RELOC) != 0) |
{ |
Elf_Internal_Rela *internal_relocs; |
Elf_Internal_Rela *rel, *relend; |
int action_discarded; |
int ret; |
/* Get the swapped relocs. */ |
internal_relocs |
= _bfd_elf_link_read_relocs (input_bfd, o, flinfo->external_relocs, |
flinfo->internal_relocs, FALSE); |
if (internal_relocs == NULL |
&& o->reloc_count > 0) |
return FALSE; |
/* We need to reverse-copy input .ctors/.dtors sections if |
they are placed in .init_array/.finit_array for output. */ |
if (o->size > address_size |
&& ((strncmp (o->name, ".ctors", 6) == 0 |
&& strcmp (o->output_section->name, |
".init_array") == 0) |
|| (strncmp (o->name, ".dtors", 6) == 0 |
&& strcmp (o->output_section->name, |
".fini_array") == 0)) |
&& (o->name[6] == 0 || o->name[6] == '.')) |
{ |
if (o->size != o->reloc_count * address_size) |
{ |
(*_bfd_error_handler) |
(_("error: %B: size of section %A is not " |
"multiple of address size"), |
input_bfd, o); |
bfd_set_error (bfd_error_on_input); |
return FALSE; |
} |
o->flags |= SEC_ELF_REVERSE_COPY; |
} |
action_discarded = -1; |
if (!elf_section_ignore_discarded_relocs (o)) |
action_discarded = (*bed->action_discarded) (o); |
/* Run through the relocs evaluating complex reloc symbols and |
looking for relocs against symbols from discarded sections |
or section symbols from removed link-once sections. |
Complain about relocs against discarded sections. Zero |
relocs against removed link-once sections. */ |
rel = internal_relocs; |
relend = rel + o->reloc_count * bed->s->int_rels_per_ext_rel; |
for ( ; rel < relend; rel++) |
{ |
unsigned long r_symndx = rel->r_info >> r_sym_shift; |
unsigned int s_type; |
asection **ps, *sec; |
struct elf_link_hash_entry *h = NULL; |
const char *sym_name; |
if (r_symndx == STN_UNDEF) |
continue; |
if (r_symndx >= locsymcount |
|| (elf_bad_symtab (input_bfd) |
&& flinfo->sections[r_symndx] == NULL)) |
{ |
h = sym_hashes[r_symndx - extsymoff]; |
/* Badly formatted input files can contain relocs that |
reference non-existant symbols. Check here so that |
we do not seg fault. */ |
if (h == NULL) |
{ |
char buffer [32]; |
sprintf_vma (buffer, rel->r_info); |
(*_bfd_error_handler) |
(_("error: %B contains a reloc (0x%s) for section %A " |
"that references a non-existent global symbol"), |
input_bfd, o, buffer); |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
while (h->root.type == bfd_link_hash_indirect |
|| h->root.type == bfd_link_hash_warning) |
h = (struct elf_link_hash_entry *) h->root.u.i.link; |
s_type = h->type; |
ps = NULL; |
if (h->root.type == bfd_link_hash_defined |
|| h->root.type == bfd_link_hash_defweak) |
ps = &h->root.u.def.section; |
sym_name = h->root.root.string; |
} |
else |
{ |
Elf_Internal_Sym *sym = isymbuf + r_symndx; |
s_type = ELF_ST_TYPE (sym->st_info); |
ps = &flinfo->sections[r_symndx]; |
sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr, |
sym, *ps); |
} |
if ((s_type == STT_RELC || s_type == STT_SRELC) |
&& !flinfo->info->relocatable) |
{ |
bfd_vma val; |
bfd_vma dot = (rel->r_offset |
+ o->output_offset + o->output_section->vma); |
#ifdef DEBUG |
printf ("Encountered a complex symbol!"); |
printf (" (input_bfd %s, section %s, reloc %ld\n", |
input_bfd->filename, o->name, |
(long) (rel - internal_relocs)); |
printf (" symbol: idx %8.8lx, name %s\n", |
r_symndx, sym_name); |
printf (" reloc : info %8.8lx, addr %8.8lx\n", |
(unsigned long) rel->r_info, |
(unsigned long) rel->r_offset); |
#endif |
if (!eval_symbol (&val, &sym_name, input_bfd, flinfo, dot, |
isymbuf, locsymcount, s_type == STT_SRELC)) |
return FALSE; |
/* Symbol evaluated OK. Update to absolute value. */ |
set_symbol_value (input_bfd, isymbuf, locsymcount, |
r_symndx, val); |
continue; |
} |
if (action_discarded != -1 && ps != NULL) |
{ |
/* Complain if the definition comes from a |
discarded section. */ |
if ((sec = *ps) != NULL && discarded_section (sec)) |
{ |
BFD_ASSERT (r_symndx != STN_UNDEF); |
if (action_discarded & COMPLAIN) |
(*flinfo->info->callbacks->einfo) |
(_("%X`%s' referenced in section `%A' of %B: " |
"defined in discarded section `%A' of %B\n"), |
sym_name, o, input_bfd, sec, sec->owner); |
/* Try to do the best we can to support buggy old |
versions of gcc. Pretend that the symbol is |
really defined in the kept linkonce section. |
FIXME: This is quite broken. Modifying the |
symbol here means we will be changing all later |
uses of the symbol, not just in this section. */ |
if (action_discarded & PRETEND) |
{ |
asection *kept; |
kept = _bfd_elf_check_kept_section (sec, |
flinfo->info); |
if (kept != NULL) |
{ |
*ps = kept; |
continue; |
} |
} |
} |
} |
} |
/* Relocate the section by invoking a back end routine. |
The back end routine is responsible for adjusting the |
section contents as necessary, and (if using Rela relocs |
and generating a relocatable output file) adjusting the |
reloc addend as necessary. |
The back end routine does not have to worry about setting |
the reloc address or the reloc symbol index. |
The back end routine is given a pointer to the swapped in |
internal symbols, and can access the hash table entries |
for the external symbols via elf_sym_hashes (input_bfd). |
When generating relocatable output, the back end routine |
must handle STB_LOCAL/STT_SECTION symbols specially. The |
output symbol is going to be a section symbol |
corresponding to the output section, which will require |
the addend to be adjusted. */ |
ret = (*relocate_section) (output_bfd, flinfo->info, |
input_bfd, o, contents, |
internal_relocs, |
isymbuf, |
flinfo->sections); |
if (!ret) |
return FALSE; |
if (ret == 2 |
|| flinfo->info->relocatable |
|| flinfo->info->emitrelocations) |
{ |
Elf_Internal_Rela *irela; |
Elf_Internal_Rela *irelaend, *irelamid; |
bfd_vma last_offset; |
struct elf_link_hash_entry **rel_hash; |
struct elf_link_hash_entry **rel_hash_list, **rela_hash_list; |
Elf_Internal_Shdr *input_rel_hdr, *input_rela_hdr; |
unsigned int next_erel; |
bfd_boolean rela_normal; |
struct bfd_elf_section_data *esdi, *esdo; |
esdi = elf_section_data (o); |
esdo = elf_section_data (o->output_section); |
rela_normal = FALSE; |
/* Adjust the reloc addresses and symbol indices. */ |
irela = internal_relocs; |
irelaend = irela + o->reloc_count * bed->s->int_rels_per_ext_rel; |
rel_hash = esdo->rel.hashes + esdo->rel.count; |
/* We start processing the REL relocs, if any. When we reach |
IRELAMID in the loop, we switch to the RELA relocs. */ |
irelamid = irela; |
if (esdi->rel.hdr != NULL) |
irelamid += (NUM_SHDR_ENTRIES (esdi->rel.hdr) |
* bed->s->int_rels_per_ext_rel); |
rel_hash_list = rel_hash; |
rela_hash_list = NULL; |
last_offset = o->output_offset; |
if (!flinfo->info->relocatable) |
last_offset += o->output_section->vma; |
for (next_erel = 0; irela < irelaend; irela++, next_erel++) |
{ |
unsigned long r_symndx; |
asection *sec; |
Elf_Internal_Sym sym; |
if (next_erel == bed->s->int_rels_per_ext_rel) |
{ |
rel_hash++; |
next_erel = 0; |
} |
if (irela == irelamid) |
{ |
rel_hash = esdo->rela.hashes + esdo->rela.count; |
rela_hash_list = rel_hash; |
rela_normal = bed->rela_normal; |
} |
irela->r_offset = _bfd_elf_section_offset (output_bfd, |
flinfo->info, o, |
irela->r_offset); |
if (irela->r_offset >= (bfd_vma) -2) |
{ |
/* This is a reloc for a deleted entry or somesuch. |
Turn it into an R_*_NONE reloc, at the same |
offset as the last reloc. elf_eh_frame.c and |
bfd_elf_discard_info rely on reloc offsets |
being ordered. */ |
irela->r_offset = last_offset; |
irela->r_info = 0; |
irela->r_addend = 0; |
continue; |
} |
irela->r_offset += o->output_offset; |
/* Relocs in an executable have to be virtual addresses. */ |
if (!flinfo->info->relocatable) |
irela->r_offset += o->output_section->vma; |
last_offset = irela->r_offset; |
r_symndx = irela->r_info >> r_sym_shift; |
if (r_symndx == STN_UNDEF) |
continue; |
if (r_symndx >= locsymcount |
|| (elf_bad_symtab (input_bfd) |
&& flinfo->sections[r_symndx] == NULL)) |
{ |
struct elf_link_hash_entry *rh; |
unsigned long indx; |
/* This is a reloc against a global symbol. We |
have not yet output all the local symbols, so |
we do not know the symbol index of any global |
symbol. We set the rel_hash entry for this |
reloc to point to the global hash table entry |
for this symbol. The symbol index is then |
set at the end of bfd_elf_final_link. */ |
indx = r_symndx - extsymoff; |
rh = elf_sym_hashes (input_bfd)[indx]; |
while (rh->root.type == bfd_link_hash_indirect |
|| rh->root.type == bfd_link_hash_warning) |
rh = (struct elf_link_hash_entry *) rh->root.u.i.link; |
/* Setting the index to -2 tells |
elf_link_output_extsym that this symbol is |
used by a reloc. */ |
BFD_ASSERT (rh->indx < 0); |
rh->indx = -2; |
*rel_hash = rh; |
continue; |
} |
/* This is a reloc against a local symbol. */ |
*rel_hash = NULL; |
sym = isymbuf[r_symndx]; |
sec = flinfo->sections[r_symndx]; |
if (ELF_ST_TYPE (sym.st_info) == STT_SECTION) |
{ |
/* I suppose the backend ought to fill in the |
section of any STT_SECTION symbol against a |
processor specific section. */ |
r_symndx = STN_UNDEF; |
if (bfd_is_abs_section (sec)) |
; |
else if (sec == NULL || sec->owner == NULL) |
{ |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
else |
{ |
asection *osec = sec->output_section; |
/* If we have discarded a section, the output |
section will be the absolute section. In |
case of discarded SEC_MERGE sections, use |
the kept section. relocate_section should |
have already handled discarded linkonce |
sections. */ |
if (bfd_is_abs_section (osec) |
&& sec->kept_section != NULL |
&& sec->kept_section->output_section != NULL) |
{ |
osec = sec->kept_section->output_section; |
irela->r_addend -= osec->vma; |
} |
if (!bfd_is_abs_section (osec)) |
{ |
r_symndx = osec->target_index; |
if (r_symndx == STN_UNDEF) |
{ |
irela->r_addend += osec->vma; |
osec = _bfd_nearby_section (output_bfd, osec, |
osec->vma); |
irela->r_addend -= osec->vma; |
r_symndx = osec->target_index; |
} |
} |
} |
/* Adjust the addend according to where the |
section winds up in the output section. */ |
if (rela_normal) |
irela->r_addend += sec->output_offset; |
} |
else |
{ |
if (flinfo->indices[r_symndx] == -1) |
{ |
unsigned long shlink; |
const char *name; |
asection *osec; |
long indx; |
if (flinfo->info->strip == strip_all) |
{ |
/* You can't do ld -r -s. */ |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
/* This symbol was skipped earlier, but |
since it is needed by a reloc, we |
must output it now. */ |
shlink = symtab_hdr->sh_link; |
name = (bfd_elf_string_from_elf_section |
(input_bfd, shlink, sym.st_name)); |
if (name == NULL) |
return FALSE; |
osec = sec->output_section; |
sym.st_shndx = |
_bfd_elf_section_from_bfd_section (output_bfd, |
osec); |
if (sym.st_shndx == SHN_BAD) |
return FALSE; |
sym.st_value += sec->output_offset; |
if (!flinfo->info->relocatable) |
{ |
sym.st_value += osec->vma; |
if (ELF_ST_TYPE (sym.st_info) == STT_TLS) |
{ |
/* STT_TLS symbols are relative to PT_TLS |
segment base. */ |
BFD_ASSERT (elf_hash_table (flinfo->info) |
->tls_sec != NULL); |
sym.st_value -= (elf_hash_table (flinfo->info) |
->tls_sec->vma); |
} |
} |
indx = bfd_get_symcount (output_bfd); |
ret = elf_link_output_sym (flinfo, name, &sym, sec, |
NULL); |
if (ret == 0) |
return FALSE; |
else if (ret == 1) |
flinfo->indices[r_symndx] = indx; |
else |
abort (); |
} |
r_symndx = flinfo->indices[r_symndx]; |
} |
irela->r_info = ((bfd_vma) r_symndx << r_sym_shift |
| (irela->r_info & r_type_mask)); |
} |
/* Swap out the relocs. */ |
input_rel_hdr = esdi->rel.hdr; |
if (input_rel_hdr && input_rel_hdr->sh_size != 0) |
{ |
if (!bed->elf_backend_emit_relocs (output_bfd, o, |
input_rel_hdr, |
internal_relocs, |
rel_hash_list)) |
return FALSE; |
internal_relocs += (NUM_SHDR_ENTRIES (input_rel_hdr) |
* bed->s->int_rels_per_ext_rel); |
rel_hash_list += NUM_SHDR_ENTRIES (input_rel_hdr); |
} |
input_rela_hdr = esdi->rela.hdr; |
if (input_rela_hdr && input_rela_hdr->sh_size != 0) |
{ |
if (!bed->elf_backend_emit_relocs (output_bfd, o, |
input_rela_hdr, |
internal_relocs, |
rela_hash_list)) |
return FALSE; |
} |
} |
} |
/* Write out the modified section contents. */ |
if (bed->elf_backend_write_section |
&& (*bed->elf_backend_write_section) (output_bfd, flinfo->info, o, |
contents)) |
{ |
/* Section written out. */ |
} |
else switch (o->sec_info_type) |
{ |
case SEC_INFO_TYPE_STABS: |
if (! (_bfd_write_section_stabs |
(output_bfd, |
&elf_hash_table (flinfo->info)->stab_info, |
o, &elf_section_data (o)->sec_info, contents))) |
return FALSE; |
break; |
case SEC_INFO_TYPE_MERGE: |
if (! _bfd_write_merged_section (output_bfd, o, |
elf_section_data (o)->sec_info)) |
return FALSE; |
break; |
case SEC_INFO_TYPE_EH_FRAME: |
{ |
if (! _bfd_elf_write_section_eh_frame (output_bfd, flinfo->info, |
o, contents)) |
return FALSE; |
} |
break; |
default: |
{ |
/* FIXME: octets_per_byte. */ |
if (! (o->flags & SEC_EXCLUDE)) |
{ |
file_ptr offset = (file_ptr) o->output_offset; |
bfd_size_type todo = o->size; |
if ((o->flags & SEC_ELF_REVERSE_COPY)) |
{ |
/* Reverse-copy input section to output. */ |
do |
{ |
todo -= address_size; |
if (! bfd_set_section_contents (output_bfd, |
o->output_section, |
contents + todo, |
offset, |
address_size)) |
return FALSE; |
if (todo == 0) |
break; |
offset += address_size; |
} |
while (1); |
} |
else if (! bfd_set_section_contents (output_bfd, |
o->output_section, |
contents, |
offset, todo)) |
return FALSE; |
} |
} |
break; |
} |
} |
return TRUE; |
} |
/* Generate a reloc when linking an ELF file. This is a reloc |
requested by the linker, and does not come from any input file. This |
is used to build constructor and destructor tables when linking |
with -Ur. */ |
static bfd_boolean |
elf_reloc_link_order (bfd *output_bfd, |
struct bfd_link_info *info, |
asection *output_section, |
struct bfd_link_order *link_order) |
{ |
reloc_howto_type *howto; |
long indx; |
bfd_vma offset; |
bfd_vma addend; |
struct bfd_elf_section_reloc_data *reldata; |
struct elf_link_hash_entry **rel_hash_ptr; |
Elf_Internal_Shdr *rel_hdr; |
const struct elf_backend_data *bed = get_elf_backend_data (output_bfd); |
Elf_Internal_Rela irel[MAX_INT_RELS_PER_EXT_REL]; |
bfd_byte *erel; |
unsigned int i; |
struct bfd_elf_section_data *esdo = elf_section_data (output_section); |
howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc); |
if (howto == NULL) |
{ |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
addend = link_order->u.reloc.p->addend; |
if (esdo->rel.hdr) |
reldata = &esdo->rel; |
else if (esdo->rela.hdr) |
reldata = &esdo->rela; |
else |
{ |
reldata = NULL; |
BFD_ASSERT (0); |
} |
/* Figure out the symbol index. */ |
rel_hash_ptr = reldata->hashes + reldata->count; |
if (link_order->type == bfd_section_reloc_link_order) |
{ |
indx = link_order->u.reloc.p->u.section->target_index; |
BFD_ASSERT (indx != 0); |
*rel_hash_ptr = NULL; |
} |
else |
{ |
struct elf_link_hash_entry *h; |
/* Treat a reloc against a defined symbol as though it were |
actually against the section. */ |
h = ((struct elf_link_hash_entry *) |
bfd_wrapped_link_hash_lookup (output_bfd, info, |
link_order->u.reloc.p->u.name, |
FALSE, FALSE, TRUE)); |
if (h != NULL |
&& (h->root.type == bfd_link_hash_defined |
|| h->root.type == bfd_link_hash_defweak)) |
{ |
asection *section; |
section = h->root.u.def.section; |
indx = section->output_section->target_index; |
*rel_hash_ptr = NULL; |
/* It seems that we ought to add the symbol value to the |
addend here, but in practice it has already been added |
because it was passed to constructor_callback. */ |
addend += section->output_section->vma + section->output_offset; |
} |
else if (h != NULL) |
{ |
/* Setting the index to -2 tells elf_link_output_extsym that |
this symbol is used by a reloc. */ |
h->indx = -2; |
*rel_hash_ptr = h; |
indx = 0; |
} |
else |
{ |
if (! ((*info->callbacks->unattached_reloc) |
(info, link_order->u.reloc.p->u.name, NULL, NULL, 0))) |
return FALSE; |
indx = 0; |
} |
} |
/* If this is an inplace reloc, we must write the addend into the |
object file. */ |
if (howto->partial_inplace && addend != 0) |
{ |
bfd_size_type size; |
bfd_reloc_status_type rstat; |
bfd_byte *buf; |
bfd_boolean ok; |
const char *sym_name; |
size = (bfd_size_type) bfd_get_reloc_size (howto); |
buf = (bfd_byte *) bfd_zmalloc (size); |
if (buf == NULL) |
return FALSE; |
rstat = _bfd_relocate_contents (howto, output_bfd, addend, buf); |
switch (rstat) |
{ |
case bfd_reloc_ok: |
break; |
default: |
case bfd_reloc_outofrange: |
abort (); |
case bfd_reloc_overflow: |
if (link_order->type == bfd_section_reloc_link_order) |
sym_name = bfd_section_name (output_bfd, |
link_order->u.reloc.p->u.section); |
else |
sym_name = link_order->u.reloc.p->u.name; |
if (! ((*info->callbacks->reloc_overflow) |
(info, NULL, sym_name, howto->name, addend, NULL, |
NULL, (bfd_vma) 0))) |
{ |
free (buf); |
return FALSE; |
} |
break; |
} |
ok = bfd_set_section_contents (output_bfd, output_section, buf, |
link_order->offset, size); |
free (buf); |
if (! ok) |
return FALSE; |
} |
/* The address of a reloc is relative to the section in a |
relocatable file, and is a virtual address in an executable |
file. */ |
offset = link_order->offset; |
if (! info->relocatable) |
offset += output_section->vma; |
for (i = 0; i < bed->s->int_rels_per_ext_rel; i++) |
{ |
irel[i].r_offset = offset; |
irel[i].r_info = 0; |
irel[i].r_addend = 0; |
} |
if (bed->s->arch_size == 32) |
irel[0].r_info = ELF32_R_INFO (indx, howto->type); |
else |
irel[0].r_info = ELF64_R_INFO (indx, howto->type); |
rel_hdr = reldata->hdr; |
erel = rel_hdr->contents; |
if (rel_hdr->sh_type == SHT_REL) |
{ |
erel += reldata->count * bed->s->sizeof_rel; |
(*bed->s->swap_reloc_out) (output_bfd, irel, erel); |
} |
else |
{ |
irel[0].r_addend = addend; |
erel += reldata->count * bed->s->sizeof_rela; |
(*bed->s->swap_reloca_out) (output_bfd, irel, erel); |
} |
++reldata->count; |
return TRUE; |
} |
/* Get the output vma of the section pointed to by the sh_link field. */ |
static bfd_vma |
elf_get_linked_section_vma (struct bfd_link_order *p) |
{ |
Elf_Internal_Shdr **elf_shdrp; |
asection *s; |
int elfsec; |
s = p->u.indirect.section; |
elf_shdrp = elf_elfsections (s->owner); |
elfsec = _bfd_elf_section_from_bfd_section (s->owner, s); |
elfsec = elf_shdrp[elfsec]->sh_link; |
/* PR 290: |
The Intel C compiler generates SHT_IA_64_UNWIND with |
SHF_LINK_ORDER. But it doesn't set the sh_link or |
sh_info fields. Hence we could get the situation |
where elfsec is 0. */ |
if (elfsec == 0) |
{ |
const struct elf_backend_data *bed |
= get_elf_backend_data (s->owner); |
if (bed->link_order_error_handler) |
bed->link_order_error_handler |
(_("%B: warning: sh_link not set for section `%A'"), s->owner, s); |
return 0; |
} |
else |
{ |
s = elf_shdrp[elfsec]->bfd_section; |
return s->output_section->vma + s->output_offset; |
} |
} |
/* Compare two sections based on the locations of the sections they are |
linked to. Used by elf_fixup_link_order. */ |
static int |
compare_link_order (const void * a, const void * b) |
{ |
bfd_vma apos; |
bfd_vma bpos; |
apos = elf_get_linked_section_vma (*(struct bfd_link_order **)a); |
bpos = elf_get_linked_section_vma (*(struct bfd_link_order **)b); |
if (apos < bpos) |
return -1; |
return apos > bpos; |
} |
/* Looks for sections with SHF_LINK_ORDER set. Rearranges them into the same |
order as their linked sections. Returns false if this could not be done |
because an output section includes both ordered and unordered |
sections. Ideally we'd do this in the linker proper. */ |
static bfd_boolean |
elf_fixup_link_order (bfd *abfd, asection *o) |
{ |
int seen_linkorder; |
int seen_other; |
int n; |
struct bfd_link_order *p; |
bfd *sub; |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
unsigned elfsec; |
struct bfd_link_order **sections; |
asection *s, *other_sec, *linkorder_sec; |
bfd_vma offset; |
other_sec = NULL; |
linkorder_sec = NULL; |
seen_other = 0; |
seen_linkorder = 0; |
for (p = o->map_head.link_order; p != NULL; p = p->next) |
{ |
if (p->type == bfd_indirect_link_order) |
{ |
s = p->u.indirect.section; |
sub = s->owner; |
if (bfd_get_flavour (sub) == bfd_target_elf_flavour |
&& elf_elfheader (sub)->e_ident[EI_CLASS] == bed->s->elfclass |
&& (elfsec = _bfd_elf_section_from_bfd_section (sub, s)) |
&& elfsec < elf_numsections (sub) |
&& elf_elfsections (sub)[elfsec]->sh_flags & SHF_LINK_ORDER |
&& elf_elfsections (sub)[elfsec]->sh_link < elf_numsections (sub)) |
{ |
seen_linkorder++; |
linkorder_sec = s; |
} |
else |
{ |
seen_other++; |
other_sec = s; |
} |
} |
else |
seen_other++; |
if (seen_other && seen_linkorder) |
{ |
if (other_sec && linkorder_sec) |
(*_bfd_error_handler) (_("%A has both ordered [`%A' in %B] and unordered [`%A' in %B] sections"), |
o, linkorder_sec, |
linkorder_sec->owner, other_sec, |
other_sec->owner); |
else |
(*_bfd_error_handler) (_("%A has both ordered and unordered sections"), |
o); |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
} |
if (!seen_linkorder) |
return TRUE; |
sections = (struct bfd_link_order **) |
bfd_malloc (seen_linkorder * sizeof (struct bfd_link_order *)); |
if (sections == NULL) |
return FALSE; |
seen_linkorder = 0; |
for (p = o->map_head.link_order; p != NULL; p = p->next) |
{ |
sections[seen_linkorder++] = p; |
} |
/* Sort the input sections in the order of their linked section. */ |
qsort (sections, seen_linkorder, sizeof (struct bfd_link_order *), |
compare_link_order); |
/* Change the offsets of the sections. */ |
offset = 0; |
for (n = 0; n < seen_linkorder; n++) |
{ |
s = sections[n]->u.indirect.section; |
offset &= ~(bfd_vma) 0 << s->alignment_power; |
s->output_offset = offset; |
sections[n]->offset = offset; |
/* FIXME: octets_per_byte. */ |
offset += sections[n]->size; |
} |
free (sections); |
return TRUE; |
} |
static void |
elf_final_link_free (bfd *obfd, struct elf_final_link_info *flinfo) |
{ |
asection *o; |
if (flinfo->symstrtab != NULL) |
_bfd_stringtab_free (flinfo->symstrtab); |
if (flinfo->contents != NULL) |
free (flinfo->contents); |
if (flinfo->external_relocs != NULL) |
free (flinfo->external_relocs); |
if (flinfo->internal_relocs != NULL) |
free (flinfo->internal_relocs); |
if (flinfo->external_syms != NULL) |
free (flinfo->external_syms); |
if (flinfo->locsym_shndx != NULL) |
free (flinfo->locsym_shndx); |
if (flinfo->internal_syms != NULL) |
free (flinfo->internal_syms); |
if (flinfo->indices != NULL) |
free (flinfo->indices); |
if (flinfo->sections != NULL) |
free (flinfo->sections); |
if (flinfo->symbuf != NULL) |
free (flinfo->symbuf); |
if (flinfo->symshndxbuf != NULL) |
free (flinfo->symshndxbuf); |
for (o = obfd->sections; o != NULL; o = o->next) |
{ |
struct bfd_elf_section_data *esdo = elf_section_data (o); |
if ((o->flags & SEC_RELOC) != 0 && esdo->rel.hashes != NULL) |
free (esdo->rel.hashes); |
if ((o->flags & SEC_RELOC) != 0 && esdo->rela.hashes != NULL) |
free (esdo->rela.hashes); |
} |
} |
/* Do the final step of an ELF link. */ |
bfd_boolean |
bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) |
{ |
bfd_boolean dynamic; |
bfd_boolean emit_relocs; |
bfd *dynobj; |
struct elf_final_link_info flinfo; |
asection *o; |
struct bfd_link_order *p; |
bfd *sub; |
bfd_size_type max_contents_size; |
bfd_size_type max_external_reloc_size; |
bfd_size_type max_internal_reloc_count; |
bfd_size_type max_sym_count; |
bfd_size_type max_sym_shndx_count; |
file_ptr off; |
Elf_Internal_Sym elfsym; |
unsigned int i; |
Elf_Internal_Shdr *symtab_hdr; |
Elf_Internal_Shdr *symtab_shndx_hdr; |
Elf_Internal_Shdr *symstrtab_hdr; |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
struct elf_outext_info eoinfo; |
bfd_boolean merged; |
size_t relativecount = 0; |
asection *reldyn = 0; |
bfd_size_type amt; |
asection *attr_section = NULL; |
bfd_vma attr_size = 0; |
const char *std_attrs_section; |
if (! is_elf_hash_table (info->hash)) |
return FALSE; |
if (info->shared) |
abfd->flags |= DYNAMIC; |
dynamic = elf_hash_table (info)->dynamic_sections_created; |
dynobj = elf_hash_table (info)->dynobj; |
emit_relocs = (info->relocatable |
|| info->emitrelocations); |
flinfo.info = info; |
flinfo.output_bfd = abfd; |
flinfo.symstrtab = _bfd_elf_stringtab_init (); |
if (flinfo.symstrtab == NULL) |
return FALSE; |
if (! dynamic) |
{ |
flinfo.dynsym_sec = NULL; |
flinfo.hash_sec = NULL; |
flinfo.symver_sec = NULL; |
} |
else |
{ |
flinfo.dynsym_sec = bfd_get_linker_section (dynobj, ".dynsym"); |
flinfo.hash_sec = bfd_get_linker_section (dynobj, ".hash"); |
/* Note that dynsym_sec can be NULL (on VMS). */ |
flinfo.symver_sec = bfd_get_linker_section (dynobj, ".gnu.version"); |
/* Note that it is OK if symver_sec is NULL. */ |
} |
flinfo.contents = NULL; |
flinfo.external_relocs = NULL; |
flinfo.internal_relocs = NULL; |
flinfo.external_syms = NULL; |
flinfo.locsym_shndx = NULL; |
flinfo.internal_syms = NULL; |
flinfo.indices = NULL; |
flinfo.sections = NULL; |
flinfo.symbuf = NULL; |
flinfo.symshndxbuf = NULL; |
flinfo.symbuf_count = 0; |
flinfo.shndxbuf_size = 0; |
flinfo.filesym_count = 0; |
/* The object attributes have been merged. Remove the input |
sections from the link, and set the contents of the output |
secton. */ |
std_attrs_section = get_elf_backend_data (abfd)->obj_attrs_section; |
for (o = abfd->sections; o != NULL; o = o->next) |
{ |
if ((std_attrs_section && strcmp (o->name, std_attrs_section) == 0) |
|| strcmp (o->name, ".gnu.attributes") == 0) |
{ |
for (p = o->map_head.link_order; p != NULL; p = p->next) |
{ |
asection *input_section; |
if (p->type != bfd_indirect_link_order) |
continue; |
input_section = p->u.indirect.section; |
/* Hack: reset the SEC_HAS_CONTENTS flag so that |
elf_link_input_bfd ignores this section. */ |
input_section->flags &= ~SEC_HAS_CONTENTS; |
} |
attr_size = bfd_elf_obj_attr_size (abfd); |
if (attr_size) |
{ |
bfd_set_section_size (abfd, o, attr_size); |
attr_section = o; |
/* Skip this section later on. */ |
o->map_head.link_order = NULL; |
} |
else |
o->flags |= SEC_EXCLUDE; |
} |
} |
/* Count up the number of relocations we will output for each output |
section, so that we know the sizes of the reloc sections. We |
also figure out some maximum sizes. */ |
max_contents_size = 0; |
max_external_reloc_size = 0; |
max_internal_reloc_count = 0; |
max_sym_count = 0; |
max_sym_shndx_count = 0; |
merged = FALSE; |
for (o = abfd->sections; o != NULL; o = o->next) |
{ |
struct bfd_elf_section_data *esdo = elf_section_data (o); |
o->reloc_count = 0; |
for (p = o->map_head.link_order; p != NULL; p = p->next) |
{ |
unsigned int reloc_count = 0; |
struct bfd_elf_section_data *esdi = NULL; |
if (p->type == bfd_section_reloc_link_order |
|| p->type == bfd_symbol_reloc_link_order) |
reloc_count = 1; |
else if (p->type == bfd_indirect_link_order) |
{ |
asection *sec; |
sec = p->u.indirect.section; |
esdi = elf_section_data (sec); |
/* Mark all sections which are to be included in the |
link. This will normally be every section. We need |
to do this so that we can identify any sections which |
the linker has decided to not include. */ |
sec->linker_mark = TRUE; |
if (sec->flags & SEC_MERGE) |
merged = TRUE; |
if (esdo->this_hdr.sh_type == SHT_REL |
|| esdo->this_hdr.sh_type == SHT_RELA) |
/* Some backends use reloc_count in relocation sections |
to count particular types of relocs. Of course, |
reloc sections themselves can't have relocations. */ |
reloc_count = 0; |
else if (info->relocatable || info->emitrelocations) |
reloc_count = sec->reloc_count; |
else if (bed->elf_backend_count_relocs) |
reloc_count = (*bed->elf_backend_count_relocs) (info, sec); |
if (sec->rawsize > max_contents_size) |
max_contents_size = sec->rawsize; |
if (sec->size > max_contents_size) |
max_contents_size = sec->size; |
/* We are interested in just local symbols, not all |
symbols. */ |
if (bfd_get_flavour (sec->owner) == bfd_target_elf_flavour |
&& (sec->owner->flags & DYNAMIC) == 0) |
{ |
size_t sym_count; |
if (elf_bad_symtab (sec->owner)) |
sym_count = (elf_tdata (sec->owner)->symtab_hdr.sh_size |
/ bed->s->sizeof_sym); |
else |
sym_count = elf_tdata (sec->owner)->symtab_hdr.sh_info; |
if (sym_count > max_sym_count) |
max_sym_count = sym_count; |
if (sym_count > max_sym_shndx_count |
&& elf_symtab_shndx (sec->owner) != 0) |
max_sym_shndx_count = sym_count; |
if ((sec->flags & SEC_RELOC) != 0) |
{ |
size_t ext_size = 0; |
if (esdi->rel.hdr != NULL) |
ext_size = esdi->rel.hdr->sh_size; |
if (esdi->rela.hdr != NULL) |
ext_size += esdi->rela.hdr->sh_size; |
if (ext_size > max_external_reloc_size) |
max_external_reloc_size = ext_size; |
if (sec->reloc_count > max_internal_reloc_count) |
max_internal_reloc_count = sec->reloc_count; |
} |
} |
} |
if (reloc_count == 0) |
continue; |
o->reloc_count += reloc_count; |
if (p->type == bfd_indirect_link_order |
&& (info->relocatable || info->emitrelocations)) |
{ |
if (esdi->rel.hdr) |
esdo->rel.count += NUM_SHDR_ENTRIES (esdi->rel.hdr); |
if (esdi->rela.hdr) |
esdo->rela.count += NUM_SHDR_ENTRIES (esdi->rela.hdr); |
} |
else |
{ |
if (o->use_rela_p) |
esdo->rela.count += reloc_count; |
else |
esdo->rel.count += reloc_count; |
} |
} |
if (o->reloc_count > 0) |
o->flags |= SEC_RELOC; |
else |
{ |
/* Explicitly clear the SEC_RELOC flag. The linker tends to |
set it (this is probably a bug) and if it is set |
assign_section_numbers will create a reloc section. */ |
o->flags &=~ SEC_RELOC; |
} |
/* If the SEC_ALLOC flag is not set, force the section VMA to |
zero. This is done in elf_fake_sections as well, but forcing |
the VMA to 0 here will ensure that relocs against these |
sections are handled correctly. */ |
if ((o->flags & SEC_ALLOC) == 0 |
&& ! o->user_set_vma) |
o->vma = 0; |
} |
if (! info->relocatable && merged) |
elf_link_hash_traverse (elf_hash_table (info), |
_bfd_elf_link_sec_merge_syms, abfd); |
/* Figure out the file positions for everything but the symbol table |
and the relocs. We set symcount to force assign_section_numbers |
to create a symbol table. */ |
bfd_get_symcount (abfd) = info->strip == strip_all ? 0 : 1; |
BFD_ASSERT (! abfd->output_has_begun); |
if (! _bfd_elf_compute_section_file_positions (abfd, info)) |
goto error_return; |
/* Set sizes, and assign file positions for reloc sections. */ |
for (o = abfd->sections; o != NULL; o = o->next) |
{ |
struct bfd_elf_section_data *esdo = elf_section_data (o); |
if ((o->flags & SEC_RELOC) != 0) |
{ |
if (esdo->rel.hdr |
&& !(_bfd_elf_link_size_reloc_section (abfd, &esdo->rel))) |
goto error_return; |
if (esdo->rela.hdr |
&& !(_bfd_elf_link_size_reloc_section (abfd, &esdo->rela))) |
goto error_return; |
} |
/* Now, reset REL_COUNT and REL_COUNT2 so that we can use them |
to count upwards while actually outputting the relocations. */ |
esdo->rel.count = 0; |
esdo->rela.count = 0; |
} |
_bfd_elf_assign_file_positions_for_relocs (abfd); |
/* We have now assigned file positions for all the sections except |
.symtab and .strtab. We start the .symtab section at the current |
file position, and write directly to it. We build the .strtab |
section in memory. */ |
bfd_get_symcount (abfd) = 0; |
symtab_hdr = &elf_tdata (abfd)->symtab_hdr; |
/* sh_name is set in prep_headers. */ |
symtab_hdr->sh_type = SHT_SYMTAB; |
/* sh_flags, sh_addr and sh_size all start off zero. */ |
symtab_hdr->sh_entsize = bed->s->sizeof_sym; |
/* sh_link is set in assign_section_numbers. */ |
/* sh_info is set below. */ |
/* sh_offset is set just below. */ |
symtab_hdr->sh_addralign = (bfd_vma) 1 << bed->s->log_file_align; |
off = elf_next_file_pos (abfd); |
off = _bfd_elf_assign_file_position_for_section (symtab_hdr, off, TRUE); |
/* Note that at this point elf_next_file_pos (abfd) is |
incorrect. We do not yet know the size of the .symtab section. |
We correct next_file_pos below, after we do know the size. */ |
/* Allocate a buffer to hold swapped out symbols. This is to avoid |
continuously seeking to the right position in the file. */ |
if (! info->keep_memory || max_sym_count < 20) |
flinfo.symbuf_size = 20; |
else |
flinfo.symbuf_size = max_sym_count; |
amt = flinfo.symbuf_size; |
amt *= bed->s->sizeof_sym; |
flinfo.symbuf = (bfd_byte *) bfd_malloc (amt); |
if (flinfo.symbuf == NULL) |
goto error_return; |
if (elf_numsections (abfd) > (SHN_LORESERVE & 0xFFFF)) |
{ |
/* Wild guess at number of output symbols. realloc'd as needed. */ |
amt = 2 * max_sym_count + elf_numsections (abfd) + 1000; |
flinfo.shndxbuf_size = amt; |
amt *= sizeof (Elf_External_Sym_Shndx); |
flinfo.symshndxbuf = (Elf_External_Sym_Shndx *) bfd_zmalloc (amt); |
if (flinfo.symshndxbuf == NULL) |
goto error_return; |
} |
/* Start writing out the symbol table. The first symbol is always a |
dummy symbol. */ |
if (info->strip != strip_all |
|| emit_relocs) |
{ |
elfsym.st_value = 0; |
elfsym.st_size = 0; |
elfsym.st_info = 0; |
elfsym.st_other = 0; |
elfsym.st_shndx = SHN_UNDEF; |
elfsym.st_target_internal = 0; |
if (elf_link_output_sym (&flinfo, NULL, &elfsym, bfd_und_section_ptr, |
NULL) != 1) |
goto error_return; |
} |
/* Output a symbol for each section. We output these even if we are |
discarding local symbols, since they are used for relocs. These |
symbols have no names. We store the index of each one in the |
index field of the section, so that we can find it again when |
outputting relocs. */ |
if (info->strip != strip_all |
|| emit_relocs) |
{ |
elfsym.st_size = 0; |
elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION); |
elfsym.st_other = 0; |
elfsym.st_value = 0; |
elfsym.st_target_internal = 0; |
for (i = 1; i < elf_numsections (abfd); i++) |
{ |
o = bfd_section_from_elf_index (abfd, i); |
if (o != NULL) |
{ |
o->target_index = bfd_get_symcount (abfd); |
elfsym.st_shndx = i; |
if (!info->relocatable) |
elfsym.st_value = o->vma; |
if (elf_link_output_sym (&flinfo, NULL, &elfsym, o, NULL) != 1) |
goto error_return; |
} |
} |
} |
/* Allocate some memory to hold information read in from the input |
files. */ |
if (max_contents_size != 0) |
{ |
flinfo.contents = (bfd_byte *) bfd_malloc (max_contents_size); |
if (flinfo.contents == NULL) |
goto error_return; |
} |
if (max_external_reloc_size != 0) |
{ |
flinfo.external_relocs = bfd_malloc (max_external_reloc_size); |
if (flinfo.external_relocs == NULL) |
goto error_return; |
} |
if (max_internal_reloc_count != 0) |
{ |
amt = max_internal_reloc_count * bed->s->int_rels_per_ext_rel; |
amt *= sizeof (Elf_Internal_Rela); |
flinfo.internal_relocs = (Elf_Internal_Rela *) bfd_malloc (amt); |
if (flinfo.internal_relocs == NULL) |
goto error_return; |
} |
if (max_sym_count != 0) |
{ |
amt = max_sym_count * bed->s->sizeof_sym; |
flinfo.external_syms = (bfd_byte *) bfd_malloc (amt); |
if (flinfo.external_syms == NULL) |
goto error_return; |
amt = max_sym_count * sizeof (Elf_Internal_Sym); |
flinfo.internal_syms = (Elf_Internal_Sym *) bfd_malloc (amt); |
if (flinfo.internal_syms == NULL) |
goto error_return; |
amt = max_sym_count * sizeof (long); |
flinfo.indices = (long int *) bfd_malloc (amt); |
if (flinfo.indices == NULL) |
goto error_return; |
amt = max_sym_count * sizeof (asection *); |
flinfo.sections = (asection **) bfd_malloc (amt); |
if (flinfo.sections == NULL) |
goto error_return; |
} |
if (max_sym_shndx_count != 0) |
{ |
amt = max_sym_shndx_count * sizeof (Elf_External_Sym_Shndx); |
flinfo.locsym_shndx = (Elf_External_Sym_Shndx *) bfd_malloc (amt); |
if (flinfo.locsym_shndx == NULL) |
goto error_return; |
} |
if (elf_hash_table (info)->tls_sec) |
{ |
bfd_vma base, end = 0; |
asection *sec; |
for (sec = elf_hash_table (info)->tls_sec; |
sec && (sec->flags & SEC_THREAD_LOCAL); |
sec = sec->next) |
{ |
bfd_size_type size = sec->size; |
if (size == 0 |
&& (sec->flags & SEC_HAS_CONTENTS) == 0) |
{ |
struct bfd_link_order *ord = sec->map_tail.link_order; |
if (ord != NULL) |
size = ord->offset + ord->size; |
} |
end = sec->vma + size; |
} |
base = elf_hash_table (info)->tls_sec->vma; |
/* Only align end of TLS section if static TLS doesn't have special |
alignment requirements. */ |
if (bed->static_tls_alignment == 1) |
end = align_power (end, |
elf_hash_table (info)->tls_sec->alignment_power); |
elf_hash_table (info)->tls_size = end - base; |
} |
/* Reorder SHF_LINK_ORDER sections. */ |
for (o = abfd->sections; o != NULL; o = o->next) |
{ |
if (!elf_fixup_link_order (abfd, o)) |
return FALSE; |
} |
/* Since ELF permits relocations to be against local symbols, we |
must have the local symbols available when we do the relocations. |
Since we would rather only read the local symbols once, and we |
would rather not keep them in memory, we handle all the |
relocations for a single input file at the same time. |
Unfortunately, there is no way to know the total number of local |
symbols until we have seen all of them, and the local symbol |
indices precede the global symbol indices. This means that when |
we are generating relocatable output, and we see a reloc against |
a global symbol, we can not know the symbol index until we have |
finished examining all the local symbols to see which ones we are |
going to output. To deal with this, we keep the relocations in |
memory, and don't output them until the end of the link. This is |
an unfortunate waste of memory, but I don't see a good way around |
it. Fortunately, it only happens when performing a relocatable |
link, which is not the common case. FIXME: If keep_memory is set |
we could write the relocs out and then read them again; I don't |
know how bad the memory loss will be. */ |
for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) |
sub->output_has_begun = FALSE; |
for (o = abfd->sections; o != NULL; o = o->next) |
{ |
for (p = o->map_head.link_order; p != NULL; p = p->next) |
{ |
if (p->type == bfd_indirect_link_order |
&& (bfd_get_flavour ((sub = p->u.indirect.section->owner)) |
== bfd_target_elf_flavour) |
&& elf_elfheader (sub)->e_ident[EI_CLASS] == bed->s->elfclass) |
{ |
if (! sub->output_has_begun) |
{ |
if (! elf_link_input_bfd (&flinfo, sub)) |
goto error_return; |
sub->output_has_begun = TRUE; |
} |
} |
else if (p->type == bfd_section_reloc_link_order |
|| p->type == bfd_symbol_reloc_link_order) |
{ |
if (! elf_reloc_link_order (abfd, info, o, p)) |
goto error_return; |
} |
else |
{ |
if (! _bfd_default_link_order (abfd, info, o, p)) |
{ |
if (p->type == bfd_indirect_link_order |
&& (bfd_get_flavour (sub) |
== bfd_target_elf_flavour) |
&& (elf_elfheader (sub)->e_ident[EI_CLASS] |
!= bed->s->elfclass)) |
{ |
const char *iclass, *oclass; |
if (bed->s->elfclass == ELFCLASS64) |
{ |
iclass = "ELFCLASS32"; |
oclass = "ELFCLASS64"; |
} |
else |
{ |
iclass = "ELFCLASS64"; |
oclass = "ELFCLASS32"; |
} |
bfd_set_error (bfd_error_wrong_format); |
(*_bfd_error_handler) |
(_("%B: file class %s incompatible with %s"), |
sub, iclass, oclass); |
} |
goto error_return; |
} |
} |
} |
} |
/* Free symbol buffer if needed. */ |
if (!info->reduce_memory_overheads) |
{ |
for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) |
if (bfd_get_flavour (sub) == bfd_target_elf_flavour |
&& elf_tdata (sub)->symbuf) |
{ |
free (elf_tdata (sub)->symbuf); |
elf_tdata (sub)->symbuf = NULL; |
} |
} |
/* Output a FILE symbol so that following locals are not associated |
with the wrong input file. */ |
memset (&elfsym, 0, sizeof (elfsym)); |
elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE); |
elfsym.st_shndx = SHN_ABS; |
if (flinfo.filesym_count > 1 |
&& !elf_link_output_sym (&flinfo, NULL, &elfsym, |
bfd_und_section_ptr, NULL)) |
return FALSE; |
/* Output any global symbols that got converted to local in a |
version script or due to symbol visibility. We do this in a |
separate step since ELF requires all local symbols to appear |
prior to any global symbols. FIXME: We should only do this if |
some global symbols were, in fact, converted to become local. |
FIXME: Will this work correctly with the Irix 5 linker? */ |
eoinfo.failed = FALSE; |
eoinfo.flinfo = &flinfo; |
eoinfo.localsyms = TRUE; |
eoinfo.need_second_pass = FALSE; |
eoinfo.second_pass = FALSE; |
bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo); |
if (eoinfo.failed) |
return FALSE; |
if (flinfo.filesym_count == 1 |
&& !elf_link_output_sym (&flinfo, NULL, &elfsym, |
bfd_und_section_ptr, NULL)) |
return FALSE; |
if (eoinfo.need_second_pass) |
{ |
eoinfo.second_pass = TRUE; |
bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo); |
if (eoinfo.failed) |
return FALSE; |
} |
/* If backend needs to output some local symbols not present in the hash |
table, do it now. */ |
if (bed->elf_backend_output_arch_local_syms) |
{ |
typedef int (*out_sym_func) |
(void *, const char *, Elf_Internal_Sym *, asection *, |
struct elf_link_hash_entry *); |
if (! ((*bed->elf_backend_output_arch_local_syms) |
(abfd, info, &flinfo, (out_sym_func) elf_link_output_sym))) |
return FALSE; |
} |
/* That wrote out all the local symbols. Finish up the symbol table |
with the global symbols. Even if we want to strip everything we |
can, we still need to deal with those global symbols that got |
converted to local in a version script. */ |
/* The sh_info field records the index of the first non local symbol. */ |
symtab_hdr->sh_info = bfd_get_symcount (abfd); |
if (dynamic |
&& flinfo.dynsym_sec != NULL |
&& flinfo.dynsym_sec->output_section != bfd_abs_section_ptr) |
{ |
Elf_Internal_Sym sym; |
bfd_byte *dynsym = flinfo.dynsym_sec->contents; |
long last_local = 0; |
/* Write out the section symbols for the output sections. */ |
if (info->shared || elf_hash_table (info)->is_relocatable_executable) |
{ |
asection *s; |
sym.st_size = 0; |
sym.st_name = 0; |
sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION); |
sym.st_other = 0; |
sym.st_target_internal = 0; |
for (s = abfd->sections; s != NULL; s = s->next) |
{ |
int indx; |
bfd_byte *dest; |
long dynindx; |
dynindx = elf_section_data (s)->dynindx; |
if (dynindx <= 0) |
continue; |
indx = elf_section_data (s)->this_idx; |
BFD_ASSERT (indx > 0); |
sym.st_shndx = indx; |
if (! check_dynsym (abfd, &sym)) |
return FALSE; |
sym.st_value = s->vma; |
dest = dynsym + dynindx * bed->s->sizeof_sym; |
if (last_local < dynindx) |
last_local = dynindx; |
bed->s->swap_symbol_out (abfd, &sym, dest, 0); |
} |
} |
/* Write out the local dynsyms. */ |
if (elf_hash_table (info)->dynlocal) |
{ |
struct elf_link_local_dynamic_entry *e; |
for (e = elf_hash_table (info)->dynlocal; e ; e = e->next) |
{ |
asection *s; |
bfd_byte *dest; |
/* Copy the internal symbol and turn off visibility. |
Note that we saved a word of storage and overwrote |
the original st_name with the dynstr_index. */ |
sym = e->isym; |
sym.st_other &= ~ELF_ST_VISIBILITY (-1); |
s = bfd_section_from_elf_index (e->input_bfd, |
e->isym.st_shndx); |
if (s != NULL) |
{ |
sym.st_shndx = |
elf_section_data (s->output_section)->this_idx; |
if (! check_dynsym (abfd, &sym)) |
return FALSE; |
sym.st_value = (s->output_section->vma |
+ s->output_offset |
+ e->isym.st_value); |
} |
if (last_local < e->dynindx) |
last_local = e->dynindx; |
dest = dynsym + e->dynindx * bed->s->sizeof_sym; |
bed->s->swap_symbol_out (abfd, &sym, dest, 0); |
} |
} |
elf_section_data (flinfo.dynsym_sec->output_section)->this_hdr.sh_info = |
last_local + 1; |
} |
/* We get the global symbols from the hash table. */ |
eoinfo.failed = FALSE; |
eoinfo.localsyms = FALSE; |
eoinfo.flinfo = &flinfo; |
bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo); |
if (eoinfo.failed) |
return FALSE; |
/* If backend needs to output some symbols not present in the hash |
table, do it now. */ |
if (bed->elf_backend_output_arch_syms) |
{ |
typedef int (*out_sym_func) |
(void *, const char *, Elf_Internal_Sym *, asection *, |
struct elf_link_hash_entry *); |
if (! ((*bed->elf_backend_output_arch_syms) |
(abfd, info, &flinfo, (out_sym_func) elf_link_output_sym))) |
return FALSE; |
} |
/* Flush all symbols to the file. */ |
if (! elf_link_flush_output_syms (&flinfo, bed)) |
return FALSE; |
/* Now we know the size of the symtab section. */ |
off += symtab_hdr->sh_size; |
symtab_shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr; |
if (symtab_shndx_hdr->sh_name != 0) |
{ |
symtab_shndx_hdr->sh_type = SHT_SYMTAB_SHNDX; |
symtab_shndx_hdr->sh_entsize = sizeof (Elf_External_Sym_Shndx); |
symtab_shndx_hdr->sh_addralign = sizeof (Elf_External_Sym_Shndx); |
amt = bfd_get_symcount (abfd) * sizeof (Elf_External_Sym_Shndx); |
symtab_shndx_hdr->sh_size = amt; |
off = _bfd_elf_assign_file_position_for_section (symtab_shndx_hdr, |
off, TRUE); |
if (bfd_seek (abfd, symtab_shndx_hdr->sh_offset, SEEK_SET) != 0 |
|| (bfd_bwrite (flinfo.symshndxbuf, amt, abfd) != amt)) |
return FALSE; |
} |
/* Finish up and write out the symbol string table (.strtab) |
section. */ |
symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr; |
/* sh_name was set in prep_headers. */ |
symstrtab_hdr->sh_type = SHT_STRTAB; |
symstrtab_hdr->sh_flags = 0; |
symstrtab_hdr->sh_addr = 0; |
symstrtab_hdr->sh_size = _bfd_stringtab_size (flinfo.symstrtab); |
symstrtab_hdr->sh_entsize = 0; |
symstrtab_hdr->sh_link = 0; |
symstrtab_hdr->sh_info = 0; |
/* sh_offset is set just below. */ |
symstrtab_hdr->sh_addralign = 1; |
off = _bfd_elf_assign_file_position_for_section (symstrtab_hdr, off, TRUE); |
elf_next_file_pos (abfd) = off; |
if (bfd_get_symcount (abfd) > 0) |
{ |
if (bfd_seek (abfd, symstrtab_hdr->sh_offset, SEEK_SET) != 0 |
|| ! _bfd_stringtab_emit (abfd, flinfo.symstrtab)) |
return FALSE; |
} |
/* Adjust the relocs to have the correct symbol indices. */ |
for (o = abfd->sections; o != NULL; o = o->next) |
{ |
struct bfd_elf_section_data *esdo = elf_section_data (o); |
if ((o->flags & SEC_RELOC) == 0) |
continue; |
if (esdo->rel.hdr != NULL) |
elf_link_adjust_relocs (abfd, &esdo->rel); |
if (esdo->rela.hdr != NULL) |
elf_link_adjust_relocs (abfd, &esdo->rela); |
/* Set the reloc_count field to 0 to prevent write_relocs from |
trying to swap the relocs out itself. */ |
o->reloc_count = 0; |
} |
if (dynamic && info->combreloc && dynobj != NULL) |
relativecount = elf_link_sort_relocs (abfd, info, &reldyn); |
/* If we are linking against a dynamic object, or generating a |
shared library, finish up the dynamic linking information. */ |
if (dynamic) |
{ |
bfd_byte *dyncon, *dynconend; |
/* Fix up .dynamic entries. */ |
o = bfd_get_linker_section (dynobj, ".dynamic"); |
BFD_ASSERT (o != NULL); |
dyncon = o->contents; |
dynconend = o->contents + o->size; |
for (; dyncon < dynconend; dyncon += bed->s->sizeof_dyn) |
{ |
Elf_Internal_Dyn dyn; |
const char *name; |
unsigned int type; |
bed->s->swap_dyn_in (dynobj, dyncon, &dyn); |
switch (dyn.d_tag) |
{ |
default: |
continue; |
case DT_NULL: |
if (relativecount > 0 && dyncon + bed->s->sizeof_dyn < dynconend) |
{ |
switch (elf_section_data (reldyn)->this_hdr.sh_type) |
{ |
case SHT_REL: dyn.d_tag = DT_RELCOUNT; break; |
case SHT_RELA: dyn.d_tag = DT_RELACOUNT; break; |
default: continue; |
} |
dyn.d_un.d_val = relativecount; |
relativecount = 0; |
break; |
} |
continue; |
case DT_INIT: |
name = info->init_function; |
goto get_sym; |
case DT_FINI: |
name = info->fini_function; |
get_sym: |
{ |
struct elf_link_hash_entry *h; |
h = elf_link_hash_lookup (elf_hash_table (info), name, |
FALSE, FALSE, TRUE); |
if (h != NULL |
&& (h->root.type == bfd_link_hash_defined |
|| h->root.type == bfd_link_hash_defweak)) |
{ |
dyn.d_un.d_ptr = h->root.u.def.value; |
o = h->root.u.def.section; |
if (o->output_section != NULL) |
dyn.d_un.d_ptr += (o->output_section->vma |
+ o->output_offset); |
else |
{ |
/* The symbol is imported from another shared |
library and does not apply to this one. */ |
dyn.d_un.d_ptr = 0; |
} |
break; |
} |
} |
continue; |
case DT_PREINIT_ARRAYSZ: |
name = ".preinit_array"; |
goto get_size; |
case DT_INIT_ARRAYSZ: |
name = ".init_array"; |
goto get_size; |
case DT_FINI_ARRAYSZ: |
name = ".fini_array"; |
get_size: |
o = bfd_get_section_by_name (abfd, name); |
if (o == NULL) |
{ |
(*_bfd_error_handler) |
(_("%B: could not find output section %s"), abfd, name); |
goto error_return; |
} |
if (o->size == 0) |
(*_bfd_error_handler) |
(_("warning: %s section has zero size"), name); |
dyn.d_un.d_val = o->size; |
break; |
case DT_PREINIT_ARRAY: |
name = ".preinit_array"; |
goto get_vma; |
case DT_INIT_ARRAY: |
name = ".init_array"; |
goto get_vma; |
case DT_FINI_ARRAY: |
name = ".fini_array"; |
goto get_vma; |
case DT_HASH: |
name = ".hash"; |
goto get_vma; |
case DT_GNU_HASH: |
name = ".gnu.hash"; |
goto get_vma; |
case DT_STRTAB: |
name = ".dynstr"; |
goto get_vma; |
case DT_SYMTAB: |
name = ".dynsym"; |
goto get_vma; |
case DT_VERDEF: |
name = ".gnu.version_d"; |
goto get_vma; |
case DT_VERNEED: |
name = ".gnu.version_r"; |
goto get_vma; |
case DT_VERSYM: |
name = ".gnu.version"; |
get_vma: |
o = bfd_get_section_by_name (abfd, name); |
if (o == NULL) |
{ |
(*_bfd_error_handler) |
(_("%B: could not find output section %s"), abfd, name); |
goto error_return; |
} |
if (elf_section_data (o->output_section)->this_hdr.sh_type == SHT_NOTE) |
{ |
(*_bfd_error_handler) |
(_("warning: section '%s' is being made into a note"), name); |
bfd_set_error (bfd_error_nonrepresentable_section); |
goto error_return; |
} |
dyn.d_un.d_ptr = o->vma; |
break; |
case DT_REL: |
case DT_RELA: |
case DT_RELSZ: |
case DT_RELASZ: |
if (dyn.d_tag == DT_REL || dyn.d_tag == DT_RELSZ) |
type = SHT_REL; |
else |
type = SHT_RELA; |
dyn.d_un.d_val = 0; |
dyn.d_un.d_ptr = 0; |
for (i = 1; i < elf_numsections (abfd); i++) |
{ |
Elf_Internal_Shdr *hdr; |
hdr = elf_elfsections (abfd)[i]; |
if (hdr->sh_type == type |
&& (hdr->sh_flags & SHF_ALLOC) != 0) |
{ |
if (dyn.d_tag == DT_RELSZ || dyn.d_tag == DT_RELASZ) |
dyn.d_un.d_val += hdr->sh_size; |
else |
{ |
if (dyn.d_un.d_ptr == 0 |
|| hdr->sh_addr < dyn.d_un.d_ptr) |
dyn.d_un.d_ptr = hdr->sh_addr; |
} |
} |
} |
break; |
} |
bed->s->swap_dyn_out (dynobj, &dyn, dyncon); |
} |
} |
/* If we have created any dynamic sections, then output them. */ |
if (dynobj != NULL) |
{ |
if (! (*bed->elf_backend_finish_dynamic_sections) (abfd, info)) |
goto error_return; |
/* Check for DT_TEXTREL (late, in case the backend removes it). */ |
if (((info->warn_shared_textrel && info->shared) |
|| info->error_textrel) |
&& (o = bfd_get_linker_section (dynobj, ".dynamic")) != NULL) |
{ |
bfd_byte *dyncon, *dynconend; |
dyncon = o->contents; |
dynconend = o->contents + o->size; |
for (; dyncon < dynconend; dyncon += bed->s->sizeof_dyn) |
{ |
Elf_Internal_Dyn dyn; |
bed->s->swap_dyn_in (dynobj, dyncon, &dyn); |
if (dyn.d_tag == DT_TEXTREL) |
{ |
if (info->error_textrel) |
info->callbacks->einfo |
(_("%P%X: read-only segment has dynamic relocations.\n")); |
else |
info->callbacks->einfo |
(_("%P: warning: creating a DT_TEXTREL in a shared object.\n")); |
break; |
} |
} |
} |
for (o = dynobj->sections; o != NULL; o = o->next) |
{ |
if ((o->flags & SEC_HAS_CONTENTS) == 0 |
|| o->size == 0 |
|| o->output_section == bfd_abs_section_ptr) |
continue; |
if ((o->flags & SEC_LINKER_CREATED) == 0) |
{ |
/* At this point, we are only interested in sections |
created by _bfd_elf_link_create_dynamic_sections. */ |
continue; |
} |
if (elf_hash_table (info)->stab_info.stabstr == o) |
continue; |
if (elf_hash_table (info)->eh_info.hdr_sec == o) |
continue; |
if (strcmp (o->name, ".dynstr") != 0) |
{ |
/* FIXME: octets_per_byte. */ |
if (! bfd_set_section_contents (abfd, o->output_section, |
o->contents, |
(file_ptr) o->output_offset, |
o->size)) |
goto error_return; |
} |
else |
{ |
/* The contents of the .dynstr section are actually in a |
stringtab. */ |
off = elf_section_data (o->output_section)->this_hdr.sh_offset; |
if (bfd_seek (abfd, off, SEEK_SET) != 0 |
|| ! _bfd_elf_strtab_emit (abfd, |
elf_hash_table (info)->dynstr)) |
goto error_return; |
} |
} |
} |
if (info->relocatable) |
{ |
bfd_boolean failed = FALSE; |
bfd_map_over_sections (abfd, bfd_elf_set_group_contents, &failed); |
if (failed) |
goto error_return; |
} |
/* If we have optimized stabs strings, output them. */ |
if (elf_hash_table (info)->stab_info.stabstr != NULL) |
{ |
if (! _bfd_write_stab_strings (abfd, &elf_hash_table (info)->stab_info)) |
goto error_return; |
} |
if (! _bfd_elf_write_section_eh_frame_hdr (abfd, info)) |
goto error_return; |
elf_final_link_free (abfd, &flinfo); |
elf_linker (abfd) = TRUE; |
if (attr_section) |
{ |
bfd_byte *contents = (bfd_byte *) bfd_malloc (attr_size); |
if (contents == NULL) |
return FALSE; /* Bail out and fail. */ |
bfd_elf_set_obj_attr_contents (abfd, contents, attr_size); |
bfd_set_section_contents (abfd, attr_section, contents, 0, attr_size); |
free (contents); |
} |
return TRUE; |
error_return: |
elf_final_link_free (abfd, &flinfo); |
return FALSE; |
} |
/* Initialize COOKIE for input bfd ABFD. */ |
static bfd_boolean |
init_reloc_cookie (struct elf_reloc_cookie *cookie, |
struct bfd_link_info *info, bfd *abfd) |
{ |
Elf_Internal_Shdr *symtab_hdr; |
const struct elf_backend_data *bed; |
bed = get_elf_backend_data (abfd); |
symtab_hdr = &elf_tdata (abfd)->symtab_hdr; |
cookie->abfd = abfd; |
cookie->sym_hashes = elf_sym_hashes (abfd); |
cookie->bad_symtab = elf_bad_symtab (abfd); |
if (cookie->bad_symtab) |
{ |
cookie->locsymcount = symtab_hdr->sh_size / bed->s->sizeof_sym; |
cookie->extsymoff = 0; |
} |
else |
{ |
cookie->locsymcount = symtab_hdr->sh_info; |
cookie->extsymoff = symtab_hdr->sh_info; |
} |
if (bed->s->arch_size == 32) |
cookie->r_sym_shift = 8; |
else |
cookie->r_sym_shift = 32; |
cookie->locsyms = (Elf_Internal_Sym *) symtab_hdr->contents; |
if (cookie->locsyms == NULL && cookie->locsymcount != 0) |
{ |
cookie->locsyms = bfd_elf_get_elf_syms (abfd, symtab_hdr, |
cookie->locsymcount, 0, |
NULL, NULL, NULL); |
if (cookie->locsyms == NULL) |
{ |
info->callbacks->einfo (_("%P%X: can not read symbols: %E\n")); |
return FALSE; |
} |
if (info->keep_memory) |
symtab_hdr->contents = (bfd_byte *) cookie->locsyms; |
} |
return TRUE; |
} |
/* Free the memory allocated by init_reloc_cookie, if appropriate. */ |
static void |
fini_reloc_cookie (struct elf_reloc_cookie *cookie, bfd *abfd) |
{ |
Elf_Internal_Shdr *symtab_hdr; |
symtab_hdr = &elf_tdata (abfd)->symtab_hdr; |
if (cookie->locsyms != NULL |
&& symtab_hdr->contents != (unsigned char *) cookie->locsyms) |
free (cookie->locsyms); |
} |
/* Initialize the relocation information in COOKIE for input section SEC |
of input bfd ABFD. */ |
static bfd_boolean |
init_reloc_cookie_rels (struct elf_reloc_cookie *cookie, |
struct bfd_link_info *info, bfd *abfd, |
asection *sec) |
{ |
const struct elf_backend_data *bed; |
if (sec->reloc_count == 0) |
{ |
cookie->rels = NULL; |
cookie->relend = NULL; |
} |
else |
{ |
bed = get_elf_backend_data (abfd); |
cookie->rels = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, |
info->keep_memory); |
if (cookie->rels == NULL) |
return FALSE; |
cookie->rel = cookie->rels; |
cookie->relend = (cookie->rels |
+ sec->reloc_count * bed->s->int_rels_per_ext_rel); |
} |
cookie->rel = cookie->rels; |
return TRUE; |
} |
/* Free the memory allocated by init_reloc_cookie_rels, |
if appropriate. */ |
static void |
fini_reloc_cookie_rels (struct elf_reloc_cookie *cookie, |
asection *sec) |
{ |
if (cookie->rels && elf_section_data (sec)->relocs != cookie->rels) |
free (cookie->rels); |
} |
/* Initialize the whole of COOKIE for input section SEC. */ |
static bfd_boolean |
init_reloc_cookie_for_section (struct elf_reloc_cookie *cookie, |
struct bfd_link_info *info, |
asection *sec) |
{ |
if (!init_reloc_cookie (cookie, info, sec->owner)) |
goto error1; |
if (!init_reloc_cookie_rels (cookie, info, sec->owner, sec)) |
goto error2; |
return TRUE; |
error2: |
fini_reloc_cookie (cookie, sec->owner); |
error1: |
return FALSE; |
} |
/* Free the memory allocated by init_reloc_cookie_for_section, |
if appropriate. */ |
static void |
fini_reloc_cookie_for_section (struct elf_reloc_cookie *cookie, |
asection *sec) |
{ |
fini_reloc_cookie_rels (cookie, sec); |
fini_reloc_cookie (cookie, sec->owner); |
} |
/* Garbage collect unused sections. */ |
/* Default gc_mark_hook. */ |
asection * |
_bfd_elf_gc_mark_hook (asection *sec, |
struct bfd_link_info *info ATTRIBUTE_UNUSED, |
Elf_Internal_Rela *rel ATTRIBUTE_UNUSED, |
struct elf_link_hash_entry *h, |
Elf_Internal_Sym *sym) |
{ |
const char *sec_name; |
if (h != NULL) |
{ |
switch (h->root.type) |
{ |
case bfd_link_hash_defined: |
case bfd_link_hash_defweak: |
return h->root.u.def.section; |
case bfd_link_hash_common: |
return h->root.u.c.p->section; |
case bfd_link_hash_undefined: |
case bfd_link_hash_undefweak: |
/* To work around a glibc bug, keep all XXX input sections |
when there is an as yet undefined reference to __start_XXX |
or __stop_XXX symbols. The linker will later define such |
symbols for orphan input sections that have a name |
representable as a C identifier. */ |
if (strncmp (h->root.root.string, "__start_", 8) == 0) |
sec_name = h->root.root.string + 8; |
else if (strncmp (h->root.root.string, "__stop_", 7) == 0) |
sec_name = h->root.root.string + 7; |
else |
sec_name = NULL; |
if (sec_name && *sec_name != '\0') |
{ |
bfd *i; |
for (i = info->input_bfds; i; i = i->link_next) |
{ |
sec = bfd_get_section_by_name (i, sec_name); |
if (sec) |
sec->flags |= SEC_KEEP; |
} |
} |
break; |
default: |
break; |
} |
} |
else |
return bfd_section_from_elf_index (sec->owner, sym->st_shndx); |
return NULL; |
} |
/* COOKIE->rel describes a relocation against section SEC, which is |
a section we've decided to keep. Return the section that contains |
the relocation symbol, or NULL if no section contains it. */ |
asection * |
_bfd_elf_gc_mark_rsec (struct bfd_link_info *info, asection *sec, |
elf_gc_mark_hook_fn gc_mark_hook, |
struct elf_reloc_cookie *cookie) |
{ |
unsigned long r_symndx; |
struct elf_link_hash_entry *h; |
r_symndx = cookie->rel->r_info >> cookie->r_sym_shift; |
if (r_symndx == STN_UNDEF) |
return NULL; |
if (r_symndx >= cookie->locsymcount |
|| ELF_ST_BIND (cookie->locsyms[r_symndx].st_info) != STB_LOCAL) |
{ |
h = cookie->sym_hashes[r_symndx - cookie->extsymoff]; |
while (h->root.type == bfd_link_hash_indirect |
|| h->root.type == bfd_link_hash_warning) |
h = (struct elf_link_hash_entry *) h->root.u.i.link; |
h->mark = 1; |
/* If this symbol is weak and there is a non-weak definition, we |
keep the non-weak definition because many backends put |
dynamic reloc info on the non-weak definition for code |
handling copy relocs. */ |
if (h->u.weakdef != NULL) |
h->u.weakdef->mark = 1; |
return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL); |
} |
return (*gc_mark_hook) (sec, info, cookie->rel, NULL, |
&cookie->locsyms[r_symndx]); |
} |
/* COOKIE->rel describes a relocation against section SEC, which is |
a section we've decided to keep. Mark the section that contains |
the relocation symbol. */ |
bfd_boolean |
_bfd_elf_gc_mark_reloc (struct bfd_link_info *info, |
asection *sec, |
elf_gc_mark_hook_fn gc_mark_hook, |
struct elf_reloc_cookie *cookie) |
{ |
asection *rsec; |
rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie); |
if (rsec && !rsec->gc_mark) |
{ |
if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour |
|| (rsec->owner->flags & DYNAMIC) != 0) |
rsec->gc_mark = 1; |
else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook)) |
return FALSE; |
} |
return TRUE; |
} |
/* The mark phase of garbage collection. For a given section, mark |
it and any sections in this section's group, and all the sections |
which define symbols to which it refers. */ |
bfd_boolean |
_bfd_elf_gc_mark (struct bfd_link_info *info, |
asection *sec, |
elf_gc_mark_hook_fn gc_mark_hook) |
{ |
bfd_boolean ret; |
asection *group_sec, *eh_frame; |
sec->gc_mark = 1; |
/* Mark all the sections in the group. */ |
group_sec = elf_section_data (sec)->next_in_group; |
if (group_sec && !group_sec->gc_mark) |
if (!_bfd_elf_gc_mark (info, group_sec, gc_mark_hook)) |
return FALSE; |
/* Look through the section relocs. */ |
ret = TRUE; |
eh_frame = elf_eh_frame_section (sec->owner); |
if ((sec->flags & SEC_RELOC) != 0 |
&& sec->reloc_count > 0 |
&& sec != eh_frame) |
{ |
struct elf_reloc_cookie cookie; |
if (!init_reloc_cookie_for_section (&cookie, info, sec)) |
ret = FALSE; |
else |
{ |
for (; cookie.rel < cookie.relend; cookie.rel++) |
if (!_bfd_elf_gc_mark_reloc (info, sec, gc_mark_hook, &cookie)) |
{ |
ret = FALSE; |
break; |
} |
fini_reloc_cookie_for_section (&cookie, sec); |
} |
} |
if (ret && eh_frame && elf_fde_list (sec)) |
{ |
struct elf_reloc_cookie cookie; |
if (!init_reloc_cookie_for_section (&cookie, info, eh_frame)) |
ret = FALSE; |
else |
{ |
if (!_bfd_elf_gc_mark_fdes (info, sec, eh_frame, |
gc_mark_hook, &cookie)) |
ret = FALSE; |
fini_reloc_cookie_for_section (&cookie, eh_frame); |
} |
} |
return ret; |
} |
/* Keep debug and special sections. */ |
bfd_boolean |
_bfd_elf_gc_mark_extra_sections (struct bfd_link_info *info, |
elf_gc_mark_hook_fn mark_hook ATTRIBUTE_UNUSED) |
{ |
bfd *ibfd; |
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) |
{ |
asection *isec; |
bfd_boolean some_kept; |
bfd_boolean debug_frag_seen; |
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) |
continue; |
/* Ensure all linker created sections are kept, |
see if any other section is already marked, |
and note if we have any fragmented debug sections. */ |
debug_frag_seen = some_kept = FALSE; |
for (isec = ibfd->sections; isec != NULL; isec = isec->next) |
{ |
if ((isec->flags & SEC_LINKER_CREATED) != 0) |
isec->gc_mark = 1; |
else if (isec->gc_mark) |
some_kept = TRUE; |
if (debug_frag_seen == FALSE |
&& (isec->flags & SEC_DEBUGGING) |
&& CONST_STRNEQ (isec->name, ".debug_line.")) |
debug_frag_seen = TRUE; |
} |
/* If no section in this file will be kept, then we can |
toss out the debug and special sections. */ |
if (!some_kept) |
continue; |
/* Keep debug and special sections like .comment when they are |
not part of a group, or when we have single-member groups. */ |
for (isec = ibfd->sections; isec != NULL; isec = isec->next) |
if ((elf_next_in_group (isec) == NULL |
|| elf_next_in_group (isec) == isec) |
&& ((isec->flags & SEC_DEBUGGING) != 0 |
|| (isec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0)) |
isec->gc_mark = 1; |
if (! debug_frag_seen) |
continue; |
/* Look for CODE sections which are going to be discarded, |
and find and discard any fragmented debug sections which |
are associated with that code section. */ |
for (isec = ibfd->sections; isec != NULL; isec = isec->next) |
if ((isec->flags & SEC_CODE) != 0 |
&& isec->gc_mark == 0) |
{ |
unsigned int ilen; |
asection *dsec; |
ilen = strlen (isec->name); |
/* Association is determined by the name of the debug section |
containing the name of the code section as a suffix. For |
example .debug_line.text.foo is a debug section associated |
with .text.foo. */ |
for (dsec = ibfd->sections; dsec != NULL; dsec = dsec->next) |
{ |
unsigned int dlen; |
if (dsec->gc_mark == 0 |
|| (dsec->flags & SEC_DEBUGGING) == 0) |
continue; |
dlen = strlen (dsec->name); |
if (dlen > ilen |
&& strncmp (dsec->name + (dlen - ilen), |
isec->name, ilen) == 0) |
{ |
dsec->gc_mark = 0; |
break; |
} |
} |
} |
} |
return TRUE; |
} |
/* Sweep symbols in swept sections. Called via elf_link_hash_traverse. */ |
struct elf_gc_sweep_symbol_info |
{ |
struct bfd_link_info *info; |
void (*hide_symbol) (struct bfd_link_info *, struct elf_link_hash_entry *, |
bfd_boolean); |
}; |
static bfd_boolean |
elf_gc_sweep_symbol (struct elf_link_hash_entry *h, void *data) |
{ |
if (!h->mark |
&& (((h->root.type == bfd_link_hash_defined |
|| h->root.type == bfd_link_hash_defweak) |
&& !(h->def_regular |
&& h->root.u.def.section->gc_mark)) |
|| h->root.type == bfd_link_hash_undefined |
|| h->root.type == bfd_link_hash_undefweak)) |
{ |
struct elf_gc_sweep_symbol_info *inf; |
inf = (struct elf_gc_sweep_symbol_info *) data; |
(*inf->hide_symbol) (inf->info, h, TRUE); |
h->def_regular = 0; |
h->ref_regular = 0; |
h->ref_regular_nonweak = 0; |
} |
return TRUE; |
} |
/* The sweep phase of garbage collection. Remove all garbage sections. */ |
typedef bfd_boolean (*gc_sweep_hook_fn) |
(bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *); |
static bfd_boolean |
elf_gc_sweep (bfd *abfd, struct bfd_link_info *info) |
{ |
bfd *sub; |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
gc_sweep_hook_fn gc_sweep_hook = bed->gc_sweep_hook; |
unsigned long section_sym_count; |
struct elf_gc_sweep_symbol_info sweep_info; |
for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) |
{ |
asection *o; |
if (bfd_get_flavour (sub) != bfd_target_elf_flavour) |
continue; |
for (o = sub->sections; o != NULL; o = o->next) |
{ |
/* When any section in a section group is kept, we keep all |
sections in the section group. If the first member of |
the section group is excluded, we will also exclude the |
group section. */ |
if (o->flags & SEC_GROUP) |
{ |
asection *first = elf_next_in_group (o); |
o->gc_mark = first->gc_mark; |
} |
if (o->gc_mark) |
continue; |
/* Skip sweeping sections already excluded. */ |
if (o->flags & SEC_EXCLUDE) |
continue; |
/* Since this is early in the link process, it is simple |
to remove a section from the output. */ |
o->flags |= SEC_EXCLUDE; |
if (info->print_gc_sections && o->size != 0) |
_bfd_error_handler (_("Removing unused section '%s' in file '%B'"), sub, o->name); |
/* But we also have to update some of the relocation |
info we collected before. */ |
if (gc_sweep_hook |
&& (o->flags & SEC_RELOC) != 0 |
&& o->reloc_count > 0 |
&& !bfd_is_abs_section (o->output_section)) |
{ |
Elf_Internal_Rela *internal_relocs; |
bfd_boolean r; |
internal_relocs |
= _bfd_elf_link_read_relocs (o->owner, o, NULL, NULL, |
info->keep_memory); |
if (internal_relocs == NULL) |
return FALSE; |
r = (*gc_sweep_hook) (o->owner, info, o, internal_relocs); |
if (elf_section_data (o)->relocs != internal_relocs) |
free (internal_relocs); |
if (!r) |
return FALSE; |
} |
} |
} |
/* Remove the symbols that were in the swept sections from the dynamic |
symbol table. GCFIXME: Anyone know how to get them out of the |
static symbol table as well? */ |
sweep_info.info = info; |
sweep_info.hide_symbol = bed->elf_backend_hide_symbol; |
elf_link_hash_traverse (elf_hash_table (info), elf_gc_sweep_symbol, |
&sweep_info); |
_bfd_elf_link_renumber_dynsyms (abfd, info, §ion_sym_count); |
return TRUE; |
} |
/* Propagate collected vtable information. This is called through |
elf_link_hash_traverse. */ |
static bfd_boolean |
elf_gc_propagate_vtable_entries_used (struct elf_link_hash_entry *h, void *okp) |
{ |
/* Those that are not vtables. */ |
if (h->vtable == NULL || h->vtable->parent == NULL) |
return TRUE; |
/* Those vtables that do not have parents, we cannot merge. */ |
if (h->vtable->parent == (struct elf_link_hash_entry *) -1) |
return TRUE; |
/* If we've already been done, exit. */ |
if (h->vtable->used && h->vtable->used[-1]) |
return TRUE; |
/* Make sure the parent's table is up to date. */ |
elf_gc_propagate_vtable_entries_used (h->vtable->parent, okp); |
if (h->vtable->used == NULL) |
{ |
/* None of this table's entries were referenced. Re-use the |
parent's table. */ |
h->vtable->used = h->vtable->parent->vtable->used; |
h->vtable->size = h->vtable->parent->vtable->size; |
} |
else |
{ |
size_t n; |
bfd_boolean *cu, *pu; |
/* Or the parent's entries into ours. */ |
cu = h->vtable->used; |
cu[-1] = TRUE; |
pu = h->vtable->parent->vtable->used; |
if (pu != NULL) |
{ |
const struct elf_backend_data *bed; |
unsigned int log_file_align; |
bed = get_elf_backend_data (h->root.u.def.section->owner); |
log_file_align = bed->s->log_file_align; |
n = h->vtable->parent->vtable->size >> log_file_align; |
while (n--) |
{ |
if (*pu) |
*cu = TRUE; |
pu++; |
cu++; |
} |
} |
} |
return TRUE; |
} |
static bfd_boolean |
elf_gc_smash_unused_vtentry_relocs (struct elf_link_hash_entry *h, void *okp) |
{ |
asection *sec; |
bfd_vma hstart, hend; |
Elf_Internal_Rela *relstart, *relend, *rel; |
const struct elf_backend_data *bed; |
unsigned int log_file_align; |
/* Take care of both those symbols that do not describe vtables as |
well as those that are not loaded. */ |
if (h->vtable == NULL || h->vtable->parent == NULL) |
return TRUE; |
BFD_ASSERT (h->root.type == bfd_link_hash_defined |
|| h->root.type == bfd_link_hash_defweak); |
sec = h->root.u.def.section; |
hstart = h->root.u.def.value; |
hend = hstart + h->size; |
relstart = _bfd_elf_link_read_relocs (sec->owner, sec, NULL, NULL, TRUE); |
if (!relstart) |
return *(bfd_boolean *) okp = FALSE; |
bed = get_elf_backend_data (sec->owner); |
log_file_align = bed->s->log_file_align; |
relend = relstart + sec->reloc_count * bed->s->int_rels_per_ext_rel; |
for (rel = relstart; rel < relend; ++rel) |
if (rel->r_offset >= hstart && rel->r_offset < hend) |
{ |
/* If the entry is in use, do nothing. */ |
if (h->vtable->used |
&& (rel->r_offset - hstart) < h->vtable->size) |
{ |
bfd_vma entry = (rel->r_offset - hstart) >> log_file_align; |
if (h->vtable->used[entry]) |
continue; |
} |
/* Otherwise, kill it. */ |
rel->r_offset = rel->r_info = rel->r_addend = 0; |
} |
return TRUE; |
} |
/* Mark sections containing dynamically referenced symbols. When |
building shared libraries, we must assume that any visible symbol is |
referenced. */ |
bfd_boolean |
bfd_elf_gc_mark_dynamic_ref_symbol (struct elf_link_hash_entry *h, void *inf) |
{ |
struct bfd_link_info *info = (struct bfd_link_info *) inf; |
if ((h->root.type == bfd_link_hash_defined |
|| h->root.type == bfd_link_hash_defweak) |
&& (h->ref_dynamic |
|| ((!info->executable || info->export_dynamic) |
&& h->def_regular |
&& ELF_ST_VISIBILITY (h->other) != STV_INTERNAL |
&& ELF_ST_VISIBILITY (h->other) != STV_HIDDEN |
&& (strchr (h->root.root.string, ELF_VER_CHR) != NULL |
|| !bfd_hide_sym_by_version (info->version_info, |
h->root.root.string))))) |
h->root.u.def.section->flags |= SEC_KEEP; |
return TRUE; |
} |
/* Keep all sections containing symbols undefined on the command-line, |
and the section containing the entry symbol. */ |
void |
_bfd_elf_gc_keep (struct bfd_link_info *info) |
{ |
struct bfd_sym_chain *sym; |
for (sym = info->gc_sym_list; sym != NULL; sym = sym->next) |
{ |
struct elf_link_hash_entry *h; |
h = elf_link_hash_lookup (elf_hash_table (info), sym->name, |
FALSE, FALSE, FALSE); |
if (h != NULL |
&& (h->root.type == bfd_link_hash_defined |
|| h->root.type == bfd_link_hash_defweak) |
&& !bfd_is_abs_section (h->root.u.def.section)) |
h->root.u.def.section->flags |= SEC_KEEP; |
} |
} |
/* Do mark and sweep of unused sections. */ |
bfd_boolean |
bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info) |
{ |
bfd_boolean ok = TRUE; |
bfd *sub; |
elf_gc_mark_hook_fn gc_mark_hook; |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
if (!bed->can_gc_sections |
|| !is_elf_hash_table (info->hash)) |
{ |
(*_bfd_error_handler)(_("Warning: gc-sections option ignored")); |
return TRUE; |
} |
bed->gc_keep (info); |
/* Try to parse each bfd's .eh_frame section. Point elf_eh_frame_section |
at the .eh_frame section if we can mark the FDEs individually. */ |
_bfd_elf_begin_eh_frame_parsing (info); |
for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) |
{ |
asection *sec; |
struct elf_reloc_cookie cookie; |
sec = bfd_get_section_by_name (sub, ".eh_frame"); |
while (sec && init_reloc_cookie_for_section (&cookie, info, sec)) |
{ |
_bfd_elf_parse_eh_frame (sub, info, sec, &cookie); |
if (elf_section_data (sec)->sec_info |
&& (sec->flags & SEC_LINKER_CREATED) == 0) |
elf_eh_frame_section (sub) = sec; |
fini_reloc_cookie_for_section (&cookie, sec); |
sec = bfd_get_next_section_by_name (sec); |
} |
} |
_bfd_elf_end_eh_frame_parsing (info); |
/* Apply transitive closure to the vtable entry usage info. */ |
elf_link_hash_traverse (elf_hash_table (info), |
elf_gc_propagate_vtable_entries_used, |
&ok); |
if (!ok) |
return FALSE; |
/* Kill the vtable relocations that were not used. */ |
elf_link_hash_traverse (elf_hash_table (info), |
elf_gc_smash_unused_vtentry_relocs, |
&ok); |
if (!ok) |
return FALSE; |
/* Mark dynamically referenced symbols. */ |
if (elf_hash_table (info)->dynamic_sections_created) |
elf_link_hash_traverse (elf_hash_table (info), |
bed->gc_mark_dynamic_ref, |
info); |
/* Grovel through relocs to find out who stays ... */ |
gc_mark_hook = bed->gc_mark_hook; |
for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) |
{ |
asection *o; |
if (bfd_get_flavour (sub) != bfd_target_elf_flavour) |
continue; |
/* Start at sections marked with SEC_KEEP (ref _bfd_elf_gc_keep). |
Also treat note sections as a root, if the section is not part |
of a group. */ |
for (o = sub->sections; o != NULL; o = o->next) |
if (!o->gc_mark |
&& (o->flags & SEC_EXCLUDE) == 0 |
&& ((o->flags & SEC_KEEP) != 0 |
|| (elf_section_data (o)->this_hdr.sh_type == SHT_NOTE |
&& elf_next_in_group (o) == NULL ))) |
{ |
if (!_bfd_elf_gc_mark (info, o, gc_mark_hook)) |
return FALSE; |
} |
} |
/* Allow the backend to mark additional target specific sections. */ |
bed->gc_mark_extra_sections (info, gc_mark_hook); |
/* ... and mark SEC_EXCLUDE for those that go. */ |
return elf_gc_sweep (abfd, info); |
} |
/* Called from check_relocs to record the existence of a VTINHERIT reloc. */ |
bfd_boolean |
bfd_elf_gc_record_vtinherit (bfd *abfd, |
asection *sec, |
struct elf_link_hash_entry *h, |
bfd_vma offset) |
{ |
struct elf_link_hash_entry **sym_hashes, **sym_hashes_end; |
struct elf_link_hash_entry **search, *child; |
bfd_size_type extsymcount; |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
/* The sh_info field of the symtab header tells us where the |
external symbols start. We don't care about the local symbols at |
this point. */ |
extsymcount = elf_tdata (abfd)->symtab_hdr.sh_size / bed->s->sizeof_sym; |
if (!elf_bad_symtab (abfd)) |
extsymcount -= elf_tdata (abfd)->symtab_hdr.sh_info; |
sym_hashes = elf_sym_hashes (abfd); |
sym_hashes_end = sym_hashes + extsymcount; |
/* Hunt down the child symbol, which is in this section at the same |
offset as the relocation. */ |
for (search = sym_hashes; search != sym_hashes_end; ++search) |
{ |
if ((child = *search) != NULL |
&& (child->root.type == bfd_link_hash_defined |
|| child->root.type == bfd_link_hash_defweak) |
&& child->root.u.def.section == sec |
&& child->root.u.def.value == offset) |
goto win; |
} |
(*_bfd_error_handler) ("%B: %A+%lu: No symbol found for INHERIT", |
abfd, sec, (unsigned long) offset); |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
win: |
if (!child->vtable) |
{ |
child->vtable = (struct elf_link_virtual_table_entry *) |
bfd_zalloc (abfd, sizeof (*child->vtable)); |
if (!child->vtable) |
return FALSE; |
} |
if (!h) |
{ |
/* This *should* only be the absolute section. It could potentially |
be that someone has defined a non-global vtable though, which |
would be bad. It isn't worth paging in the local symbols to be |
sure though; that case should simply be handled by the assembler. */ |
child->vtable->parent = (struct elf_link_hash_entry *) -1; |
} |
else |
child->vtable->parent = h; |
return TRUE; |
} |
/* Called from check_relocs to record the existence of a VTENTRY reloc. */ |
bfd_boolean |
bfd_elf_gc_record_vtentry (bfd *abfd ATTRIBUTE_UNUSED, |
asection *sec ATTRIBUTE_UNUSED, |
struct elf_link_hash_entry *h, |
bfd_vma addend) |
{ |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
unsigned int log_file_align = bed->s->log_file_align; |
if (!h->vtable) |
{ |
h->vtable = (struct elf_link_virtual_table_entry *) |
bfd_zalloc (abfd, sizeof (*h->vtable)); |
if (!h->vtable) |
return FALSE; |
} |
if (addend >= h->vtable->size) |
{ |
size_t size, bytes, file_align; |
bfd_boolean *ptr = h->vtable->used; |
/* While the symbol is undefined, we have to be prepared to handle |
a zero size. */ |
file_align = 1 << log_file_align; |
if (h->root.type == bfd_link_hash_undefined) |
size = addend + file_align; |
else |
{ |
size = h->size; |
if (addend >= size) |
{ |
/* Oops! We've got a reference past the defined end of |
the table. This is probably a bug -- shall we warn? */ |
size = addend + file_align; |
} |
} |
size = (size + file_align - 1) & -file_align; |
/* Allocate one extra entry for use as a "done" flag for the |
consolidation pass. */ |
bytes = ((size >> log_file_align) + 1) * sizeof (bfd_boolean); |
if (ptr) |
{ |
ptr = (bfd_boolean *) bfd_realloc (ptr - 1, bytes); |
if (ptr != NULL) |
{ |
size_t oldbytes; |
oldbytes = (((h->vtable->size >> log_file_align) + 1) |
* sizeof (bfd_boolean)); |
memset (((char *) ptr) + oldbytes, 0, bytes - oldbytes); |
} |
} |
else |
ptr = (bfd_boolean *) bfd_zmalloc (bytes); |
if (ptr == NULL) |
return FALSE; |
/* And arrange for that done flag to be at index -1. */ |
h->vtable->used = ptr + 1; |
h->vtable->size = size; |
} |
h->vtable->used[addend >> log_file_align] = TRUE; |
return TRUE; |
} |
/* Map an ELF section header flag to its corresponding string. */ |
typedef struct |
{ |
char *flag_name; |
flagword flag_value; |
} elf_flags_to_name_table; |
static elf_flags_to_name_table elf_flags_to_names [] = |
{ |
{ "SHF_WRITE", SHF_WRITE }, |
{ "SHF_ALLOC", SHF_ALLOC }, |
{ "SHF_EXECINSTR", SHF_EXECINSTR }, |
{ "SHF_MERGE", SHF_MERGE }, |
{ "SHF_STRINGS", SHF_STRINGS }, |
{ "SHF_INFO_LINK", SHF_INFO_LINK}, |
{ "SHF_LINK_ORDER", SHF_LINK_ORDER}, |
{ "SHF_OS_NONCONFORMING", SHF_OS_NONCONFORMING}, |
{ "SHF_GROUP", SHF_GROUP }, |
{ "SHF_TLS", SHF_TLS }, |
{ "SHF_MASKOS", SHF_MASKOS }, |
{ "SHF_EXCLUDE", SHF_EXCLUDE }, |
}; |
/* Returns TRUE if the section is to be included, otherwise FALSE. */ |
bfd_boolean |
bfd_elf_lookup_section_flags (struct bfd_link_info *info, |
struct flag_info *flaginfo, |
asection *section) |
{ |
const bfd_vma sh_flags = elf_section_flags (section); |
if (!flaginfo->flags_initialized) |
{ |
bfd *obfd = info->output_bfd; |
const struct elf_backend_data *bed = get_elf_backend_data (obfd); |
struct flag_info_list *tf = flaginfo->flag_list; |
int with_hex = 0; |
int without_hex = 0; |
for (tf = flaginfo->flag_list; tf != NULL; tf = tf->next) |
{ |
unsigned i; |
flagword (*lookup) (char *); |
lookup = bed->elf_backend_lookup_section_flags_hook; |
if (lookup != NULL) |
{ |
flagword hexval = (*lookup) ((char *) tf->name); |
if (hexval != 0) |
{ |
if (tf->with == with_flags) |
with_hex |= hexval; |
else if (tf->with == without_flags) |
without_hex |= hexval; |
tf->valid = TRUE; |
continue; |
} |
} |
for (i = 0; i < ARRAY_SIZE (elf_flags_to_names); ++i) |
{ |
if (strcmp (tf->name, elf_flags_to_names[i].flag_name) == 0) |
{ |
if (tf->with == with_flags) |
with_hex |= elf_flags_to_names[i].flag_value; |
else if (tf->with == without_flags) |
without_hex |= elf_flags_to_names[i].flag_value; |
tf->valid = TRUE; |
break; |
} |
} |
if (!tf->valid) |
{ |
info->callbacks->einfo |
(_("Unrecognized INPUT_SECTION_FLAG %s\n"), tf->name); |
return FALSE; |
} |
} |
flaginfo->flags_initialized = TRUE; |
flaginfo->only_with_flags |= with_hex; |
flaginfo->not_with_flags |= without_hex; |
} |
if ((flaginfo->only_with_flags & sh_flags) != flaginfo->only_with_flags) |
return FALSE; |
if ((flaginfo->not_with_flags & sh_flags) != 0) |
return FALSE; |
return TRUE; |
} |
struct alloc_got_off_arg { |
bfd_vma gotoff; |
struct bfd_link_info *info; |
}; |
/* We need a special top-level link routine to convert got reference counts |
to real got offsets. */ |
static bfd_boolean |
elf_gc_allocate_got_offsets (struct elf_link_hash_entry *h, void *arg) |
{ |
struct alloc_got_off_arg *gofarg = (struct alloc_got_off_arg *) arg; |
bfd *obfd = gofarg->info->output_bfd; |
const struct elf_backend_data *bed = get_elf_backend_data (obfd); |
if (h->got.refcount > 0) |
{ |
h->got.offset = gofarg->gotoff; |
gofarg->gotoff += bed->got_elt_size (obfd, gofarg->info, h, NULL, 0); |
} |
else |
h->got.offset = (bfd_vma) -1; |
return TRUE; |
} |
/* And an accompanying bit to work out final got entry offsets once |
we're done. Should be called from final_link. */ |
bfd_boolean |
bfd_elf_gc_common_finalize_got_offsets (bfd *abfd, |
struct bfd_link_info *info) |
{ |
bfd *i; |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
bfd_vma gotoff; |
struct alloc_got_off_arg gofarg; |
BFD_ASSERT (abfd == info->output_bfd); |
if (! is_elf_hash_table (info->hash)) |
return FALSE; |
/* The GOT offset is relative to the .got section, but the GOT header is |
put into the .got.plt section, if the backend uses it. */ |
if (bed->want_got_plt) |
gotoff = 0; |
else |
gotoff = bed->got_header_size; |
/* Do the local .got entries first. */ |
for (i = info->input_bfds; i; i = i->link_next) |
{ |
bfd_signed_vma *local_got; |
bfd_size_type j, locsymcount; |
Elf_Internal_Shdr *symtab_hdr; |
if (bfd_get_flavour (i) != bfd_target_elf_flavour) |
continue; |
local_got = elf_local_got_refcounts (i); |
if (!local_got) |
continue; |
symtab_hdr = &elf_tdata (i)->symtab_hdr; |
if (elf_bad_symtab (i)) |
locsymcount = symtab_hdr->sh_size / bed->s->sizeof_sym; |
else |
locsymcount = symtab_hdr->sh_info; |
for (j = 0; j < locsymcount; ++j) |
{ |
if (local_got[j] > 0) |
{ |
local_got[j] = gotoff; |
gotoff += bed->got_elt_size (abfd, info, NULL, i, j); |
} |
else |
local_got[j] = (bfd_vma) -1; |
} |
} |
/* Then the global .got entries. .plt refcounts are handled by |
adjust_dynamic_symbol */ |
gofarg.gotoff = gotoff; |
gofarg.info = info; |
elf_link_hash_traverse (elf_hash_table (info), |
elf_gc_allocate_got_offsets, |
&gofarg); |
return TRUE; |
} |
/* Many folk need no more in the way of final link than this, once |
got entry reference counting is enabled. */ |
bfd_boolean |
bfd_elf_gc_common_final_link (bfd *abfd, struct bfd_link_info *info) |
{ |
if (!bfd_elf_gc_common_finalize_got_offsets (abfd, info)) |
return FALSE; |
/* Invoke the regular ELF backend linker to do all the work. */ |
return bfd_elf_final_link (abfd, info); |
} |
bfd_boolean |
bfd_elf_reloc_symbol_deleted_p (bfd_vma offset, void *cookie) |
{ |
struct elf_reloc_cookie *rcookie = (struct elf_reloc_cookie *) cookie; |
if (rcookie->bad_symtab) |
rcookie->rel = rcookie->rels; |
for (; rcookie->rel < rcookie->relend; rcookie->rel++) |
{ |
unsigned long r_symndx; |
if (! rcookie->bad_symtab) |
if (rcookie->rel->r_offset > offset) |
return FALSE; |
if (rcookie->rel->r_offset != offset) |
continue; |
r_symndx = rcookie->rel->r_info >> rcookie->r_sym_shift; |
if (r_symndx == STN_UNDEF) |
return TRUE; |
if (r_symndx >= rcookie->locsymcount |
|| ELF_ST_BIND (rcookie->locsyms[r_symndx].st_info) != STB_LOCAL) |
{ |
struct elf_link_hash_entry *h; |
h = rcookie->sym_hashes[r_symndx - rcookie->extsymoff]; |
while (h->root.type == bfd_link_hash_indirect |
|| h->root.type == bfd_link_hash_warning) |
h = (struct elf_link_hash_entry *) h->root.u.i.link; |
if ((h->root.type == bfd_link_hash_defined |
|| h->root.type == bfd_link_hash_defweak) |
&& discarded_section (h->root.u.def.section)) |
return TRUE; |
else |
return FALSE; |
} |
else |
{ |
/* It's not a relocation against a global symbol, |
but it could be a relocation against a local |
symbol for a discarded section. */ |
asection *isec; |
Elf_Internal_Sym *isym; |
/* Need to: get the symbol; get the section. */ |
isym = &rcookie->locsyms[r_symndx]; |
isec = bfd_section_from_elf_index (rcookie->abfd, isym->st_shndx); |
if (isec != NULL && discarded_section (isec)) |
return TRUE; |
} |
return FALSE; |
} |
return FALSE; |
} |
/* Discard unneeded references to discarded sections. |
Returns TRUE if any section's size was changed. */ |
/* This function assumes that the relocations are in sorted order, |
which is true for all known assemblers. */ |
bfd_boolean |
bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info) |
{ |
struct elf_reloc_cookie cookie; |
asection *stab, *eh; |
const struct elf_backend_data *bed; |
bfd *abfd; |
bfd_boolean ret = FALSE; |
if (info->traditional_format |
|| !is_elf_hash_table (info->hash)) |
return FALSE; |
_bfd_elf_begin_eh_frame_parsing (info); |
for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next) |
{ |
if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) |
continue; |
bed = get_elf_backend_data (abfd); |
eh = NULL; |
if (!info->relocatable) |
{ |
eh = bfd_get_section_by_name (abfd, ".eh_frame"); |
while (eh != NULL |
&& (eh->size == 0 |
|| bfd_is_abs_section (eh->output_section))) |
eh = bfd_get_next_section_by_name (eh); |
} |
stab = bfd_get_section_by_name (abfd, ".stab"); |
if (stab != NULL |
&& (stab->size == 0 |
|| bfd_is_abs_section (stab->output_section) |
|| stab->sec_info_type != SEC_INFO_TYPE_STABS)) |
stab = NULL; |
if (stab == NULL |
&& eh == NULL |
&& bed->elf_backend_discard_info == NULL) |
continue; |
if (!init_reloc_cookie (&cookie, info, abfd)) |
return FALSE; |
if (stab != NULL |
&& stab->reloc_count > 0 |
&& init_reloc_cookie_rels (&cookie, info, abfd, stab)) |
{ |
if (_bfd_discard_section_stabs (abfd, stab, |
elf_section_data (stab)->sec_info, |
bfd_elf_reloc_symbol_deleted_p, |
&cookie)) |
ret = TRUE; |
fini_reloc_cookie_rels (&cookie, stab); |
} |
while (eh != NULL |
&& init_reloc_cookie_rels (&cookie, info, abfd, eh)) |
{ |
_bfd_elf_parse_eh_frame (abfd, info, eh, &cookie); |
if (_bfd_elf_discard_section_eh_frame (abfd, info, eh, |
bfd_elf_reloc_symbol_deleted_p, |
&cookie)) |
ret = TRUE; |
fini_reloc_cookie_rels (&cookie, eh); |
eh = bfd_get_next_section_by_name (eh); |
} |
if (bed->elf_backend_discard_info != NULL |
&& (*bed->elf_backend_discard_info) (abfd, &cookie, info)) |
ret = TRUE; |
fini_reloc_cookie (&cookie, abfd); |
} |
_bfd_elf_end_eh_frame_parsing (info); |
if (info->eh_frame_hdr |
&& !info->relocatable |
&& _bfd_elf_discard_section_eh_frame_hdr (output_bfd, info)) |
ret = TRUE; |
return ret; |
} |
bfd_boolean |
_bfd_elf_section_already_linked (bfd *abfd, |
asection *sec, |
struct bfd_link_info *info) |
{ |
flagword flags; |
const char *name, *key; |
struct bfd_section_already_linked *l; |
struct bfd_section_already_linked_hash_entry *already_linked_list; |
if (sec->output_section == bfd_abs_section_ptr) |
return FALSE; |
flags = sec->flags; |
/* Return if it isn't a linkonce section. A comdat group section |
also has SEC_LINK_ONCE set. */ |
if ((flags & SEC_LINK_ONCE) == 0) |
return FALSE; |
/* Don't put group member sections on our list of already linked |
sections. They are handled as a group via their group section. */ |
if (elf_sec_group (sec) != NULL) |
return FALSE; |
/* For a SHT_GROUP section, use the group signature as the key. */ |
name = sec->name; |
if ((flags & SEC_GROUP) != 0 |
&& elf_next_in_group (sec) != NULL |
&& elf_group_name (elf_next_in_group (sec)) != NULL) |
key = elf_group_name (elf_next_in_group (sec)); |
else |
{ |
/* Otherwise we should have a .gnu.linkonce.<type>.<key> section. */ |
if (CONST_STRNEQ (name, ".gnu.linkonce.") |
&& (key = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL) |
key++; |
else |
/* Must be a user linkonce section that doesn't follow gcc's |
naming convention. In this case we won't be matching |
single member groups. */ |
key = name; |
} |
already_linked_list = bfd_section_already_linked_table_lookup (key); |
for (l = already_linked_list->entry; l != NULL; l = l->next) |
{ |
/* We may have 2 different types of sections on the list: group |
sections with a signature of <key> (<key> is some string), |
and linkonce sections named .gnu.linkonce.<type>.<key>. |
Match like sections. LTO plugin sections are an exception. |
They are always named .gnu.linkonce.t.<key> and match either |
type of section. */ |
if (((flags & SEC_GROUP) == (l->sec->flags & SEC_GROUP) |
&& ((flags & SEC_GROUP) != 0 |
|| strcmp (name, l->sec->name) == 0)) |
|| (l->sec->owner->flags & BFD_PLUGIN) != 0) |
{ |
/* The section has already been linked. See if we should |
issue a warning. */ |
if (!_bfd_handle_already_linked (sec, l, info)) |
return FALSE; |
if (flags & SEC_GROUP) |
{ |
asection *first = elf_next_in_group (sec); |
asection *s = first; |
while (s != NULL) |
{ |
s->output_section = bfd_abs_section_ptr; |
/* Record which group discards it. */ |
s->kept_section = l->sec; |
s = elf_next_in_group (s); |
/* These lists are circular. */ |
if (s == first) |
break; |
} |
} |
return TRUE; |
} |
} |
/* A single member comdat group section may be discarded by a |
linkonce section and vice versa. */ |
if ((flags & SEC_GROUP) != 0) |
{ |
asection *first = elf_next_in_group (sec); |
if (first != NULL && elf_next_in_group (first) == first) |
/* Check this single member group against linkonce sections. */ |
for (l = already_linked_list->entry; l != NULL; l = l->next) |
if ((l->sec->flags & SEC_GROUP) == 0 |
&& bfd_elf_match_symbols_in_sections (l->sec, first, info)) |
{ |
first->output_section = bfd_abs_section_ptr; |
first->kept_section = l->sec; |
sec->output_section = bfd_abs_section_ptr; |
break; |
} |
} |
else |
/* Check this linkonce section against single member groups. */ |
for (l = already_linked_list->entry; l != NULL; l = l->next) |
if (l->sec->flags & SEC_GROUP) |
{ |
asection *first = elf_next_in_group (l->sec); |
if (first != NULL |
&& elf_next_in_group (first) == first |
&& bfd_elf_match_symbols_in_sections (first, sec, info)) |
{ |
sec->output_section = bfd_abs_section_ptr; |
sec->kept_section = first; |
break; |
} |
} |
/* Do not complain on unresolved relocations in `.gnu.linkonce.r.F' |
referencing its discarded `.gnu.linkonce.t.F' counterpart - g++-3.4 |
specific as g++-4.x is using COMDAT groups (without the `.gnu.linkonce' |
prefix) instead. `.gnu.linkonce.r.*' were the `.rodata' part of its |
matching `.gnu.linkonce.t.*'. If `.gnu.linkonce.r.F' is not discarded |
but its `.gnu.linkonce.t.F' is discarded means we chose one-only |
`.gnu.linkonce.t.F' section from a different bfd not requiring any |
`.gnu.linkonce.r.F'. Thus `.gnu.linkonce.r.F' should be discarded. |
The reverse order cannot happen as there is never a bfd with only the |
`.gnu.linkonce.r.F' section. The order of sections in a bfd does not |
matter as here were are looking only for cross-bfd sections. */ |
if ((flags & SEC_GROUP) == 0 && CONST_STRNEQ (name, ".gnu.linkonce.r.")) |
for (l = already_linked_list->entry; l != NULL; l = l->next) |
if ((l->sec->flags & SEC_GROUP) == 0 |
&& CONST_STRNEQ (l->sec->name, ".gnu.linkonce.t.")) |
{ |
if (abfd != l->sec->owner) |
sec->output_section = bfd_abs_section_ptr; |
break; |
} |
/* This is the first section with this name. Record it. */ |
if (!bfd_section_already_linked_table_insert (already_linked_list, sec)) |
info->callbacks->einfo (_("%F%P: already_linked_table: %E\n")); |
return sec->output_section == bfd_abs_section_ptr; |
} |
bfd_boolean |
_bfd_elf_common_definition (Elf_Internal_Sym *sym) |
{ |
return sym->st_shndx == SHN_COMMON; |
} |
unsigned int |
_bfd_elf_common_section_index (asection *sec ATTRIBUTE_UNUSED) |
{ |
return SHN_COMMON; |
} |
asection * |
_bfd_elf_common_section (asection *sec ATTRIBUTE_UNUSED) |
{ |
return bfd_com_section_ptr; |
} |
bfd_vma |
_bfd_elf_default_got_elt_size (bfd *abfd, |
struct bfd_link_info *info ATTRIBUTE_UNUSED, |
struct elf_link_hash_entry *h ATTRIBUTE_UNUSED, |
bfd *ibfd ATTRIBUTE_UNUSED, |
unsigned long symndx ATTRIBUTE_UNUSED) |
{ |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
return bed->s->arch_size / 8; |
} |
/* Routines to support the creation of dynamic relocs. */ |
/* Returns the name of the dynamic reloc section associated with SEC. */ |
static const char * |
get_dynamic_reloc_section_name (bfd * abfd, |
asection * sec, |
bfd_boolean is_rela) |
{ |
char *name; |
const char *old_name = bfd_get_section_name (NULL, sec); |
const char *prefix = is_rela ? ".rela" : ".rel"; |
if (old_name == NULL) |
return NULL; |
name = bfd_alloc (abfd, strlen (prefix) + strlen (old_name) + 1); |
sprintf (name, "%s%s", prefix, old_name); |
return name; |
} |
/* Returns the dynamic reloc section associated with SEC. |
If necessary compute the name of the dynamic reloc section based |
on SEC's name (looked up in ABFD's string table) and the setting |
of IS_RELA. */ |
asection * |
_bfd_elf_get_dynamic_reloc_section (bfd * abfd, |
asection * sec, |
bfd_boolean is_rela) |
{ |
asection * reloc_sec = elf_section_data (sec)->sreloc; |
if (reloc_sec == NULL) |
{ |
const char * name = get_dynamic_reloc_section_name (abfd, sec, is_rela); |
if (name != NULL) |
{ |
reloc_sec = bfd_get_linker_section (abfd, name); |
if (reloc_sec != NULL) |
elf_section_data (sec)->sreloc = reloc_sec; |
} |
} |
return reloc_sec; |
} |
/* Returns the dynamic reloc section associated with SEC. If the |
section does not exist it is created and attached to the DYNOBJ |
bfd and stored in the SRELOC field of SEC's elf_section_data |
structure. |
ALIGNMENT is the alignment for the newly created section and |
IS_RELA defines whether the name should be .rela.<SEC's name> |
or .rel.<SEC's name>. The section name is looked up in the |
string table associated with ABFD. */ |
asection * |
_bfd_elf_make_dynamic_reloc_section (asection * sec, |
bfd * dynobj, |
unsigned int alignment, |
bfd * abfd, |
bfd_boolean is_rela) |
{ |
asection * reloc_sec = elf_section_data (sec)->sreloc; |
if (reloc_sec == NULL) |
{ |
const char * name = get_dynamic_reloc_section_name (abfd, sec, is_rela); |
if (name == NULL) |
return NULL; |
reloc_sec = bfd_get_linker_section (dynobj, name); |
if (reloc_sec == NULL) |
{ |
flagword flags = (SEC_HAS_CONTENTS | SEC_READONLY |
| SEC_IN_MEMORY | SEC_LINKER_CREATED); |
if ((sec->flags & SEC_ALLOC) != 0) |
flags |= SEC_ALLOC | SEC_LOAD; |
reloc_sec = bfd_make_section_anyway_with_flags (dynobj, name, flags); |
if (reloc_sec != NULL) |
{ |
/* _bfd_elf_get_sec_type_attr chooses a section type by |
name. Override as it may be wrong, eg. for a user |
section named "auto" we'll get ".relauto" which is |
seen to be a .rela section. */ |
elf_section_type (reloc_sec) = is_rela ? SHT_RELA : SHT_REL; |
if (! bfd_set_section_alignment (dynobj, reloc_sec, alignment)) |
reloc_sec = NULL; |
} |
} |
elf_section_data (sec)->sreloc = reloc_sec; |
} |
return reloc_sec; |
} |
/* Copy the ELF symbol type associated with a linker hash entry. */ |
void |
_bfd_elf_copy_link_hash_symbol_type (bfd *abfd ATTRIBUTE_UNUSED, |
struct bfd_link_hash_entry * hdest, |
struct bfd_link_hash_entry * hsrc) |
{ |
struct elf_link_hash_entry *ehdest = (struct elf_link_hash_entry *)hdest; |
struct elf_link_hash_entry *ehsrc = (struct elf_link_hash_entry *)hsrc; |
ehdest->type = ehsrc->type; |
ehdest->target_internal = ehsrc->target_internal; |
} |
/* Append a RELA relocation REL to section S in BFD. */ |
void |
elf_append_rela (bfd *abfd, asection *s, Elf_Internal_Rela *rel) |
{ |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
bfd_byte *loc = s->contents + (s->reloc_count++ * bed->s->sizeof_rela); |
BFD_ASSERT (loc + bed->s->sizeof_rela <= s->contents + s->size); |
bed->s->swap_reloca_out (abfd, rel, loc); |
} |
/* Append a REL relocation REL to section S in BFD. */ |
void |
elf_append_rel (bfd *abfd, asection *s, Elf_Internal_Rela *rel) |
{ |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
bfd_byte *loc = s->contents + (s->reloc_count++ * bed->s->sizeof_rel); |
BFD_ASSERT (loc + bed->s->sizeof_rel <= s->contents + s->size); |
bed->s->swap_reloc_out (abfd, rel, loc); |
} |
/contrib/toolchain/binutils/bfd/format.c |
---|
0,0 → 1,561 |
/* Generic BFD support for file formats. |
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1999, 2000, 2001, 2002, |
2003, 2005, 2007, 2008, 2009 Free Software Foundation, Inc. |
Written by Cygnus Support. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* |
SECTION |
File formats |
A format is a BFD concept of high level file contents type. The |
formats supported by BFD are: |
o <<bfd_object>> |
The BFD may contain data, symbols, relocations and debug info. |
o <<bfd_archive>> |
The BFD contains other BFDs and an optional index. |
o <<bfd_core>> |
The BFD contains the result of an executable core dump. |
SUBSECTION |
File format functions |
*/ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
/* IMPORT from targets.c. */ |
extern const size_t _bfd_target_vector_entries; |
/* |
FUNCTION |
bfd_check_format |
SYNOPSIS |
bfd_boolean bfd_check_format (bfd *abfd, bfd_format format); |
DESCRIPTION |
Verify if the file attached to the BFD @var{abfd} is compatible |
with the format @var{format} (i.e., one of <<bfd_object>>, |
<<bfd_archive>> or <<bfd_core>>). |
If the BFD has been set to a specific target before the |
call, only the named target and format combination is |
checked. If the target has not been set, or has been set to |
<<default>>, then all the known target backends is |
interrogated to determine a match. If the default target |
matches, it is used. If not, exactly one target must recognize |
the file, or an error results. |
The function returns <<TRUE>> on success, otherwise <<FALSE>> |
with one of the following error codes: |
o <<bfd_error_invalid_operation>> - |
if <<format>> is not one of <<bfd_object>>, <<bfd_archive>> or |
<<bfd_core>>. |
o <<bfd_error_system_call>> - |
if an error occured during a read - even some file mismatches |
can cause bfd_error_system_calls. |
o <<file_not_recognised>> - |
none of the backends recognised the file format. |
o <<bfd_error_file_ambiguously_recognized>> - |
more than one backend recognised the file format. |
*/ |
bfd_boolean |
bfd_check_format (bfd *abfd, bfd_format format) |
{ |
return bfd_check_format_matches (abfd, format, NULL); |
} |
struct bfd_preserve |
{ |
void *marker; |
void *tdata; |
flagword flags; |
const struct bfd_arch_info *arch_info; |
struct bfd_section *sections; |
struct bfd_section *section_last; |
unsigned int section_count; |
struct bfd_hash_table section_htab; |
}; |
/* When testing an object for compatibility with a particular target |
back-end, the back-end object_p function needs to set up certain |
fields in the bfd on successfully recognizing the object. This |
typically happens in a piecemeal fashion, with failures possible at |
many points. On failure, the bfd is supposed to be restored to its |
initial state, which is virtually impossible. However, restoring a |
subset of the bfd state works in practice. This function stores |
the subset. */ |
static bfd_boolean |
bfd_preserve_save (bfd *abfd, struct bfd_preserve *preserve) |
{ |
preserve->tdata = abfd->tdata.any; |
preserve->arch_info = abfd->arch_info; |
preserve->flags = abfd->flags; |
preserve->sections = abfd->sections; |
preserve->section_last = abfd->section_last; |
preserve->section_count = abfd->section_count; |
preserve->section_htab = abfd->section_htab; |
preserve->marker = bfd_alloc (abfd, 1); |
if (preserve->marker == NULL) |
return FALSE; |
return bfd_hash_table_init (&abfd->section_htab, bfd_section_hash_newfunc, |
sizeof (struct section_hash_entry)); |
} |
/* Clear out a subset of BFD state. */ |
static void |
bfd_reinit (bfd *abfd) |
{ |
abfd->tdata.any = NULL; |
abfd->arch_info = &bfd_default_arch_struct; |
abfd->flags &= BFD_FLAGS_SAVED; |
bfd_section_list_clear (abfd); |
} |
/* Restores bfd state saved by bfd_preserve_save. */ |
static void |
bfd_preserve_restore (bfd *abfd, struct bfd_preserve *preserve) |
{ |
bfd_hash_table_free (&abfd->section_htab); |
abfd->tdata.any = preserve->tdata; |
abfd->arch_info = preserve->arch_info; |
abfd->flags = preserve->flags; |
abfd->section_htab = preserve->section_htab; |
abfd->sections = preserve->sections; |
abfd->section_last = preserve->section_last; |
abfd->section_count = preserve->section_count; |
/* bfd_release frees all memory more recently bfd_alloc'd than |
its arg, as well as its arg. */ |
bfd_release (abfd, preserve->marker); |
preserve->marker = NULL; |
} |
/* Called when the bfd state saved by bfd_preserve_save is no longer |
needed. */ |
static void |
bfd_preserve_finish (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_preserve *preserve) |
{ |
/* It would be nice to be able to free more memory here, eg. old |
tdata, but that's not possible since these blocks are sitting |
inside bfd_alloc'd memory. The section hash is on a separate |
objalloc. */ |
bfd_hash_table_free (&preserve->section_htab); |
preserve->marker = NULL; |
} |
/* |
FUNCTION |
bfd_check_format_matches |
SYNOPSIS |
bfd_boolean bfd_check_format_matches |
(bfd *abfd, bfd_format format, char ***matching); |
DESCRIPTION |
Like <<bfd_check_format>>, except when it returns FALSE with |
<<bfd_errno>> set to <<bfd_error_file_ambiguously_recognized>>. In that |
case, if @var{matching} is not NULL, it will be filled in with |
a NULL-terminated list of the names of the formats that matched, |
allocated with <<malloc>>. |
Then the user may choose a format and try again. |
When done with the list that @var{matching} points to, the caller |
should free it. |
*/ |
bfd_boolean |
bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching) |
{ |
extern const bfd_target binary_vec; |
const bfd_target * const *target; |
const bfd_target **matching_vector = NULL; |
const bfd_target *save_targ, *right_targ, *ar_right_targ, *match_targ; |
int match_count, best_count, best_match; |
int ar_match_index; |
struct bfd_preserve preserve; |
if (matching != NULL) |
*matching = NULL; |
if (!bfd_read_p (abfd) |
|| (unsigned int) abfd->format >= (unsigned int) bfd_type_end) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
if (abfd->format != bfd_unknown) |
return abfd->format == format; |
if (matching != NULL || *bfd_associated_vector != NULL) |
{ |
bfd_size_type amt; |
amt = sizeof (*matching_vector) * 2 * _bfd_target_vector_entries; |
matching_vector = (const bfd_target **) bfd_malloc (amt); |
if (!matching_vector) |
return FALSE; |
} |
/* Presume the answer is yes. */ |
abfd->format = format; |
save_targ = abfd->xvec; |
preserve.marker = NULL; |
/* If the target type was explicitly specified, just check that target. */ |
if (!abfd->target_defaulted) |
{ |
if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) /* rewind! */ |
goto err_ret; |
right_targ = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd)); |
if (right_targ) |
goto ok_ret; |
/* For a long time the code has dropped through to check all |
targets if the specified target was wrong. I don't know why, |
and I'm reluctant to change it. However, in the case of an |
archive, it can cause problems. If the specified target does |
not permit archives (e.g., the binary target), then we should |
not allow some other target to recognize it as an archive, but |
should instead allow the specified target to recognize it as an |
object. When I first made this change, it broke the PE target, |
because the specified pei-i386 target did not recognize the |
actual pe-i386 archive. Since there may be other problems of |
this sort, I changed this test to check only for the binary |
target. */ |
if (format == bfd_archive && save_targ == &binary_vec) |
goto err_unrecog; |
} |
/* Since the target type was defaulted, check them all in the hope |
that one will be uniquely recognized. */ |
right_targ = NULL; |
ar_right_targ = NULL; |
match_targ = NULL; |
best_match = 256; |
best_count = 0; |
match_count = 0; |
ar_match_index = _bfd_target_vector_entries; |
for (target = bfd_target_vector; *target != NULL; target++) |
{ |
const bfd_target *temp; |
/* Don't check the default target twice. */ |
if (*target == &binary_vec |
|| (!abfd->target_defaulted && *target == save_targ) |
|| (*target)->match_priority > best_match) |
continue; |
/* If we already tried a match, the bfd is modified and may |
have sections attached, which will confuse the next |
_bfd_check_format call. */ |
bfd_reinit (abfd); |
/* Change BFD's target temporarily. */ |
abfd->xvec = *target; |
if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) |
goto err_ret; |
/* If _bfd_check_format neglects to set bfd_error, assume |
bfd_error_wrong_format. We didn't used to even pay any |
attention to bfd_error, so I suspect that some |
_bfd_check_format might have this problem. */ |
bfd_set_error (bfd_error_wrong_format); |
temp = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd)); |
if (temp) |
{ |
match_targ = temp; |
if (preserve.marker != NULL) |
bfd_preserve_finish (abfd, &preserve); |
if (abfd->format != bfd_archive |
|| (bfd_has_map (abfd) |
&& bfd_get_error () != bfd_error_wrong_object_format)) |
{ |
/* This format checks out as ok! */ |
right_targ = temp; |
/* If this is the default target, accept it, even if |
other targets might match. People who want those |
other targets have to set the GNUTARGET variable. */ |
if (temp == bfd_default_vector[0]) |
goto ok_ret; |
if (matching_vector) |
matching_vector[match_count] = temp; |
match_count++; |
if (temp->match_priority < best_match) |
{ |
best_match = temp->match_priority; |
best_count = 0; |
} |
best_count++; |
} |
else |
{ |
/* An archive with no armap or objects of the wrong |
type. We want this target to match if we get no |
better matches. */ |
if (ar_right_targ != bfd_default_vector[0]) |
ar_right_targ = *target; |
if (matching_vector) |
matching_vector[ar_match_index] = *target; |
ar_match_index++; |
} |
if (!bfd_preserve_save (abfd, &preserve)) |
goto err_ret; |
} |
else if (bfd_get_error () != bfd_error_wrong_format) |
goto err_ret; |
} |
if (best_count == 1) |
match_count = 1; |
if (match_count == 0) |
{ |
/* Try partial matches. */ |
right_targ = ar_right_targ; |
if (right_targ == bfd_default_vector[0]) |
{ |
match_count = 1; |
} |
else |
{ |
match_count = ar_match_index - _bfd_target_vector_entries; |
if (matching_vector && match_count > 1) |
memcpy (matching_vector, |
matching_vector + _bfd_target_vector_entries, |
sizeof (*matching_vector) * match_count); |
} |
} |
/* We have more than one equally good match. If any of the best |
matches is a target in config.bfd targ_defvec or targ_selvecs, |
choose it. */ |
if (match_count > 1) |
{ |
const bfd_target * const *assoc = bfd_associated_vector; |
while ((right_targ = *assoc++) != NULL) |
{ |
int i = match_count; |
while (--i >= 0) |
if (matching_vector[i] == right_targ |
&& right_targ->match_priority <= best_match) |
break; |
if (i >= 0) |
{ |
match_count = 1; |
break; |
} |
} |
} |
/* We still have more than one equally good match, and at least some |
of the targets support match priority. Choose the first of the |
best matches. */ |
if (match_count > 1 && best_count != match_count) |
{ |
int i; |
for (i = 0; i < match_count; i++) |
{ |
right_targ = matching_vector[i]; |
if (right_targ->match_priority <= best_match) |
break; |
} |
match_count = 1; |
} |
/* There is way too much undoing of half-known state here. We |
really shouldn't iterate on live bfd's. Note that saving the |
whole bfd and restoring it would be even worse; the first thing |
you notice is that the cached bfd file position gets out of sync. */ |
if (preserve.marker != NULL) |
bfd_preserve_restore (abfd, &preserve); |
if (match_count == 1) |
{ |
abfd->xvec = right_targ; |
/* If we come out of the loop knowing that the last target that |
matched is the one we want, then ABFD should still be in a usable |
state (except possibly for XVEC). */ |
if (match_targ != right_targ) |
{ |
bfd_reinit (abfd); |
if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) |
goto err_ret; |
match_targ = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd)); |
BFD_ASSERT (match_targ != NULL); |
} |
ok_ret: |
/* If the file was opened for update, then `output_has_begun' |
some time ago when the file was created. Do not recompute |
sections sizes or alignments in _bfd_set_section_contents. |
We can not set this flag until after checking the format, |
because it will interfere with creation of BFD sections. */ |
if (abfd->direction == both_direction) |
abfd->output_has_begun = TRUE; |
if (matching_vector) |
free (matching_vector); |
/* File position has moved, BTW. */ |
return TRUE; |
} |
if (match_count == 0) |
{ |
err_unrecog: |
bfd_set_error (bfd_error_file_not_recognized); |
err_ret: |
abfd->xvec = save_targ; |
abfd->format = bfd_unknown; |
if (matching_vector) |
free (matching_vector); |
if (preserve.marker != NULL) |
bfd_preserve_restore (abfd, &preserve); |
return FALSE; |
} |
/* Restore original target type and format. */ |
abfd->xvec = save_targ; |
abfd->format = bfd_unknown; |
bfd_set_error (bfd_error_file_ambiguously_recognized); |
if (matching) |
{ |
*matching = (char **) matching_vector; |
matching_vector[match_count] = NULL; |
/* Return target names. This is a little nasty. Maybe we |
should do another bfd_malloc? */ |
while (--match_count >= 0) |
{ |
const char *name = matching_vector[match_count]->name; |
*(const char **) &matching_vector[match_count] = name; |
} |
} |
return FALSE; |
} |
/* |
FUNCTION |
bfd_set_format |
SYNOPSIS |
bfd_boolean bfd_set_format (bfd *abfd, bfd_format format); |
DESCRIPTION |
This function sets the file format of the BFD @var{abfd} to the |
format @var{format}. If the target set in the BFD does not |
support the format requested, the format is invalid, or the BFD |
is not open for writing, then an error occurs. |
*/ |
bfd_boolean |
bfd_set_format (bfd *abfd, bfd_format format) |
{ |
if (bfd_read_p (abfd) |
|| (unsigned int) abfd->format >= (unsigned int) bfd_type_end) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
if (abfd->format != bfd_unknown) |
return abfd->format == format; |
/* Presume the answer is yes. */ |
abfd->format = format; |
if (!BFD_SEND_FMT (abfd, _bfd_set_format, (abfd))) |
{ |
abfd->format = bfd_unknown; |
return FALSE; |
} |
return TRUE; |
} |
/* |
FUNCTION |
bfd_format_string |
SYNOPSIS |
const char *bfd_format_string (bfd_format format); |
DESCRIPTION |
Return a pointer to a const string |
<<invalid>>, <<object>>, <<archive>>, <<core>>, or <<unknown>>, |
depending upon the value of @var{format}. |
*/ |
const char * |
bfd_format_string (bfd_format format) |
{ |
if (((int) format < (int) bfd_unknown) |
|| ((int) format >= (int) bfd_type_end)) |
return "invalid"; |
switch (format) |
{ |
case bfd_object: |
return "object"; /* Linker/assembler/compiler output. */ |
case bfd_archive: |
return "archive"; /* Object archive file. */ |
case bfd_core: |
return "core"; /* Core dump. */ |
default: |
return "unknown"; |
} |
} |
/contrib/toolchain/binutils/bfd/genlink.h |
---|
0,0 → 1,110 |
/* genlink.h -- interface to the BFD generic linker |
Copyright 1993, 1994, 1996, 2002, 2005, 2007 Free Software Foundation, Inc. |
Written by Ian Lance Taylor, Cygnus Support. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#ifndef GENLINK_H |
#define GENLINK_H |
/* This header file is internal to BFD. It describes the internal |
structures and functions used by the BFD generic linker, in case |
any of the more specific linkers want to use or call them. Note |
that some functions, such as _bfd_generic_link_hash_table_create, |
are declared in libbfd.h, because they are expected to be widely |
used. The functions and structures in this file will probably only |
be used by a few files besides linker.c itself. In fact, this file |
is not particularly complete; I have only put in the interfaces I |
actually needed. */ |
/* The generic linker uses a hash table which is a derived class of |
the standard linker hash table, just as the other backend specific |
linkers do. Do not confuse the generic linker hash table with the |
standard BFD linker hash table it is built upon. */ |
/* Generic linker hash table entries. */ |
struct generic_link_hash_entry |
{ |
struct bfd_link_hash_entry root; |
/* Whether this symbol has been written out. */ |
bfd_boolean written; |
/* Symbol from input BFD. */ |
asymbol *sym; |
}; |
/* Generic linker hash table. */ |
struct generic_link_hash_table |
{ |
struct bfd_link_hash_table root; |
}; |
/* Look up an entry in a generic link hash table. */ |
#define _bfd_generic_link_hash_lookup(table, string, create, copy, follow) \ |
((struct generic_link_hash_entry *) \ |
bfd_link_hash_lookup (&(table)->root, (string), (create), (copy), (follow))) |
/* Traverse a generic link hash table. */ |
#define _bfd_generic_link_hash_traverse(table, func, info) \ |
(bfd_link_hash_traverse \ |
(&(table)->root, \ |
(bfd_boolean (*) (struct bfd_link_hash_entry *, void *)) (func), \ |
(info))) |
/* Get the generic link hash table from the info structure. This is |
just a cast. */ |
#define _bfd_generic_hash_table(p) \ |
((struct generic_link_hash_table *) ((p)->hash)) |
/* The generic linker reads in the asymbol structures for an input BFD |
and keeps them in the outsymbol and symcount fields. */ |
#define _bfd_generic_link_get_symbols(abfd) ((abfd)->outsymbols) |
#define _bfd_generic_link_get_symcount(abfd) ((abfd)->symcount) |
/* Add the symbols of input_bfd to the symbols being built for |
output_bfd. */ |
extern bfd_boolean _bfd_generic_link_output_symbols |
(bfd *, bfd *, struct bfd_link_info *, size_t *); |
/* This structure is used to pass information to |
_bfd_generic_link_write_global_symbol, which may be called via |
_bfd_generic_link_hash_traverse. */ |
struct generic_write_global_symbol_info |
{ |
struct bfd_link_info *info; |
bfd *output_bfd; |
size_t *psymalloc; |
}; |
/* Write out a single global symbol. This is expected to be called |
via _bfd_generic_link_hash_traverse. The second argument must |
actually be a struct generic_write_global_symbol_info *. */ |
extern bfd_boolean _bfd_generic_link_write_global_symbol |
(struct generic_link_hash_entry *, void *); |
/* Generic link hash table entry creation routine. */ |
struct bfd_hash_entry *_bfd_generic_link_hash_newfunc |
(struct bfd_hash_entry *, struct bfd_hash_table *, const char *); |
#endif |
/contrib/toolchain/binutils/bfd/hash.c |
---|
0,0 → 1,912 |
/* hash.c -- hash table routines for BFD |
Copyright 1993, 1994, 1995, 1997, 1999, 2001, 2002, 2003, 2004, 2005, |
2006, 2007, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. |
Written by Steve Chamberlain <sac@cygnus.com> |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
#include "objalloc.h" |
#include "libiberty.h" |
/* |
SECTION |
Hash Tables |
@cindex Hash tables |
BFD provides a simple set of hash table functions. Routines |
are provided to initialize a hash table, to free a hash table, |
to look up a string in a hash table and optionally create an |
entry for it, and to traverse a hash table. There is |
currently no routine to delete an string from a hash table. |
The basic hash table does not permit any data to be stored |
with a string. However, a hash table is designed to present a |
base class from which other types of hash tables may be |
derived. These derived types may store additional information |
with the string. Hash tables were implemented in this way, |
rather than simply providing a data pointer in a hash table |
entry, because they were designed for use by the linker back |
ends. The linker may create thousands of hash table entries, |
and the overhead of allocating private data and storing and |
following pointers becomes noticeable. |
The basic hash table code is in <<hash.c>>. |
@menu |
@* Creating and Freeing a Hash Table:: |
@* Looking Up or Entering a String:: |
@* Traversing a Hash Table:: |
@* Deriving a New Hash Table Type:: |
@end menu |
INODE |
Creating and Freeing a Hash Table, Looking Up or Entering a String, Hash Tables, Hash Tables |
SUBSECTION |
Creating and freeing a hash table |
@findex bfd_hash_table_init |
@findex bfd_hash_table_init_n |
To create a hash table, create an instance of a <<struct |
bfd_hash_table>> (defined in <<bfd.h>>) and call |
<<bfd_hash_table_init>> (if you know approximately how many |
entries you will need, the function <<bfd_hash_table_init_n>>, |
which takes a @var{size} argument, may be used). |
<<bfd_hash_table_init>> returns <<FALSE>> if some sort of |
error occurs. |
@findex bfd_hash_newfunc |
The function <<bfd_hash_table_init>> take as an argument a |
function to use to create new entries. For a basic hash |
table, use the function <<bfd_hash_newfunc>>. @xref{Deriving |
a New Hash Table Type}, for why you would want to use a |
different value for this argument. |
@findex bfd_hash_allocate |
<<bfd_hash_table_init>> will create an objalloc which will be |
used to allocate new entries. You may allocate memory on this |
objalloc using <<bfd_hash_allocate>>. |
@findex bfd_hash_table_free |
Use <<bfd_hash_table_free>> to free up all the memory that has |
been allocated for a hash table. This will not free up the |
<<struct bfd_hash_table>> itself, which you must provide. |
@findex bfd_hash_set_default_size |
Use <<bfd_hash_set_default_size>> to set the default size of |
hash table to use. |
INODE |
Looking Up or Entering a String, Traversing a Hash Table, Creating and Freeing a Hash Table, Hash Tables |
SUBSECTION |
Looking up or entering a string |
@findex bfd_hash_lookup |
The function <<bfd_hash_lookup>> is used both to look up a |
string in the hash table and to create a new entry. |
If the @var{create} argument is <<FALSE>>, <<bfd_hash_lookup>> |
will look up a string. If the string is found, it will |
returns a pointer to a <<struct bfd_hash_entry>>. If the |
string is not found in the table <<bfd_hash_lookup>> will |
return <<NULL>>. You should not modify any of the fields in |
the returns <<struct bfd_hash_entry>>. |
If the @var{create} argument is <<TRUE>>, the string will be |
entered into the hash table if it is not already there. |
Either way a pointer to a <<struct bfd_hash_entry>> will be |
returned, either to the existing structure or to a newly |
created one. In this case, a <<NULL>> return means that an |
error occurred. |
If the @var{create} argument is <<TRUE>>, and a new entry is |
created, the @var{copy} argument is used to decide whether to |
copy the string onto the hash table objalloc or not. If |
@var{copy} is passed as <<FALSE>>, you must be careful not to |
deallocate or modify the string as long as the hash table |
exists. |
INODE |
Traversing a Hash Table, Deriving a New Hash Table Type, Looking Up or Entering a String, Hash Tables |
SUBSECTION |
Traversing a hash table |
@findex bfd_hash_traverse |
The function <<bfd_hash_traverse>> may be used to traverse a |
hash table, calling a function on each element. The traversal |
is done in a random order. |
<<bfd_hash_traverse>> takes as arguments a function and a |
generic <<void *>> pointer. The function is called with a |
hash table entry (a <<struct bfd_hash_entry *>>) and the |
generic pointer passed to <<bfd_hash_traverse>>. The function |
must return a <<boolean>> value, which indicates whether to |
continue traversing the hash table. If the function returns |
<<FALSE>>, <<bfd_hash_traverse>> will stop the traversal and |
return immediately. |
INODE |
Deriving a New Hash Table Type, , Traversing a Hash Table, Hash Tables |
SUBSECTION |
Deriving a new hash table type |
Many uses of hash tables want to store additional information |
which each entry in the hash table. Some also find it |
convenient to store additional information with the hash table |
itself. This may be done using a derived hash table. |
Since C is not an object oriented language, creating a derived |
hash table requires sticking together some boilerplate |
routines with a few differences specific to the type of hash |
table you want to create. |
An example of a derived hash table is the linker hash table. |
The structures for this are defined in <<bfdlink.h>>. The |
functions are in <<linker.c>>. |
You may also derive a hash table from an already derived hash |
table. For example, the a.out linker backend code uses a hash |
table derived from the linker hash table. |
@menu |
@* Define the Derived Structures:: |
@* Write the Derived Creation Routine:: |
@* Write Other Derived Routines:: |
@end menu |
INODE |
Define the Derived Structures, Write the Derived Creation Routine, Deriving a New Hash Table Type, Deriving a New Hash Table Type |
SUBSUBSECTION |
Define the derived structures |
You must define a structure for an entry in the hash table, |
and a structure for the hash table itself. |
The first field in the structure for an entry in the hash |
table must be of the type used for an entry in the hash table |
you are deriving from. If you are deriving from a basic hash |
table this is <<struct bfd_hash_entry>>, which is defined in |
<<bfd.h>>. The first field in the structure for the hash |
table itself must be of the type of the hash table you are |
deriving from itself. If you are deriving from a basic hash |
table, this is <<struct bfd_hash_table>>. |
For example, the linker hash table defines <<struct |
bfd_link_hash_entry>> (in <<bfdlink.h>>). The first field, |
<<root>>, is of type <<struct bfd_hash_entry>>. Similarly, |
the first field in <<struct bfd_link_hash_table>>, <<table>>, |
is of type <<struct bfd_hash_table>>. |
INODE |
Write the Derived Creation Routine, Write Other Derived Routines, Define the Derived Structures, Deriving a New Hash Table Type |
SUBSUBSECTION |
Write the derived creation routine |
You must write a routine which will create and initialize an |
entry in the hash table. This routine is passed as the |
function argument to <<bfd_hash_table_init>>. |
In order to permit other hash tables to be derived from the |
hash table you are creating, this routine must be written in a |
standard way. |
The first argument to the creation routine is a pointer to a |
hash table entry. This may be <<NULL>>, in which case the |
routine should allocate the right amount of space. Otherwise |
the space has already been allocated by a hash table type |
derived from this one. |
After allocating space, the creation routine must call the |
creation routine of the hash table type it is derived from, |
passing in a pointer to the space it just allocated. This |
will initialize any fields used by the base hash table. |
Finally the creation routine must initialize any local fields |
for the new hash table type. |
Here is a boilerplate example of a creation routine. |
@var{function_name} is the name of the routine. |
@var{entry_type} is the type of an entry in the hash table you |
are creating. @var{base_newfunc} is the name of the creation |
routine of the hash table type your hash table is derived |
from. |
EXAMPLE |
.struct bfd_hash_entry * |
.@var{function_name} (struct bfd_hash_entry *entry, |
. struct bfd_hash_table *table, |
. const char *string) |
.{ |
. struct @var{entry_type} *ret = (@var{entry_type} *) entry; |
. |
. {* Allocate the structure if it has not already been allocated by a |
. derived class. *} |
. if (ret == NULL) |
. { |
. ret = bfd_hash_allocate (table, sizeof (* ret)); |
. if (ret == NULL) |
. return NULL; |
. } |
. |
. {* Call the allocation method of the base class. *} |
. ret = ((@var{entry_type} *) |
. @var{base_newfunc} ((struct bfd_hash_entry *) ret, table, string)); |
. |
. {* Initialize the local fields here. *} |
. |
. return (struct bfd_hash_entry *) ret; |
.} |
DESCRIPTION |
The creation routine for the linker hash table, which is in |
<<linker.c>>, looks just like this example. |
@var{function_name} is <<_bfd_link_hash_newfunc>>. |
@var{entry_type} is <<struct bfd_link_hash_entry>>. |
@var{base_newfunc} is <<bfd_hash_newfunc>>, the creation |
routine for a basic hash table. |
<<_bfd_link_hash_newfunc>> also initializes the local fields |
in a linker hash table entry: <<type>>, <<written>> and |
<<next>>. |
INODE |
Write Other Derived Routines, , Write the Derived Creation Routine, Deriving a New Hash Table Type |
SUBSUBSECTION |
Write other derived routines |
You will want to write other routines for your new hash table, |
as well. |
You will want an initialization routine which calls the |
initialization routine of the hash table you are deriving from |
and initializes any other local fields. For the linker hash |
table, this is <<_bfd_link_hash_table_init>> in <<linker.c>>. |
You will want a lookup routine which calls the lookup routine |
of the hash table you are deriving from and casts the result. |
The linker hash table uses <<bfd_link_hash_lookup>> in |
<<linker.c>> (this actually takes an additional argument which |
it uses to decide how to return the looked up value). |
You may want a traversal routine. This should just call the |
traversal routine of the hash table you are deriving from with |
appropriate casts. The linker hash table uses |
<<bfd_link_hash_traverse>> in <<linker.c>>. |
These routines may simply be defined as macros. For example, |
the a.out backend linker hash table, which is derived from the |
linker hash table, uses macros for the lookup and traversal |
routines. These are <<aout_link_hash_lookup>> and |
<<aout_link_hash_traverse>> in aoutx.h. |
*/ |
/* The default number of entries to use when creating a hash table. */ |
#define DEFAULT_SIZE 4051 |
/* The following function returns a nearest prime number which is |
greater than N, and near a power of two. Copied from libiberty. |
Returns zero for ridiculously large N to signify an error. */ |
static unsigned long |
higher_prime_number (unsigned long n) |
{ |
/* These are primes that are near, but slightly smaller than, a |
power of two. */ |
static const unsigned long primes[] = |
{ |
(unsigned long) 31, |
(unsigned long) 61, |
(unsigned long) 127, |
(unsigned long) 251, |
(unsigned long) 509, |
(unsigned long) 1021, |
(unsigned long) 2039, |
(unsigned long) 4093, |
(unsigned long) 8191, |
(unsigned long) 16381, |
(unsigned long) 32749, |
(unsigned long) 65521, |
(unsigned long) 131071, |
(unsigned long) 262139, |
(unsigned long) 524287, |
(unsigned long) 1048573, |
(unsigned long) 2097143, |
(unsigned long) 4194301, |
(unsigned long) 8388593, |
(unsigned long) 16777213, |
(unsigned long) 33554393, |
(unsigned long) 67108859, |
(unsigned long) 134217689, |
(unsigned long) 268435399, |
(unsigned long) 536870909, |
(unsigned long) 1073741789, |
(unsigned long) 2147483647, |
/* 4294967291L */ |
((unsigned long) 2147483647) + ((unsigned long) 2147483644), |
}; |
const unsigned long *low = &primes[0]; |
const unsigned long *high = &primes[sizeof (primes) / sizeof (primes[0])]; |
while (low != high) |
{ |
const unsigned long *mid = low + (high - low) / 2; |
if (n >= *mid) |
low = mid + 1; |
else |
high = mid; |
} |
if (n >= *low) |
return 0; |
return *low; |
} |
static unsigned long bfd_default_hash_table_size = DEFAULT_SIZE; |
/* Create a new hash table, given a number of entries. */ |
bfd_boolean |
bfd_hash_table_init_n (struct bfd_hash_table *table, |
struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *, |
struct bfd_hash_table *, |
const char *), |
unsigned int entsize, |
unsigned int size) |
{ |
unsigned long alloc; |
alloc = size; |
alloc *= sizeof (struct bfd_hash_entry *); |
if (alloc / sizeof (struct bfd_hash_entry *) != size) |
{ |
bfd_set_error (bfd_error_no_memory); |
return FALSE; |
} |
table->memory = (void *) objalloc_create (); |
if (table->memory == NULL) |
{ |
bfd_set_error (bfd_error_no_memory); |
return FALSE; |
} |
table->table = (struct bfd_hash_entry **) |
objalloc_alloc ((struct objalloc *) table->memory, alloc); |
if (table->table == NULL) |
{ |
bfd_set_error (bfd_error_no_memory); |
return FALSE; |
} |
memset ((void *) table->table, 0, alloc); |
table->size = size; |
table->entsize = entsize; |
table->count = 0; |
table->frozen = 0; |
table->newfunc = newfunc; |
return TRUE; |
} |
/* Create a new hash table with the default number of entries. */ |
bfd_boolean |
bfd_hash_table_init (struct bfd_hash_table *table, |
struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *, |
struct bfd_hash_table *, |
const char *), |
unsigned int entsize) |
{ |
return bfd_hash_table_init_n (table, newfunc, entsize, |
bfd_default_hash_table_size); |
} |
/* Free a hash table. */ |
void |
bfd_hash_table_free (struct bfd_hash_table *table) |
{ |
objalloc_free ((struct objalloc *) table->memory); |
table->memory = NULL; |
} |
static inline unsigned long |
bfd_hash_hash (const char *string, unsigned int *lenp) |
{ |
const unsigned char *s; |
unsigned long hash; |
unsigned int len; |
unsigned int c; |
hash = 0; |
len = 0; |
s = (const unsigned char *) string; |
while ((c = *s++) != '\0') |
{ |
hash += c + (c << 17); |
hash ^= hash >> 2; |
} |
len = (s - (const unsigned char *) string) - 1; |
hash += len + (len << 17); |
hash ^= hash >> 2; |
if (lenp != NULL) |
*lenp = len; |
return hash; |
} |
/* Look up a string in a hash table. */ |
struct bfd_hash_entry * |
bfd_hash_lookup (struct bfd_hash_table *table, |
const char *string, |
bfd_boolean create, |
bfd_boolean copy) |
{ |
unsigned long hash; |
struct bfd_hash_entry *hashp; |
unsigned int len; |
unsigned int _index; |
hash = bfd_hash_hash (string, &len); |
_index = hash % table->size; |
for (hashp = table->table[_index]; |
hashp != NULL; |
hashp = hashp->next) |
{ |
if (hashp->hash == hash |
&& strcmp (hashp->string, string) == 0) |
return hashp; |
} |
if (! create) |
return NULL; |
if (copy) |
{ |
char *new_string; |
new_string = (char *) objalloc_alloc ((struct objalloc *) table->memory, |
len + 1); |
if (!new_string) |
{ |
bfd_set_error (bfd_error_no_memory); |
return NULL; |
} |
memcpy (new_string, string, len + 1); |
string = new_string; |
} |
return bfd_hash_insert (table, string, hash); |
} |
/* Insert an entry in a hash table. */ |
struct bfd_hash_entry * |
bfd_hash_insert (struct bfd_hash_table *table, |
const char *string, |
unsigned long hash) |
{ |
struct bfd_hash_entry *hashp; |
unsigned int _index; |
hashp = (*table->newfunc) (NULL, table, string); |
if (hashp == NULL) |
return NULL; |
hashp->string = string; |
hashp->hash = hash; |
_index = hash % table->size; |
hashp->next = table->table[_index]; |
table->table[_index] = hashp; |
table->count++; |
if (!table->frozen && table->count > table->size * 3 / 4) |
{ |
unsigned long newsize = higher_prime_number (table->size); |
struct bfd_hash_entry **newtable; |
unsigned int hi; |
unsigned long alloc = newsize * sizeof (struct bfd_hash_entry *); |
/* If we can't find a higher prime, or we can't possibly alloc |
that much memory, don't try to grow the table. */ |
if (newsize == 0 || alloc / sizeof (struct bfd_hash_entry *) != newsize) |
{ |
table->frozen = 1; |
return hashp; |
} |
newtable = ((struct bfd_hash_entry **) |
objalloc_alloc ((struct objalloc *) table->memory, alloc)); |
if (newtable == NULL) |
{ |
table->frozen = 1; |
return hashp; |
} |
memset (newtable, 0, alloc); |
for (hi = 0; hi < table->size; hi ++) |
while (table->table[hi]) |
{ |
struct bfd_hash_entry *chain = table->table[hi]; |
struct bfd_hash_entry *chain_end = chain; |
while (chain_end->next && chain_end->next->hash == chain->hash) |
chain_end = chain_end->next; |
table->table[hi] = chain_end->next; |
_index = chain->hash % newsize; |
chain_end->next = newtable[_index]; |
newtable[_index] = chain; |
} |
table->table = newtable; |
table->size = newsize; |
} |
return hashp; |
} |
/* Rename an entry in a hash table. */ |
void |
bfd_hash_rename (struct bfd_hash_table *table, |
const char *string, |
struct bfd_hash_entry *ent) |
{ |
unsigned int _index; |
struct bfd_hash_entry **pph; |
_index = ent->hash % table->size; |
for (pph = &table->table[_index]; *pph != NULL; pph = &(*pph)->next) |
if (*pph == ent) |
break; |
if (*pph == NULL) |
abort (); |
*pph = ent->next; |
ent->string = string; |
ent->hash = bfd_hash_hash (string, NULL); |
_index = ent->hash % table->size; |
ent->next = table->table[_index]; |
table->table[_index] = ent; |
} |
/* Replace an entry in a hash table. */ |
void |
bfd_hash_replace (struct bfd_hash_table *table, |
struct bfd_hash_entry *old, |
struct bfd_hash_entry *nw) |
{ |
unsigned int _index; |
struct bfd_hash_entry **pph; |
_index = old->hash % table->size; |
for (pph = &table->table[_index]; |
(*pph) != NULL; |
pph = &(*pph)->next) |
{ |
if (*pph == old) |
{ |
*pph = nw; |
return; |
} |
} |
abort (); |
} |
/* Allocate space in a hash table. */ |
void * |
bfd_hash_allocate (struct bfd_hash_table *table, |
unsigned int size) |
{ |
void * ret; |
ret = objalloc_alloc ((struct objalloc *) table->memory, size); |
if (ret == NULL && size != 0) |
bfd_set_error (bfd_error_no_memory); |
return ret; |
} |
/* Base method for creating a new hash table entry. */ |
struct bfd_hash_entry * |
bfd_hash_newfunc (struct bfd_hash_entry *entry, |
struct bfd_hash_table *table, |
const char *string ATTRIBUTE_UNUSED) |
{ |
if (entry == NULL) |
entry = (struct bfd_hash_entry *) bfd_hash_allocate (table, |
sizeof (* entry)); |
return entry; |
} |
/* Traverse a hash table. */ |
void |
bfd_hash_traverse (struct bfd_hash_table *table, |
bfd_boolean (*func) (struct bfd_hash_entry *, void *), |
void * info) |
{ |
unsigned int i; |
table->frozen = 1; |
for (i = 0; i < table->size; i++) |
{ |
struct bfd_hash_entry *p; |
for (p = table->table[i]; p != NULL; p = p->next) |
if (! (*func) (p, info)) |
goto out; |
} |
out: |
table->frozen = 0; |
} |
unsigned long |
bfd_hash_set_default_size (unsigned long hash_size) |
{ |
/* Extend this prime list if you want more granularity of hash table size. */ |
static const unsigned long hash_size_primes[] = |
{ |
31, 61, 127, 251, 509, 1021, 2039, 4091, 8191, 16381, 32749, 65537 |
}; |
unsigned int _index; |
/* Work out best prime number near the hash_size. */ |
for (_index = 0; _index < ARRAY_SIZE (hash_size_primes) - 1; ++_index) |
if (hash_size <= hash_size_primes[_index]) |
break; |
bfd_default_hash_table_size = hash_size_primes[_index]; |
return bfd_default_hash_table_size; |
} |
/* A few different object file formats (a.out, COFF, ELF) use a string |
table. These functions support adding strings to a string table, |
returning the byte offset, and writing out the table. |
Possible improvements: |
+ look for strings matching trailing substrings of other strings |
+ better data structures? balanced trees? |
+ look at reducing memory use elsewhere -- maybe if we didn't have |
to construct the entire symbol table at once, we could get by |
with smaller amounts of VM? (What effect does that have on the |
string table reductions?) */ |
/* An entry in the strtab hash table. */ |
struct strtab_hash_entry |
{ |
struct bfd_hash_entry root; |
/* Index in string table. */ |
bfd_size_type index; |
/* Next string in strtab. */ |
struct strtab_hash_entry *next; |
}; |
/* The strtab hash table. */ |
struct bfd_strtab_hash |
{ |
struct bfd_hash_table table; |
/* Size of strtab--also next available index. */ |
bfd_size_type size; |
/* First string in strtab. */ |
struct strtab_hash_entry *first; |
/* Last string in strtab. */ |
struct strtab_hash_entry *last; |
/* Whether to precede strings with a two byte length, as in the |
XCOFF .debug section. */ |
bfd_boolean xcoff; |
}; |
/* Routine to create an entry in a strtab. */ |
static struct bfd_hash_entry * |
strtab_hash_newfunc (struct bfd_hash_entry *entry, |
struct bfd_hash_table *table, |
const char *string) |
{ |
struct strtab_hash_entry *ret = (struct strtab_hash_entry *) entry; |
/* Allocate the structure if it has not already been allocated by a |
subclass. */ |
if (ret == NULL) |
ret = (struct strtab_hash_entry *) bfd_hash_allocate (table, |
sizeof (* ret)); |
if (ret == NULL) |
return NULL; |
/* Call the allocation method of the superclass. */ |
ret = (struct strtab_hash_entry *) |
bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string); |
if (ret) |
{ |
/* Initialize the local fields. */ |
ret->index = (bfd_size_type) -1; |
ret->next = NULL; |
} |
return (struct bfd_hash_entry *) ret; |
} |
/* Look up an entry in an strtab. */ |
#define strtab_hash_lookup(t, string, create, copy) \ |
((struct strtab_hash_entry *) \ |
bfd_hash_lookup (&(t)->table, (string), (create), (copy))) |
/* Create a new strtab. */ |
struct bfd_strtab_hash * |
_bfd_stringtab_init (void) |
{ |
struct bfd_strtab_hash *table; |
bfd_size_type amt = sizeof (* table); |
table = (struct bfd_strtab_hash *) bfd_malloc (amt); |
if (table == NULL) |
return NULL; |
if (!bfd_hash_table_init (&table->table, strtab_hash_newfunc, |
sizeof (struct strtab_hash_entry))) |
{ |
free (table); |
return NULL; |
} |
table->size = 0; |
table->first = NULL; |
table->last = NULL; |
table->xcoff = FALSE; |
return table; |
} |
/* Create a new strtab in which the strings are output in the format |
used in the XCOFF .debug section: a two byte length precedes each |
string. */ |
struct bfd_strtab_hash * |
_bfd_xcoff_stringtab_init (void) |
{ |
struct bfd_strtab_hash *ret; |
ret = _bfd_stringtab_init (); |
if (ret != NULL) |
ret->xcoff = TRUE; |
return ret; |
} |
/* Free a strtab. */ |
void |
_bfd_stringtab_free (struct bfd_strtab_hash *table) |
{ |
bfd_hash_table_free (&table->table); |
free (table); |
} |
/* Get the index of a string in a strtab, adding it if it is not |
already present. If HASH is FALSE, we don't really use the hash |
table, and we don't eliminate duplicate strings. If COPY is true |
then store a copy of STR if creating a new entry. */ |
bfd_size_type |
_bfd_stringtab_add (struct bfd_strtab_hash *tab, |
const char *str, |
bfd_boolean hash, |
bfd_boolean copy) |
{ |
struct strtab_hash_entry *entry; |
if (hash) |
{ |
entry = strtab_hash_lookup (tab, str, TRUE, copy); |
if (entry == NULL) |
return (bfd_size_type) -1; |
} |
else |
{ |
entry = (struct strtab_hash_entry *) bfd_hash_allocate (&tab->table, |
sizeof (* entry)); |
if (entry == NULL) |
return (bfd_size_type) -1; |
if (! copy) |
entry->root.string = str; |
else |
{ |
size_t len = strlen (str) + 1; |
char *n; |
n = (char *) bfd_hash_allocate (&tab->table, len); |
if (n == NULL) |
return (bfd_size_type) -1; |
memcpy (n, str, len); |
entry->root.string = n; |
} |
entry->index = (bfd_size_type) -1; |
entry->next = NULL; |
} |
if (entry->index == (bfd_size_type) -1) |
{ |
entry->index = tab->size; |
tab->size += strlen (str) + 1; |
if (tab->xcoff) |
{ |
entry->index += 2; |
tab->size += 2; |
} |
if (tab->first == NULL) |
tab->first = entry; |
else |
tab->last->next = entry; |
tab->last = entry; |
} |
return entry->index; |
} |
/* Get the number of bytes in a strtab. */ |
bfd_size_type |
_bfd_stringtab_size (struct bfd_strtab_hash *tab) |
{ |
return tab->size; |
} |
/* Write out a strtab. ABFD must already be at the right location in |
the file. */ |
bfd_boolean |
_bfd_stringtab_emit (bfd *abfd, struct bfd_strtab_hash *tab) |
{ |
bfd_boolean xcoff; |
struct strtab_hash_entry *entry; |
xcoff = tab->xcoff; |
for (entry = tab->first; entry != NULL; entry = entry->next) |
{ |
const char *str; |
size_t len; |
str = entry->root.string; |
len = strlen (str) + 1; |
if (xcoff) |
{ |
bfd_byte buf[2]; |
/* The output length includes the null byte. */ |
bfd_put_16 (abfd, (bfd_vma) len, buf); |
if (bfd_bwrite ((void *) buf, (bfd_size_type) 2, abfd) != 2) |
return FALSE; |
} |
if (bfd_bwrite ((void *) str, (bfd_size_type) len, abfd) != len) |
return FALSE; |
} |
return TRUE; |
} |
/contrib/toolchain/binutils/bfd/ihex.c |
---|
0,0 → 1,1001 |
/* BFD back-end for Intel Hex objects. |
Copyright 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, |
2006, 2007, 2009, 2011 Free Software Foundation, Inc. |
Written by Ian Lance Taylor of Cygnus Support <ian@cygnus.com>. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* This is what Intel Hex files look like: |
1. INTEL FORMATS |
A. Intel 1 |
16-bit address-field format, for files 64k bytes in length or less. |
DATA RECORD |
Byte 1 Header = colon(:) |
2..3 The number of data bytes in hex notation |
4..5 High byte of the record load address |
6..7 Low byte of the record load address |
8..9 Record type, must be "00" |
10..x Data bytes in hex notation: |
x = (number of bytes - 1) * 2 + 11 |
x+1..x+2 Checksum in hex notation |
x+3..x+4 Carriage return, line feed |
END RECORD |
Byte 1 Header = colon (:) |
2..3 The byte count, must be "00" |
4..7 Transfer-address (usually "0000") |
the jump-to address, execution start address |
8..9 Record type, must be "01" |
10..11 Checksum, in hex notation |
12..13 Carriage return, line feed |
B. INTEL 2 |
MCS-86 format, using a 20-bit address for files larger than 64K bytes. |
DATA RECORD |
Byte 1 Header = colon (:) |
2..3 The byte count of this record, hex notation |
4..5 High byte of the record load address |
6..7 Low byte of the record load address |
8..9 Record type, must be "00" |
10..x The data bytes in hex notation: |
x = (number of data bytes - 1) * 2 + 11 |
x+1..x+2 Checksum in hex notation |
x+3..x+4 Carriage return, line feed |
EXTENDED ADDRESS RECORD |
Byte 1 Header = colon(:) |
2..3 The byte count, must be "02" |
4..7 Load address, must be "0000" |
8..9 Record type, must be "02" |
10..11 High byte of the offset address |
12..13 Low byte of the offset address |
14..15 Checksum in hex notation |
16..17 Carriage return, line feed |
The checksums are the two's complement of the 8-bit sum |
without carry of the byte count, offset address, and the |
record type. |
START ADDRESS RECORD |
Byte 1 Header = colon (:) |
2..3 The byte count, must be "04" |
4..7 Load address, must be "0000" |
8..9 Record type, must be "03" |
10..13 8086 CS value |
14..17 8086 IP value |
18..19 Checksum in hex notation |
20..21 Carriage return, line feed |
Another document reports these additional types: |
EXTENDED LINEAR ADDRESS RECORD |
Byte 1 Header = colon (:) |
2..3 The byte count, must be "02" |
4..7 Load address, must be "0000" |
8..9 Record type, must be "04" |
10..13 Upper 16 bits of address of subsequent records |
14..15 Checksum in hex notation |
16..17 Carriage return, line feed |
START LINEAR ADDRESS RECORD |
Byte 1 Header = colon (:) |
2..3 The byte count, must be "02" |
4..7 Load address, must be "0000" |
8..9 Record type, must be "05" |
10..13 Upper 16 bits of start address |
14..15 Checksum in hex notation |
16..17 Carriage return, line feed |
The MRI compiler uses this, which is a repeat of type 5: |
EXTENDED START RECORD |
Byte 1 Header = colon (:) |
2..3 The byte count, must be "04" |
4..7 Load address, must be "0000" |
8..9 Record type, must be "05" |
10..13 Upper 16 bits of start address |
14..17 Lower 16 bits of start address |
18..19 Checksum in hex notation |
20..21 Carriage return, line feed. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
#include "libiberty.h" |
#include "safe-ctype.h" |
/* The number of bytes we put on one line during output. */ |
#define CHUNK 16 |
/* Macros for converting between hex and binary. */ |
#define NIBBLE(x) (hex_value (x)) |
#define HEX2(buffer) ((NIBBLE ((buffer)[0]) << 4) + NIBBLE ((buffer)[1])) |
#define HEX4(buffer) ((HEX2 (buffer) << 8) + HEX2 ((buffer) + 2)) |
#define ISHEX(x) (hex_p (x)) |
/* When we write out an ihex value, the values can not be output as |
they are seen. Instead, we hold them in memory in this structure. */ |
struct ihex_data_list |
{ |
struct ihex_data_list *next; |
bfd_byte *data; |
bfd_vma where; |
bfd_size_type size; |
}; |
/* The ihex tdata information. */ |
struct ihex_data_struct |
{ |
struct ihex_data_list *head; |
struct ihex_data_list *tail; |
}; |
/* Initialize by filling in the hex conversion array. */ |
static void |
ihex_init (void) |
{ |
static bfd_boolean inited; |
if (! inited) |
{ |
inited = TRUE; |
hex_init (); |
} |
} |
/* Create an ihex object. */ |
static bfd_boolean |
ihex_mkobject (bfd *abfd) |
{ |
struct ihex_data_struct *tdata; |
tdata = (struct ihex_data_struct *) bfd_alloc (abfd, sizeof (* tdata)); |
if (tdata == NULL) |
return FALSE; |
abfd->tdata.ihex_data = tdata; |
tdata->head = NULL; |
tdata->tail = NULL; |
return TRUE; |
} |
/* Read a byte from a BFD. Set *ERRORPTR if an error occurred. |
Return EOF on error or end of file. */ |
static INLINE int |
ihex_get_byte (bfd *abfd, bfd_boolean *errorptr) |
{ |
bfd_byte c; |
if (bfd_bread (&c, (bfd_size_type) 1, abfd) != 1) |
{ |
if (bfd_get_error () != bfd_error_file_truncated) |
*errorptr = TRUE; |
return EOF; |
} |
return (int) (c & 0xff); |
} |
/* Report a problem in an Intel Hex file. */ |
static void |
ihex_bad_byte (bfd *abfd, unsigned int lineno, int c, bfd_boolean error) |
{ |
if (c == EOF) |
{ |
if (! error) |
bfd_set_error (bfd_error_file_truncated); |
} |
else |
{ |
char buf[10]; |
if (! ISPRINT (c)) |
sprintf (buf, "\\%03o", (unsigned int) c); |
else |
{ |
buf[0] = c; |
buf[1] = '\0'; |
} |
(*_bfd_error_handler) |
(_("%B:%d: unexpected character `%s' in Intel Hex file"), |
abfd, lineno, buf); |
bfd_set_error (bfd_error_bad_value); |
} |
} |
/* Read an Intel hex file and turn it into sections. We create a new |
section for each contiguous set of bytes. */ |
static bfd_boolean |
ihex_scan (bfd *abfd) |
{ |
bfd_vma segbase; |
bfd_vma extbase; |
asection *sec; |
unsigned int lineno; |
bfd_boolean error; |
bfd_byte *buf = NULL; |
size_t bufsize; |
int c; |
if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) |
goto error_return; |
abfd->start_address = 0; |
segbase = 0; |
extbase = 0; |
sec = NULL; |
lineno = 1; |
error = FALSE; |
bufsize = 0; |
while ((c = ihex_get_byte (abfd, &error)) != EOF) |
{ |
if (c == '\r') |
continue; |
else if (c == '\n') |
{ |
++lineno; |
continue; |
} |
else if (c != ':') |
{ |
ihex_bad_byte (abfd, lineno, c, error); |
goto error_return; |
} |
else |
{ |
file_ptr pos; |
char hdr[8]; |
unsigned int i; |
unsigned int len; |
bfd_vma addr; |
unsigned int type; |
unsigned int chars; |
unsigned int chksum; |
/* This is a data record. */ |
pos = bfd_tell (abfd) - 1; |
/* Read the header bytes. */ |
if (bfd_bread (hdr, (bfd_size_type) 8, abfd) != 8) |
goto error_return; |
for (i = 0; i < 8; i++) |
{ |
if (! ISHEX (hdr[i])) |
{ |
ihex_bad_byte (abfd, lineno, hdr[i], error); |
goto error_return; |
} |
} |
len = HEX2 (hdr); |
addr = HEX4 (hdr + 2); |
type = HEX2 (hdr + 6); |
/* Read the data bytes. */ |
chars = len * 2 + 2; |
if (chars >= bufsize) |
{ |
buf = (bfd_byte *) bfd_realloc (buf, (bfd_size_type) chars); |
if (buf == NULL) |
goto error_return; |
bufsize = chars; |
} |
if (bfd_bread (buf, (bfd_size_type) chars, abfd) != chars) |
goto error_return; |
for (i = 0; i < chars; i++) |
{ |
if (! ISHEX (buf[i])) |
{ |
ihex_bad_byte (abfd, lineno, hdr[i], error); |
goto error_return; |
} |
} |
/* Check the checksum. */ |
chksum = len + addr + (addr >> 8) + type; |
for (i = 0; i < len; i++) |
chksum += HEX2 (buf + 2 * i); |
if (((- chksum) & 0xff) != (unsigned int) HEX2 (buf + 2 * i)) |
{ |
(*_bfd_error_handler) |
(_("%B:%u: bad checksum in Intel Hex file (expected %u, found %u)"), |
abfd, lineno, |
(- chksum) & 0xff, (unsigned int) HEX2 (buf + 2 * i)); |
bfd_set_error (bfd_error_bad_value); |
goto error_return; |
} |
switch (type) |
{ |
case 0: |
/* This is a data record. */ |
if (sec != NULL |
&& sec->vma + sec->size == extbase + segbase + addr) |
{ |
/* This data goes at the end of the section we are |
currently building. */ |
sec->size += len; |
} |
else if (len > 0) |
{ |
char secbuf[20]; |
char *secname; |
bfd_size_type amt; |
flagword flags; |
sprintf (secbuf, ".sec%d", bfd_count_sections (abfd) + 1); |
amt = strlen (secbuf) + 1; |
secname = (char *) bfd_alloc (abfd, amt); |
if (secname == NULL) |
goto error_return; |
strcpy (secname, secbuf); |
flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC; |
sec = bfd_make_section_with_flags (abfd, secname, flags); |
if (sec == NULL) |
goto error_return; |
sec->vma = extbase + segbase + addr; |
sec->lma = extbase + segbase + addr; |
sec->size = len; |
sec->filepos = pos; |
} |
break; |
case 1: |
/* An end record. */ |
if (abfd->start_address == 0) |
abfd->start_address = addr; |
if (buf != NULL) |
free (buf); |
return TRUE; |
case 2: |
/* An extended address record. */ |
if (len != 2) |
{ |
(*_bfd_error_handler) |
(_("%B:%u: bad extended address record length in Intel Hex file"), |
abfd, lineno); |
bfd_set_error (bfd_error_bad_value); |
goto error_return; |
} |
segbase = HEX4 (buf) << 4; |
sec = NULL; |
break; |
case 3: |
/* An extended start address record. */ |
if (len != 4) |
{ |
(*_bfd_error_handler) |
(_("%B:%u: bad extended start address length in Intel Hex file"), |
abfd, lineno); |
bfd_set_error (bfd_error_bad_value); |
goto error_return; |
} |
abfd->start_address += (HEX4 (buf) << 4) + HEX4 (buf + 4); |
sec = NULL; |
break; |
case 4: |
/* An extended linear address record. */ |
if (len != 2) |
{ |
(*_bfd_error_handler) |
(_("%B:%u: bad extended linear address record length in Intel Hex file"), |
abfd, lineno); |
bfd_set_error (bfd_error_bad_value); |
goto error_return; |
} |
extbase = HEX4 (buf) << 16; |
sec = NULL; |
break; |
case 5: |
/* An extended linear start address record. */ |
if (len != 2 && len != 4) |
{ |
(*_bfd_error_handler) |
(_("%B:%u: bad extended linear start address length in Intel Hex file"), |
abfd, lineno); |
bfd_set_error (bfd_error_bad_value); |
goto error_return; |
} |
if (len == 2) |
abfd->start_address += HEX4 (buf) << 16; |
else |
abfd->start_address = (HEX4 (buf) << 16) + HEX4 (buf + 4); |
sec = NULL; |
break; |
default: |
(*_bfd_error_handler) |
(_("%B:%u: unrecognized ihex type %u in Intel Hex file"), |
abfd, lineno, type); |
bfd_set_error (bfd_error_bad_value); |
goto error_return; |
} |
} |
} |
if (error) |
goto error_return; |
if (buf != NULL) |
free (buf); |
return TRUE; |
error_return: |
if (buf != NULL) |
free (buf); |
return FALSE; |
} |
/* Try to recognize an Intel Hex file. */ |
static const bfd_target * |
ihex_object_p (bfd *abfd) |
{ |
void * tdata_save; |
bfd_byte b[9]; |
unsigned int i; |
unsigned int type; |
ihex_init (); |
if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) |
return NULL; |
if (bfd_bread (b, (bfd_size_type) 9, abfd) != 9) |
{ |
if (bfd_get_error () == bfd_error_file_truncated) |
bfd_set_error (bfd_error_wrong_format); |
return NULL; |
} |
if (b[0] != ':') |
{ |
bfd_set_error (bfd_error_wrong_format); |
return NULL; |
} |
for (i = 1; i < 9; i++) |
{ |
if (! ISHEX (b[i])) |
{ |
bfd_set_error (bfd_error_wrong_format); |
return NULL; |
} |
} |
type = HEX2 (b + 7); |
if (type > 5) |
{ |
bfd_set_error (bfd_error_wrong_format); |
return NULL; |
} |
/* OK, it looks like it really is an Intel Hex file. */ |
tdata_save = abfd->tdata.any; |
if (! ihex_mkobject (abfd) || ! ihex_scan (abfd)) |
{ |
if (abfd->tdata.any != tdata_save && abfd->tdata.any != NULL) |
bfd_release (abfd, abfd->tdata.any); |
abfd->tdata.any = tdata_save; |
return NULL; |
} |
return abfd->xvec; |
} |
/* Read the contents of a section in an Intel Hex file. */ |
static bfd_boolean |
ihex_read_section (bfd *abfd, asection *section, bfd_byte *contents) |
{ |
int c; |
bfd_byte *p; |
bfd_byte *buf = NULL; |
size_t bufsize; |
bfd_boolean error; |
if (bfd_seek (abfd, section->filepos, SEEK_SET) != 0) |
goto error_return; |
p = contents; |
bufsize = 0; |
error = FALSE; |
while ((c = ihex_get_byte (abfd, &error)) != EOF) |
{ |
char hdr[8]; |
unsigned int len; |
unsigned int type; |
unsigned int i; |
if (c == '\r' || c == '\n') |
continue; |
/* This is called after ihex_scan has succeeded, so we ought to |
know the exact format. */ |
BFD_ASSERT (c == ':'); |
if (bfd_bread (hdr, (bfd_size_type) 8, abfd) != 8) |
goto error_return; |
len = HEX2 (hdr); |
type = HEX2 (hdr + 6); |
/* We should only see type 0 records here. */ |
if (type != 0) |
{ |
(*_bfd_error_handler) |
(_("%B: internal error in ihex_read_section"), abfd); |
bfd_set_error (bfd_error_bad_value); |
goto error_return; |
} |
if (len * 2 > bufsize) |
{ |
buf = (bfd_byte *) bfd_realloc (buf, (bfd_size_type) len * 2); |
if (buf == NULL) |
goto error_return; |
bufsize = len * 2; |
} |
if (bfd_bread (buf, (bfd_size_type) len * 2, abfd) != len * 2) |
goto error_return; |
for (i = 0; i < len; i++) |
*p++ = HEX2 (buf + 2 * i); |
if ((bfd_size_type) (p - contents) >= section->size) |
{ |
/* We've read everything in the section. */ |
if (buf != NULL) |
free (buf); |
return TRUE; |
} |
/* Skip the checksum. */ |
if (bfd_bread (buf, (bfd_size_type) 2, abfd) != 2) |
goto error_return; |
} |
if ((bfd_size_type) (p - contents) < section->size) |
{ |
(*_bfd_error_handler) |
(_("%B: bad section length in ihex_read_section"), abfd); |
bfd_set_error (bfd_error_bad_value); |
goto error_return; |
} |
if (buf != NULL) |
free (buf); |
return TRUE; |
error_return: |
if (buf != NULL) |
free (buf); |
return FALSE; |
} |
/* Get the contents of a section in an Intel Hex file. */ |
static bfd_boolean |
ihex_get_section_contents (bfd *abfd, |
asection *section, |
void * location, |
file_ptr offset, |
bfd_size_type count) |
{ |
if (section->used_by_bfd == NULL) |
{ |
section->used_by_bfd = bfd_alloc (abfd, section->size); |
if (section->used_by_bfd == NULL) |
return FALSE; |
if (! ihex_read_section (abfd, section, |
(bfd_byte *) section->used_by_bfd)) |
return FALSE; |
} |
memcpy (location, (bfd_byte *) section->used_by_bfd + offset, |
(size_t) count); |
return TRUE; |
} |
/* Set the contents of a section in an Intel Hex file. */ |
static bfd_boolean |
ihex_set_section_contents (bfd *abfd, |
asection *section, |
const void * location, |
file_ptr offset, |
bfd_size_type count) |
{ |
struct ihex_data_list *n; |
bfd_byte *data; |
struct ihex_data_struct *tdata; |
if (count == 0 |
|| (section->flags & SEC_ALLOC) == 0 |
|| (section->flags & SEC_LOAD) == 0) |
return TRUE; |
n = (struct ihex_data_list *) bfd_alloc (abfd, sizeof (* n)); |
if (n == NULL) |
return FALSE; |
data = (bfd_byte *) bfd_alloc (abfd, count); |
if (data == NULL) |
return FALSE; |
memcpy (data, location, (size_t) count); |
n->data = data; |
n->where = section->lma + offset; |
n->size = count; |
/* Sort the records by address. Optimize for the common case of |
adding a record to the end of the list. */ |
tdata = abfd->tdata.ihex_data; |
if (tdata->tail != NULL |
&& n->where >= tdata->tail->where) |
{ |
tdata->tail->next = n; |
n->next = NULL; |
tdata->tail = n; |
} |
else |
{ |
struct ihex_data_list **pp; |
for (pp = &tdata->head; |
*pp != NULL && (*pp)->where < n->where; |
pp = &(*pp)->next) |
; |
n->next = *pp; |
*pp = n; |
if (n->next == NULL) |
tdata->tail = n; |
} |
return TRUE; |
} |
/* Write a record out to an Intel Hex file. */ |
static bfd_boolean |
ihex_write_record (bfd *abfd, |
size_t count, |
unsigned int addr, |
unsigned int type, |
bfd_byte *data) |
{ |
static const char digs[] = "0123456789ABCDEF"; |
char buf[9 + CHUNK * 2 + 4]; |
char *p; |
unsigned int chksum; |
unsigned int i; |
size_t total; |
#define TOHEX(buf, v) \ |
((buf)[0] = digs[((v) >> 4) & 0xf], (buf)[1] = digs[(v) & 0xf]) |
buf[0] = ':'; |
TOHEX (buf + 1, count); |
TOHEX (buf + 3, (addr >> 8) & 0xff); |
TOHEX (buf + 5, addr & 0xff); |
TOHEX (buf + 7, type); |
chksum = count + addr + (addr >> 8) + type; |
for (i = 0, p = buf + 9; i < count; i++, p += 2, data++) |
{ |
TOHEX (p, *data); |
chksum += *data; |
} |
TOHEX (p, (- chksum) & 0xff); |
p[2] = '\r'; |
p[3] = '\n'; |
total = 9 + count * 2 + 4; |
if (bfd_bwrite (buf, (bfd_size_type) total, abfd) != total) |
return FALSE; |
return TRUE; |
} |
/* Write out an Intel Hex file. */ |
static bfd_boolean |
ihex_write_object_contents (bfd *abfd) |
{ |
bfd_vma segbase; |
bfd_vma extbase; |
struct ihex_data_list *l; |
segbase = 0; |
extbase = 0; |
for (l = abfd->tdata.ihex_data->head; l != NULL; l = l->next) |
{ |
bfd_vma where; |
bfd_byte *p; |
bfd_size_type count; |
where = l->where; |
p = l->data; |
count = l->size; |
while (count > 0) |
{ |
size_t now; |
unsigned int rec_addr; |
now = count; |
if (count > CHUNK) |
now = CHUNK; |
if (where > segbase + extbase + 0xffff) |
{ |
bfd_byte addr[2]; |
/* We need a new base address. */ |
if (where <= 0xfffff) |
{ |
/* The addresses should be sorted. */ |
BFD_ASSERT (extbase == 0); |
segbase = where & 0xf0000; |
addr[0] = (bfd_byte)(segbase >> 12) & 0xff; |
addr[1] = (bfd_byte)(segbase >> 4) & 0xff; |
if (! ihex_write_record (abfd, 2, 0, 2, addr)) |
return FALSE; |
} |
else |
{ |
/* The extended address record and the extended |
linear address record are combined, at least by |
some readers. We need an extended linear address |
record here, so if we've already written out an |
extended address record, zero it out to avoid |
confusion. */ |
if (segbase != 0) |
{ |
addr[0] = 0; |
addr[1] = 0; |
if (! ihex_write_record (abfd, 2, 0, 2, addr)) |
return FALSE; |
segbase = 0; |
} |
extbase = where & 0xffff0000; |
if (where > extbase + 0xffff) |
{ |
char buf[20]; |
sprintf_vma (buf, where); |
(*_bfd_error_handler) |
(_("%s: address 0x%s out of range for Intel Hex file"), |
bfd_get_filename (abfd), buf); |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
addr[0] = (bfd_byte)(extbase >> 24) & 0xff; |
addr[1] = (bfd_byte)(extbase >> 16) & 0xff; |
if (! ihex_write_record (abfd, 2, 0, 4, addr)) |
return FALSE; |
} |
} |
rec_addr = where - (extbase + segbase); |
/* Output records shouldn't cross 64K boundaries. */ |
if (rec_addr + now > 0xffff) |
now = 0x10000 - rec_addr; |
if (! ihex_write_record (abfd, now, rec_addr, 0, p)) |
return FALSE; |
where += now; |
p += now; |
count -= now; |
} |
} |
if (abfd->start_address != 0) |
{ |
bfd_vma start; |
bfd_byte startbuf[4]; |
start = abfd->start_address; |
if (start <= 0xfffff) |
{ |
startbuf[0] = (bfd_byte)((start & 0xf0000) >> 12) & 0xff; |
startbuf[1] = 0; |
startbuf[2] = (bfd_byte)(start >> 8) & 0xff; |
startbuf[3] = (bfd_byte)start & 0xff; |
if (! ihex_write_record (abfd, 4, 0, 3, startbuf)) |
return FALSE; |
} |
else |
{ |
startbuf[0] = (bfd_byte)(start >> 24) & 0xff; |
startbuf[1] = (bfd_byte)(start >> 16) & 0xff; |
startbuf[2] = (bfd_byte)(start >> 8) & 0xff; |
startbuf[3] = (bfd_byte)start & 0xff; |
if (! ihex_write_record (abfd, 4, 0, 5, startbuf)) |
return FALSE; |
} |
} |
if (! ihex_write_record (abfd, 0, 0, 1, NULL)) |
return FALSE; |
return TRUE; |
} |
/* Set the architecture for the output file. The architecture is |
irrelevant, so we ignore errors about unknown architectures. */ |
static bfd_boolean |
ihex_set_arch_mach (bfd *abfd, |
enum bfd_architecture arch, |
unsigned long mach) |
{ |
if (! bfd_default_set_arch_mach (abfd, arch, mach)) |
{ |
if (arch != bfd_arch_unknown) |
return FALSE; |
} |
return TRUE; |
} |
/* Get the size of the headers, for the linker. */ |
static int |
ihex_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED, |
struct bfd_link_info *info ATTRIBUTE_UNUSED) |
{ |
return 0; |
} |
/* Some random definitions for the target vector. */ |
#define ihex_close_and_cleanup _bfd_generic_close_and_cleanup |
#define ihex_bfd_free_cached_info _bfd_generic_bfd_free_cached_info |
#define ihex_new_section_hook _bfd_generic_new_section_hook |
#define ihex_get_section_contents_in_window _bfd_generic_get_section_contents_in_window |
#define ihex_get_symtab_upper_bound bfd_0l |
#define ihex_canonicalize_symtab ((long (*) (bfd *, asymbol **)) bfd_0l) |
#define ihex_make_empty_symbol _bfd_generic_make_empty_symbol |
#define ihex_print_symbol _bfd_nosymbols_print_symbol |
#define ihex_get_symbol_info _bfd_nosymbols_get_symbol_info |
#define ihex_bfd_is_target_special_symbol ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) |
#define ihex_bfd_is_local_label_name _bfd_nosymbols_bfd_is_local_label_name |
#define ihex_get_lineno _bfd_nosymbols_get_lineno |
#define ihex_find_nearest_line _bfd_nosymbols_find_nearest_line |
#define ihex_find_inliner_info _bfd_nosymbols_find_inliner_info |
#define ihex_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol |
#define ihex_read_minisymbols _bfd_nosymbols_read_minisymbols |
#define ihex_minisymbol_to_symbol _bfd_nosymbols_minisymbol_to_symbol |
#define ihex_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents |
#define ihex_bfd_relax_section bfd_generic_relax_section |
#define ihex_bfd_gc_sections bfd_generic_gc_sections |
#define ihex_bfd_lookup_section_flags bfd_generic_lookup_section_flags |
#define ihex_bfd_merge_sections bfd_generic_merge_sections |
#define ihex_bfd_is_group_section bfd_generic_is_group_section |
#define ihex_bfd_discard_group bfd_generic_discard_group |
#define ihex_section_already_linked _bfd_generic_section_already_linked |
#define ihex_bfd_define_common_symbol bfd_generic_define_common_symbol |
#define ihex_bfd_link_hash_table_create _bfd_generic_link_hash_table_create |
#define ihex_bfd_link_hash_table_free _bfd_generic_link_hash_table_free |
#define ihex_bfd_link_add_symbols _bfd_generic_link_add_symbols |
#define ihex_bfd_link_just_syms _bfd_generic_link_just_syms |
#define ihex_bfd_copy_link_hash_symbol_type \ |
_bfd_generic_copy_link_hash_symbol_type |
#define ihex_bfd_final_link _bfd_generic_final_link |
#define ihex_bfd_link_split_section _bfd_generic_link_split_section |
/* The Intel Hex target vector. */ |
const bfd_target ihex_vec = |
{ |
"ihex", /* Name. */ |
bfd_target_ihex_flavour, |
BFD_ENDIAN_UNKNOWN, /* Target byte order. */ |
BFD_ENDIAN_UNKNOWN, /* Target headers byte order. */ |
0, /* Object flags. */ |
(SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD), /* Section flags. */ |
0, /* Leading underscore. */ |
' ', /* AR_pad_char. */ |
16, /* AR_max_namelen. */ |
0, /* match priority. */ |
bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Data. */ |
bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Headers. */ |
{ |
_bfd_dummy_target, |
ihex_object_p, /* bfd_check_format. */ |
_bfd_dummy_target, |
_bfd_dummy_target, |
}, |
{ |
bfd_false, |
ihex_mkobject, |
_bfd_generic_mkarchive, |
bfd_false, |
}, |
{ /* bfd_write_contents. */ |
bfd_false, |
ihex_write_object_contents, |
_bfd_write_archive_contents, |
bfd_false, |
}, |
BFD_JUMP_TABLE_GENERIC (ihex), |
BFD_JUMP_TABLE_COPY (_bfd_generic), |
BFD_JUMP_TABLE_CORE (_bfd_nocore), |
BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), |
BFD_JUMP_TABLE_SYMBOLS (ihex), |
BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), |
BFD_JUMP_TABLE_WRITE (ihex), |
BFD_JUMP_TABLE_LINK (ihex), |
BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), |
NULL, |
NULL |
}; |
/contrib/toolchain/binutils/bfd/init.c |
---|
0,0 → 1,55 |
/* bfd initialization stuff |
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 2003, 2005, 2007 |
Free Software Foundation, Inc. |
Written by Steve Chamberlain of Cygnus Support. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
/* |
SECTION |
Initialization |
SUBSECTION |
Initialization functions |
These are the functions that handle initializing a BFD. |
*/ |
/* |
FUNCTION |
bfd_init |
SYNOPSIS |
void bfd_init (void); |
DESCRIPTION |
This routine must be called before any other BFD function to |
initialize magical internal data structures. |
*/ |
/* Actually, there is currently nothing for this function to do. |
However, someday it may be needed, so keep it around. */ |
void |
bfd_init (void) |
{ |
} |
/contrib/toolchain/binutils/bfd/libaout.h |
---|
0,0 → 1,691 |
/* BFD back-end data structures for a.out (and similar) files. |
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, |
2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 |
Free Software Foundation, Inc. |
Written by Cygnus Support. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#ifndef LIBAOUT_H |
#define LIBAOUT_H |
/* We try to encapsulate the differences in the various a.out file |
variants in a few routines, and otherwise share large masses of code. |
This means we only have to fix bugs in one place, most of the time. */ |
#include "bfdlink.h" |
/* Macros for accessing components in an aout header. */ |
#define H_PUT_64 bfd_h_put_64 |
#define H_PUT_32 bfd_h_put_32 |
#define H_PUT_16 bfd_h_put_16 |
#define H_PUT_8 bfd_h_put_8 |
#define H_PUT_S64 bfd_h_put_signed_64 |
#define H_PUT_S32 bfd_h_put_signed_32 |
#define H_PUT_S16 bfd_h_put_signed_16 |
#define H_PUT_S8 bfd_h_put_signed_8 |
#define H_GET_64 bfd_h_get_64 |
#define H_GET_32 bfd_h_get_32 |
#define H_GET_16 bfd_h_get_16 |
#define H_GET_8 bfd_h_get_8 |
#define H_GET_S64 bfd_h_get_signed_64 |
#define H_GET_S32 bfd_h_get_signed_32 |
#define H_GET_S16 bfd_h_get_signed_16 |
#define H_GET_S8 bfd_h_get_signed_8 |
/* Parameterize the a.out code based on whether it is being built |
for a 32-bit architecture or a 64-bit architecture. */ |
/* Do not "beautify" the CONCAT* macro args. Traditional C will not |
remove whitespace added here, and thus will fail to concatenate |
the tokens. */ |
#if ARCH_SIZE==64 |
#define GET_WORD H_GET_64 |
#define GET_SWORD H_GET_S64 |
#define GET_MAGIC H_GET_32 |
#define PUT_WORD H_PUT_64 |
#define PUT_MAGIC H_PUT_32 |
#ifndef NAME |
#define NAME(x,y) CONCAT3 (x,_64_,y) |
#endif |
#define JNAME(x) CONCAT2 (x,_64) |
#define BYTES_IN_WORD 8 |
#else |
#if ARCH_SIZE==16 |
#define GET_WORD H_GET_16 |
#define GET_SWORD H_GET_S16 |
#define GET_MAGIC H_GET_16 |
#define PUT_WORD H_PUT_16 |
#define PUT_MAGIC H_PUT_16 |
#ifndef NAME |
#define NAME(x,y) CONCAT3 (x,_16_,y) |
#endif |
#define JNAME(x) CONCAT2 (x,_16) |
#define BYTES_IN_WORD 2 |
#else /* ARCH_SIZE == 32 */ |
#define GET_WORD H_GET_32 |
#define GET_SWORD H_GET_S32 |
#define GET_MAGIC H_GET_32 |
#define PUT_WORD H_PUT_32 |
#define PUT_MAGIC H_PUT_32 |
#ifndef NAME |
#define NAME(x,y) CONCAT3 (x,_32_,y) |
#endif |
#define JNAME(x) CONCAT2 (x,_32) |
#define BYTES_IN_WORD 4 |
#endif /* ARCH_SIZE==32 */ |
#endif /* ARCH_SIZE==64 */ |
/* Declare at file level, since used in parameter lists, which have |
weird scope. */ |
struct external_exec; |
struct external_nlist; |
struct reloc_ext_external; |
struct reloc_std_external; |
/* a.out backend linker hash table entries. */ |
struct aout_link_hash_entry |
{ |
struct bfd_link_hash_entry root; |
/* Whether this symbol has been written out. */ |
bfd_boolean written; |
/* Symbol index in output file. */ |
int indx; |
}; |
/* a.out backend linker hash table. */ |
struct aout_link_hash_table |
{ |
struct bfd_link_hash_table root; |
}; |
/* Look up an entry in an a.out link hash table. */ |
#define aout_link_hash_lookup(table, string, create, copy, follow) \ |
((struct aout_link_hash_entry *) \ |
bfd_link_hash_lookup (&(table)->root, (string), (create), (copy), (follow))) |
/* Traverse an a.out link hash table. */ |
#define aout_link_hash_traverse(table, func, info) \ |
(bfd_link_hash_traverse \ |
(&(table)->root, \ |
(bfd_boolean (*) (struct bfd_link_hash_entry *, void *)) (func), \ |
(info))) |
/* Get the a.out link hash table from the info structure. This is |
just a cast. */ |
#define aout_hash_table(p) ((struct aout_link_hash_table *) ((p)->hash)) |
/* Back-end information for various a.out targets. */ |
struct aout_backend_data |
{ |
/* Are ZMAGIC files mapped contiguously? If so, the text section may |
need more padding, if the segment size (granularity for memory access |
control) is larger than the page size. */ |
unsigned char zmagic_mapped_contiguous; |
/* If this flag is set, ZMAGIC/NMAGIC file headers get mapped in with the |
text section, which starts immediately after the file header. |
If not, the text section starts on the next page. */ |
unsigned char text_includes_header; |
/* If this flag is set, then if the entry address is not in the |
first SEGMENT_SIZE bytes of the text section, it is taken to be |
the address of the start of the text section. This can be useful |
for kernels. */ |
unsigned char entry_is_text_address; |
/* The value to pass to N_SET_FLAGS. */ |
unsigned char exec_hdr_flags; |
/* If the text section VMA isn't specified, and we need an absolute |
address, use this as the default. If we're producing a relocatable |
file, zero is always used. */ |
/* ?? Perhaps a callback would be a better choice? Will this do anything |
reasonable for a format that handles multiple CPUs with different |
load addresses for each? */ |
bfd_vma default_text_vma; |
/* Callback for setting the page and segment sizes, if they can't be |
trivially determined from the architecture. */ |
bfd_boolean (*set_sizes) (bfd *); |
/* zmagic files only. For go32, the length of the exec header contributes |
to the size of the text section in the file for alignment purposes but |
does *not* get counted in the length of the text section. */ |
unsigned char exec_header_not_counted; |
/* Callback from the add symbols phase of the linker code to handle |
a dynamic object. */ |
bfd_boolean (*add_dynamic_symbols) |
(bfd *, struct bfd_link_info *, struct external_nlist **, |
bfd_size_type *, char **); |
/* Callback from the add symbols phase of the linker code to handle |
adding a single symbol to the global linker hash table. */ |
bfd_boolean (*add_one_symbol) |
(struct bfd_link_info *, bfd *, const char *, flagword, |
asection *, bfd_vma, const char *, bfd_boolean, bfd_boolean, |
struct bfd_link_hash_entry **); |
/* Called to handle linking a dynamic object. */ |
bfd_boolean (*link_dynamic_object) |
(struct bfd_link_info *, bfd *); |
/* Called for each global symbol being written out by the linker. |
This should write out the dynamic symbol information. */ |
bfd_boolean (*write_dynamic_symbol) |
(bfd *, struct bfd_link_info *, struct aout_link_hash_entry *); |
/* If this callback is not NULL, the linker calls it for each reloc. |
RELOC is a pointer to the unswapped reloc. If *SKIP is set to |
TRUE, the reloc will be skipped. *RELOCATION may be changed to |
change the effects of the relocation. */ |
bfd_boolean (*check_dynamic_reloc) |
(struct bfd_link_info *info, bfd *input_bfd, |
asection *input_section, struct aout_link_hash_entry *h, |
void * reloc, bfd_byte *contents, bfd_boolean *skip, |
bfd_vma *relocation); |
/* Called at the end of a link to finish up any dynamic linking |
information. */ |
bfd_boolean (*finish_dynamic_link) (bfd *, struct bfd_link_info *); |
}; |
#define aout_backend_info(abfd) \ |
((const struct aout_backend_data *)((abfd)->xvec->backend_data)) |
/* This is the layout in memory of a "struct exec" while we process it. |
All 'lengths' are given as a number of bytes. |
All 'alignments' are for relinkable files only; an alignment of |
'n' indicates the corresponding segment must begin at an |
address that is a multiple of (2**n). */ |
struct internal_exec |
{ |
long a_info; /* Magic number and flags, packed. */ |
bfd_vma a_text; /* Length of text, in bytes. */ |
bfd_vma a_data; /* Length of data, in bytes. */ |
bfd_vma a_bss; /* Length of uninitialized data area in mem. */ |
bfd_vma a_syms; /* Length of symbol table data in file. */ |
bfd_vma a_entry; /* Start address. */ |
bfd_vma a_trsize; /* Length of text's relocation info, in bytes. */ |
bfd_vma a_drsize; /* Length of data's relocation info, in bytes. */ |
/* Added for i960 */ |
bfd_vma a_tload; /* Text runtime load address. */ |
bfd_vma a_dload; /* Data runtime load address. */ |
unsigned char a_talign; /* Alignment of text segment. */ |
unsigned char a_dalign; /* Alignment of data segment. */ |
unsigned char a_balign; /* Alignment of bss segment. */ |
char a_relaxable; /* Enough info for linker relax. */ |
}; |
/* Magic number is written |
< MSB > |
3130292827262524232221201918171615141312111009080706050403020100 |
< FLAGS >< MACHINE TYPE >< MAGIC NUMBER > */ |
/* Magic number for NetBSD is |
<MSB > |
3130292827262524232221201918171615141312111009080706050403020100 |
< FLAGS >< MACHINE TYPE >< MAGIC NUMBER > */ |
enum machine_type |
{ |
M_UNKNOWN = 0, |
M_68010 = 1, |
M_68020 = 2, |
M_SPARC = 3, |
/* Skip a bunch so we don't run into any of SUN's numbers. */ |
/* Make these up for the ns32k. */ |
M_NS32032 = (64), /* NS32032 running ? */ |
M_NS32532 = (64 + 5), /* NS32532 running mach. */ |
M_386 = 100, |
M_29K = 101, /* AMD 29000. */ |
M_386_DYNIX = 102, /* Sequent running dynix. */ |
M_ARM = 103, /* Advanced Risc Machines ARM. */ |
M_SPARCLET = 131, /* SPARClet = M_SPARC + 128. */ |
M_386_NETBSD = 134, /* NetBSD/i386 binary. */ |
M_68K_NETBSD = 135, /* NetBSD/m68k binary. */ |
M_68K4K_NETBSD = 136, /* NetBSD/m68k4k binary. */ |
M_532_NETBSD = 137, /* NetBSD/ns32k binary. */ |
M_SPARC_NETBSD = 138, /* NetBSD/sparc binary. */ |
M_PMAX_NETBSD = 139, /* NetBSD/pmax (MIPS little-endian) binary. */ |
M_VAX_NETBSD = 140, /* NetBSD/vax binary. */ |
M_ALPHA_NETBSD = 141, /* NetBSD/alpha binary. */ |
M_ARM6_NETBSD = 143, /* NetBSD/arm32 binary. */ |
M_SPARCLET_1 = 147, /* 0x93, reserved. */ |
M_POWERPC_NETBSD = 149, /* NetBSD/powerpc (big-endian) binary. */ |
M_VAX4K_NETBSD = 150, /* NetBSD/vax 4K pages binary. */ |
M_MIPS1 = 151, /* MIPS R2000/R3000 binary. */ |
M_MIPS2 = 152, /* MIPS R4000/R6000 binary. */ |
M_88K_OPENBSD = 153, /* OpenBSD/m88k binary. */ |
M_HPPA_OPENBSD = 154, /* OpenBSD/hppa binary. */ |
M_SPARC64_NETBSD = 156, /* NetBSD/sparc64 binary. */ |
M_X86_64_NETBSD = 157, /* NetBSD/amd64 binary. */ |
M_SPARCLET_2 = 163, /* 0xa3, reserved. */ |
M_SPARCLET_3 = 179, /* 0xb3, reserved. */ |
M_SPARCLET_4 = 195, /* 0xc3, reserved. */ |
M_HP200 = 200, /* HP 200 (68010) BSD binary. */ |
M_HP300 = (300 % 256), /* HP 300 (68020+68881) BSD binary. */ |
M_HPUX = (0x20c % 256), /* HP 200/300 HPUX binary. */ |
M_SPARCLET_5 = 211, /* 0xd3, reserved. */ |
M_SPARCLET_6 = 227, /* 0xe3, reserved. */ |
/*M_SPARCLET_7 = 243 / * 0xf3, reserved. */ |
M_SPARCLITE_LE = 243, |
M_CRIS = 255 /* Axis CRIS binary. */ |
}; |
#define N_DYNAMIC(exec) ((exec).a_info & 0x80000000) |
#ifndef N_MAGIC |
# define N_MAGIC(exec) ((exec).a_info & 0xffff) |
#endif |
#ifndef N_MACHTYPE |
# define N_MACHTYPE(exec) ((enum machine_type)(((exec).a_info >> 16) & 0xff)) |
#endif |
#ifndef N_FLAGS |
# define N_FLAGS(exec) (((exec).a_info >> 24) & 0xff) |
#endif |
#ifndef N_SET_INFO |
# define N_SET_INFO(exec, magic, type, flags) \ |
((exec).a_info = ((magic) & 0xffff) \ |
| (((int)(type) & 0xff) << 16) \ |
| (((flags) & 0xff) << 24)) |
#endif |
#ifndef N_SET_DYNAMIC |
# define N_SET_DYNAMIC(exec, dynamic) \ |
((exec).a_info = (dynamic) ? (long) ((exec).a_info | 0x80000000) : \ |
((exec).a_info & 0x7fffffff)) |
#endif |
#ifndef N_SET_MAGIC |
# define N_SET_MAGIC(exec, magic) \ |
((exec).a_info = (((exec).a_info & 0xffff0000) | ((magic) & 0xffff))) |
#endif |
#ifndef N_SET_MACHTYPE |
# define N_SET_MACHTYPE(exec, machtype) \ |
((exec).a_info = \ |
((exec).a_info&0xff00ffff) | ((((int)(machtype))&0xff) << 16)) |
#endif |
#ifndef N_SET_FLAGS |
# define N_SET_FLAGS(exec, flags) \ |
((exec).a_info = \ |
((exec).a_info&0x00ffffff) | (((flags) & 0xff) << 24)) |
#endif |
typedef struct aout_symbol |
{ |
asymbol symbol; |
short desc; |
char other; |
unsigned char type; |
} aout_symbol_type; |
/* The `tdata' struct for all a.out-like object file formats. |
Various things depend on this struct being around any time an a.out |
file is being handled. An example is dbxread.c in GDB. */ |
enum aout_subformat { |
default_format = 0, |
/* Used on HP 9000/300 running HP/UX. See hp300hpux.c. */ |
gnu_encap_format, |
/* Used on Linux, 386BSD, etc. See include/aout/aout64.h. */ |
q_magic_format |
}; |
enum aout_magic { |
undecided_magic = 0, |
z_magic, |
o_magic, |
n_magic |
}; |
struct aoutdata |
{ |
struct internal_exec *hdr; /* Exec file header. */ |
aout_symbol_type *symbols; /* Symtab for input bfd. */ |
/* For ease, we do this. */ |
asection *textsec; |
asection *datasec; |
asection *bsssec; |
/* We remember these offsets so that after check_file_format, we have |
no dependencies on the particular format of the exec_hdr. */ |
file_ptr sym_filepos; |
file_ptr str_filepos; |
/* Size of a relocation entry in external form. */ |
unsigned reloc_entry_size; |
/* Size of a symbol table entry in external form. */ |
unsigned symbol_entry_size; |
/* Page size - needed for alignment of demand paged files. */ |
unsigned long page_size; |
/* Segment size - needed for alignment of demand paged files. */ |
unsigned long segment_size; |
/* Zmagic disk block size - need to align the start of the text |
section in ZMAGIC binaries. Normally the same as page_size. */ |
unsigned long zmagic_disk_block_size; |
unsigned exec_bytes_size; |
unsigned vma_adjusted : 1; |
/* Used when a bfd supports several highly similar formats. */ |
enum aout_subformat subformat; |
enum aout_magic magic; |
/* A buffer for find_nearest_line. */ |
char *line_buf; |
/* The external symbol information. */ |
struct external_nlist *external_syms; |
bfd_size_type external_sym_count; |
bfd_window sym_window; |
char *external_strings; |
bfd_size_type external_string_size; |
bfd_window string_window; |
struct aout_link_hash_entry **sym_hashes; |
/* A pointer for shared library information. */ |
void * dynamic_info; |
/* A mapping from local symbols to offsets into the global offset |
table, used when linking on SunOS. This is indexed by the symbol |
index. */ |
bfd_vma *local_got_offsets; |
}; |
struct aout_data_struct |
{ |
struct aoutdata a; |
struct internal_exec e; |
}; |
#define adata(bfd) ((bfd)->tdata.aout_data->a) |
#define exec_hdr(bfd) (adata (bfd).hdr) |
#define obj_aout_symbols(bfd) (adata (bfd).symbols) |
#define obj_textsec(bfd) (adata (bfd).textsec) |
#define obj_datasec(bfd) (adata (bfd).datasec) |
#define obj_bsssec(bfd) (adata (bfd).bsssec) |
#define obj_sym_filepos(bfd) (adata (bfd).sym_filepos) |
#define obj_str_filepos(bfd) (adata (bfd).str_filepos) |
#define obj_reloc_entry_size(bfd) (adata (bfd).reloc_entry_size) |
#define obj_symbol_entry_size(bfd) (adata (bfd).symbol_entry_size) |
#define obj_aout_subformat(bfd) (adata (bfd).subformat) |
#define obj_aout_external_syms(bfd) (adata (bfd).external_syms) |
#define obj_aout_external_sym_count(bfd) (adata (bfd).external_sym_count) |
#define obj_aout_sym_window(bfd) (adata (bfd).sym_window) |
#define obj_aout_external_strings(bfd) (adata (bfd).external_strings) |
#define obj_aout_external_string_size(bfd) (adata (bfd).external_string_size) |
#define obj_aout_string_window(bfd) (adata (bfd).string_window) |
#define obj_aout_sym_hashes(bfd) (adata (bfd).sym_hashes) |
#define obj_aout_dynamic_info(bfd) (adata (bfd).dynamic_info) |
/* We take the address of the first element of an asymbol to ensure that the |
macro is only ever applied to an asymbol. */ |
#define aout_symbol(asymbol) ((aout_symbol_type *)(&(asymbol)->the_bfd)) |
/* Information we keep for each a.out section. This is currently only |
used by the a.out backend linker. */ |
struct aout_section_data_struct |
{ |
/* The unswapped relocation entries for this section. */ |
void * relocs; |
}; |
#define aout_section_data(s) \ |
((struct aout_section_data_struct *) (s)->used_by_bfd) |
#define set_aout_section_data(s,v) \ |
((s)->used_by_bfd = (void *)&(v)->relocs) |
/* Prototype declarations for functions defined in aoutx.h. */ |
extern bfd_boolean NAME (aout, squirt_out_relocs) |
(bfd *, asection *); |
extern bfd_boolean NAME (aout, make_sections) |
(bfd *); |
extern const bfd_target * NAME (aout, some_aout_object_p) |
(bfd *, struct internal_exec *, const bfd_target *(*) (bfd *)); |
extern bfd_boolean NAME (aout, mkobject) |
(bfd *); |
extern enum machine_type NAME (aout, machine_type) |
(enum bfd_architecture, unsigned long, bfd_boolean *); |
extern bfd_boolean NAME (aout, set_arch_mach) |
(bfd *, enum bfd_architecture, unsigned long); |
extern bfd_boolean NAME (aout, new_section_hook) |
(bfd *, asection *); |
extern bfd_boolean NAME (aout, set_section_contents) |
(bfd *, sec_ptr, const void *, file_ptr, bfd_size_type); |
extern asymbol * NAME (aout, make_empty_symbol) |
(bfd *); |
extern bfd_boolean NAME (aout, translate_symbol_table) |
(bfd *, aout_symbol_type *, struct external_nlist *, bfd_size_type, |
char *, bfd_size_type, bfd_boolean); |
extern bfd_boolean NAME (aout, slurp_symbol_table) |
(bfd *); |
extern bfd_boolean NAME (aout, write_syms) |
(bfd *); |
extern void NAME (aout, reclaim_symbol_table) |
(bfd *); |
extern long NAME (aout, get_symtab_upper_bound) |
(bfd *); |
extern long NAME (aout, canonicalize_symtab) |
(bfd *, asymbol **); |
extern void NAME (aout, swap_ext_reloc_in) |
(bfd *, struct reloc_ext_external *, arelent *, asymbol **, |
bfd_size_type); |
extern void NAME (aout, swap_std_reloc_in) |
(bfd *, struct reloc_std_external *, arelent *, asymbol **, |
bfd_size_type); |
extern reloc_howto_type * NAME (aout, reloc_type_lookup) |
(bfd *, bfd_reloc_code_real_type); |
extern reloc_howto_type * NAME (aout, reloc_name_lookup) |
(bfd *, const char *); |
extern bfd_boolean NAME (aout, slurp_reloc_table) |
(bfd *, sec_ptr, asymbol **); |
extern long NAME (aout, canonicalize_reloc) |
(bfd *, sec_ptr, arelent **, asymbol **); |
extern long NAME (aout, get_reloc_upper_bound) |
(bfd *, sec_ptr); |
extern void NAME (aout, reclaim_reloc) |
(bfd *, sec_ptr); |
extern alent * NAME (aout, get_lineno) |
(bfd *, asymbol *); |
extern void NAME (aout, print_symbol) |
(bfd *, void *, asymbol *, bfd_print_symbol_type); |
extern void NAME (aout, get_symbol_info) |
(bfd *, asymbol *, symbol_info *); |
extern bfd_boolean NAME (aout, find_nearest_line) |
(bfd *, asection *, asymbol **, bfd_vma, const char **, |
const char **, unsigned int *); |
extern long NAME (aout, read_minisymbols) |
(bfd *, bfd_boolean, void * *, unsigned int *); |
extern asymbol * NAME (aout, minisymbol_to_symbol) |
(bfd *, bfd_boolean, const void *, asymbol *); |
extern int NAME (aout, sizeof_headers) |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean NAME (aout, adjust_sizes_and_vmas) |
(bfd *, bfd_size_type *, file_ptr *); |
extern void NAME (aout, swap_exec_header_in) |
(bfd *, struct external_exec *, struct internal_exec *); |
extern void NAME (aout, swap_exec_header_out) |
(bfd *, struct internal_exec *, struct external_exec *); |
extern struct bfd_hash_entry * NAME (aout, link_hash_newfunc) |
(struct bfd_hash_entry *, struct bfd_hash_table *, const char *); |
extern bfd_boolean NAME (aout, link_hash_table_init) |
(struct aout_link_hash_table *, bfd *, |
struct bfd_hash_entry *(*) (struct bfd_hash_entry *, |
struct bfd_hash_table *, |
const char *), |
unsigned int); |
extern struct bfd_link_hash_table * NAME (aout, link_hash_table_create) |
(bfd *); |
extern bfd_boolean NAME (aout, link_add_symbols) |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean NAME (aout, final_link) |
(bfd *, struct bfd_link_info *, |
void (*) (bfd *, file_ptr *, file_ptr *, file_ptr *)); |
extern bfd_boolean NAME (aout, bfd_free_cached_info) |
(bfd *); |
#define aout_32_find_inliner_info _bfd_nosymbols_find_inliner_info |
#if 0 /* Are these needed? */ |
#define aout_16_find_inliner_info _bfd_nosymbols_find_inliner_info |
#define aout_64_find_inliner_info _bfd_nosymbols_find_inliner_info |
#endif |
/* A.out uses the generic versions of these routines... */ |
#define aout_16_get_section_contents _bfd_generic_get_section_contents |
#define aout_32_get_section_contents _bfd_generic_get_section_contents |
#define aout_64_get_section_contents _bfd_generic_get_section_contents |
#ifndef NO_WRITE_HEADER_KLUDGE |
#define NO_WRITE_HEADER_KLUDGE 0 |
#endif |
#ifndef aout_32_bfd_is_local_label_name |
#define aout_32_bfd_is_local_label_name bfd_generic_is_local_label_name |
#endif |
#ifndef aout_32_bfd_is_target_special_symbol |
#define aout_32_bfd_is_target_special_symbol \ |
((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) |
#endif |
#ifndef WRITE_HEADERS |
#define WRITE_HEADERS(abfd, execp) \ |
{ \ |
bfd_size_type text_size; /* Dummy vars. */ \ |
file_ptr text_end; \ |
\ |
if (adata(abfd).magic == undecided_magic) \ |
NAME (aout, adjust_sizes_and_vmas) (abfd, & text_size, & text_end); \ |
\ |
execp->a_syms = bfd_get_symcount (abfd) * EXTERNAL_NLIST_SIZE; \ |
execp->a_entry = bfd_get_start_address (abfd); \ |
\ |
execp->a_trsize = ((obj_textsec (abfd)->reloc_count) * \ |
obj_reloc_entry_size (abfd)); \ |
execp->a_drsize = ((obj_datasec (abfd)->reloc_count) * \ |
obj_reloc_entry_size (abfd)); \ |
NAME (aout, swap_exec_header_out) (abfd, execp, & exec_bytes); \ |
\ |
if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 \ |
|| bfd_bwrite (& exec_bytes, (bfd_size_type) EXEC_BYTES_SIZE, \ |
abfd) != EXEC_BYTES_SIZE) \ |
return FALSE; \ |
/* Now write out reloc info, followed by syms and strings. */ \ |
\ |
if (bfd_get_outsymbols (abfd) != NULL \ |
&& bfd_get_symcount (abfd) != 0) \ |
{ \ |
if (bfd_seek (abfd, (file_ptr) (N_SYMOFF(*execp)), SEEK_SET) != 0)\ |
return FALSE; \ |
\ |
if (! NAME (aout, write_syms) (abfd)) \ |
return FALSE; \ |
} \ |
\ |
if (bfd_seek (abfd, (file_ptr) (N_TRELOFF (*execp)), SEEK_SET) != 0) \ |
return FALSE; \ |
if (!NAME (aout, squirt_out_relocs) (abfd, obj_textsec (abfd))) \ |
return FALSE; \ |
\ |
if (bfd_seek (abfd, (file_ptr) (N_DRELOFF (*execp)), SEEK_SET) != 0) \ |
return FALSE; \ |
if (!NAME (aout, squirt_out_relocs) (abfd, obj_datasec (abfd))) \ |
return FALSE; \ |
} |
#endif |
/* Test if a read-only section can be merged with .text. This is |
possible if: |
1. Section has file contents and is read-only. |
2. The VMA of the section is after the end of .text and before |
the start of .data. |
3. The image is demand-pageable (otherwise, a_text in the header |
will not reflect the gap between .text and .data). */ |
#define aout_section_merge_with_text_p(abfd, sec) \ |
(((sec)->flags & (SEC_HAS_CONTENTS | SEC_READONLY)) == \ |
(SEC_HAS_CONTENTS | SEC_READONLY) \ |
&& obj_textsec (abfd) != NULL \ |
&& obj_datasec (abfd) != NULL \ |
&& (sec)->vma >= (obj_textsec (abfd)->vma + \ |
obj_textsec (abfd)->size) \ |
&& ((sec)->vma + (sec)->size) <= obj_datasec (abfd)->vma \ |
&& ((abfd)->flags & D_PAGED) != 0) |
#endif /* ! defined (LIBAOUT_H) */ |
/contrib/toolchain/binutils/bfd/libbfd.c |
---|
0,0 → 1,1141 |
/* Assorted BFD support routines, only used internally. |
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, |
2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011 |
Free Software Foundation, Inc. |
Written by Cygnus Support. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
#ifndef HAVE_GETPAGESIZE |
#define getpagesize() 2048 |
#endif |
/* |
SECTION |
Implementation details |
SUBSECTION |
Internal functions |
DESCRIPTION |
These routines are used within BFD. |
They are not intended for export, but are documented here for |
completeness. |
*/ |
/* A routine which is used in target vectors for unsupported |
operations. */ |
bfd_boolean |
bfd_false (bfd *ignore ATTRIBUTE_UNUSED) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
/* A routine which is used in target vectors for supported operations |
which do not actually do anything. */ |
bfd_boolean |
bfd_true (bfd *ignore ATTRIBUTE_UNUSED) |
{ |
return TRUE; |
} |
/* A routine which is used in target vectors for unsupported |
operations which return a pointer value. */ |
void * |
bfd_nullvoidptr (bfd *ignore ATTRIBUTE_UNUSED) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return NULL; |
} |
int |
bfd_0 (bfd *ignore ATTRIBUTE_UNUSED) |
{ |
return 0; |
} |
unsigned int |
bfd_0u (bfd *ignore ATTRIBUTE_UNUSED) |
{ |
return 0; |
} |
long |
bfd_0l (bfd *ignore ATTRIBUTE_UNUSED) |
{ |
return 0; |
} |
/* A routine which is used in target vectors for unsupported |
operations which return -1 on error. */ |
long |
_bfd_n1 (bfd *ignore_abfd ATTRIBUTE_UNUSED) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return -1; |
} |
void |
bfd_void (bfd *ignore ATTRIBUTE_UNUSED) |
{ |
} |
long |
_bfd_norelocs_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED, |
asection *sec ATTRIBUTE_UNUSED) |
{ |
return sizeof (arelent *); |
} |
long |
_bfd_norelocs_canonicalize_reloc (bfd *abfd ATTRIBUTE_UNUSED, |
asection *sec ATTRIBUTE_UNUSED, |
arelent **relptr, |
asymbol **symbols ATTRIBUTE_UNUSED) |
{ |
*relptr = NULL; |
return 0; |
} |
bfd_boolean |
_bfd_nocore_core_file_matches_executable_p |
(bfd *ignore_core_bfd ATTRIBUTE_UNUSED, |
bfd *ignore_exec_bfd ATTRIBUTE_UNUSED) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
/* Routine to handle core_file_failing_command entry point for targets |
without core file support. */ |
char * |
_bfd_nocore_core_file_failing_command (bfd *ignore_abfd ATTRIBUTE_UNUSED) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return NULL; |
} |
/* Routine to handle core_file_failing_signal entry point for targets |
without core file support. */ |
int |
_bfd_nocore_core_file_failing_signal (bfd *ignore_abfd ATTRIBUTE_UNUSED) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return 0; |
} |
/* Routine to handle the core_file_pid entry point for targets without |
core file support. */ |
int |
_bfd_nocore_core_file_pid (bfd *ignore_abfd ATTRIBUTE_UNUSED) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return 0; |
} |
const bfd_target * |
_bfd_dummy_target (bfd *ignore_abfd ATTRIBUTE_UNUSED) |
{ |
bfd_set_error (bfd_error_wrong_format); |
return 0; |
} |
/* Allocate memory using malloc. */ |
void * |
bfd_malloc (bfd_size_type size) |
{ |
void *ptr; |
if (size != (size_t) size) |
{ |
bfd_set_error (bfd_error_no_memory); |
return NULL; |
} |
ptr = malloc ((size_t) size); |
if (ptr == NULL && (size_t) size != 0) |
bfd_set_error (bfd_error_no_memory); |
return ptr; |
} |
/* Allocate memory using malloc, nmemb * size with overflow checking. */ |
void * |
bfd_malloc2 (bfd_size_type nmemb, bfd_size_type size) |
{ |
void *ptr; |
if ((nmemb | size) >= HALF_BFD_SIZE_TYPE |
&& size != 0 |
&& nmemb > ~(bfd_size_type) 0 / size) |
{ |
bfd_set_error (bfd_error_no_memory); |
return NULL; |
} |
size *= nmemb; |
if (size != (size_t) size) |
{ |
bfd_set_error (bfd_error_no_memory); |
return NULL; |
} |
ptr = malloc ((size_t) size); |
if (ptr == NULL && (size_t) size != 0) |
bfd_set_error (bfd_error_no_memory); |
return ptr; |
} |
/* Reallocate memory using realloc. */ |
void * |
bfd_realloc (void *ptr, bfd_size_type size) |
{ |
void *ret; |
if (size != (size_t) size) |
{ |
bfd_set_error (bfd_error_no_memory); |
return NULL; |
} |
if (ptr == NULL) |
ret = malloc ((size_t) size); |
else |
ret = realloc (ptr, (size_t) size); |
if (ret == NULL && (size_t) size != 0) |
bfd_set_error (bfd_error_no_memory); |
return ret; |
} |
/* Reallocate memory using realloc, nmemb * size with overflow checking. */ |
void * |
bfd_realloc2 (void *ptr, bfd_size_type nmemb, bfd_size_type size) |
{ |
void *ret; |
if ((nmemb | size) >= HALF_BFD_SIZE_TYPE |
&& size != 0 |
&& nmemb > ~(bfd_size_type) 0 / size) |
{ |
bfd_set_error (bfd_error_no_memory); |
return NULL; |
} |
size *= nmemb; |
if (size != (size_t) size) |
{ |
bfd_set_error (bfd_error_no_memory); |
return NULL; |
} |
if (ptr == NULL) |
ret = malloc ((size_t) size); |
else |
ret = realloc (ptr, (size_t) size); |
if (ret == NULL && (size_t) size != 0) |
bfd_set_error (bfd_error_no_memory); |
return ret; |
} |
/* Reallocate memory using realloc. |
If this fails the pointer is freed before returning. */ |
void * |
bfd_realloc_or_free (void *ptr, bfd_size_type size) |
{ |
size_t amount = (size_t) size; |
void *ret; |
if (size != amount) |
ret = NULL; |
else if (ptr == NULL) |
ret = malloc (amount); |
else |
ret = realloc (ptr, amount); |
if (ret == NULL) |
{ |
if (amount > 0) |
bfd_set_error (bfd_error_no_memory); |
if (ptr != NULL) |
free (ptr); |
} |
return ret; |
} |
/* Allocate memory using malloc and clear it. */ |
void * |
bfd_zmalloc (bfd_size_type size) |
{ |
void *ptr; |
if (size != (size_t) size) |
{ |
bfd_set_error (bfd_error_no_memory); |
return NULL; |
} |
ptr = malloc ((size_t) size); |
if ((size_t) size != 0) |
{ |
if (ptr == NULL) |
bfd_set_error (bfd_error_no_memory); |
else |
memset (ptr, 0, (size_t) size); |
} |
return ptr; |
} |
/* Allocate memory using malloc (nmemb * size) with overflow checking |
and clear it. */ |
void * |
bfd_zmalloc2 (bfd_size_type nmemb, bfd_size_type size) |
{ |
void *ptr; |
if ((nmemb | size) >= HALF_BFD_SIZE_TYPE |
&& size != 0 |
&& nmemb > ~(bfd_size_type) 0 / size) |
{ |
bfd_set_error (bfd_error_no_memory); |
return NULL; |
} |
size *= nmemb; |
if (size != (size_t) size) |
{ |
bfd_set_error (bfd_error_no_memory); |
return NULL; |
} |
ptr = malloc ((size_t) size); |
if ((size_t) size != 0) |
{ |
if (ptr == NULL) |
bfd_set_error (bfd_error_no_memory); |
else |
memset (ptr, 0, (size_t) size); |
} |
return ptr; |
} |
/* |
INTERNAL_FUNCTION |
bfd_write_bigendian_4byte_int |
SYNOPSIS |
bfd_boolean bfd_write_bigendian_4byte_int (bfd *, unsigned int); |
DESCRIPTION |
Write a 4 byte integer @var{i} to the output BFD @var{abfd}, in big |
endian order regardless of what else is going on. This is useful in |
archives. |
*/ |
bfd_boolean |
bfd_write_bigendian_4byte_int (bfd *abfd, unsigned int i) |
{ |
bfd_byte buffer[4]; |
bfd_putb32 ((bfd_vma) i, buffer); |
return bfd_bwrite (buffer, (bfd_size_type) 4, abfd) == 4; |
} |
/** The do-it-yourself (byte) sex-change kit */ |
/* The middle letter e.g. get<b>short indicates Big or Little endian |
target machine. It doesn't matter what the byte order of the host |
machine is; these routines work for either. */ |
/* FIXME: Should these take a count argument? |
Answer (gnu@cygnus.com): No, but perhaps they should be inline |
functions in swap.h #ifdef __GNUC__. |
Gprof them later and find out. */ |
/* |
FUNCTION |
bfd_put_size |
FUNCTION |
bfd_get_size |
DESCRIPTION |
These macros as used for reading and writing raw data in |
sections; each access (except for bytes) is vectored through |
the target format of the BFD and mangled accordingly. The |
mangling performs any necessary endian translations and |
removes alignment restrictions. Note that types accepted and |
returned by these macros are identical so they can be swapped |
around in macros---for example, @file{libaout.h} defines <<GET_WORD>> |
to either <<bfd_get_32>> or <<bfd_get_64>>. |
In the put routines, @var{val} must be a <<bfd_vma>>. If we are on a |
system without prototypes, the caller is responsible for making |
sure that is true, with a cast if necessary. We don't cast |
them in the macro definitions because that would prevent <<lint>> |
or <<gcc -Wall>> from detecting sins such as passing a pointer. |
To detect calling these with less than a <<bfd_vma>>, use |
<<gcc -Wconversion>> on a host with 64 bit <<bfd_vma>>'s. |
. |
.{* Byte swapping macros for user section data. *} |
. |
.#define bfd_put_8(abfd, val, ptr) \ |
. ((void) (*((unsigned char *) (ptr)) = (val) & 0xff)) |
.#define bfd_put_signed_8 \ |
. bfd_put_8 |
.#define bfd_get_8(abfd, ptr) \ |
. (*(const unsigned char *) (ptr) & 0xff) |
.#define bfd_get_signed_8(abfd, ptr) \ |
. (((*(const unsigned char *) (ptr) & 0xff) ^ 0x80) - 0x80) |
. |
.#define bfd_put_16(abfd, val, ptr) \ |
. BFD_SEND (abfd, bfd_putx16, ((val),(ptr))) |
.#define bfd_put_signed_16 \ |
. bfd_put_16 |
.#define bfd_get_16(abfd, ptr) \ |
. BFD_SEND (abfd, bfd_getx16, (ptr)) |
.#define bfd_get_signed_16(abfd, ptr) \ |
. BFD_SEND (abfd, bfd_getx_signed_16, (ptr)) |
. |
.#define bfd_put_32(abfd, val, ptr) \ |
. BFD_SEND (abfd, bfd_putx32, ((val),(ptr))) |
.#define bfd_put_signed_32 \ |
. bfd_put_32 |
.#define bfd_get_32(abfd, ptr) \ |
. BFD_SEND (abfd, bfd_getx32, (ptr)) |
.#define bfd_get_signed_32(abfd, ptr) \ |
. BFD_SEND (abfd, bfd_getx_signed_32, (ptr)) |
. |
.#define bfd_put_64(abfd, val, ptr) \ |
. BFD_SEND (abfd, bfd_putx64, ((val), (ptr))) |
.#define bfd_put_signed_64 \ |
. bfd_put_64 |
.#define bfd_get_64(abfd, ptr) \ |
. BFD_SEND (abfd, bfd_getx64, (ptr)) |
.#define bfd_get_signed_64(abfd, ptr) \ |
. BFD_SEND (abfd, bfd_getx_signed_64, (ptr)) |
. |
.#define bfd_get(bits, abfd, ptr) \ |
. ((bits) == 8 ? (bfd_vma) bfd_get_8 (abfd, ptr) \ |
. : (bits) == 16 ? bfd_get_16 (abfd, ptr) \ |
. : (bits) == 32 ? bfd_get_32 (abfd, ptr) \ |
. : (bits) == 64 ? bfd_get_64 (abfd, ptr) \ |
. : (abort (), (bfd_vma) - 1)) |
. |
.#define bfd_put(bits, abfd, val, ptr) \ |
. ((bits) == 8 ? bfd_put_8 (abfd, val, ptr) \ |
. : (bits) == 16 ? bfd_put_16 (abfd, val, ptr) \ |
. : (bits) == 32 ? bfd_put_32 (abfd, val, ptr) \ |
. : (bits) == 64 ? bfd_put_64 (abfd, val, ptr) \ |
. : (abort (), (void) 0)) |
. |
*/ |
/* |
FUNCTION |
bfd_h_put_size |
bfd_h_get_size |
DESCRIPTION |
These macros have the same function as their <<bfd_get_x>> |
brethren, except that they are used for removing information |
for the header records of object files. Believe it or not, |
some object files keep their header records in big endian |
order and their data in little endian order. |
. |
.{* Byte swapping macros for file header data. *} |
. |
.#define bfd_h_put_8(abfd, val, ptr) \ |
. bfd_put_8 (abfd, val, ptr) |
.#define bfd_h_put_signed_8(abfd, val, ptr) \ |
. bfd_put_8 (abfd, val, ptr) |
.#define bfd_h_get_8(abfd, ptr) \ |
. bfd_get_8 (abfd, ptr) |
.#define bfd_h_get_signed_8(abfd, ptr) \ |
. bfd_get_signed_8 (abfd, ptr) |
. |
.#define bfd_h_put_16(abfd, val, ptr) \ |
. BFD_SEND (abfd, bfd_h_putx16, (val, ptr)) |
.#define bfd_h_put_signed_16 \ |
. bfd_h_put_16 |
.#define bfd_h_get_16(abfd, ptr) \ |
. BFD_SEND (abfd, bfd_h_getx16, (ptr)) |
.#define bfd_h_get_signed_16(abfd, ptr) \ |
. BFD_SEND (abfd, bfd_h_getx_signed_16, (ptr)) |
. |
.#define bfd_h_put_32(abfd, val, ptr) \ |
. BFD_SEND (abfd, bfd_h_putx32, (val, ptr)) |
.#define bfd_h_put_signed_32 \ |
. bfd_h_put_32 |
.#define bfd_h_get_32(abfd, ptr) \ |
. BFD_SEND (abfd, bfd_h_getx32, (ptr)) |
.#define bfd_h_get_signed_32(abfd, ptr) \ |
. BFD_SEND (abfd, bfd_h_getx_signed_32, (ptr)) |
. |
.#define bfd_h_put_64(abfd, val, ptr) \ |
. BFD_SEND (abfd, bfd_h_putx64, (val, ptr)) |
.#define bfd_h_put_signed_64 \ |
. bfd_h_put_64 |
.#define bfd_h_get_64(abfd, ptr) \ |
. BFD_SEND (abfd, bfd_h_getx64, (ptr)) |
.#define bfd_h_get_signed_64(abfd, ptr) \ |
. BFD_SEND (abfd, bfd_h_getx_signed_64, (ptr)) |
. |
.{* Aliases for the above, which should eventually go away. *} |
. |
.#define H_PUT_64 bfd_h_put_64 |
.#define H_PUT_32 bfd_h_put_32 |
.#define H_PUT_16 bfd_h_put_16 |
.#define H_PUT_8 bfd_h_put_8 |
.#define H_PUT_S64 bfd_h_put_signed_64 |
.#define H_PUT_S32 bfd_h_put_signed_32 |
.#define H_PUT_S16 bfd_h_put_signed_16 |
.#define H_PUT_S8 bfd_h_put_signed_8 |
.#define H_GET_64 bfd_h_get_64 |
.#define H_GET_32 bfd_h_get_32 |
.#define H_GET_16 bfd_h_get_16 |
.#define H_GET_8 bfd_h_get_8 |
.#define H_GET_S64 bfd_h_get_signed_64 |
.#define H_GET_S32 bfd_h_get_signed_32 |
.#define H_GET_S16 bfd_h_get_signed_16 |
.#define H_GET_S8 bfd_h_get_signed_8 |
. |
.*/ |
/* Sign extension to bfd_signed_vma. */ |
#define COERCE16(x) (((bfd_signed_vma) (x) ^ 0x8000) - 0x8000) |
#define COERCE32(x) (((bfd_signed_vma) (x) ^ 0x80000000) - 0x80000000) |
#define EIGHT_GAZILLION ((bfd_int64_t) 1 << 63) |
#define COERCE64(x) \ |
(((bfd_int64_t) (x) ^ EIGHT_GAZILLION) - EIGHT_GAZILLION) |
bfd_vma |
bfd_getb16 (const void *p) |
{ |
const bfd_byte *addr = (const bfd_byte *) p; |
return (addr[0] << 8) | addr[1]; |
} |
bfd_vma |
bfd_getl16 (const void *p) |
{ |
const bfd_byte *addr = (const bfd_byte *) p; |
return (addr[1] << 8) | addr[0]; |
} |
bfd_signed_vma |
bfd_getb_signed_16 (const void *p) |
{ |
const bfd_byte *addr = (const bfd_byte *) p; |
return COERCE16 ((addr[0] << 8) | addr[1]); |
} |
bfd_signed_vma |
bfd_getl_signed_16 (const void *p) |
{ |
const bfd_byte *addr = (const bfd_byte *) p; |
return COERCE16 ((addr[1] << 8) | addr[0]); |
} |
void |
bfd_putb16 (bfd_vma data, void *p) |
{ |
bfd_byte *addr = (bfd_byte *) p; |
addr[0] = (data >> 8) & 0xff; |
addr[1] = data & 0xff; |
} |
void |
bfd_putl16 (bfd_vma data, void *p) |
{ |
bfd_byte *addr = (bfd_byte *) p; |
addr[0] = data & 0xff; |
addr[1] = (data >> 8) & 0xff; |
} |
bfd_vma |
bfd_getb32 (const void *p) |
{ |
const bfd_byte *addr = (const bfd_byte *) p; |
unsigned long v; |
v = (unsigned long) addr[0] << 24; |
v |= (unsigned long) addr[1] << 16; |
v |= (unsigned long) addr[2] << 8; |
v |= (unsigned long) addr[3]; |
return v; |
} |
bfd_vma |
bfd_getl32 (const void *p) |
{ |
const bfd_byte *addr = (const bfd_byte *) p; |
unsigned long v; |
v = (unsigned long) addr[0]; |
v |= (unsigned long) addr[1] << 8; |
v |= (unsigned long) addr[2] << 16; |
v |= (unsigned long) addr[3] << 24; |
return v; |
} |
bfd_signed_vma |
bfd_getb_signed_32 (const void *p) |
{ |
const bfd_byte *addr = (const bfd_byte *) p; |
unsigned long v; |
v = (unsigned long) addr[0] << 24; |
v |= (unsigned long) addr[1] << 16; |
v |= (unsigned long) addr[2] << 8; |
v |= (unsigned long) addr[3]; |
return COERCE32 (v); |
} |
bfd_signed_vma |
bfd_getl_signed_32 (const void *p) |
{ |
const bfd_byte *addr = (const bfd_byte *) p; |
unsigned long v; |
v = (unsigned long) addr[0]; |
v |= (unsigned long) addr[1] << 8; |
v |= (unsigned long) addr[2] << 16; |
v |= (unsigned long) addr[3] << 24; |
return COERCE32 (v); |
} |
bfd_uint64_t |
bfd_getb64 (const void *p ATTRIBUTE_UNUSED) |
{ |
#ifdef BFD_HOST_64_BIT |
const bfd_byte *addr = (const bfd_byte *) p; |
bfd_uint64_t v; |
v = addr[0]; v <<= 8; |
v |= addr[1]; v <<= 8; |
v |= addr[2]; v <<= 8; |
v |= addr[3]; v <<= 8; |
v |= addr[4]; v <<= 8; |
v |= addr[5]; v <<= 8; |
v |= addr[6]; v <<= 8; |
v |= addr[7]; |
return v; |
#else |
BFD_FAIL(); |
return 0; |
#endif |
} |
bfd_uint64_t |
bfd_getl64 (const void *p ATTRIBUTE_UNUSED) |
{ |
#ifdef BFD_HOST_64_BIT |
const bfd_byte *addr = (const bfd_byte *) p; |
bfd_uint64_t v; |
v = addr[7]; v <<= 8; |
v |= addr[6]; v <<= 8; |
v |= addr[5]; v <<= 8; |
v |= addr[4]; v <<= 8; |
v |= addr[3]; v <<= 8; |
v |= addr[2]; v <<= 8; |
v |= addr[1]; v <<= 8; |
v |= addr[0]; |
return v; |
#else |
BFD_FAIL(); |
return 0; |
#endif |
} |
bfd_int64_t |
bfd_getb_signed_64 (const void *p ATTRIBUTE_UNUSED) |
{ |
#ifdef BFD_HOST_64_BIT |
const bfd_byte *addr = (const bfd_byte *) p; |
bfd_uint64_t v; |
v = addr[0]; v <<= 8; |
v |= addr[1]; v <<= 8; |
v |= addr[2]; v <<= 8; |
v |= addr[3]; v <<= 8; |
v |= addr[4]; v <<= 8; |
v |= addr[5]; v <<= 8; |
v |= addr[6]; v <<= 8; |
v |= addr[7]; |
return COERCE64 (v); |
#else |
BFD_FAIL(); |
return 0; |
#endif |
} |
bfd_int64_t |
bfd_getl_signed_64 (const void *p ATTRIBUTE_UNUSED) |
{ |
#ifdef BFD_HOST_64_BIT |
const bfd_byte *addr = (const bfd_byte *) p; |
bfd_uint64_t v; |
v = addr[7]; v <<= 8; |
v |= addr[6]; v <<= 8; |
v |= addr[5]; v <<= 8; |
v |= addr[4]; v <<= 8; |
v |= addr[3]; v <<= 8; |
v |= addr[2]; v <<= 8; |
v |= addr[1]; v <<= 8; |
v |= addr[0]; |
return COERCE64 (v); |
#else |
BFD_FAIL(); |
return 0; |
#endif |
} |
void |
bfd_putb32 (bfd_vma data, void *p) |
{ |
bfd_byte *addr = (bfd_byte *) p; |
addr[0] = (data >> 24) & 0xff; |
addr[1] = (data >> 16) & 0xff; |
addr[2] = (data >> 8) & 0xff; |
addr[3] = data & 0xff; |
} |
void |
bfd_putl32 (bfd_vma data, void *p) |
{ |
bfd_byte *addr = (bfd_byte *) p; |
addr[0] = data & 0xff; |
addr[1] = (data >> 8) & 0xff; |
addr[2] = (data >> 16) & 0xff; |
addr[3] = (data >> 24) & 0xff; |
} |
void |
bfd_putb64 (bfd_uint64_t data ATTRIBUTE_UNUSED, void *p ATTRIBUTE_UNUSED) |
{ |
#ifdef BFD_HOST_64_BIT |
bfd_byte *addr = (bfd_byte *) p; |
addr[0] = (data >> (7*8)) & 0xff; |
addr[1] = (data >> (6*8)) & 0xff; |
addr[2] = (data >> (5*8)) & 0xff; |
addr[3] = (data >> (4*8)) & 0xff; |
addr[4] = (data >> (3*8)) & 0xff; |
addr[5] = (data >> (2*8)) & 0xff; |
addr[6] = (data >> (1*8)) & 0xff; |
addr[7] = (data >> (0*8)) & 0xff; |
#else |
BFD_FAIL(); |
#endif |
} |
void |
bfd_putl64 (bfd_uint64_t data ATTRIBUTE_UNUSED, void *p ATTRIBUTE_UNUSED) |
{ |
#ifdef BFD_HOST_64_BIT |
bfd_byte *addr = (bfd_byte *) p; |
addr[7] = (data >> (7*8)) & 0xff; |
addr[6] = (data >> (6*8)) & 0xff; |
addr[5] = (data >> (5*8)) & 0xff; |
addr[4] = (data >> (4*8)) & 0xff; |
addr[3] = (data >> (3*8)) & 0xff; |
addr[2] = (data >> (2*8)) & 0xff; |
addr[1] = (data >> (1*8)) & 0xff; |
addr[0] = (data >> (0*8)) & 0xff; |
#else |
BFD_FAIL(); |
#endif |
} |
void |
bfd_put_bits (bfd_uint64_t data, void *p, int bits, bfd_boolean big_p) |
{ |
bfd_byte *addr = (bfd_byte *) p; |
int i; |
int bytes; |
if (bits % 8 != 0) |
abort (); |
bytes = bits / 8; |
for (i = 0; i < bytes; i++) |
{ |
int addr_index = big_p ? bytes - i - 1 : i; |
addr[addr_index] = data & 0xff; |
data >>= 8; |
} |
} |
bfd_uint64_t |
bfd_get_bits (const void *p, int bits, bfd_boolean big_p) |
{ |
const bfd_byte *addr = (const bfd_byte *) p; |
bfd_uint64_t data; |
int i; |
int bytes; |
if (bits % 8 != 0) |
abort (); |
data = 0; |
bytes = bits / 8; |
for (i = 0; i < bytes; i++) |
{ |
int addr_index = big_p ? i : bytes - i - 1; |
data = (data << 8) | addr[addr_index]; |
} |
return data; |
} |
/* Default implementation */ |
bfd_boolean |
_bfd_generic_get_section_contents (bfd *abfd, |
sec_ptr section, |
void *location, |
file_ptr offset, |
bfd_size_type count) |
{ |
bfd_size_type sz; |
if (count == 0) |
return TRUE; |
if (section->compress_status != COMPRESS_SECTION_NONE) |
{ |
(*_bfd_error_handler) |
(_("%B: unable to get decompressed section %A"), |
abfd, section); |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
/* We do allow reading of a section after bfd_final_link has |
written the contents out to disk. In that situation, rawsize is |
just a stale version of size, so ignore it. Otherwise we must be |
reading an input section, where rawsize, if different to size, |
is the on-disk size. */ |
if (abfd->direction != write_direction && section->rawsize != 0) |
sz = section->rawsize; |
else |
sz = section->size; |
if (offset + count < count |
|| offset + count > sz) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0 |
|| bfd_bread (location, count, abfd) != count) |
return FALSE; |
return TRUE; |
} |
bfd_boolean |
_bfd_generic_get_section_contents_in_window |
(bfd *abfd ATTRIBUTE_UNUSED, |
sec_ptr section ATTRIBUTE_UNUSED, |
bfd_window *w ATTRIBUTE_UNUSED, |
file_ptr offset ATTRIBUTE_UNUSED, |
bfd_size_type count ATTRIBUTE_UNUSED) |
{ |
#ifdef USE_MMAP |
bfd_size_type sz; |
if (count == 0) |
return TRUE; |
if (abfd->xvec->_bfd_get_section_contents |
!= _bfd_generic_get_section_contents) |
{ |
/* We don't know what changes the bfd's get_section_contents |
method may have to make. So punt trying to map the file |
window, and let get_section_contents do its thing. */ |
/* @@ FIXME : If the internal window has a refcount of 1 and was |
allocated with malloc instead of mmap, just reuse it. */ |
bfd_free_window (w); |
w->i = bfd_zmalloc (sizeof (bfd_window_internal)); |
if (w->i == NULL) |
return FALSE; |
w->i->data = bfd_malloc (count); |
if (w->i->data == NULL) |
{ |
free (w->i); |
w->i = NULL; |
return FALSE; |
} |
w->i->mapped = 0; |
w->i->refcount = 1; |
w->size = w->i->size = count; |
w->data = w->i->data; |
return bfd_get_section_contents (abfd, section, w->data, offset, count); |
} |
if (abfd->direction != write_direction && section->rawsize != 0) |
sz = section->rawsize; |
else |
sz = section->size; |
if (offset + count > sz |
|| ! bfd_get_file_window (abfd, section->filepos + offset, count, w, |
TRUE)) |
return FALSE; |
return TRUE; |
#else |
abort (); |
#endif |
} |
/* This generic function can only be used in implementations where creating |
NEW sections is disallowed. It is useful in patching existing sections |
in read-write files, though. See other set_section_contents functions |
to see why it doesn't work for new sections. */ |
bfd_boolean |
_bfd_generic_set_section_contents (bfd *abfd, |
sec_ptr section, |
const void *location, |
file_ptr offset, |
bfd_size_type count) |
{ |
if (count == 0) |
return TRUE; |
if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0 |
|| bfd_bwrite (location, count, abfd) != count) |
return FALSE; |
return TRUE; |
} |
/* |
INTERNAL_FUNCTION |
bfd_log2 |
SYNOPSIS |
unsigned int bfd_log2 (bfd_vma x); |
DESCRIPTION |
Return the log base 2 of the value supplied, rounded up. E.g., an |
@var{x} of 1025 returns 11. A @var{x} of 0 returns 0. |
*/ |
unsigned int |
bfd_log2 (bfd_vma x) |
{ |
unsigned int result = 0; |
if (x <= 1) |
return result; |
--x; |
do |
++result; |
while ((x >>= 1) != 0); |
return result; |
} |
bfd_boolean |
bfd_generic_is_local_label_name (bfd *abfd, const char *name) |
{ |
char locals_prefix = (bfd_get_symbol_leading_char (abfd) == '_') ? 'L' : '.'; |
return name[0] == locals_prefix; |
} |
/* Can be used from / for bfd_merge_private_bfd_data to check that |
endianness matches between input and output file. Returns |
TRUE for a match, otherwise returns FALSE and emits an error. */ |
bfd_boolean |
_bfd_generic_verify_endian_match (bfd *ibfd, bfd *obfd) |
{ |
if (ibfd->xvec->byteorder != obfd->xvec->byteorder |
&& ibfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN |
&& obfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN) |
{ |
const char *msg; |
if (bfd_big_endian (ibfd)) |
msg = _("%B: compiled for a big endian system and target is little endian"); |
else |
msg = _("%B: compiled for a little endian system and target is big endian"); |
(*_bfd_error_handler) (msg, ibfd); |
bfd_set_error (bfd_error_wrong_format); |
return FALSE; |
} |
return TRUE; |
} |
/* Give a warning at runtime if someone compiles code which calls |
old routines. */ |
void |
warn_deprecated (const char *what, |
const char *file, |
int line, |
const char *func) |
{ |
/* Poor man's tracking of functions we've already warned about. */ |
static size_t mask = 0; |
if (~(size_t) func & ~mask) |
{ |
fflush (stdout); |
/* Note: separate sentences in order to allow |
for translation into other languages. */ |
if (func) |
fprintf (stderr, _("Deprecated %s called at %s line %d in %s\n"), |
what, file, line, func); |
else |
fprintf (stderr, _("Deprecated %s called\n"), what); |
fflush (stderr); |
mask |= ~(size_t) func; |
} |
} |
/* Helper function for reading uleb128 encoded data. */ |
bfd_vma |
read_unsigned_leb128 (bfd *abfd ATTRIBUTE_UNUSED, |
bfd_byte *buf, |
unsigned int *bytes_read_ptr) |
{ |
bfd_vma result; |
unsigned int num_read; |
unsigned int shift; |
unsigned char byte; |
result = 0; |
shift = 0; |
num_read = 0; |
do |
{ |
byte = bfd_get_8 (abfd, buf); |
buf++; |
num_read++; |
result |= (((bfd_vma) byte & 0x7f) << shift); |
shift += 7; |
} |
while (byte & 0x80); |
*bytes_read_ptr = num_read; |
return result; |
} |
/* Helper function for reading sleb128 encoded data. */ |
bfd_signed_vma |
read_signed_leb128 (bfd *abfd ATTRIBUTE_UNUSED, |
bfd_byte *buf, |
unsigned int *bytes_read_ptr) |
{ |
bfd_vma result; |
unsigned int shift; |
unsigned int num_read; |
unsigned char byte; |
result = 0; |
shift = 0; |
num_read = 0; |
do |
{ |
byte = bfd_get_8 (abfd, buf); |
buf ++; |
num_read ++; |
result |= (((bfd_vma) byte & 0x7f) << shift); |
shift += 7; |
} |
while (byte & 0x80); |
if (shift < 8 * sizeof (result) && (byte & 0x40)) |
result |= (((bfd_vma) -1) << shift); |
*bytes_read_ptr = num_read; |
return result; |
} |
bfd_boolean |
_bfd_generic_find_line (bfd *abfd ATTRIBUTE_UNUSED, |
asymbol **symbols ATTRIBUTE_UNUSED, |
asymbol *symbol ATTRIBUTE_UNUSED, |
const char **filename_ptr ATTRIBUTE_UNUSED, |
unsigned int *linenumber_ptr ATTRIBUTE_UNUSED) |
{ |
return FALSE; |
} |
bfd_boolean |
_bfd_generic_find_nearest_line_discriminator (bfd *abfd ATTRIBUTE_UNUSED, |
asection *section ATTRIBUTE_UNUSED, |
asymbol **symbols ATTRIBUTE_UNUSED, |
bfd_vma offset ATTRIBUTE_UNUSED, |
const char **filename_ptr ATTRIBUTE_UNUSED, |
const char **functionname_ptr ATTRIBUTE_UNUSED, |
unsigned int *line_ptr ATTRIBUTE_UNUSED, |
unsigned int *discriminator_ptr ATTRIBUTE_UNUSED) |
{ |
return FALSE; |
} |
bfd_boolean |
_bfd_generic_init_private_section_data (bfd *ibfd ATTRIBUTE_UNUSED, |
asection *isec ATTRIBUTE_UNUSED, |
bfd *obfd ATTRIBUTE_UNUSED, |
asection *osec ATTRIBUTE_UNUSED, |
struct bfd_link_info *link_info ATTRIBUTE_UNUSED) |
{ |
return TRUE; |
} |
/contrib/toolchain/binutils/bfd/libbfd.h |
---|
0,0 → 1,2857 |
/* DO NOT EDIT! -*- buffer-read-only: t -*- This file is automatically |
generated from "libbfd-in.h", "init.c", "libbfd.c", "bfdio.c", |
"bfdwin.c", "cache.c", "reloc.c", "archures.c" and "elf.c". |
Run "make headers" in your build bfd/ to regenerate. */ |
/* libbfd.h -- Declarations used by bfd library *implementation*. |
(This include file is not for users of the library.) |
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, |
1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, |
2010, 2011, 2012 |
Free Software Foundation, Inc. |
Written by Cygnus Support. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "hashtab.h" |
/* Align an address upward to a boundary, expressed as a number of bytes. |
E.g. align to an 8-byte boundary with argument of 8. Take care never |
to wrap around if the address is within boundary-1 of the end of the |
address space. */ |
#define BFD_ALIGN(this, boundary) \ |
((((bfd_vma) (this) + (boundary) - 1) >= (bfd_vma) (this)) \ |
? (((bfd_vma) (this) + ((boundary) - 1)) & ~ (bfd_vma) ((boundary)-1)) \ |
: ~ (bfd_vma) 0) |
/* If you want to read and write large blocks, you might want to do it |
in quanta of this amount */ |
#define DEFAULT_BUFFERSIZE 8192 |
/* Set a tdata field. Can't use the other macros for this, since they |
do casts, and casting to the left of assignment isn't portable. */ |
#define set_tdata(bfd, v) ((bfd)->tdata.any = (v)) |
/* If BFD_IN_MEMORY is set for a BFD, then the iostream fields points |
to an instance of this structure. */ |
struct bfd_in_memory |
{ |
/* Size of buffer. */ |
bfd_size_type size; |
/* Buffer holding contents of BFD. */ |
bfd_byte *buffer; |
}; |
struct section_hash_entry |
{ |
struct bfd_hash_entry root; |
asection section; |
}; |
/* tdata for an archive. For an input archive, cache |
needs to be free()'d. For an output archive, symdefs do. */ |
struct artdata |
{ |
file_ptr first_file_filepos; |
/* Speed up searching the armap */ |
htab_t cache; |
bfd *archive_head; /* Only interesting in output routines. */ |
carsym *symdefs; /* The symdef entries. */ |
symindex symdef_count; /* How many there are. */ |
char *extended_names; /* Clever intel extension. */ |
bfd_size_type extended_names_size; /* Size of extended names. */ |
/* When more compilers are standard C, this can be a time_t. */ |
long armap_timestamp; /* Timestamp value written into armap. |
This is used for BSD archives to check |
that the timestamp is recent enough |
for the BSD linker to not complain, |
just before we finish writing an |
archive. */ |
file_ptr armap_datepos; /* Position within archive to seek to |
rewrite the date field. */ |
void *tdata; /* Backend specific information. */ |
}; |
#define bfd_ardata(bfd) ((bfd)->tdata.aout_ar_data) |
/* Goes in bfd's arelt_data slot */ |
struct areltdata |
{ |
char * arch_header; /* It's actually a string. */ |
bfd_size_type parsed_size; /* Octets of filesize not including ar_hdr. */ |
bfd_size_type extra_size; /* BSD4.4: extra bytes after the header. */ |
char *filename; /* Null-terminated. */ |
file_ptr origin; /* For element of a thin archive. */ |
void *parent_cache; /* Where and how to find this member. */ |
file_ptr key; |
}; |
#define arelt_size(bfd) (((struct areltdata *)((bfd)->arelt_data))->parsed_size) |
extern void *bfd_malloc |
(bfd_size_type); |
extern void *bfd_realloc |
(void *, bfd_size_type); |
extern void *bfd_realloc_or_free |
(void *, bfd_size_type); |
extern void *bfd_zmalloc |
(bfd_size_type); |
extern void *bfd_malloc2 |
(bfd_size_type, bfd_size_type); |
extern void *bfd_realloc2 |
(void *, bfd_size_type, bfd_size_type); |
extern void *bfd_zmalloc2 |
(bfd_size_type, bfd_size_type); |
extern void _bfd_default_error_handler (const char *s, ...); |
extern bfd_error_handler_type _bfd_error_handler; |
extern bfd_assert_handler_type _bfd_assert_handler; |
/* These routines allocate and free things on the BFD's objalloc. */ |
extern void *bfd_alloc2 |
(bfd *, bfd_size_type, bfd_size_type); |
extern void *bfd_zalloc2 |
(bfd *, bfd_size_type, bfd_size_type); |
extern void bfd_release |
(bfd *, void *); |
bfd * _bfd_create_empty_archive_element_shell |
(bfd *obfd); |
bfd * _bfd_look_for_bfd_in_cache |
(bfd *, file_ptr); |
bfd_boolean _bfd_add_bfd_to_archive_cache |
(bfd *, file_ptr, bfd *); |
bfd_boolean _bfd_generic_mkarchive |
(bfd *abfd); |
char *_bfd_append_relative_path |
(bfd *arch, char *elt_name); |
const bfd_target *bfd_generic_archive_p |
(bfd *abfd); |
bfd_boolean bfd_slurp_armap |
(bfd *abfd); |
bfd_boolean bfd_slurp_bsd_armap_f2 |
(bfd *abfd); |
#define bfd_slurp_bsd_armap bfd_slurp_armap |
#define bfd_slurp_coff_armap bfd_slurp_armap |
bfd_boolean _bfd_slurp_extended_name_table |
(bfd *abfd); |
extern bfd_boolean _bfd_construct_extended_name_table |
(bfd *, bfd_boolean, char **, bfd_size_type *); |
bfd_boolean _bfd_write_archive_contents |
(bfd *abfd); |
bfd_boolean _bfd_compute_and_write_armap |
(bfd *, unsigned int elength); |
bfd *_bfd_get_elt_at_filepos |
(bfd *archive, file_ptr filepos); |
extern bfd *_bfd_generic_get_elt_at_index |
(bfd *, symindex); |
bfd * _bfd_new_bfd |
(void); |
bfd_boolean _bfd_free_cached_info |
(bfd *); |
bfd_boolean bfd_false |
(bfd *ignore); |
bfd_boolean bfd_true |
(bfd *ignore); |
void *bfd_nullvoidptr |
(bfd *ignore); |
int bfd_0 |
(bfd *ignore); |
unsigned int bfd_0u |
(bfd *ignore); |
long bfd_0l |
(bfd *ignore); |
long _bfd_n1 |
(bfd *ignore); |
void bfd_void |
(bfd *ignore); |
bfd *_bfd_new_bfd_contained_in |
(bfd *); |
const bfd_target *_bfd_dummy_target |
(bfd *abfd); |
void bfd_dont_truncate_arname |
(bfd *abfd, const char *filename, char *hdr); |
void bfd_bsd_truncate_arname |
(bfd *abfd, const char *filename, char *hdr); |
void bfd_gnu_truncate_arname |
(bfd *abfd, const char *filename, char *hdr); |
bfd_boolean bsd_write_armap |
(bfd *arch, unsigned int elength, struct orl *map, unsigned int orl_count, |
int stridx); |
bfd_boolean coff_write_armap |
(bfd *arch, unsigned int elength, struct orl *map, unsigned int orl_count, |
int stridx); |
extern void *_bfd_generic_read_ar_hdr |
(bfd *); |
extern void _bfd_ar_spacepad |
(char *, size_t, const char *, long); |
extern bfd_boolean _bfd_ar_sizepad |
(char *, size_t, bfd_size_type); |
extern void *_bfd_generic_read_ar_hdr_mag |
(bfd *, const char *); |
extern bfd_boolean _bfd_generic_write_ar_hdr |
(bfd *, bfd *); |
extern bfd_boolean _bfd_bsd44_write_ar_hdr |
(bfd *, bfd *); |
bfd * bfd_generic_openr_next_archived_file |
(bfd *archive, bfd *last_file); |
int bfd_generic_stat_arch_elt |
(bfd *, struct stat *); |
#define _bfd_read_ar_hdr(abfd) \ |
BFD_SEND (abfd, _bfd_read_ar_hdr_fn, (abfd)) |
#define _bfd_write_ar_hdr(archive, abfd) \ |
BFD_SEND (abfd, _bfd_write_ar_hdr_fn, (archive, abfd)) |
/* Generic routines to use for BFD_JUMP_TABLE_GENERIC. Use |
BFD_JUMP_TABLE_GENERIC (_bfd_generic). */ |
#define _bfd_generic_close_and_cleanup _bfd_archive_close_and_cleanup |
extern bfd_boolean _bfd_archive_close_and_cleanup |
(bfd *); |
#define _bfd_generic_bfd_free_cached_info bfd_true |
extern bfd_boolean _bfd_generic_new_section_hook |
(bfd *, asection *); |
extern bfd_boolean _bfd_generic_get_section_contents |
(bfd *, asection *, void *, file_ptr, bfd_size_type); |
extern bfd_boolean _bfd_generic_get_section_contents_in_window |
(bfd *, asection *, bfd_window *, file_ptr, bfd_size_type); |
/* Generic routines to use for BFD_JUMP_TABLE_COPY. Use |
BFD_JUMP_TABLE_COPY (_bfd_generic). */ |
#define _bfd_generic_bfd_copy_private_bfd_data \ |
((bfd_boolean (*) (bfd *, bfd *)) bfd_true) |
#define _bfd_generic_bfd_merge_private_bfd_data \ |
((bfd_boolean (*) (bfd *, bfd *)) bfd_true) |
#define _bfd_generic_bfd_set_private_flags \ |
((bfd_boolean (*) (bfd *, flagword)) bfd_true) |
#define _bfd_generic_bfd_copy_private_section_data \ |
((bfd_boolean (*) (bfd *, asection *, bfd *, asection *)) bfd_true) |
#define _bfd_generic_bfd_copy_private_symbol_data \ |
((bfd_boolean (*) (bfd *, asymbol *, bfd *, asymbol *)) bfd_true) |
#define _bfd_generic_bfd_copy_private_header_data \ |
((bfd_boolean (*) (bfd *, bfd *)) bfd_true) |
#define _bfd_generic_bfd_print_private_bfd_data \ |
((bfd_boolean (*) (bfd *, void *)) bfd_true) |
extern bfd_boolean _bfd_generic_init_private_section_data |
(bfd *, asection *, bfd *, asection *, struct bfd_link_info *); |
/* Routines to use for BFD_JUMP_TABLE_CORE when there is no core file |
support. Use BFD_JUMP_TABLE_CORE (_bfd_nocore). */ |
extern char *_bfd_nocore_core_file_failing_command |
(bfd *); |
extern int _bfd_nocore_core_file_failing_signal |
(bfd *); |
extern bfd_boolean _bfd_nocore_core_file_matches_executable_p |
(bfd *, bfd *); |
extern int _bfd_nocore_core_file_pid |
(bfd *); |
/* Routines to use for BFD_JUMP_TABLE_ARCHIVE when there is no archive |
file support. Use BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive). */ |
#define _bfd_noarchive_slurp_armap bfd_false |
#define _bfd_noarchive_slurp_extended_name_table bfd_false |
#define _bfd_noarchive_construct_extended_name_table \ |
((bfd_boolean (*) (bfd *, char **, bfd_size_type *, const char **)) \ |
bfd_false) |
#define _bfd_noarchive_truncate_arname \ |
((void (*) (bfd *, const char *, char *)) bfd_void) |
#define _bfd_noarchive_write_armap \ |
((bfd_boolean (*) (bfd *, unsigned int, struct orl *, unsigned int, int)) \ |
bfd_false) |
#define _bfd_noarchive_read_ar_hdr bfd_nullvoidptr |
#define _bfd_noarchive_write_ar_hdr \ |
((bfd_boolean (*) (bfd *, bfd *)) bfd_false) |
#define _bfd_noarchive_openr_next_archived_file \ |
((bfd *(*) (bfd *, bfd *)) bfd_nullvoidptr) |
#define _bfd_noarchive_get_elt_at_index \ |
((bfd *(*) (bfd *, symindex)) bfd_nullvoidptr) |
#define _bfd_noarchive_generic_stat_arch_elt bfd_generic_stat_arch_elt |
#define _bfd_noarchive_update_armap_timestamp bfd_false |
/* Routines to use for BFD_JUMP_TABLE_ARCHIVE to get BSD style |
archives. Use BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_bsd). */ |
#define _bfd_archive_bsd_slurp_armap bfd_slurp_bsd_armap |
#define _bfd_archive_bsd_slurp_extended_name_table \ |
_bfd_slurp_extended_name_table |
extern bfd_boolean _bfd_archive_bsd_construct_extended_name_table |
(bfd *, char **, bfd_size_type *, const char **); |
#define _bfd_archive_bsd_truncate_arname bfd_bsd_truncate_arname |
#define _bfd_archive_bsd_write_armap bsd_write_armap |
#define _bfd_archive_bsd_read_ar_hdr _bfd_generic_read_ar_hdr |
#define _bfd_archive_bsd_write_ar_hdr _bfd_generic_write_ar_hdr |
#define _bfd_archive_bsd_openr_next_archived_file \ |
bfd_generic_openr_next_archived_file |
#define _bfd_archive_bsd_get_elt_at_index _bfd_generic_get_elt_at_index |
#define _bfd_archive_bsd_generic_stat_arch_elt \ |
bfd_generic_stat_arch_elt |
extern bfd_boolean _bfd_archive_bsd_update_armap_timestamp |
(bfd *); |
/* Routines to use for BFD_JUMP_TABLE_ARCHIVE to get COFF style |
archives. Use BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff). */ |
#define _bfd_archive_coff_slurp_armap bfd_slurp_coff_armap |
#define _bfd_archive_coff_slurp_extended_name_table \ |
_bfd_slurp_extended_name_table |
extern bfd_boolean _bfd_archive_coff_construct_extended_name_table |
(bfd *, char **, bfd_size_type *, const char **); |
#define _bfd_archive_coff_truncate_arname bfd_dont_truncate_arname |
#define _bfd_archive_coff_write_armap coff_write_armap |
#define _bfd_archive_coff_read_ar_hdr _bfd_generic_read_ar_hdr |
#define _bfd_archive_coff_write_ar_hdr _bfd_generic_write_ar_hdr |
#define _bfd_archive_coff_openr_next_archived_file \ |
bfd_generic_openr_next_archived_file |
#define _bfd_archive_coff_get_elt_at_index _bfd_generic_get_elt_at_index |
#define _bfd_archive_coff_generic_stat_arch_elt \ |
bfd_generic_stat_arch_elt |
#define _bfd_archive_coff_update_armap_timestamp bfd_true |
/* Routines to use for BFD_JUMP_TABLE_ARCHIVE to get BSD4.4 style |
archives. Use BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_bsd44). */ |
#define _bfd_archive_bsd44_slurp_armap bfd_slurp_bsd_armap |
#define _bfd_archive_bsd44_slurp_extended_name_table \ |
_bfd_slurp_extended_name_table |
extern bfd_boolean _bfd_archive_bsd44_construct_extended_name_table |
(bfd *, char **, bfd_size_type *, const char **); |
#define _bfd_archive_bsd44_truncate_arname bfd_bsd_truncate_arname |
#define _bfd_archive_bsd44_write_armap bsd_write_armap |
#define _bfd_archive_bsd44_read_ar_hdr _bfd_generic_read_ar_hdr |
#define _bfd_archive_bsd44_write_ar_hdr _bfd_bsd44_write_ar_hdr |
#define _bfd_archive_bsd44_openr_next_archived_file \ |
bfd_generic_openr_next_archived_file |
#define _bfd_archive_bsd44_get_elt_at_index _bfd_generic_get_elt_at_index |
#define _bfd_archive_bsd44_generic_stat_arch_elt \ |
bfd_generic_stat_arch_elt |
#define _bfd_archive_bsd44_update_armap_timestamp \ |
_bfd_archive_bsd_update_armap_timestamp |
/* Routines to use for BFD_JUMP_TABLE_ARCHIVE to get VMS style |
archives. Use BFD_JUMP_TABLE_ARCHIVE (_bfd_vms_lib). Some of them |
are irrelevant and never called, so defined as NULL. */ |
extern bfd_boolean _bfd_vms_lib_write_archive_contents (bfd *arch); |
#define _bfd_vms_lib_slurp_armap NULL |
#define _bfd_vms_lib_slurp_extended_name_table NULL |
#define _bfd_vms_lib_construct_extended_name_table NULL |
#define _bfd_vms_lib_truncate_arname NULL |
#define _bfd_vms_lib_write_armap NULL |
#define _bfd_vms_lib_read_ar_hdr NULL |
#define _bfd_vms_lib_write_ar_hdr NULL |
extern bfd *_bfd_vms_lib_openr_next_archived_file (bfd *, bfd *); |
extern bfd *_bfd_vms_lib_get_elt_at_index (bfd *, symindex); |
extern int _bfd_vms_lib_generic_stat_arch_elt (bfd *, struct stat *); |
#define _bfd_vms_lib_update_armap_timestamp bfd_true |
/* Extra routines for VMS style archives. */ |
extern symindex _bfd_vms_lib_find_symbol (bfd *, const char *); |
extern bfd *_bfd_vms_lib_get_imagelib_file (bfd *); |
extern const bfd_target *_bfd_vms_lib_alpha_archive_p (bfd *abfd); |
extern const bfd_target *_bfd_vms_lib_ia64_archive_p (bfd *abfd); |
extern bfd_boolean _bfd_vms_lib_alpha_mkarchive (bfd *abfd); |
extern bfd_boolean _bfd_vms_lib_ia64_mkarchive (bfd *abfd); |
/* Routines to use for BFD_JUMP_TABLE_SYMBOLS where there is no symbol |
support. Use BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols). */ |
#define _bfd_nosymbols_get_symtab_upper_bound _bfd_n1 |
#define _bfd_nosymbols_canonicalize_symtab \ |
((long (*) (bfd *, asymbol **)) _bfd_n1) |
#define _bfd_nosymbols_make_empty_symbol _bfd_generic_make_empty_symbol |
#define _bfd_nosymbols_print_symbol \ |
((void (*) (bfd *, void *, asymbol *, bfd_print_symbol_type)) bfd_void) |
#define _bfd_nosymbols_get_symbol_info \ |
((void (*) (bfd *, asymbol *, symbol_info *)) bfd_void) |
#define _bfd_nosymbols_bfd_is_local_label_name \ |
((bfd_boolean (*) (bfd *, const char *)) bfd_false) |
#define _bfd_nosymbols_bfd_is_target_special_symbol \ |
((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) |
#define _bfd_nosymbols_get_lineno \ |
((alent *(*) (bfd *, asymbol *)) bfd_nullvoidptr) |
#define _bfd_nosymbols_find_nearest_line \ |
((bfd_boolean (*) (bfd *, asection *, asymbol **, bfd_vma, const char **, \ |
const char **, unsigned int *)) \ |
bfd_false) |
#define _bfd_nosymbols_find_inliner_info \ |
((bfd_boolean (*) (bfd *, const char **, const char **, unsigned int *)) \ |
bfd_false) |
#define _bfd_nosymbols_bfd_make_debug_symbol \ |
((asymbol *(*) (bfd *, void *, unsigned long)) bfd_nullvoidptr) |
#define _bfd_nosymbols_read_minisymbols \ |
((long (*) (bfd *, bfd_boolean, void **, unsigned int *)) _bfd_n1) |
#define _bfd_nosymbols_minisymbol_to_symbol \ |
((asymbol *(*) (bfd *, bfd_boolean, const void *, asymbol *)) \ |
bfd_nullvoidptr) |
/* Routines to use for BFD_JUMP_TABLE_RELOCS when there is no reloc |
support. Use BFD_JUMP_TABLE_RELOCS (_bfd_norelocs). */ |
extern long _bfd_norelocs_get_reloc_upper_bound (bfd *, asection *); |
extern long _bfd_norelocs_canonicalize_reloc (bfd *, asection *, |
arelent **, asymbol **); |
#define _bfd_norelocs_bfd_reloc_type_lookup \ |
((reloc_howto_type *(*) (bfd *, bfd_reloc_code_real_type)) bfd_nullvoidptr) |
#define _bfd_norelocs_bfd_reloc_name_lookup \ |
((reloc_howto_type *(*) (bfd *, const char *)) bfd_nullvoidptr) |
/* Routines to use for BFD_JUMP_TABLE_WRITE for targets which may not |
be written. Use BFD_JUMP_TABLE_WRITE (_bfd_nowrite). */ |
#define _bfd_nowrite_set_arch_mach \ |
((bfd_boolean (*) (bfd *, enum bfd_architecture, unsigned long)) \ |
bfd_false) |
#define _bfd_nowrite_set_section_contents \ |
((bfd_boolean (*) (bfd *, asection *, const void *, file_ptr, bfd_size_type)) \ |
bfd_false) |
/* Generic routines to use for BFD_JUMP_TABLE_WRITE. Use |
BFD_JUMP_TABLE_WRITE (_bfd_generic). */ |
#define _bfd_generic_set_arch_mach bfd_default_set_arch_mach |
extern bfd_boolean _bfd_generic_set_section_contents |
(bfd *, asection *, const void *, file_ptr, bfd_size_type); |
/* Routines to use for BFD_JUMP_TABLE_LINK for targets which do not |
support linking. Use BFD_JUMP_TABLE_LINK (_bfd_nolink). */ |
#define _bfd_nolink_sizeof_headers \ |
((int (*) (bfd *, struct bfd_link_info *)) bfd_0) |
#define _bfd_nolink_bfd_get_relocated_section_contents \ |
((bfd_byte *(*) (bfd *, struct bfd_link_info *, struct bfd_link_order *, \ |
bfd_byte *, bfd_boolean, asymbol **)) \ |
bfd_nullvoidptr) |
#define _bfd_nolink_bfd_relax_section \ |
((bfd_boolean (*) \ |
(bfd *, asection *, struct bfd_link_info *, bfd_boolean *)) \ |
bfd_false) |
#define _bfd_nolink_bfd_gc_sections \ |
((bfd_boolean (*) (bfd *, struct bfd_link_info *)) \ |
bfd_false) |
#define _bfd_nolink_bfd_lookup_section_flags \ |
((bfd_boolean (*) (struct bfd_link_info *, struct flag_info *, asection *)) \ |
bfd_0) |
#define _bfd_nolink_bfd_merge_sections \ |
((bfd_boolean (*) (bfd *, struct bfd_link_info *)) \ |
bfd_false) |
#define _bfd_nolink_bfd_is_group_section \ |
((bfd_boolean (*) (bfd *, const struct bfd_section *)) \ |
bfd_false) |
#define _bfd_nolink_bfd_discard_group \ |
((bfd_boolean (*) (bfd *, struct bfd_section *)) \ |
bfd_false) |
#define _bfd_nolink_bfd_link_hash_table_create \ |
((struct bfd_link_hash_table *(*) (bfd *)) bfd_nullvoidptr) |
#define _bfd_nolink_bfd_link_hash_table_free \ |
((void (*) (struct bfd_link_hash_table *)) bfd_void) |
#define _bfd_nolink_bfd_link_add_symbols \ |
((bfd_boolean (*) (bfd *, struct bfd_link_info *)) bfd_false) |
#define _bfd_nolink_bfd_link_just_syms \ |
((void (*) (asection *, struct bfd_link_info *)) bfd_void) |
#define _bfd_nolink_bfd_copy_link_hash_symbol_type \ |
((void (*) (bfd *, struct bfd_link_hash_entry *, \ |
struct bfd_link_hash_entry *)) bfd_void) |
#define _bfd_nolink_bfd_final_link \ |
((bfd_boolean (*) (bfd *, struct bfd_link_info *)) bfd_false) |
#define _bfd_nolink_bfd_link_split_section \ |
((bfd_boolean (*) (bfd *, struct bfd_section *)) bfd_false) |
#define _bfd_nolink_section_already_linked \ |
((bfd_boolean (*) (bfd *, asection *, \ |
struct bfd_link_info *)) bfd_false) |
#define _bfd_nolink_bfd_define_common_symbol \ |
((bfd_boolean (*) (bfd *, struct bfd_link_info *, \ |
struct bfd_link_hash_entry *)) bfd_false) |
/* Routines to use for BFD_JUMP_TABLE_DYNAMIC for targets which do not |
have dynamic symbols or relocs. Use BFD_JUMP_TABLE_DYNAMIC |
(_bfd_nodynamic). */ |
#define _bfd_nodynamic_get_dynamic_symtab_upper_bound _bfd_n1 |
#define _bfd_nodynamic_canonicalize_dynamic_symtab \ |
((long (*) (bfd *, asymbol **)) _bfd_n1) |
#define _bfd_nodynamic_get_synthetic_symtab \ |
((long (*) (bfd *, long, asymbol **, long, asymbol **, asymbol **)) _bfd_n1) |
#define _bfd_nodynamic_get_dynamic_reloc_upper_bound _bfd_n1 |
#define _bfd_nodynamic_canonicalize_dynamic_reloc \ |
((long (*) (bfd *, arelent **, asymbol **)) _bfd_n1) |
/* Generic routine to determine of the given symbol is a local |
label. */ |
extern bfd_boolean bfd_generic_is_local_label_name |
(bfd *, const char *); |
/* Generic minisymbol routines. */ |
extern long _bfd_generic_read_minisymbols |
(bfd *, bfd_boolean, void **, unsigned int *); |
extern asymbol *_bfd_generic_minisymbol_to_symbol |
(bfd *, bfd_boolean, const void *, asymbol *); |
/* Find the nearest line using .stab/.stabstr sections. */ |
extern bfd_boolean _bfd_stab_section_find_nearest_line |
(bfd *, asymbol **, asection *, bfd_vma, bfd_boolean *, |
const char **, const char **, unsigned int *, void **); |
/* Find the nearest line using DWARF 1 debugging information. */ |
extern bfd_boolean _bfd_dwarf1_find_nearest_line |
(bfd *, asection *, asymbol **, bfd_vma, const char **, |
const char **, unsigned int *); |
struct dwarf_debug_section |
{ |
const char *uncompressed_name; |
const char *compressed_name; |
}; |
/* Map of uncompressed DWARF debug section name to compressed one. It |
is terminated by NULL uncompressed_name. */ |
extern const struct dwarf_debug_section dwarf_debug_sections[]; |
/* Find the nearest line using DWARF 2 debugging information. */ |
extern bfd_boolean _bfd_dwarf2_find_nearest_line |
(bfd *, const struct dwarf_debug_section *, asection *, asymbol **, bfd_vma, |
const char **, const char **, unsigned int *, unsigned int *, unsigned int, |
void **); |
/* Find the line using DWARF 2 debugging information. */ |
extern bfd_boolean _bfd_dwarf2_find_line |
(bfd *, asymbol **, asymbol *, const char **, |
unsigned int *, unsigned int *, unsigned int, void **); |
bfd_boolean _bfd_generic_find_line |
(bfd *, asymbol **, asymbol *, const char **, unsigned int *); |
bfd_boolean _bfd_generic_find_nearest_line_discriminator |
(bfd *, asection *, asymbol **, bfd_vma, const char **, const char **, |
unsigned int *, unsigned int *); |
/* Find inliner info after calling bfd_find_nearest_line. */ |
extern bfd_boolean _bfd_dwarf2_find_inliner_info |
(bfd *, const char **, const char **, unsigned int *, void **); |
/* Read DWARF 2 debugging information. */ |
extern bfd_boolean _bfd_dwarf2_slurp_debug_info |
(bfd *, bfd *, const struct dwarf_debug_section *, asymbol **, void **); |
/* Clean up the data used to handle DWARF 2 debugging information. */ |
extern void _bfd_dwarf2_cleanup_debug_info |
(bfd *, void **); |
/* Create a new section entry. */ |
extern struct bfd_hash_entry *bfd_section_hash_newfunc |
(struct bfd_hash_entry *, struct bfd_hash_table *, const char *); |
/* A routine to create entries for a bfd_link_hash_table. */ |
extern struct bfd_hash_entry *_bfd_link_hash_newfunc |
(struct bfd_hash_entry *entry, struct bfd_hash_table *table, |
const char *string); |
/* Initialize a bfd_link_hash_table. */ |
extern bfd_boolean _bfd_link_hash_table_init |
(struct bfd_link_hash_table *, bfd *, |
struct bfd_hash_entry *(*) (struct bfd_hash_entry *, |
struct bfd_hash_table *, |
const char *), |
unsigned int); |
/* Generic link hash table creation routine. */ |
extern struct bfd_link_hash_table *_bfd_generic_link_hash_table_create |
(bfd *); |
/* Generic link hash table destruction routine. */ |
extern void _bfd_generic_link_hash_table_free |
(struct bfd_link_hash_table *); |
/* Generic add symbol routine. */ |
extern bfd_boolean _bfd_generic_link_add_symbols |
(bfd *, struct bfd_link_info *); |
/* Generic add symbol routine. This version is used by targets for |
which the linker must collect constructors and destructors by name, |
as the collect2 program does. */ |
extern bfd_boolean _bfd_generic_link_add_symbols_collect |
(bfd *, struct bfd_link_info *); |
/* Generic archive add symbol routine. */ |
extern bfd_boolean _bfd_generic_link_add_archive_symbols |
(bfd *, struct bfd_link_info *, |
bfd_boolean (*) (bfd *, struct bfd_link_info *, bfd_boolean *)); |
/* Forward declaration to avoid prototype errors. */ |
typedef struct bfd_link_hash_entry _bfd_link_hash_entry; |
/* Generic routine to add a single symbol. */ |
extern bfd_boolean _bfd_generic_link_add_one_symbol |
(struct bfd_link_info *, bfd *, const char *name, flagword, |
asection *, bfd_vma, const char *, bfd_boolean copy, |
bfd_boolean constructor, struct bfd_link_hash_entry **); |
/* Generic routine to mark section as supplying symbols only. */ |
extern void _bfd_generic_link_just_syms |
(asection *, struct bfd_link_info *); |
/* Generic routine that does nothing. */ |
extern void _bfd_generic_copy_link_hash_symbol_type |
(bfd *, struct bfd_link_hash_entry *, struct bfd_link_hash_entry *); |
/* Generic link routine. */ |
extern bfd_boolean _bfd_generic_final_link |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean _bfd_generic_link_split_section |
(bfd *, struct bfd_section *); |
extern bfd_boolean _bfd_generic_section_already_linked |
(bfd *, asection *, struct bfd_link_info *); |
/* Generic reloc_link_order processing routine. */ |
extern bfd_boolean _bfd_generic_reloc_link_order |
(bfd *, struct bfd_link_info *, asection *, struct bfd_link_order *); |
/* Default link order processing routine. */ |
extern bfd_boolean _bfd_default_link_order |
(bfd *, struct bfd_link_info *, asection *, struct bfd_link_order *); |
/* Count the number of reloc entries in a link order list. */ |
extern unsigned int _bfd_count_link_order_relocs |
(struct bfd_link_order *); |
/* Final link relocation routine. */ |
extern bfd_reloc_status_type _bfd_final_link_relocate |
(reloc_howto_type *, bfd *, asection *, bfd_byte *, |
bfd_vma, bfd_vma, bfd_vma); |
/* Relocate a particular location by a howto and a value. */ |
extern bfd_reloc_status_type _bfd_relocate_contents |
(reloc_howto_type *, bfd *, bfd_vma, bfd_byte *); |
/* Clear a given location using a given howto. */ |
extern void _bfd_clear_contents (reloc_howto_type *howto, bfd *input_bfd, |
asection *input_section, bfd_byte *location); |
/* Link stabs in sections in the first pass. */ |
extern bfd_boolean _bfd_link_section_stabs |
(bfd *, struct stab_info *, asection *, asection *, void **, |
bfd_size_type *); |
/* Eliminate stabs for discarded functions and symbols. */ |
extern bfd_boolean _bfd_discard_section_stabs |
(bfd *, asection *, void *, bfd_boolean (*) (bfd_vma, void *), void *); |
/* Write out the .stab section when linking stabs in sections. */ |
extern bfd_boolean _bfd_write_section_stabs |
(bfd *, struct stab_info *, asection *, void **, bfd_byte *); |
/* Write out the .stabstr string table when linking stabs in sections. */ |
extern bfd_boolean _bfd_write_stab_strings |
(bfd *, struct stab_info *); |
/* Find an offset within a .stab section when linking stabs in |
sections. */ |
extern bfd_vma _bfd_stab_section_offset |
(asection *, void *, bfd_vma); |
/* Register a SEC_MERGE section as a candidate for merging. */ |
extern bfd_boolean _bfd_add_merge_section |
(bfd *, void **, asection *, void **); |
/* Attempt to merge SEC_MERGE sections. */ |
extern bfd_boolean _bfd_merge_sections |
(bfd *, struct bfd_link_info *, void *, void (*) (bfd *, asection *)); |
/* Write out a merged section. */ |
extern bfd_boolean _bfd_write_merged_section |
(bfd *, asection *, void *); |
/* Find an offset within a modified SEC_MERGE section. */ |
extern bfd_vma _bfd_merged_section_offset |
(bfd *, asection **, void *, bfd_vma); |
/* Tidy up when done. */ |
extern void _bfd_merge_sections_free (void *); |
/* Create a string table. */ |
extern struct bfd_strtab_hash *_bfd_stringtab_init |
(void); |
/* Create an XCOFF .debug section style string table. */ |
extern struct bfd_strtab_hash *_bfd_xcoff_stringtab_init |
(void); |
/* Free a string table. */ |
extern void _bfd_stringtab_free |
(struct bfd_strtab_hash *); |
/* Get the size of a string table. */ |
extern bfd_size_type _bfd_stringtab_size |
(struct bfd_strtab_hash *); |
/* Add a string to a string table. */ |
extern bfd_size_type _bfd_stringtab_add |
(struct bfd_strtab_hash *, const char *, bfd_boolean hash, bfd_boolean copy); |
/* Write out a string table. */ |
extern bfd_boolean _bfd_stringtab_emit |
(bfd *, struct bfd_strtab_hash *); |
/* Check that endianness of input and output file match. */ |
extern bfd_boolean _bfd_generic_verify_endian_match |
(bfd *, bfd *); |
/* Macros to tell if bfds are read or write enabled. |
Note that bfds open for read may be scribbled into if the fd passed |
to bfd_fdopenr is actually open both for read and write |
simultaneously. However an output bfd will never be open for |
read. Therefore sometimes you want to check bfd_read_p or |
!bfd_read_p, and only sometimes bfd_write_p. |
*/ |
#define bfd_read_p(abfd) \ |
((abfd)->direction == read_direction || (abfd)->direction == both_direction) |
#define bfd_write_p(abfd) \ |
((abfd)->direction == write_direction || (abfd)->direction == both_direction) |
void bfd_assert |
(const char*,int); |
#define BFD_ASSERT(x) \ |
do { if (!(x)) bfd_assert(__FILE__,__LINE__); } while (0) |
#define BFD_FAIL() \ |
do { bfd_assert(__FILE__,__LINE__); } while (0) |
extern void _bfd_abort |
(const char *, int, const char *) ATTRIBUTE_NORETURN; |
/* if gcc >= 2.6, we can give a function name, too */ |
#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 6) |
#define __PRETTY_FUNCTION__ ((char *) NULL) |
#endif |
#undef abort |
#define abort() _bfd_abort (__FILE__, __LINE__, __PRETTY_FUNCTION__) |
/* Manipulate a system FILE but using BFD's "file_ptr", rather than |
the system "off_t" or "off64_t", as the offset. */ |
extern file_ptr real_ftell (FILE *file); |
extern int real_fseek (FILE *file, file_ptr offset, int whence); |
extern FILE *real_fopen (const char *filename, const char *modes); |
/* List of supported target vectors, and the default vector (if |
bfd_default_vector[0] is NULL, there is no default). */ |
extern const bfd_target * const *bfd_target_vector; |
extern const bfd_target *bfd_default_vector[]; |
/* List of associated target vectors. */ |
extern const bfd_target * const *bfd_associated_vector; |
/* Functions shared by the ECOFF and MIPS ELF backends, which have no |
other common header files. */ |
#if defined(__STDC__) || defined(ALMOST_STDC) |
struct ecoff_find_line; |
#endif |
extern bfd_boolean _bfd_ecoff_locate_line |
(bfd *, asection *, bfd_vma, struct ecoff_debug_info * const, |
const struct ecoff_debug_swap * const, struct ecoff_find_line *, |
const char **, const char **, unsigned int *); |
extern bfd_boolean _bfd_ecoff_get_accumulated_pdr |
(void *, bfd_byte *); |
extern bfd_boolean _bfd_ecoff_get_accumulated_sym |
(void *, bfd_byte *); |
extern bfd_boolean _bfd_ecoff_get_accumulated_ss |
(void *, bfd_byte *); |
extern bfd_vma _bfd_get_gp_value |
(bfd *); |
extern void _bfd_set_gp_value |
(bfd *, bfd_vma); |
/* Function shared by the COFF and ELF SH backends, which have no |
other common header files. */ |
#ifndef _bfd_sh_align_load_span |
extern bfd_boolean _bfd_sh_align_load_span |
(bfd *, asection *, bfd_byte *, |
bfd_boolean (*) (bfd *, asection *, void *, bfd_byte *, bfd_vma), |
void *, bfd_vma **, bfd_vma *, bfd_vma, bfd_vma, bfd_boolean *); |
#endif |
/* This is the shape of the elements inside the already_linked hash |
table. It maps a name onto a list of already_linked elements with |
the same name. */ |
struct bfd_section_already_linked_hash_entry |
{ |
struct bfd_hash_entry root; |
struct bfd_section_already_linked *entry; |
}; |
struct bfd_section_already_linked |
{ |
struct bfd_section_already_linked *next; |
asection *sec; |
}; |
extern struct bfd_section_already_linked_hash_entry * |
bfd_section_already_linked_table_lookup (const char *); |
extern bfd_boolean bfd_section_already_linked_table_insert |
(struct bfd_section_already_linked_hash_entry *, asection *); |
extern void bfd_section_already_linked_table_traverse |
(bfd_boolean (*) (struct bfd_section_already_linked_hash_entry *, |
void *), void *); |
extern bfd_vma read_unsigned_leb128 (bfd *, bfd_byte *, unsigned int *); |
extern bfd_signed_vma read_signed_leb128 (bfd *, bfd_byte *, unsigned int *); |
/* Extracted from init.c. */ |
/* Extracted from libbfd.c. */ |
bfd_boolean bfd_write_bigendian_4byte_int (bfd *, unsigned int); |
unsigned int bfd_log2 (bfd_vma x); |
/* Extracted from bfdio.c. */ |
struct bfd_iovec |
{ |
/* To avoid problems with macros, a "b" rather than "f" |
prefix is prepended to each method name. */ |
/* Attempt to read/write NBYTES on ABFD's IOSTREAM storing/fetching |
bytes starting at PTR. Return the number of bytes actually |
transfered (a read past end-of-file returns less than NBYTES), |
or -1 (setting <<bfd_error>>) if an error occurs. */ |
file_ptr (*bread) (struct bfd *abfd, void *ptr, file_ptr nbytes); |
file_ptr (*bwrite) (struct bfd *abfd, const void *ptr, |
file_ptr nbytes); |
/* Return the current IOSTREAM file offset, or -1 (setting <<bfd_error>> |
if an error occurs. */ |
file_ptr (*btell) (struct bfd *abfd); |
/* For the following, on successful completion a value of 0 is returned. |
Otherwise, a value of -1 is returned (and <<bfd_error>> is set). */ |
int (*bseek) (struct bfd *abfd, file_ptr offset, int whence); |
int (*bclose) (struct bfd *abfd); |
int (*bflush) (struct bfd *abfd); |
int (*bstat) (struct bfd *abfd, struct stat *sb); |
/* Mmap a part of the files. ADDR, LEN, PROT, FLAGS and OFFSET are the usual |
mmap parameter, except that LEN and OFFSET do not need to be page |
aligned. Returns (void *)-1 on failure, mmapped address on success. |
Also write in MAP_ADDR the address of the page aligned buffer and in |
MAP_LEN the size mapped (a page multiple). Use unmap with MAP_ADDR and |
MAP_LEN to unmap. */ |
void *(*bmmap) (struct bfd *abfd, void *addr, bfd_size_type len, |
int prot, int flags, file_ptr offset, |
void **map_addr, bfd_size_type *map_len); |
}; |
extern const struct bfd_iovec _bfd_memory_iovec; |
/* Extracted from bfdwin.c. */ |
struct _bfd_window_internal { |
struct _bfd_window_internal *next; |
void *data; |
bfd_size_type size; |
int refcount : 31; /* should be enough... */ |
unsigned mapped : 1; /* 1 = mmap, 0 = malloc */ |
}; |
/* Extracted from cache.c. */ |
bfd_boolean bfd_cache_init (bfd *abfd); |
bfd_boolean bfd_cache_close (bfd *abfd); |
FILE* bfd_open_file (bfd *abfd); |
/* Extracted from reloc.c. */ |
#ifdef _BFD_MAKE_TABLE_bfd_reloc_code_real |
static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", |
"BFD_RELOC_64", |
"BFD_RELOC_32", |
"BFD_RELOC_26", |
"BFD_RELOC_24", |
"BFD_RELOC_16", |
"BFD_RELOC_14", |
"BFD_RELOC_8", |
"BFD_RELOC_64_PCREL", |
"BFD_RELOC_32_PCREL", |
"BFD_RELOC_24_PCREL", |
"BFD_RELOC_16_PCREL", |
"BFD_RELOC_12_PCREL", |
"BFD_RELOC_8_PCREL", |
"BFD_RELOC_32_SECREL", |
"BFD_RELOC_32_GOT_PCREL", |
"BFD_RELOC_16_GOT_PCREL", |
"BFD_RELOC_8_GOT_PCREL", |
"BFD_RELOC_32_GOTOFF", |
"BFD_RELOC_16_GOTOFF", |
"BFD_RELOC_LO16_GOTOFF", |
"BFD_RELOC_HI16_GOTOFF", |
"BFD_RELOC_HI16_S_GOTOFF", |
"BFD_RELOC_8_GOTOFF", |
"BFD_RELOC_64_PLT_PCREL", |
"BFD_RELOC_32_PLT_PCREL", |
"BFD_RELOC_24_PLT_PCREL", |
"BFD_RELOC_16_PLT_PCREL", |
"BFD_RELOC_8_PLT_PCREL", |
"BFD_RELOC_64_PLTOFF", |
"BFD_RELOC_32_PLTOFF", |
"BFD_RELOC_16_PLTOFF", |
"BFD_RELOC_LO16_PLTOFF", |
"BFD_RELOC_HI16_PLTOFF", |
"BFD_RELOC_HI16_S_PLTOFF", |
"BFD_RELOC_8_PLTOFF", |
"BFD_RELOC_SIZE32", |
"BFD_RELOC_SIZE64", |
"BFD_RELOC_68K_GLOB_DAT", |
"BFD_RELOC_68K_JMP_SLOT", |
"BFD_RELOC_68K_RELATIVE", |
"BFD_RELOC_68K_TLS_GD32", |
"BFD_RELOC_68K_TLS_GD16", |
"BFD_RELOC_68K_TLS_GD8", |
"BFD_RELOC_68K_TLS_LDM32", |
"BFD_RELOC_68K_TLS_LDM16", |
"BFD_RELOC_68K_TLS_LDM8", |
"BFD_RELOC_68K_TLS_LDO32", |
"BFD_RELOC_68K_TLS_LDO16", |
"BFD_RELOC_68K_TLS_LDO8", |
"BFD_RELOC_68K_TLS_IE32", |
"BFD_RELOC_68K_TLS_IE16", |
"BFD_RELOC_68K_TLS_IE8", |
"BFD_RELOC_68K_TLS_LE32", |
"BFD_RELOC_68K_TLS_LE16", |
"BFD_RELOC_68K_TLS_LE8", |
"BFD_RELOC_32_BASEREL", |
"BFD_RELOC_16_BASEREL", |
"BFD_RELOC_LO16_BASEREL", |
"BFD_RELOC_HI16_BASEREL", |
"BFD_RELOC_HI16_S_BASEREL", |
"BFD_RELOC_8_BASEREL", |
"BFD_RELOC_RVA", |
"BFD_RELOC_8_FFnn", |
"BFD_RELOC_32_PCREL_S2", |
"BFD_RELOC_16_PCREL_S2", |
"BFD_RELOC_23_PCREL_S2", |
"BFD_RELOC_HI22", |
"BFD_RELOC_LO10", |
"BFD_RELOC_GPREL16", |
"BFD_RELOC_GPREL32", |
"BFD_RELOC_I960_CALLJ", |
"BFD_RELOC_NONE", |
"BFD_RELOC_SPARC_WDISP22", |
"BFD_RELOC_SPARC22", |
"BFD_RELOC_SPARC13", |
"BFD_RELOC_SPARC_GOT10", |
"BFD_RELOC_SPARC_GOT13", |
"BFD_RELOC_SPARC_GOT22", |
"BFD_RELOC_SPARC_PC10", |
"BFD_RELOC_SPARC_PC22", |
"BFD_RELOC_SPARC_WPLT30", |
"BFD_RELOC_SPARC_COPY", |
"BFD_RELOC_SPARC_GLOB_DAT", |
"BFD_RELOC_SPARC_JMP_SLOT", |
"BFD_RELOC_SPARC_RELATIVE", |
"BFD_RELOC_SPARC_UA16", |
"BFD_RELOC_SPARC_UA32", |
"BFD_RELOC_SPARC_UA64", |
"BFD_RELOC_SPARC_GOTDATA_HIX22", |
"BFD_RELOC_SPARC_GOTDATA_LOX10", |
"BFD_RELOC_SPARC_GOTDATA_OP_HIX22", |
"BFD_RELOC_SPARC_GOTDATA_OP_LOX10", |
"BFD_RELOC_SPARC_GOTDATA_OP", |
"BFD_RELOC_SPARC_JMP_IREL", |
"BFD_RELOC_SPARC_IRELATIVE", |
"BFD_RELOC_SPARC_BASE13", |
"BFD_RELOC_SPARC_BASE22", |
"BFD_RELOC_SPARC_10", |
"BFD_RELOC_SPARC_11", |
"BFD_RELOC_SPARC_OLO10", |
"BFD_RELOC_SPARC_HH22", |
"BFD_RELOC_SPARC_HM10", |
"BFD_RELOC_SPARC_LM22", |
"BFD_RELOC_SPARC_PC_HH22", |
"BFD_RELOC_SPARC_PC_HM10", |
"BFD_RELOC_SPARC_PC_LM22", |
"BFD_RELOC_SPARC_WDISP16", |
"BFD_RELOC_SPARC_WDISP19", |
"BFD_RELOC_SPARC_7", |
"BFD_RELOC_SPARC_6", |
"BFD_RELOC_SPARC_5", |
"BFD_RELOC_SPARC_PLT32", |
"BFD_RELOC_SPARC_PLT64", |
"BFD_RELOC_SPARC_HIX22", |
"BFD_RELOC_SPARC_LOX10", |
"BFD_RELOC_SPARC_H44", |
"BFD_RELOC_SPARC_M44", |
"BFD_RELOC_SPARC_L44", |
"BFD_RELOC_SPARC_REGISTER", |
"BFD_RELOC_SPARC_H34", |
"BFD_RELOC_SPARC_SIZE32", |
"BFD_RELOC_SPARC_SIZE64", |
"BFD_RELOC_SPARC_WDISP10", |
"BFD_RELOC_SPARC_REV32", |
"BFD_RELOC_SPARC_TLS_GD_HI22", |
"BFD_RELOC_SPARC_TLS_GD_LO10", |
"BFD_RELOC_SPARC_TLS_GD_ADD", |
"BFD_RELOC_SPARC_TLS_GD_CALL", |
"BFD_RELOC_SPARC_TLS_LDM_HI22", |
"BFD_RELOC_SPARC_TLS_LDM_LO10", |
"BFD_RELOC_SPARC_TLS_LDM_ADD", |
"BFD_RELOC_SPARC_TLS_LDM_CALL", |
"BFD_RELOC_SPARC_TLS_LDO_HIX22", |
"BFD_RELOC_SPARC_TLS_LDO_LOX10", |
"BFD_RELOC_SPARC_TLS_LDO_ADD", |
"BFD_RELOC_SPARC_TLS_IE_HI22", |
"BFD_RELOC_SPARC_TLS_IE_LO10", |
"BFD_RELOC_SPARC_TLS_IE_LD", |
"BFD_RELOC_SPARC_TLS_IE_LDX", |
"BFD_RELOC_SPARC_TLS_IE_ADD", |
"BFD_RELOC_SPARC_TLS_LE_HIX22", |
"BFD_RELOC_SPARC_TLS_LE_LOX10", |
"BFD_RELOC_SPARC_TLS_DTPMOD32", |
"BFD_RELOC_SPARC_TLS_DTPMOD64", |
"BFD_RELOC_SPARC_TLS_DTPOFF32", |
"BFD_RELOC_SPARC_TLS_DTPOFF64", |
"BFD_RELOC_SPARC_TLS_TPOFF32", |
"BFD_RELOC_SPARC_TLS_TPOFF64", |
"BFD_RELOC_SPU_IMM7", |
"BFD_RELOC_SPU_IMM8", |
"BFD_RELOC_SPU_IMM10", |
"BFD_RELOC_SPU_IMM10W", |
"BFD_RELOC_SPU_IMM16", |
"BFD_RELOC_SPU_IMM16W", |
"BFD_RELOC_SPU_IMM18", |
"BFD_RELOC_SPU_PCREL9a", |
"BFD_RELOC_SPU_PCREL9b", |
"BFD_RELOC_SPU_PCREL16", |
"BFD_RELOC_SPU_LO16", |
"BFD_RELOC_SPU_HI16", |
"BFD_RELOC_SPU_PPU32", |
"BFD_RELOC_SPU_PPU64", |
"BFD_RELOC_SPU_ADD_PIC", |
"BFD_RELOC_ALPHA_GPDISP_HI16", |
"BFD_RELOC_ALPHA_GPDISP_LO16", |
"BFD_RELOC_ALPHA_GPDISP", |
"BFD_RELOC_ALPHA_LITERAL", |
"BFD_RELOC_ALPHA_ELF_LITERAL", |
"BFD_RELOC_ALPHA_LITUSE", |
"BFD_RELOC_ALPHA_HINT", |
"BFD_RELOC_ALPHA_LINKAGE", |
"BFD_RELOC_ALPHA_CODEADDR", |
"BFD_RELOC_ALPHA_GPREL_HI16", |
"BFD_RELOC_ALPHA_GPREL_LO16", |
"BFD_RELOC_ALPHA_BRSGP", |
"BFD_RELOC_ALPHA_NOP", |
"BFD_RELOC_ALPHA_BSR", |
"BFD_RELOC_ALPHA_LDA", |
"BFD_RELOC_ALPHA_BOH", |
"BFD_RELOC_ALPHA_TLSGD", |
"BFD_RELOC_ALPHA_TLSLDM", |
"BFD_RELOC_ALPHA_DTPMOD64", |
"BFD_RELOC_ALPHA_GOTDTPREL16", |
"BFD_RELOC_ALPHA_DTPREL64", |
"BFD_RELOC_ALPHA_DTPREL_HI16", |
"BFD_RELOC_ALPHA_DTPREL_LO16", |
"BFD_RELOC_ALPHA_DTPREL16", |
"BFD_RELOC_ALPHA_GOTTPREL16", |
"BFD_RELOC_ALPHA_TPREL64", |
"BFD_RELOC_ALPHA_TPREL_HI16", |
"BFD_RELOC_ALPHA_TPREL_LO16", |
"BFD_RELOC_ALPHA_TPREL16", |
"BFD_RELOC_MIPS_JMP", |
"BFD_RELOC_MICROMIPS_JMP", |
"BFD_RELOC_MIPS16_JMP", |
"BFD_RELOC_MIPS16_GPREL", |
"BFD_RELOC_HI16", |
"BFD_RELOC_HI16_S", |
"BFD_RELOC_LO16", |
"BFD_RELOC_HI16_PCREL", |
"BFD_RELOC_HI16_S_PCREL", |
"BFD_RELOC_LO16_PCREL", |
"BFD_RELOC_MIPS16_GOT16", |
"BFD_RELOC_MIPS16_CALL16", |
"BFD_RELOC_MIPS16_HI16", |
"BFD_RELOC_MIPS16_HI16_S", |
"BFD_RELOC_MIPS16_LO16", |
"BFD_RELOC_MIPS16_TLS_GD", |
"BFD_RELOC_MIPS16_TLS_LDM", |
"BFD_RELOC_MIPS16_TLS_DTPREL_HI16", |
"BFD_RELOC_MIPS16_TLS_DTPREL_LO16", |
"BFD_RELOC_MIPS16_TLS_GOTTPREL", |
"BFD_RELOC_MIPS16_TLS_TPREL_HI16", |
"BFD_RELOC_MIPS16_TLS_TPREL_LO16", |
"BFD_RELOC_MIPS_LITERAL", |
"BFD_RELOC_MICROMIPS_LITERAL", |
"BFD_RELOC_MICROMIPS_7_PCREL_S1", |
"BFD_RELOC_MICROMIPS_10_PCREL_S1", |
"BFD_RELOC_MICROMIPS_16_PCREL_S1", |
"BFD_RELOC_MICROMIPS_GPREL16", |
"BFD_RELOC_MICROMIPS_HI16", |
"BFD_RELOC_MICROMIPS_HI16_S", |
"BFD_RELOC_MICROMIPS_LO16", |
"BFD_RELOC_MIPS_GOT16", |
"BFD_RELOC_MICROMIPS_GOT16", |
"BFD_RELOC_MIPS_CALL16", |
"BFD_RELOC_MICROMIPS_CALL16", |
"BFD_RELOC_MIPS_GOT_HI16", |
"BFD_RELOC_MICROMIPS_GOT_HI16", |
"BFD_RELOC_MIPS_GOT_LO16", |
"BFD_RELOC_MICROMIPS_GOT_LO16", |
"BFD_RELOC_MIPS_CALL_HI16", |
"BFD_RELOC_MICROMIPS_CALL_HI16", |
"BFD_RELOC_MIPS_CALL_LO16", |
"BFD_RELOC_MICROMIPS_CALL_LO16", |
"BFD_RELOC_MIPS_SUB", |
"BFD_RELOC_MICROMIPS_SUB", |
"BFD_RELOC_MIPS_GOT_PAGE", |
"BFD_RELOC_MICROMIPS_GOT_PAGE", |
"BFD_RELOC_MIPS_GOT_OFST", |
"BFD_RELOC_MICROMIPS_GOT_OFST", |
"BFD_RELOC_MIPS_GOT_DISP", |
"BFD_RELOC_MICROMIPS_GOT_DISP", |
"BFD_RELOC_MIPS_SHIFT5", |
"BFD_RELOC_MIPS_SHIFT6", |
"BFD_RELOC_MIPS_INSERT_A", |
"BFD_RELOC_MIPS_INSERT_B", |
"BFD_RELOC_MIPS_DELETE", |
"BFD_RELOC_MIPS_HIGHEST", |
"BFD_RELOC_MICROMIPS_HIGHEST", |
"BFD_RELOC_MIPS_HIGHER", |
"BFD_RELOC_MICROMIPS_HIGHER", |
"BFD_RELOC_MIPS_SCN_DISP", |
"BFD_RELOC_MICROMIPS_SCN_DISP", |
"BFD_RELOC_MIPS_REL16", |
"BFD_RELOC_MIPS_RELGOT", |
"BFD_RELOC_MIPS_JALR", |
"BFD_RELOC_MICROMIPS_JALR", |
"BFD_RELOC_MIPS_TLS_DTPMOD32", |
"BFD_RELOC_MIPS_TLS_DTPREL32", |
"BFD_RELOC_MIPS_TLS_DTPMOD64", |
"BFD_RELOC_MIPS_TLS_DTPREL64", |
"BFD_RELOC_MIPS_TLS_GD", |
"BFD_RELOC_MICROMIPS_TLS_GD", |
"BFD_RELOC_MIPS_TLS_LDM", |
"BFD_RELOC_MICROMIPS_TLS_LDM", |
"BFD_RELOC_MIPS_TLS_DTPREL_HI16", |
"BFD_RELOC_MICROMIPS_TLS_DTPREL_HI16", |
"BFD_RELOC_MIPS_TLS_DTPREL_LO16", |
"BFD_RELOC_MICROMIPS_TLS_DTPREL_LO16", |
"BFD_RELOC_MIPS_TLS_GOTTPREL", |
"BFD_RELOC_MICROMIPS_TLS_GOTTPREL", |
"BFD_RELOC_MIPS_TLS_TPREL32", |
"BFD_RELOC_MIPS_TLS_TPREL64", |
"BFD_RELOC_MIPS_TLS_TPREL_HI16", |
"BFD_RELOC_MICROMIPS_TLS_TPREL_HI16", |
"BFD_RELOC_MIPS_TLS_TPREL_LO16", |
"BFD_RELOC_MICROMIPS_TLS_TPREL_LO16", |
"BFD_RELOC_MIPS_EH", |
"BFD_RELOC_MIPS_COPY", |
"BFD_RELOC_MIPS_JUMP_SLOT", |
"BFD_RELOC_MOXIE_10_PCREL", |
"BFD_RELOC_FRV_LABEL16", |
"BFD_RELOC_FRV_LABEL24", |
"BFD_RELOC_FRV_LO16", |
"BFD_RELOC_FRV_HI16", |
"BFD_RELOC_FRV_GPREL12", |
"BFD_RELOC_FRV_GPRELU12", |
"BFD_RELOC_FRV_GPREL32", |
"BFD_RELOC_FRV_GPRELHI", |
"BFD_RELOC_FRV_GPRELLO", |
"BFD_RELOC_FRV_GOT12", |
"BFD_RELOC_FRV_GOTHI", |
"BFD_RELOC_FRV_GOTLO", |
"BFD_RELOC_FRV_FUNCDESC", |
"BFD_RELOC_FRV_FUNCDESC_GOT12", |
"BFD_RELOC_FRV_FUNCDESC_GOTHI", |
"BFD_RELOC_FRV_FUNCDESC_GOTLO", |
"BFD_RELOC_FRV_FUNCDESC_VALUE", |
"BFD_RELOC_FRV_FUNCDESC_GOTOFF12", |
"BFD_RELOC_FRV_FUNCDESC_GOTOFFHI", |
"BFD_RELOC_FRV_FUNCDESC_GOTOFFLO", |
"BFD_RELOC_FRV_GOTOFF12", |
"BFD_RELOC_FRV_GOTOFFHI", |
"BFD_RELOC_FRV_GOTOFFLO", |
"BFD_RELOC_FRV_GETTLSOFF", |
"BFD_RELOC_FRV_TLSDESC_VALUE", |
"BFD_RELOC_FRV_GOTTLSDESC12", |
"BFD_RELOC_FRV_GOTTLSDESCHI", |
"BFD_RELOC_FRV_GOTTLSDESCLO", |
"BFD_RELOC_FRV_TLSMOFF12", |
"BFD_RELOC_FRV_TLSMOFFHI", |
"BFD_RELOC_FRV_TLSMOFFLO", |
"BFD_RELOC_FRV_GOTTLSOFF12", |
"BFD_RELOC_FRV_GOTTLSOFFHI", |
"BFD_RELOC_FRV_GOTTLSOFFLO", |
"BFD_RELOC_FRV_TLSOFF", |
"BFD_RELOC_FRV_TLSDESC_RELAX", |
"BFD_RELOC_FRV_GETTLSOFF_RELAX", |
"BFD_RELOC_FRV_TLSOFF_RELAX", |
"BFD_RELOC_FRV_TLSMOFF", |
"BFD_RELOC_MN10300_GOTOFF24", |
"BFD_RELOC_MN10300_GOT32", |
"BFD_RELOC_MN10300_GOT24", |
"BFD_RELOC_MN10300_GOT16", |
"BFD_RELOC_MN10300_COPY", |
"BFD_RELOC_MN10300_GLOB_DAT", |
"BFD_RELOC_MN10300_JMP_SLOT", |
"BFD_RELOC_MN10300_RELATIVE", |
"BFD_RELOC_MN10300_SYM_DIFF", |
"BFD_RELOC_MN10300_ALIGN", |
"BFD_RELOC_MN10300_TLS_GD", |
"BFD_RELOC_MN10300_TLS_LD", |
"BFD_RELOC_MN10300_TLS_LDO", |
"BFD_RELOC_MN10300_TLS_GOTIE", |
"BFD_RELOC_MN10300_TLS_IE", |
"BFD_RELOC_MN10300_TLS_LE", |
"BFD_RELOC_MN10300_TLS_DTPMOD", |
"BFD_RELOC_MN10300_TLS_DTPOFF", |
"BFD_RELOC_MN10300_TLS_TPOFF", |
"BFD_RELOC_MN10300_32_PCREL", |
"BFD_RELOC_MN10300_16_PCREL", |
"BFD_RELOC_386_GOT32", |
"BFD_RELOC_386_PLT32", |
"BFD_RELOC_386_COPY", |
"BFD_RELOC_386_GLOB_DAT", |
"BFD_RELOC_386_JUMP_SLOT", |
"BFD_RELOC_386_RELATIVE", |
"BFD_RELOC_386_GOTOFF", |
"BFD_RELOC_386_GOTPC", |
"BFD_RELOC_386_TLS_TPOFF", |
"BFD_RELOC_386_TLS_IE", |
"BFD_RELOC_386_TLS_GOTIE", |
"BFD_RELOC_386_TLS_LE", |
"BFD_RELOC_386_TLS_GD", |
"BFD_RELOC_386_TLS_LDM", |
"BFD_RELOC_386_TLS_LDO_32", |
"BFD_RELOC_386_TLS_IE_32", |
"BFD_RELOC_386_TLS_LE_32", |
"BFD_RELOC_386_TLS_DTPMOD32", |
"BFD_RELOC_386_TLS_DTPOFF32", |
"BFD_RELOC_386_TLS_TPOFF32", |
"BFD_RELOC_386_TLS_GOTDESC", |
"BFD_RELOC_386_TLS_DESC_CALL", |
"BFD_RELOC_386_TLS_DESC", |
"BFD_RELOC_386_IRELATIVE", |
"BFD_RELOC_X86_64_GOT32", |
"BFD_RELOC_X86_64_PLT32", |
"BFD_RELOC_X86_64_COPY", |
"BFD_RELOC_X86_64_GLOB_DAT", |
"BFD_RELOC_X86_64_JUMP_SLOT", |
"BFD_RELOC_X86_64_RELATIVE", |
"BFD_RELOC_X86_64_GOTPCREL", |
"BFD_RELOC_X86_64_32S", |
"BFD_RELOC_X86_64_DTPMOD64", |
"BFD_RELOC_X86_64_DTPOFF64", |
"BFD_RELOC_X86_64_TPOFF64", |
"BFD_RELOC_X86_64_TLSGD", |
"BFD_RELOC_X86_64_TLSLD", |
"BFD_RELOC_X86_64_DTPOFF32", |
"BFD_RELOC_X86_64_GOTTPOFF", |
"BFD_RELOC_X86_64_TPOFF32", |
"BFD_RELOC_X86_64_GOTOFF64", |
"BFD_RELOC_X86_64_GOTPC32", |
"BFD_RELOC_X86_64_GOT64", |
"BFD_RELOC_X86_64_GOTPCREL64", |
"BFD_RELOC_X86_64_GOTPC64", |
"BFD_RELOC_X86_64_GOTPLT64", |
"BFD_RELOC_X86_64_PLTOFF64", |
"BFD_RELOC_X86_64_GOTPC32_TLSDESC", |
"BFD_RELOC_X86_64_TLSDESC_CALL", |
"BFD_RELOC_X86_64_TLSDESC", |
"BFD_RELOC_X86_64_IRELATIVE", |
"BFD_RELOC_X86_64_PC32_BND", |
"BFD_RELOC_X86_64_PLT32_BND", |
"BFD_RELOC_NS32K_IMM_8", |
"BFD_RELOC_NS32K_IMM_16", |
"BFD_RELOC_NS32K_IMM_32", |
"BFD_RELOC_NS32K_IMM_8_PCREL", |
"BFD_RELOC_NS32K_IMM_16_PCREL", |
"BFD_RELOC_NS32K_IMM_32_PCREL", |
"BFD_RELOC_NS32K_DISP_8", |
"BFD_RELOC_NS32K_DISP_16", |
"BFD_RELOC_NS32K_DISP_32", |
"BFD_RELOC_NS32K_DISP_8_PCREL", |
"BFD_RELOC_NS32K_DISP_16_PCREL", |
"BFD_RELOC_NS32K_DISP_32_PCREL", |
"BFD_RELOC_PDP11_DISP_8_PCREL", |
"BFD_RELOC_PDP11_DISP_6_PCREL", |
"BFD_RELOC_PJ_CODE_HI16", |
"BFD_RELOC_PJ_CODE_LO16", |
"BFD_RELOC_PJ_CODE_DIR16", |
"BFD_RELOC_PJ_CODE_DIR32", |
"BFD_RELOC_PJ_CODE_REL16", |
"BFD_RELOC_PJ_CODE_REL32", |
"BFD_RELOC_PPC_B26", |
"BFD_RELOC_PPC_BA26", |
"BFD_RELOC_PPC_TOC16", |
"BFD_RELOC_PPC_B16", |
"BFD_RELOC_PPC_B16_BRTAKEN", |
"BFD_RELOC_PPC_B16_BRNTAKEN", |
"BFD_RELOC_PPC_BA16", |
"BFD_RELOC_PPC_BA16_BRTAKEN", |
"BFD_RELOC_PPC_BA16_BRNTAKEN", |
"BFD_RELOC_PPC_COPY", |
"BFD_RELOC_PPC_GLOB_DAT", |
"BFD_RELOC_PPC_JMP_SLOT", |
"BFD_RELOC_PPC_RELATIVE", |
"BFD_RELOC_PPC_LOCAL24PC", |
"BFD_RELOC_PPC_EMB_NADDR32", |
"BFD_RELOC_PPC_EMB_NADDR16", |
"BFD_RELOC_PPC_EMB_NADDR16_LO", |
"BFD_RELOC_PPC_EMB_NADDR16_HI", |
"BFD_RELOC_PPC_EMB_NADDR16_HA", |
"BFD_RELOC_PPC_EMB_SDAI16", |
"BFD_RELOC_PPC_EMB_SDA2I16", |
"BFD_RELOC_PPC_EMB_SDA2REL", |
"BFD_RELOC_PPC_EMB_SDA21", |
"BFD_RELOC_PPC_EMB_MRKREF", |
"BFD_RELOC_PPC_EMB_RELSEC16", |
"BFD_RELOC_PPC_EMB_RELST_LO", |
"BFD_RELOC_PPC_EMB_RELST_HI", |
"BFD_RELOC_PPC_EMB_RELST_HA", |
"BFD_RELOC_PPC_EMB_BIT_FLD", |
"BFD_RELOC_PPC_EMB_RELSDA", |
"BFD_RELOC_PPC_VLE_REL8", |
"BFD_RELOC_PPC_VLE_REL15", |
"BFD_RELOC_PPC_VLE_REL24", |
"BFD_RELOC_PPC_VLE_LO16A", |
"BFD_RELOC_PPC_VLE_LO16D", |
"BFD_RELOC_PPC_VLE_HI16A", |
"BFD_RELOC_PPC_VLE_HI16D", |
"BFD_RELOC_PPC_VLE_HA16A", |
"BFD_RELOC_PPC_VLE_HA16D", |
"BFD_RELOC_PPC_VLE_SDA21", |
"BFD_RELOC_PPC_VLE_SDA21_LO", |
"BFD_RELOC_PPC_VLE_SDAREL_LO16A", |
"BFD_RELOC_PPC_VLE_SDAREL_LO16D", |
"BFD_RELOC_PPC_VLE_SDAREL_HI16A", |
"BFD_RELOC_PPC_VLE_SDAREL_HI16D", |
"BFD_RELOC_PPC_VLE_SDAREL_HA16A", |
"BFD_RELOC_PPC_VLE_SDAREL_HA16D", |
"BFD_RELOC_PPC64_HIGHER", |
"BFD_RELOC_PPC64_HIGHER_S", |
"BFD_RELOC_PPC64_HIGHEST", |
"BFD_RELOC_PPC64_HIGHEST_S", |
"BFD_RELOC_PPC64_TOC16_LO", |
"BFD_RELOC_PPC64_TOC16_HI", |
"BFD_RELOC_PPC64_TOC16_HA", |
"BFD_RELOC_PPC64_TOC", |
"BFD_RELOC_PPC64_PLTGOT16", |
"BFD_RELOC_PPC64_PLTGOT16_LO", |
"BFD_RELOC_PPC64_PLTGOT16_HI", |
"BFD_RELOC_PPC64_PLTGOT16_HA", |
"BFD_RELOC_PPC64_ADDR16_DS", |
"BFD_RELOC_PPC64_ADDR16_LO_DS", |
"BFD_RELOC_PPC64_GOT16_DS", |
"BFD_RELOC_PPC64_GOT16_LO_DS", |
"BFD_RELOC_PPC64_PLT16_LO_DS", |
"BFD_RELOC_PPC64_SECTOFF_DS", |
"BFD_RELOC_PPC64_SECTOFF_LO_DS", |
"BFD_RELOC_PPC64_TOC16_DS", |
"BFD_RELOC_PPC64_TOC16_LO_DS", |
"BFD_RELOC_PPC64_PLTGOT16_DS", |
"BFD_RELOC_PPC64_PLTGOT16_LO_DS", |
"BFD_RELOC_PPC64_ADDR16_HIGH", |
"BFD_RELOC_PPC64_ADDR16_HIGHA", |
"BFD_RELOC_PPC_TLS", |
"BFD_RELOC_PPC_TLSGD", |
"BFD_RELOC_PPC_TLSLD", |
"BFD_RELOC_PPC_DTPMOD", |
"BFD_RELOC_PPC_TPREL16", |
"BFD_RELOC_PPC_TPREL16_LO", |
"BFD_RELOC_PPC_TPREL16_HI", |
"BFD_RELOC_PPC_TPREL16_HA", |
"BFD_RELOC_PPC_TPREL", |
"BFD_RELOC_PPC_DTPREL16", |
"BFD_RELOC_PPC_DTPREL16_LO", |
"BFD_RELOC_PPC_DTPREL16_HI", |
"BFD_RELOC_PPC_DTPREL16_HA", |
"BFD_RELOC_PPC_DTPREL", |
"BFD_RELOC_PPC_GOT_TLSGD16", |
"BFD_RELOC_PPC_GOT_TLSGD16_LO", |
"BFD_RELOC_PPC_GOT_TLSGD16_HI", |
"BFD_RELOC_PPC_GOT_TLSGD16_HA", |
"BFD_RELOC_PPC_GOT_TLSLD16", |
"BFD_RELOC_PPC_GOT_TLSLD16_LO", |
"BFD_RELOC_PPC_GOT_TLSLD16_HI", |
"BFD_RELOC_PPC_GOT_TLSLD16_HA", |
"BFD_RELOC_PPC_GOT_TPREL16", |
"BFD_RELOC_PPC_GOT_TPREL16_LO", |
"BFD_RELOC_PPC_GOT_TPREL16_HI", |
"BFD_RELOC_PPC_GOT_TPREL16_HA", |
"BFD_RELOC_PPC_GOT_DTPREL16", |
"BFD_RELOC_PPC_GOT_DTPREL16_LO", |
"BFD_RELOC_PPC_GOT_DTPREL16_HI", |
"BFD_RELOC_PPC_GOT_DTPREL16_HA", |
"BFD_RELOC_PPC64_TPREL16_DS", |
"BFD_RELOC_PPC64_TPREL16_LO_DS", |
"BFD_RELOC_PPC64_TPREL16_HIGHER", |
"BFD_RELOC_PPC64_TPREL16_HIGHERA", |
"BFD_RELOC_PPC64_TPREL16_HIGHEST", |
"BFD_RELOC_PPC64_TPREL16_HIGHESTA", |
"BFD_RELOC_PPC64_DTPREL16_DS", |
"BFD_RELOC_PPC64_DTPREL16_LO_DS", |
"BFD_RELOC_PPC64_DTPREL16_HIGHER", |
"BFD_RELOC_PPC64_DTPREL16_HIGHERA", |
"BFD_RELOC_PPC64_DTPREL16_HIGHEST", |
"BFD_RELOC_PPC64_DTPREL16_HIGHESTA", |
"BFD_RELOC_PPC64_TPREL16_HIGH", |
"BFD_RELOC_PPC64_TPREL16_HIGHA", |
"BFD_RELOC_PPC64_DTPREL16_HIGH", |
"BFD_RELOC_PPC64_DTPREL16_HIGHA", |
"BFD_RELOC_I370_D12", |
"BFD_RELOC_CTOR", |
"BFD_RELOC_ARM_PCREL_BRANCH", |
"BFD_RELOC_ARM_PCREL_BLX", |
"BFD_RELOC_THUMB_PCREL_BLX", |
"BFD_RELOC_ARM_PCREL_CALL", |
"BFD_RELOC_ARM_PCREL_JUMP", |
"BFD_RELOC_THUMB_PCREL_BRANCH7", |
"BFD_RELOC_THUMB_PCREL_BRANCH9", |
"BFD_RELOC_THUMB_PCREL_BRANCH12", |
"BFD_RELOC_THUMB_PCREL_BRANCH20", |
"BFD_RELOC_THUMB_PCREL_BRANCH23", |
"BFD_RELOC_THUMB_PCREL_BRANCH25", |
"BFD_RELOC_ARM_OFFSET_IMM", |
"BFD_RELOC_ARM_THUMB_OFFSET", |
"BFD_RELOC_ARM_TARGET1", |
"BFD_RELOC_ARM_ROSEGREL32", |
"BFD_RELOC_ARM_SBREL32", |
"BFD_RELOC_ARM_TARGET2", |
"BFD_RELOC_ARM_PREL31", |
"BFD_RELOC_ARM_MOVW", |
"BFD_RELOC_ARM_MOVT", |
"BFD_RELOC_ARM_MOVW_PCREL", |
"BFD_RELOC_ARM_MOVT_PCREL", |
"BFD_RELOC_ARM_THUMB_MOVW", |
"BFD_RELOC_ARM_THUMB_MOVT", |
"BFD_RELOC_ARM_THUMB_MOVW_PCREL", |
"BFD_RELOC_ARM_THUMB_MOVT_PCREL", |
"BFD_RELOC_ARM_JUMP_SLOT", |
"BFD_RELOC_ARM_GLOB_DAT", |
"BFD_RELOC_ARM_GOT32", |
"BFD_RELOC_ARM_PLT32", |
"BFD_RELOC_ARM_RELATIVE", |
"BFD_RELOC_ARM_GOTOFF", |
"BFD_RELOC_ARM_GOTPC", |
"BFD_RELOC_ARM_GOT_PREL", |
"BFD_RELOC_ARM_TLS_GD32", |
"BFD_RELOC_ARM_TLS_LDO32", |
"BFD_RELOC_ARM_TLS_LDM32", |
"BFD_RELOC_ARM_TLS_DTPOFF32", |
"BFD_RELOC_ARM_TLS_DTPMOD32", |
"BFD_RELOC_ARM_TLS_TPOFF32", |
"BFD_RELOC_ARM_TLS_IE32", |
"BFD_RELOC_ARM_TLS_LE32", |
"BFD_RELOC_ARM_TLS_GOTDESC", |
"BFD_RELOC_ARM_TLS_CALL", |
"BFD_RELOC_ARM_THM_TLS_CALL", |
"BFD_RELOC_ARM_TLS_DESCSEQ", |
"BFD_RELOC_ARM_THM_TLS_DESCSEQ", |
"BFD_RELOC_ARM_TLS_DESC", |
"BFD_RELOC_ARM_ALU_PC_G0_NC", |
"BFD_RELOC_ARM_ALU_PC_G0", |
"BFD_RELOC_ARM_ALU_PC_G1_NC", |
"BFD_RELOC_ARM_ALU_PC_G1", |
"BFD_RELOC_ARM_ALU_PC_G2", |
"BFD_RELOC_ARM_LDR_PC_G0", |
"BFD_RELOC_ARM_LDR_PC_G1", |
"BFD_RELOC_ARM_LDR_PC_G2", |
"BFD_RELOC_ARM_LDRS_PC_G0", |
"BFD_RELOC_ARM_LDRS_PC_G1", |
"BFD_RELOC_ARM_LDRS_PC_G2", |
"BFD_RELOC_ARM_LDC_PC_G0", |
"BFD_RELOC_ARM_LDC_PC_G1", |
"BFD_RELOC_ARM_LDC_PC_G2", |
"BFD_RELOC_ARM_ALU_SB_G0_NC", |
"BFD_RELOC_ARM_ALU_SB_G0", |
"BFD_RELOC_ARM_ALU_SB_G1_NC", |
"BFD_RELOC_ARM_ALU_SB_G1", |
"BFD_RELOC_ARM_ALU_SB_G2", |
"BFD_RELOC_ARM_LDR_SB_G0", |
"BFD_RELOC_ARM_LDR_SB_G1", |
"BFD_RELOC_ARM_LDR_SB_G2", |
"BFD_RELOC_ARM_LDRS_SB_G0", |
"BFD_RELOC_ARM_LDRS_SB_G1", |
"BFD_RELOC_ARM_LDRS_SB_G2", |
"BFD_RELOC_ARM_LDC_SB_G0", |
"BFD_RELOC_ARM_LDC_SB_G1", |
"BFD_RELOC_ARM_LDC_SB_G2", |
"BFD_RELOC_ARM_V4BX", |
"BFD_RELOC_ARM_IRELATIVE", |
"BFD_RELOC_ARM_IMMEDIATE", |
"BFD_RELOC_ARM_ADRL_IMMEDIATE", |
"BFD_RELOC_ARM_T32_IMMEDIATE", |
"BFD_RELOC_ARM_T32_ADD_IMM", |
"BFD_RELOC_ARM_T32_IMM12", |
"BFD_RELOC_ARM_T32_ADD_PC12", |
"BFD_RELOC_ARM_SHIFT_IMM", |
"BFD_RELOC_ARM_SMC", |
"BFD_RELOC_ARM_HVC", |
"BFD_RELOC_ARM_SWI", |
"BFD_RELOC_ARM_MULTI", |
"BFD_RELOC_ARM_CP_OFF_IMM", |
"BFD_RELOC_ARM_CP_OFF_IMM_S2", |
"BFD_RELOC_ARM_T32_CP_OFF_IMM", |
"BFD_RELOC_ARM_T32_CP_OFF_IMM_S2", |
"BFD_RELOC_ARM_ADR_IMM", |
"BFD_RELOC_ARM_LDR_IMM", |
"BFD_RELOC_ARM_LITERAL", |
"BFD_RELOC_ARM_IN_POOL", |
"BFD_RELOC_ARM_OFFSET_IMM8", |
"BFD_RELOC_ARM_T32_OFFSET_U8", |
"BFD_RELOC_ARM_T32_OFFSET_IMM", |
"BFD_RELOC_ARM_HWLITERAL", |
"BFD_RELOC_ARM_THUMB_ADD", |
"BFD_RELOC_ARM_THUMB_IMM", |
"BFD_RELOC_ARM_THUMB_SHIFT", |
"BFD_RELOC_SH_PCDISP8BY2", |
"BFD_RELOC_SH_PCDISP12BY2", |
"BFD_RELOC_SH_IMM3", |
"BFD_RELOC_SH_IMM3U", |
"BFD_RELOC_SH_DISP12", |
"BFD_RELOC_SH_DISP12BY2", |
"BFD_RELOC_SH_DISP12BY4", |
"BFD_RELOC_SH_DISP12BY8", |
"BFD_RELOC_SH_DISP20", |
"BFD_RELOC_SH_DISP20BY8", |
"BFD_RELOC_SH_IMM4", |
"BFD_RELOC_SH_IMM4BY2", |
"BFD_RELOC_SH_IMM4BY4", |
"BFD_RELOC_SH_IMM8", |
"BFD_RELOC_SH_IMM8BY2", |
"BFD_RELOC_SH_IMM8BY4", |
"BFD_RELOC_SH_PCRELIMM8BY2", |
"BFD_RELOC_SH_PCRELIMM8BY4", |
"BFD_RELOC_SH_SWITCH16", |
"BFD_RELOC_SH_SWITCH32", |
"BFD_RELOC_SH_USES", |
"BFD_RELOC_SH_COUNT", |
"BFD_RELOC_SH_ALIGN", |
"BFD_RELOC_SH_CODE", |
"BFD_RELOC_SH_DATA", |
"BFD_RELOC_SH_LABEL", |
"BFD_RELOC_SH_LOOP_START", |
"BFD_RELOC_SH_LOOP_END", |
"BFD_RELOC_SH_COPY", |
"BFD_RELOC_SH_GLOB_DAT", |
"BFD_RELOC_SH_JMP_SLOT", |
"BFD_RELOC_SH_RELATIVE", |
"BFD_RELOC_SH_GOTPC", |
"BFD_RELOC_SH_GOT_LOW16", |
"BFD_RELOC_SH_GOT_MEDLOW16", |
"BFD_RELOC_SH_GOT_MEDHI16", |
"BFD_RELOC_SH_GOT_HI16", |
"BFD_RELOC_SH_GOTPLT_LOW16", |
"BFD_RELOC_SH_GOTPLT_MEDLOW16", |
"BFD_RELOC_SH_GOTPLT_MEDHI16", |
"BFD_RELOC_SH_GOTPLT_HI16", |
"BFD_RELOC_SH_PLT_LOW16", |
"BFD_RELOC_SH_PLT_MEDLOW16", |
"BFD_RELOC_SH_PLT_MEDHI16", |
"BFD_RELOC_SH_PLT_HI16", |
"BFD_RELOC_SH_GOTOFF_LOW16", |
"BFD_RELOC_SH_GOTOFF_MEDLOW16", |
"BFD_RELOC_SH_GOTOFF_MEDHI16", |
"BFD_RELOC_SH_GOTOFF_HI16", |
"BFD_RELOC_SH_GOTPC_LOW16", |
"BFD_RELOC_SH_GOTPC_MEDLOW16", |
"BFD_RELOC_SH_GOTPC_MEDHI16", |
"BFD_RELOC_SH_GOTPC_HI16", |
"BFD_RELOC_SH_COPY64", |
"BFD_RELOC_SH_GLOB_DAT64", |
"BFD_RELOC_SH_JMP_SLOT64", |
"BFD_RELOC_SH_RELATIVE64", |
"BFD_RELOC_SH_GOT10BY4", |
"BFD_RELOC_SH_GOT10BY8", |
"BFD_RELOC_SH_GOTPLT10BY4", |
"BFD_RELOC_SH_GOTPLT10BY8", |
"BFD_RELOC_SH_GOTPLT32", |
"BFD_RELOC_SH_SHMEDIA_CODE", |
"BFD_RELOC_SH_IMMU5", |
"BFD_RELOC_SH_IMMS6", |
"BFD_RELOC_SH_IMMS6BY32", |
"BFD_RELOC_SH_IMMU6", |
"BFD_RELOC_SH_IMMS10", |
"BFD_RELOC_SH_IMMS10BY2", |
"BFD_RELOC_SH_IMMS10BY4", |
"BFD_RELOC_SH_IMMS10BY8", |
"BFD_RELOC_SH_IMMS16", |
"BFD_RELOC_SH_IMMU16", |
"BFD_RELOC_SH_IMM_LOW16", |
"BFD_RELOC_SH_IMM_LOW16_PCREL", |
"BFD_RELOC_SH_IMM_MEDLOW16", |
"BFD_RELOC_SH_IMM_MEDLOW16_PCREL", |
"BFD_RELOC_SH_IMM_MEDHI16", |
"BFD_RELOC_SH_IMM_MEDHI16_PCREL", |
"BFD_RELOC_SH_IMM_HI16", |
"BFD_RELOC_SH_IMM_HI16_PCREL", |
"BFD_RELOC_SH_PT_16", |
"BFD_RELOC_SH_TLS_GD_32", |
"BFD_RELOC_SH_TLS_LD_32", |
"BFD_RELOC_SH_TLS_LDO_32", |
"BFD_RELOC_SH_TLS_IE_32", |
"BFD_RELOC_SH_TLS_LE_32", |
"BFD_RELOC_SH_TLS_DTPMOD32", |
"BFD_RELOC_SH_TLS_DTPOFF32", |
"BFD_RELOC_SH_TLS_TPOFF32", |
"BFD_RELOC_SH_GOT20", |
"BFD_RELOC_SH_GOTOFF20", |
"BFD_RELOC_SH_GOTFUNCDESC", |
"BFD_RELOC_SH_GOTFUNCDESC20", |
"BFD_RELOC_SH_GOTOFFFUNCDESC", |
"BFD_RELOC_SH_GOTOFFFUNCDESC20", |
"BFD_RELOC_SH_FUNCDESC", |
"BFD_RELOC_ARC_B22_PCREL", |
"BFD_RELOC_ARC_B26", |
"BFD_RELOC_BFIN_16_IMM", |
"BFD_RELOC_BFIN_16_HIGH", |
"BFD_RELOC_BFIN_4_PCREL", |
"BFD_RELOC_BFIN_5_PCREL", |
"BFD_RELOC_BFIN_16_LOW", |
"BFD_RELOC_BFIN_10_PCREL", |
"BFD_RELOC_BFIN_11_PCREL", |
"BFD_RELOC_BFIN_12_PCREL_JUMP", |
"BFD_RELOC_BFIN_12_PCREL_JUMP_S", |
"BFD_RELOC_BFIN_24_PCREL_CALL_X", |
"BFD_RELOC_BFIN_24_PCREL_JUMP_L", |
"BFD_RELOC_BFIN_GOT17M4", |
"BFD_RELOC_BFIN_GOTHI", |
"BFD_RELOC_BFIN_GOTLO", |
"BFD_RELOC_BFIN_FUNCDESC", |
"BFD_RELOC_BFIN_FUNCDESC_GOT17M4", |
"BFD_RELOC_BFIN_FUNCDESC_GOTHI", |
"BFD_RELOC_BFIN_FUNCDESC_GOTLO", |
"BFD_RELOC_BFIN_FUNCDESC_VALUE", |
"BFD_RELOC_BFIN_FUNCDESC_GOTOFF17M4", |
"BFD_RELOC_BFIN_FUNCDESC_GOTOFFHI", |
"BFD_RELOC_BFIN_FUNCDESC_GOTOFFLO", |
"BFD_RELOC_BFIN_GOTOFF17M4", |
"BFD_RELOC_BFIN_GOTOFFHI", |
"BFD_RELOC_BFIN_GOTOFFLO", |
"BFD_RELOC_BFIN_GOT", |
"BFD_RELOC_BFIN_PLTPC", |
"BFD_ARELOC_BFIN_PUSH", |
"BFD_ARELOC_BFIN_CONST", |
"BFD_ARELOC_BFIN_ADD", |
"BFD_ARELOC_BFIN_SUB", |
"BFD_ARELOC_BFIN_MULT", |
"BFD_ARELOC_BFIN_DIV", |
"BFD_ARELOC_BFIN_MOD", |
"BFD_ARELOC_BFIN_LSHIFT", |
"BFD_ARELOC_BFIN_RSHIFT", |
"BFD_ARELOC_BFIN_AND", |
"BFD_ARELOC_BFIN_OR", |
"BFD_ARELOC_BFIN_XOR", |
"BFD_ARELOC_BFIN_LAND", |
"BFD_ARELOC_BFIN_LOR", |
"BFD_ARELOC_BFIN_LEN", |
"BFD_ARELOC_BFIN_NEG", |
"BFD_ARELOC_BFIN_COMP", |
"BFD_ARELOC_BFIN_PAGE", |
"BFD_ARELOC_BFIN_HWPAGE", |
"BFD_ARELOC_BFIN_ADDR", |
"BFD_RELOC_D10V_10_PCREL_R", |
"BFD_RELOC_D10V_10_PCREL_L", |
"BFD_RELOC_D10V_18", |
"BFD_RELOC_D10V_18_PCREL", |
"BFD_RELOC_D30V_6", |
"BFD_RELOC_D30V_9_PCREL", |
"BFD_RELOC_D30V_9_PCREL_R", |
"BFD_RELOC_D30V_15", |
"BFD_RELOC_D30V_15_PCREL", |
"BFD_RELOC_D30V_15_PCREL_R", |
"BFD_RELOC_D30V_21", |
"BFD_RELOC_D30V_21_PCREL", |
"BFD_RELOC_D30V_21_PCREL_R", |
"BFD_RELOC_D30V_32", |
"BFD_RELOC_D30V_32_PCREL", |
"BFD_RELOC_DLX_HI16_S", |
"BFD_RELOC_DLX_LO16", |
"BFD_RELOC_DLX_JMP26", |
"BFD_RELOC_M32C_HI8", |
"BFD_RELOC_M32C_RL_JUMP", |
"BFD_RELOC_M32C_RL_1ADDR", |
"BFD_RELOC_M32C_RL_2ADDR", |
"BFD_RELOC_M32R_24", |
"BFD_RELOC_M32R_10_PCREL", |
"BFD_RELOC_M32R_18_PCREL", |
"BFD_RELOC_M32R_26_PCREL", |
"BFD_RELOC_M32R_HI16_ULO", |
"BFD_RELOC_M32R_HI16_SLO", |
"BFD_RELOC_M32R_LO16", |
"BFD_RELOC_M32R_SDA16", |
"BFD_RELOC_M32R_GOT24", |
"BFD_RELOC_M32R_26_PLTREL", |
"BFD_RELOC_M32R_COPY", |
"BFD_RELOC_M32R_GLOB_DAT", |
"BFD_RELOC_M32R_JMP_SLOT", |
"BFD_RELOC_M32R_RELATIVE", |
"BFD_RELOC_M32R_GOTOFF", |
"BFD_RELOC_M32R_GOTOFF_HI_ULO", |
"BFD_RELOC_M32R_GOTOFF_HI_SLO", |
"BFD_RELOC_M32R_GOTOFF_LO", |
"BFD_RELOC_M32R_GOTPC24", |
"BFD_RELOC_M32R_GOT16_HI_ULO", |
"BFD_RELOC_M32R_GOT16_HI_SLO", |
"BFD_RELOC_M32R_GOT16_LO", |
"BFD_RELOC_M32R_GOTPC_HI_ULO", |
"BFD_RELOC_M32R_GOTPC_HI_SLO", |
"BFD_RELOC_M32R_GOTPC_LO", |
"BFD_RELOC_V850_9_PCREL", |
"BFD_RELOC_V850_22_PCREL", |
"BFD_RELOC_V850_SDA_16_16_OFFSET", |
"BFD_RELOC_V850_SDA_15_16_OFFSET", |
"BFD_RELOC_V850_ZDA_16_16_OFFSET", |
"BFD_RELOC_V850_ZDA_15_16_OFFSET", |
"BFD_RELOC_V850_TDA_6_8_OFFSET", |
"BFD_RELOC_V850_TDA_7_8_OFFSET", |
"BFD_RELOC_V850_TDA_7_7_OFFSET", |
"BFD_RELOC_V850_TDA_16_16_OFFSET", |
"BFD_RELOC_V850_TDA_4_5_OFFSET", |
"BFD_RELOC_V850_TDA_4_4_OFFSET", |
"BFD_RELOC_V850_SDA_16_16_SPLIT_OFFSET", |
"BFD_RELOC_V850_ZDA_16_16_SPLIT_OFFSET", |
"BFD_RELOC_V850_CALLT_6_7_OFFSET", |
"BFD_RELOC_V850_CALLT_16_16_OFFSET", |
"BFD_RELOC_V850_LONGCALL", |
"BFD_RELOC_V850_LONGJUMP", |
"BFD_RELOC_V850_ALIGN", |
"BFD_RELOC_V850_LO16_SPLIT_OFFSET", |
"BFD_RELOC_V850_16_PCREL", |
"BFD_RELOC_V850_17_PCREL", |
"BFD_RELOC_V850_23", |
"BFD_RELOC_V850_32_PCREL", |
"BFD_RELOC_V850_32_ABS", |
"BFD_RELOC_V850_16_SPLIT_OFFSET", |
"BFD_RELOC_V850_16_S1", |
"BFD_RELOC_V850_LO16_S1", |
"BFD_RELOC_V850_CALLT_15_16_OFFSET", |
"BFD_RELOC_V850_32_GOTPCREL", |
"BFD_RELOC_V850_16_GOT", |
"BFD_RELOC_V850_32_GOT", |
"BFD_RELOC_V850_22_PLT_PCREL", |
"BFD_RELOC_V850_32_PLT_PCREL", |
"BFD_RELOC_V850_COPY", |
"BFD_RELOC_V850_GLOB_DAT", |
"BFD_RELOC_V850_JMP_SLOT", |
"BFD_RELOC_V850_RELATIVE", |
"BFD_RELOC_V850_16_GOTOFF", |
"BFD_RELOC_V850_32_GOTOFF", |
"BFD_RELOC_V850_CODE", |
"BFD_RELOC_V850_DATA", |
"BFD_RELOC_TIC30_LDP", |
"BFD_RELOC_TIC54X_PARTLS7", |
"BFD_RELOC_TIC54X_PARTMS9", |
"BFD_RELOC_TIC54X_23", |
"BFD_RELOC_TIC54X_16_OF_23", |
"BFD_RELOC_TIC54X_MS7_OF_23", |
"BFD_RELOC_C6000_PCR_S21", |
"BFD_RELOC_C6000_PCR_S12", |
"BFD_RELOC_C6000_PCR_S10", |
"BFD_RELOC_C6000_PCR_S7", |
"BFD_RELOC_C6000_ABS_S16", |
"BFD_RELOC_C6000_ABS_L16", |
"BFD_RELOC_C6000_ABS_H16", |
"BFD_RELOC_C6000_SBR_U15_B", |
"BFD_RELOC_C6000_SBR_U15_H", |
"BFD_RELOC_C6000_SBR_U15_W", |
"BFD_RELOC_C6000_SBR_S16", |
"BFD_RELOC_C6000_SBR_L16_B", |
"BFD_RELOC_C6000_SBR_L16_H", |
"BFD_RELOC_C6000_SBR_L16_W", |
"BFD_RELOC_C6000_SBR_H16_B", |
"BFD_RELOC_C6000_SBR_H16_H", |
"BFD_RELOC_C6000_SBR_H16_W", |
"BFD_RELOC_C6000_SBR_GOT_U15_W", |
"BFD_RELOC_C6000_SBR_GOT_L16_W", |
"BFD_RELOC_C6000_SBR_GOT_H16_W", |
"BFD_RELOC_C6000_DSBT_INDEX", |
"BFD_RELOC_C6000_PREL31", |
"BFD_RELOC_C6000_COPY", |
"BFD_RELOC_C6000_JUMP_SLOT", |
"BFD_RELOC_C6000_EHTYPE", |
"BFD_RELOC_C6000_PCR_H16", |
"BFD_RELOC_C6000_PCR_L16", |
"BFD_RELOC_C6000_ALIGN", |
"BFD_RELOC_C6000_FPHEAD", |
"BFD_RELOC_C6000_NOCMP", |
"BFD_RELOC_FR30_48", |
"BFD_RELOC_FR30_20", |
"BFD_RELOC_FR30_6_IN_4", |
"BFD_RELOC_FR30_8_IN_8", |
"BFD_RELOC_FR30_9_IN_8", |
"BFD_RELOC_FR30_10_IN_8", |
"BFD_RELOC_FR30_9_PCREL", |
"BFD_RELOC_FR30_12_PCREL", |
"BFD_RELOC_MCORE_PCREL_IMM8BY4", |
"BFD_RELOC_MCORE_PCREL_IMM11BY2", |
"BFD_RELOC_MCORE_PCREL_IMM4BY2", |
"BFD_RELOC_MCORE_PCREL_32", |
"BFD_RELOC_MCORE_PCREL_JSR_IMM11BY2", |
"BFD_RELOC_MCORE_RVA", |
"BFD_RELOC_MEP_8", |
"BFD_RELOC_MEP_16", |
"BFD_RELOC_MEP_32", |
"BFD_RELOC_MEP_PCREL8A2", |
"BFD_RELOC_MEP_PCREL12A2", |
"BFD_RELOC_MEP_PCREL17A2", |
"BFD_RELOC_MEP_PCREL24A2", |
"BFD_RELOC_MEP_PCABS24A2", |
"BFD_RELOC_MEP_LOW16", |
"BFD_RELOC_MEP_HI16U", |
"BFD_RELOC_MEP_HI16S", |
"BFD_RELOC_MEP_GPREL", |
"BFD_RELOC_MEP_TPREL", |
"BFD_RELOC_MEP_TPREL7", |
"BFD_RELOC_MEP_TPREL7A2", |
"BFD_RELOC_MEP_TPREL7A4", |
"BFD_RELOC_MEP_UIMM24", |
"BFD_RELOC_MEP_ADDR24A4", |
"BFD_RELOC_MEP_GNU_VTINHERIT", |
"BFD_RELOC_MEP_GNU_VTENTRY", |
"BFD_RELOC_METAG_HIADDR16", |
"BFD_RELOC_METAG_LOADDR16", |
"BFD_RELOC_METAG_RELBRANCH", |
"BFD_RELOC_METAG_GETSETOFF", |
"BFD_RELOC_METAG_HIOG", |
"BFD_RELOC_METAG_LOOG", |
"BFD_RELOC_METAG_REL8", |
"BFD_RELOC_METAG_REL16", |
"BFD_RELOC_METAG_HI16_GOTOFF", |
"BFD_RELOC_METAG_LO16_GOTOFF", |
"BFD_RELOC_METAG_GETSET_GOTOFF", |
"BFD_RELOC_METAG_GETSET_GOT", |
"BFD_RELOC_METAG_HI16_GOTPC", |
"BFD_RELOC_METAG_LO16_GOTPC", |
"BFD_RELOC_METAG_HI16_PLT", |
"BFD_RELOC_METAG_LO16_PLT", |
"BFD_RELOC_METAG_RELBRANCH_PLT", |
"BFD_RELOC_METAG_GOTOFF", |
"BFD_RELOC_METAG_PLT", |
"BFD_RELOC_METAG_COPY", |
"BFD_RELOC_METAG_JMP_SLOT", |
"BFD_RELOC_METAG_RELATIVE", |
"BFD_RELOC_METAG_GLOB_DAT", |
"BFD_RELOC_METAG_TLS_GD", |
"BFD_RELOC_METAG_TLS_LDM", |
"BFD_RELOC_METAG_TLS_LDO_HI16", |
"BFD_RELOC_METAG_TLS_LDO_LO16", |
"BFD_RELOC_METAG_TLS_LDO", |
"BFD_RELOC_METAG_TLS_IE", |
"BFD_RELOC_METAG_TLS_IENONPIC", |
"BFD_RELOC_METAG_TLS_IENONPIC_HI16", |
"BFD_RELOC_METAG_TLS_IENONPIC_LO16", |
"BFD_RELOC_METAG_TLS_TPOFF", |
"BFD_RELOC_METAG_TLS_DTPMOD", |
"BFD_RELOC_METAG_TLS_DTPOFF", |
"BFD_RELOC_METAG_TLS_LE", |
"BFD_RELOC_METAG_TLS_LE_HI16", |
"BFD_RELOC_METAG_TLS_LE_LO16", |
"BFD_RELOC_MMIX_GETA", |
"BFD_RELOC_MMIX_GETA_1", |
"BFD_RELOC_MMIX_GETA_2", |
"BFD_RELOC_MMIX_GETA_3", |
"BFD_RELOC_MMIX_CBRANCH", |
"BFD_RELOC_MMIX_CBRANCH_J", |
"BFD_RELOC_MMIX_CBRANCH_1", |
"BFD_RELOC_MMIX_CBRANCH_2", |
"BFD_RELOC_MMIX_CBRANCH_3", |
"BFD_RELOC_MMIX_PUSHJ", |
"BFD_RELOC_MMIX_PUSHJ_1", |
"BFD_RELOC_MMIX_PUSHJ_2", |
"BFD_RELOC_MMIX_PUSHJ_3", |
"BFD_RELOC_MMIX_PUSHJ_STUBBABLE", |
"BFD_RELOC_MMIX_JMP", |
"BFD_RELOC_MMIX_JMP_1", |
"BFD_RELOC_MMIX_JMP_2", |
"BFD_RELOC_MMIX_JMP_3", |
"BFD_RELOC_MMIX_ADDR19", |
"BFD_RELOC_MMIX_ADDR27", |
"BFD_RELOC_MMIX_REG_OR_BYTE", |
"BFD_RELOC_MMIX_REG", |
"BFD_RELOC_MMIX_BASE_PLUS_OFFSET", |
"BFD_RELOC_MMIX_LOCAL", |
"BFD_RELOC_AVR_7_PCREL", |
"BFD_RELOC_AVR_13_PCREL", |
"BFD_RELOC_AVR_16_PM", |
"BFD_RELOC_AVR_LO8_LDI", |
"BFD_RELOC_AVR_HI8_LDI", |
"BFD_RELOC_AVR_HH8_LDI", |
"BFD_RELOC_AVR_MS8_LDI", |
"BFD_RELOC_AVR_LO8_LDI_NEG", |
"BFD_RELOC_AVR_HI8_LDI_NEG", |
"BFD_RELOC_AVR_HH8_LDI_NEG", |
"BFD_RELOC_AVR_MS8_LDI_NEG", |
"BFD_RELOC_AVR_LO8_LDI_PM", |
"BFD_RELOC_AVR_LO8_LDI_GS", |
"BFD_RELOC_AVR_HI8_LDI_PM", |
"BFD_RELOC_AVR_HI8_LDI_GS", |
"BFD_RELOC_AVR_HH8_LDI_PM", |
"BFD_RELOC_AVR_LO8_LDI_PM_NEG", |
"BFD_RELOC_AVR_HI8_LDI_PM_NEG", |
"BFD_RELOC_AVR_HH8_LDI_PM_NEG", |
"BFD_RELOC_AVR_CALL", |
"BFD_RELOC_AVR_LDI", |
"BFD_RELOC_AVR_6", |
"BFD_RELOC_AVR_6_ADIW", |
"BFD_RELOC_AVR_8_LO", |
"BFD_RELOC_AVR_8_HI", |
"BFD_RELOC_AVR_8_HLO", |
"BFD_RELOC_RL78_NEG8", |
"BFD_RELOC_RL78_NEG16", |
"BFD_RELOC_RL78_NEG24", |
"BFD_RELOC_RL78_NEG32", |
"BFD_RELOC_RL78_16_OP", |
"BFD_RELOC_RL78_24_OP", |
"BFD_RELOC_RL78_32_OP", |
"BFD_RELOC_RL78_8U", |
"BFD_RELOC_RL78_16U", |
"BFD_RELOC_RL78_24U", |
"BFD_RELOC_RL78_DIR3U_PCREL", |
"BFD_RELOC_RL78_DIFF", |
"BFD_RELOC_RL78_GPRELB", |
"BFD_RELOC_RL78_GPRELW", |
"BFD_RELOC_RL78_GPRELL", |
"BFD_RELOC_RL78_SYM", |
"BFD_RELOC_RL78_OP_SUBTRACT", |
"BFD_RELOC_RL78_OP_NEG", |
"BFD_RELOC_RL78_OP_AND", |
"BFD_RELOC_RL78_OP_SHRA", |
"BFD_RELOC_RL78_ABS8", |
"BFD_RELOC_RL78_ABS16", |
"BFD_RELOC_RL78_ABS16_REV", |
"BFD_RELOC_RL78_ABS32", |
"BFD_RELOC_RL78_ABS32_REV", |
"BFD_RELOC_RL78_ABS16U", |
"BFD_RELOC_RL78_ABS16UW", |
"BFD_RELOC_RL78_ABS16UL", |
"BFD_RELOC_RL78_RELAX", |
"BFD_RELOC_RL78_HI16", |
"BFD_RELOC_RL78_HI8", |
"BFD_RELOC_RL78_LO16", |
"BFD_RELOC_RL78_CODE", |
"BFD_RELOC_RX_NEG8", |
"BFD_RELOC_RX_NEG16", |
"BFD_RELOC_RX_NEG24", |
"BFD_RELOC_RX_NEG32", |
"BFD_RELOC_RX_16_OP", |
"BFD_RELOC_RX_24_OP", |
"BFD_RELOC_RX_32_OP", |
"BFD_RELOC_RX_8U", |
"BFD_RELOC_RX_16U", |
"BFD_RELOC_RX_24U", |
"BFD_RELOC_RX_DIR3U_PCREL", |
"BFD_RELOC_RX_DIFF", |
"BFD_RELOC_RX_GPRELB", |
"BFD_RELOC_RX_GPRELW", |
"BFD_RELOC_RX_GPRELL", |
"BFD_RELOC_RX_SYM", |
"BFD_RELOC_RX_OP_SUBTRACT", |
"BFD_RELOC_RX_OP_NEG", |
"BFD_RELOC_RX_ABS8", |
"BFD_RELOC_RX_ABS16", |
"BFD_RELOC_RX_ABS16_REV", |
"BFD_RELOC_RX_ABS32", |
"BFD_RELOC_RX_ABS32_REV", |
"BFD_RELOC_RX_ABS16U", |
"BFD_RELOC_RX_ABS16UW", |
"BFD_RELOC_RX_ABS16UL", |
"BFD_RELOC_RX_RELAX", |
"BFD_RELOC_390_12", |
"BFD_RELOC_390_GOT12", |
"BFD_RELOC_390_PLT32", |
"BFD_RELOC_390_COPY", |
"BFD_RELOC_390_GLOB_DAT", |
"BFD_RELOC_390_JMP_SLOT", |
"BFD_RELOC_390_RELATIVE", |
"BFD_RELOC_390_GOTPC", |
"BFD_RELOC_390_GOT16", |
"BFD_RELOC_390_PC12DBL", |
"BFD_RELOC_390_PLT12DBL", |
"BFD_RELOC_390_PC16DBL", |
"BFD_RELOC_390_PLT16DBL", |
"BFD_RELOC_390_PC24DBL", |
"BFD_RELOC_390_PLT24DBL", |
"BFD_RELOC_390_PC32DBL", |
"BFD_RELOC_390_PLT32DBL", |
"BFD_RELOC_390_GOTPCDBL", |
"BFD_RELOC_390_GOT64", |
"BFD_RELOC_390_PLT64", |
"BFD_RELOC_390_GOTENT", |
"BFD_RELOC_390_GOTOFF64", |
"BFD_RELOC_390_GOTPLT12", |
"BFD_RELOC_390_GOTPLT16", |
"BFD_RELOC_390_GOTPLT32", |
"BFD_RELOC_390_GOTPLT64", |
"BFD_RELOC_390_GOTPLTENT", |
"BFD_RELOC_390_PLTOFF16", |
"BFD_RELOC_390_PLTOFF32", |
"BFD_RELOC_390_PLTOFF64", |
"BFD_RELOC_390_TLS_LOAD", |
"BFD_RELOC_390_TLS_GDCALL", |
"BFD_RELOC_390_TLS_LDCALL", |
"BFD_RELOC_390_TLS_GD32", |
"BFD_RELOC_390_TLS_GD64", |
"BFD_RELOC_390_TLS_GOTIE12", |
"BFD_RELOC_390_TLS_GOTIE32", |
"BFD_RELOC_390_TLS_GOTIE64", |
"BFD_RELOC_390_TLS_LDM32", |
"BFD_RELOC_390_TLS_LDM64", |
"BFD_RELOC_390_TLS_IE32", |
"BFD_RELOC_390_TLS_IE64", |
"BFD_RELOC_390_TLS_IEENT", |
"BFD_RELOC_390_TLS_LE32", |
"BFD_RELOC_390_TLS_LE64", |
"BFD_RELOC_390_TLS_LDO32", |
"BFD_RELOC_390_TLS_LDO64", |
"BFD_RELOC_390_TLS_DTPMOD", |
"BFD_RELOC_390_TLS_DTPOFF", |
"BFD_RELOC_390_TLS_TPOFF", |
"BFD_RELOC_390_20", |
"BFD_RELOC_390_GOT20", |
"BFD_RELOC_390_GOTPLT20", |
"BFD_RELOC_390_TLS_GOTIE20", |
"BFD_RELOC_390_IRELATIVE", |
"BFD_RELOC_SCORE_GPREL15", |
"BFD_RELOC_SCORE_DUMMY2", |
"BFD_RELOC_SCORE_JMP", |
"BFD_RELOC_SCORE_BRANCH", |
"BFD_RELOC_SCORE_IMM30", |
"BFD_RELOC_SCORE_IMM32", |
"BFD_RELOC_SCORE16_JMP", |
"BFD_RELOC_SCORE16_BRANCH", |
"BFD_RELOC_SCORE_BCMP", |
"BFD_RELOC_SCORE_GOT15", |
"BFD_RELOC_SCORE_GOT_LO16", |
"BFD_RELOC_SCORE_CALL15", |
"BFD_RELOC_SCORE_DUMMY_HI16", |
"BFD_RELOC_IP2K_FR9", |
"BFD_RELOC_IP2K_BANK", |
"BFD_RELOC_IP2K_ADDR16CJP", |
"BFD_RELOC_IP2K_PAGE3", |
"BFD_RELOC_IP2K_LO8DATA", |
"BFD_RELOC_IP2K_HI8DATA", |
"BFD_RELOC_IP2K_EX8DATA", |
"BFD_RELOC_IP2K_LO8INSN", |
"BFD_RELOC_IP2K_HI8INSN", |
"BFD_RELOC_IP2K_PC_SKIP", |
"BFD_RELOC_IP2K_TEXT", |
"BFD_RELOC_IP2K_FR_OFFSET", |
"BFD_RELOC_VPE4KMATH_DATA", |
"BFD_RELOC_VPE4KMATH_INSN", |
"BFD_RELOC_VTABLE_INHERIT", |
"BFD_RELOC_VTABLE_ENTRY", |
"BFD_RELOC_IA64_IMM14", |
"BFD_RELOC_IA64_IMM22", |
"BFD_RELOC_IA64_IMM64", |
"BFD_RELOC_IA64_DIR32MSB", |
"BFD_RELOC_IA64_DIR32LSB", |
"BFD_RELOC_IA64_DIR64MSB", |
"BFD_RELOC_IA64_DIR64LSB", |
"BFD_RELOC_IA64_GPREL22", |
"BFD_RELOC_IA64_GPREL64I", |
"BFD_RELOC_IA64_GPREL32MSB", |
"BFD_RELOC_IA64_GPREL32LSB", |
"BFD_RELOC_IA64_GPREL64MSB", |
"BFD_RELOC_IA64_GPREL64LSB", |
"BFD_RELOC_IA64_LTOFF22", |
"BFD_RELOC_IA64_LTOFF64I", |
"BFD_RELOC_IA64_PLTOFF22", |
"BFD_RELOC_IA64_PLTOFF64I", |
"BFD_RELOC_IA64_PLTOFF64MSB", |
"BFD_RELOC_IA64_PLTOFF64LSB", |
"BFD_RELOC_IA64_FPTR64I", |
"BFD_RELOC_IA64_FPTR32MSB", |
"BFD_RELOC_IA64_FPTR32LSB", |
"BFD_RELOC_IA64_FPTR64MSB", |
"BFD_RELOC_IA64_FPTR64LSB", |
"BFD_RELOC_IA64_PCREL21B", |
"BFD_RELOC_IA64_PCREL21BI", |
"BFD_RELOC_IA64_PCREL21M", |
"BFD_RELOC_IA64_PCREL21F", |
"BFD_RELOC_IA64_PCREL22", |
"BFD_RELOC_IA64_PCREL60B", |
"BFD_RELOC_IA64_PCREL64I", |
"BFD_RELOC_IA64_PCREL32MSB", |
"BFD_RELOC_IA64_PCREL32LSB", |
"BFD_RELOC_IA64_PCREL64MSB", |
"BFD_RELOC_IA64_PCREL64LSB", |
"BFD_RELOC_IA64_LTOFF_FPTR22", |
"BFD_RELOC_IA64_LTOFF_FPTR64I", |
"BFD_RELOC_IA64_LTOFF_FPTR32MSB", |
"BFD_RELOC_IA64_LTOFF_FPTR32LSB", |
"BFD_RELOC_IA64_LTOFF_FPTR64MSB", |
"BFD_RELOC_IA64_LTOFF_FPTR64LSB", |
"BFD_RELOC_IA64_SEGREL32MSB", |
"BFD_RELOC_IA64_SEGREL32LSB", |
"BFD_RELOC_IA64_SEGREL64MSB", |
"BFD_RELOC_IA64_SEGREL64LSB", |
"BFD_RELOC_IA64_SECREL32MSB", |
"BFD_RELOC_IA64_SECREL32LSB", |
"BFD_RELOC_IA64_SECREL64MSB", |
"BFD_RELOC_IA64_SECREL64LSB", |
"BFD_RELOC_IA64_REL32MSB", |
"BFD_RELOC_IA64_REL32LSB", |
"BFD_RELOC_IA64_REL64MSB", |
"BFD_RELOC_IA64_REL64LSB", |
"BFD_RELOC_IA64_LTV32MSB", |
"BFD_RELOC_IA64_LTV32LSB", |
"BFD_RELOC_IA64_LTV64MSB", |
"BFD_RELOC_IA64_LTV64LSB", |
"BFD_RELOC_IA64_IPLTMSB", |
"BFD_RELOC_IA64_IPLTLSB", |
"BFD_RELOC_IA64_COPY", |
"BFD_RELOC_IA64_LTOFF22X", |
"BFD_RELOC_IA64_LDXMOV", |
"BFD_RELOC_IA64_TPREL14", |
"BFD_RELOC_IA64_TPREL22", |
"BFD_RELOC_IA64_TPREL64I", |
"BFD_RELOC_IA64_TPREL64MSB", |
"BFD_RELOC_IA64_TPREL64LSB", |
"BFD_RELOC_IA64_LTOFF_TPREL22", |
"BFD_RELOC_IA64_DTPMOD64MSB", |
"BFD_RELOC_IA64_DTPMOD64LSB", |
"BFD_RELOC_IA64_LTOFF_DTPMOD22", |
"BFD_RELOC_IA64_DTPREL14", |
"BFD_RELOC_IA64_DTPREL22", |
"BFD_RELOC_IA64_DTPREL64I", |
"BFD_RELOC_IA64_DTPREL32MSB", |
"BFD_RELOC_IA64_DTPREL32LSB", |
"BFD_RELOC_IA64_DTPREL64MSB", |
"BFD_RELOC_IA64_DTPREL64LSB", |
"BFD_RELOC_IA64_LTOFF_DTPREL22", |
"BFD_RELOC_M68HC11_HI8", |
"BFD_RELOC_M68HC11_LO8", |
"BFD_RELOC_M68HC11_3B", |
"BFD_RELOC_M68HC11_RL_JUMP", |
"BFD_RELOC_M68HC11_RL_GROUP", |
"BFD_RELOC_M68HC11_LO16", |
"BFD_RELOC_M68HC11_PAGE", |
"BFD_RELOC_M68HC11_24", |
"BFD_RELOC_M68HC12_5B", |
"BFD_RELOC_XGATE_RL_JUMP", |
"BFD_RELOC_XGATE_RL_GROUP", |
"BFD_RELOC_XGATE_LO16", |
"BFD_RELOC_XGATE_GPAGE", |
"BFD_RELOC_XGATE_24", |
"BFD_RELOC_XGATE_PCREL_9", |
"BFD_RELOC_XGATE_PCREL_10", |
"BFD_RELOC_XGATE_IMM8_LO", |
"BFD_RELOC_XGATE_IMM8_HI", |
"BFD_RELOC_XGATE_IMM3", |
"BFD_RELOC_XGATE_IMM4", |
"BFD_RELOC_XGATE_IMM5", |
"BFD_RELOC_M68HC12_9B", |
"BFD_RELOC_M68HC12_16B", |
"BFD_RELOC_M68HC12_9_PCREL", |
"BFD_RELOC_M68HC12_10_PCREL", |
"BFD_RELOC_M68HC12_LO8XG", |
"BFD_RELOC_M68HC12_HI8XG", |
"BFD_RELOC_16C_NUM08", |
"BFD_RELOC_16C_NUM08_C", |
"BFD_RELOC_16C_NUM16", |
"BFD_RELOC_16C_NUM16_C", |
"BFD_RELOC_16C_NUM32", |
"BFD_RELOC_16C_NUM32_C", |
"BFD_RELOC_16C_DISP04", |
"BFD_RELOC_16C_DISP04_C", |
"BFD_RELOC_16C_DISP08", |
"BFD_RELOC_16C_DISP08_C", |
"BFD_RELOC_16C_DISP16", |
"BFD_RELOC_16C_DISP16_C", |
"BFD_RELOC_16C_DISP24", |
"BFD_RELOC_16C_DISP24_C", |
"BFD_RELOC_16C_DISP24a", |
"BFD_RELOC_16C_DISP24a_C", |
"BFD_RELOC_16C_REG04", |
"BFD_RELOC_16C_REG04_C", |
"BFD_RELOC_16C_REG04a", |
"BFD_RELOC_16C_REG04a_C", |
"BFD_RELOC_16C_REG14", |
"BFD_RELOC_16C_REG14_C", |
"BFD_RELOC_16C_REG16", |
"BFD_RELOC_16C_REG16_C", |
"BFD_RELOC_16C_REG20", |
"BFD_RELOC_16C_REG20_C", |
"BFD_RELOC_16C_ABS20", |
"BFD_RELOC_16C_ABS20_C", |
"BFD_RELOC_16C_ABS24", |
"BFD_RELOC_16C_ABS24_C", |
"BFD_RELOC_16C_IMM04", |
"BFD_RELOC_16C_IMM04_C", |
"BFD_RELOC_16C_IMM16", |
"BFD_RELOC_16C_IMM16_C", |
"BFD_RELOC_16C_IMM20", |
"BFD_RELOC_16C_IMM20_C", |
"BFD_RELOC_16C_IMM24", |
"BFD_RELOC_16C_IMM24_C", |
"BFD_RELOC_16C_IMM32", |
"BFD_RELOC_16C_IMM32_C", |
"BFD_RELOC_CR16_NUM8", |
"BFD_RELOC_CR16_NUM16", |
"BFD_RELOC_CR16_NUM32", |
"BFD_RELOC_CR16_NUM32a", |
"BFD_RELOC_CR16_REGREL0", |
"BFD_RELOC_CR16_REGREL4", |
"BFD_RELOC_CR16_REGREL4a", |
"BFD_RELOC_CR16_REGREL14", |
"BFD_RELOC_CR16_REGREL14a", |
"BFD_RELOC_CR16_REGREL16", |
"BFD_RELOC_CR16_REGREL20", |
"BFD_RELOC_CR16_REGREL20a", |
"BFD_RELOC_CR16_ABS20", |
"BFD_RELOC_CR16_ABS24", |
"BFD_RELOC_CR16_IMM4", |
"BFD_RELOC_CR16_IMM8", |
"BFD_RELOC_CR16_IMM16", |
"BFD_RELOC_CR16_IMM20", |
"BFD_RELOC_CR16_IMM24", |
"BFD_RELOC_CR16_IMM32", |
"BFD_RELOC_CR16_IMM32a", |
"BFD_RELOC_CR16_DISP4", |
"BFD_RELOC_CR16_DISP8", |
"BFD_RELOC_CR16_DISP16", |
"BFD_RELOC_CR16_DISP20", |
"BFD_RELOC_CR16_DISP24", |
"BFD_RELOC_CR16_DISP24a", |
"BFD_RELOC_CR16_SWITCH8", |
"BFD_RELOC_CR16_SWITCH16", |
"BFD_RELOC_CR16_SWITCH32", |
"BFD_RELOC_CR16_GOT_REGREL20", |
"BFD_RELOC_CR16_GOTC_REGREL20", |
"BFD_RELOC_CR16_GLOB_DAT", |
"BFD_RELOC_CRX_REL4", |
"BFD_RELOC_CRX_REL8", |
"BFD_RELOC_CRX_REL8_CMP", |
"BFD_RELOC_CRX_REL16", |
"BFD_RELOC_CRX_REL24", |
"BFD_RELOC_CRX_REL32", |
"BFD_RELOC_CRX_REGREL12", |
"BFD_RELOC_CRX_REGREL22", |
"BFD_RELOC_CRX_REGREL28", |
"BFD_RELOC_CRX_REGREL32", |
"BFD_RELOC_CRX_ABS16", |
"BFD_RELOC_CRX_ABS32", |
"BFD_RELOC_CRX_NUM8", |
"BFD_RELOC_CRX_NUM16", |
"BFD_RELOC_CRX_NUM32", |
"BFD_RELOC_CRX_IMM16", |
"BFD_RELOC_CRX_IMM32", |
"BFD_RELOC_CRX_SWITCH8", |
"BFD_RELOC_CRX_SWITCH16", |
"BFD_RELOC_CRX_SWITCH32", |
"BFD_RELOC_CRIS_BDISP8", |
"BFD_RELOC_CRIS_UNSIGNED_5", |
"BFD_RELOC_CRIS_SIGNED_6", |
"BFD_RELOC_CRIS_UNSIGNED_6", |
"BFD_RELOC_CRIS_SIGNED_8", |
"BFD_RELOC_CRIS_UNSIGNED_8", |
"BFD_RELOC_CRIS_SIGNED_16", |
"BFD_RELOC_CRIS_UNSIGNED_16", |
"BFD_RELOC_CRIS_LAPCQ_OFFSET", |
"BFD_RELOC_CRIS_UNSIGNED_4", |
"BFD_RELOC_CRIS_COPY", |
"BFD_RELOC_CRIS_GLOB_DAT", |
"BFD_RELOC_CRIS_JUMP_SLOT", |
"BFD_RELOC_CRIS_RELATIVE", |
"BFD_RELOC_CRIS_32_GOT", |
"BFD_RELOC_CRIS_16_GOT", |
"BFD_RELOC_CRIS_32_GOTPLT", |
"BFD_RELOC_CRIS_16_GOTPLT", |
"BFD_RELOC_CRIS_32_GOTREL", |
"BFD_RELOC_CRIS_32_PLT_GOTREL", |
"BFD_RELOC_CRIS_32_PLT_PCREL", |
"BFD_RELOC_CRIS_32_GOT_GD", |
"BFD_RELOC_CRIS_16_GOT_GD", |
"BFD_RELOC_CRIS_32_GD", |
"BFD_RELOC_CRIS_DTP", |
"BFD_RELOC_CRIS_32_DTPREL", |
"BFD_RELOC_CRIS_16_DTPREL", |
"BFD_RELOC_CRIS_32_GOT_TPREL", |
"BFD_RELOC_CRIS_16_GOT_TPREL", |
"BFD_RELOC_CRIS_32_TPREL", |
"BFD_RELOC_CRIS_16_TPREL", |
"BFD_RELOC_CRIS_DTPMOD", |
"BFD_RELOC_CRIS_32_IE", |
"BFD_RELOC_860_COPY", |
"BFD_RELOC_860_GLOB_DAT", |
"BFD_RELOC_860_JUMP_SLOT", |
"BFD_RELOC_860_RELATIVE", |
"BFD_RELOC_860_PC26", |
"BFD_RELOC_860_PLT26", |
"BFD_RELOC_860_PC16", |
"BFD_RELOC_860_LOW0", |
"BFD_RELOC_860_SPLIT0", |
"BFD_RELOC_860_LOW1", |
"BFD_RELOC_860_SPLIT1", |
"BFD_RELOC_860_LOW2", |
"BFD_RELOC_860_SPLIT2", |
"BFD_RELOC_860_LOW3", |
"BFD_RELOC_860_LOGOT0", |
"BFD_RELOC_860_SPGOT0", |
"BFD_RELOC_860_LOGOT1", |
"BFD_RELOC_860_SPGOT1", |
"BFD_RELOC_860_LOGOTOFF0", |
"BFD_RELOC_860_SPGOTOFF0", |
"BFD_RELOC_860_LOGOTOFF1", |
"BFD_RELOC_860_SPGOTOFF1", |
"BFD_RELOC_860_LOGOTOFF2", |
"BFD_RELOC_860_LOGOTOFF3", |
"BFD_RELOC_860_LOPC", |
"BFD_RELOC_860_HIGHADJ", |
"BFD_RELOC_860_HAGOT", |
"BFD_RELOC_860_HAGOTOFF", |
"BFD_RELOC_860_HAPC", |
"BFD_RELOC_860_HIGH", |
"BFD_RELOC_860_HIGOT", |
"BFD_RELOC_860_HIGOTOFF", |
"BFD_RELOC_OPENRISC_ABS_26", |
"BFD_RELOC_OPENRISC_REL_26", |
"BFD_RELOC_H8_DIR16A8", |
"BFD_RELOC_H8_DIR16R8", |
"BFD_RELOC_H8_DIR24A8", |
"BFD_RELOC_H8_DIR24R8", |
"BFD_RELOC_H8_DIR32A16", |
"BFD_RELOC_H8_DISP32A16", |
"BFD_RELOC_XSTORMY16_REL_12", |
"BFD_RELOC_XSTORMY16_12", |
"BFD_RELOC_XSTORMY16_24", |
"BFD_RELOC_XSTORMY16_FPTR16", |
"BFD_RELOC_RELC", |
"BFD_RELOC_XC16X_PAG", |
"BFD_RELOC_XC16X_POF", |
"BFD_RELOC_XC16X_SEG", |
"BFD_RELOC_XC16X_SOF", |
"BFD_RELOC_VAX_GLOB_DAT", |
"BFD_RELOC_VAX_JMP_SLOT", |
"BFD_RELOC_VAX_RELATIVE", |
"BFD_RELOC_MT_PC16", |
"BFD_RELOC_MT_HI16", |
"BFD_RELOC_MT_LO16", |
"BFD_RELOC_MT_GNU_VTINHERIT", |
"BFD_RELOC_MT_GNU_VTENTRY", |
"BFD_RELOC_MT_PCINSN8", |
"BFD_RELOC_MSP430_10_PCREL", |
"BFD_RELOC_MSP430_16_PCREL", |
"BFD_RELOC_MSP430_16", |
"BFD_RELOC_MSP430_16_PCREL_BYTE", |
"BFD_RELOC_MSP430_16_BYTE", |
"BFD_RELOC_MSP430_2X_PCREL", |
"BFD_RELOC_MSP430_RL_PCREL", |
"BFD_RELOC_MSP430_ABS8", |
"BFD_RELOC_MSP430X_PCR20_EXT_SRC", |
"BFD_RELOC_MSP430X_PCR20_EXT_DST", |
"BFD_RELOC_MSP430X_PCR20_EXT_ODST", |
"BFD_RELOC_MSP430X_ABS20_EXT_SRC", |
"BFD_RELOC_MSP430X_ABS20_EXT_DST", |
"BFD_RELOC_MSP430X_ABS20_EXT_ODST", |
"BFD_RELOC_MSP430X_ABS20_ADR_SRC", |
"BFD_RELOC_MSP430X_ABS20_ADR_DST", |
"BFD_RELOC_MSP430X_PCR16", |
"BFD_RELOC_MSP430X_PCR20_CALL", |
"BFD_RELOC_MSP430X_ABS16", |
"BFD_RELOC_MSP430_ABS_HI16", |
"BFD_RELOC_MSP430_PREL31", |
"BFD_RELOC_MSP430_SYM_DIFF", |
"BFD_RELOC_NIOS2_S16", |
"BFD_RELOC_NIOS2_U16", |
"BFD_RELOC_NIOS2_CALL26", |
"BFD_RELOC_NIOS2_IMM5", |
"BFD_RELOC_NIOS2_CACHE_OPX", |
"BFD_RELOC_NIOS2_IMM6", |
"BFD_RELOC_NIOS2_IMM8", |
"BFD_RELOC_NIOS2_HI16", |
"BFD_RELOC_NIOS2_LO16", |
"BFD_RELOC_NIOS2_HIADJ16", |
"BFD_RELOC_NIOS2_GPREL", |
"BFD_RELOC_NIOS2_UJMP", |
"BFD_RELOC_NIOS2_CJMP", |
"BFD_RELOC_NIOS2_CALLR", |
"BFD_RELOC_NIOS2_ALIGN", |
"BFD_RELOC_NIOS2_GOT16", |
"BFD_RELOC_NIOS2_CALL16", |
"BFD_RELOC_NIOS2_GOTOFF_LO", |
"BFD_RELOC_NIOS2_GOTOFF_HA", |
"BFD_RELOC_NIOS2_PCREL_LO", |
"BFD_RELOC_NIOS2_PCREL_HA", |
"BFD_RELOC_NIOS2_TLS_GD16", |
"BFD_RELOC_NIOS2_TLS_LDM16", |
"BFD_RELOC_NIOS2_TLS_LDO16", |
"BFD_RELOC_NIOS2_TLS_IE16", |
"BFD_RELOC_NIOS2_TLS_LE16", |
"BFD_RELOC_NIOS2_TLS_DTPMOD", |
"BFD_RELOC_NIOS2_TLS_DTPREL", |
"BFD_RELOC_NIOS2_TLS_TPREL", |
"BFD_RELOC_NIOS2_COPY", |
"BFD_RELOC_NIOS2_GLOB_DAT", |
"BFD_RELOC_NIOS2_JUMP_SLOT", |
"BFD_RELOC_NIOS2_RELATIVE", |
"BFD_RELOC_NIOS2_GOTOFF", |
"BFD_RELOC_IQ2000_OFFSET_16", |
"BFD_RELOC_IQ2000_OFFSET_21", |
"BFD_RELOC_IQ2000_UHI16", |
"BFD_RELOC_XTENSA_RTLD", |
"BFD_RELOC_XTENSA_GLOB_DAT", |
"BFD_RELOC_XTENSA_JMP_SLOT", |
"BFD_RELOC_XTENSA_RELATIVE", |
"BFD_RELOC_XTENSA_PLT", |
"BFD_RELOC_XTENSA_DIFF8", |
"BFD_RELOC_XTENSA_DIFF16", |
"BFD_RELOC_XTENSA_DIFF32", |
"BFD_RELOC_XTENSA_SLOT0_OP", |
"BFD_RELOC_XTENSA_SLOT1_OP", |
"BFD_RELOC_XTENSA_SLOT2_OP", |
"BFD_RELOC_XTENSA_SLOT3_OP", |
"BFD_RELOC_XTENSA_SLOT4_OP", |
"BFD_RELOC_XTENSA_SLOT5_OP", |
"BFD_RELOC_XTENSA_SLOT6_OP", |
"BFD_RELOC_XTENSA_SLOT7_OP", |
"BFD_RELOC_XTENSA_SLOT8_OP", |
"BFD_RELOC_XTENSA_SLOT9_OP", |
"BFD_RELOC_XTENSA_SLOT10_OP", |
"BFD_RELOC_XTENSA_SLOT11_OP", |
"BFD_RELOC_XTENSA_SLOT12_OP", |
"BFD_RELOC_XTENSA_SLOT13_OP", |
"BFD_RELOC_XTENSA_SLOT14_OP", |
"BFD_RELOC_XTENSA_SLOT0_ALT", |
"BFD_RELOC_XTENSA_SLOT1_ALT", |
"BFD_RELOC_XTENSA_SLOT2_ALT", |
"BFD_RELOC_XTENSA_SLOT3_ALT", |
"BFD_RELOC_XTENSA_SLOT4_ALT", |
"BFD_RELOC_XTENSA_SLOT5_ALT", |
"BFD_RELOC_XTENSA_SLOT6_ALT", |
"BFD_RELOC_XTENSA_SLOT7_ALT", |
"BFD_RELOC_XTENSA_SLOT8_ALT", |
"BFD_RELOC_XTENSA_SLOT9_ALT", |
"BFD_RELOC_XTENSA_SLOT10_ALT", |
"BFD_RELOC_XTENSA_SLOT11_ALT", |
"BFD_RELOC_XTENSA_SLOT12_ALT", |
"BFD_RELOC_XTENSA_SLOT13_ALT", |
"BFD_RELOC_XTENSA_SLOT14_ALT", |
"BFD_RELOC_XTENSA_OP0", |
"BFD_RELOC_XTENSA_OP1", |
"BFD_RELOC_XTENSA_OP2", |
"BFD_RELOC_XTENSA_ASM_EXPAND", |
"BFD_RELOC_XTENSA_ASM_SIMPLIFY", |
"BFD_RELOC_XTENSA_TLSDESC_FN", |
"BFD_RELOC_XTENSA_TLSDESC_ARG", |
"BFD_RELOC_XTENSA_TLS_DTPOFF", |
"BFD_RELOC_XTENSA_TLS_TPOFF", |
"BFD_RELOC_XTENSA_TLS_FUNC", |
"BFD_RELOC_XTENSA_TLS_ARG", |
"BFD_RELOC_XTENSA_TLS_CALL", |
"BFD_RELOC_Z80_DISP8", |
"BFD_RELOC_Z8K_DISP7", |
"BFD_RELOC_Z8K_CALLR", |
"BFD_RELOC_Z8K_IMM4L", |
"BFD_RELOC_LM32_CALL", |
"BFD_RELOC_LM32_BRANCH", |
"BFD_RELOC_LM32_16_GOT", |
"BFD_RELOC_LM32_GOTOFF_HI16", |
"BFD_RELOC_LM32_GOTOFF_LO16", |
"BFD_RELOC_LM32_COPY", |
"BFD_RELOC_LM32_GLOB_DAT", |
"BFD_RELOC_LM32_JMP_SLOT", |
"BFD_RELOC_LM32_RELATIVE", |
"BFD_RELOC_MACH_O_SECTDIFF", |
"BFD_RELOC_MACH_O_LOCAL_SECTDIFF", |
"BFD_RELOC_MACH_O_PAIR", |
"BFD_RELOC_MACH_O_X86_64_BRANCH32", |
"BFD_RELOC_MACH_O_X86_64_BRANCH8", |
"BFD_RELOC_MACH_O_X86_64_GOT", |
"BFD_RELOC_MACH_O_X86_64_GOT_LOAD", |
"BFD_RELOC_MACH_O_X86_64_SUBTRACTOR32", |
"BFD_RELOC_MACH_O_X86_64_SUBTRACTOR64", |
"BFD_RELOC_MACH_O_X86_64_PCREL32_1", |
"BFD_RELOC_MACH_O_X86_64_PCREL32_2", |
"BFD_RELOC_MACH_O_X86_64_PCREL32_4", |
"BFD_RELOC_MICROBLAZE_32_LO", |
"BFD_RELOC_MICROBLAZE_32_LO_PCREL", |
"BFD_RELOC_MICROBLAZE_32_ROSDA", |
"BFD_RELOC_MICROBLAZE_32_RWSDA", |
"BFD_RELOC_MICROBLAZE_32_SYM_OP_SYM", |
"BFD_RELOC_MICROBLAZE_64_NONE", |
"BFD_RELOC_MICROBLAZE_64_GOTPC", |
"BFD_RELOC_MICROBLAZE_64_GOT", |
"BFD_RELOC_MICROBLAZE_64_PLT", |
"BFD_RELOC_MICROBLAZE_64_GOTOFF", |
"BFD_RELOC_MICROBLAZE_32_GOTOFF", |
"BFD_RELOC_MICROBLAZE_COPY", |
"BFD_RELOC_MICROBLAZE_64_TLS", |
"BFD_RELOC_MICROBLAZE_64_TLSGD", |
"BFD_RELOC_MICROBLAZE_64_TLSLD", |
"BFD_RELOC_MICROBLAZE_32_TLSDTPMOD", |
"BFD_RELOC_MICROBLAZE_32_TLSDTPREL", |
"BFD_RELOC_MICROBLAZE_64_TLSDTPREL", |
"BFD_RELOC_MICROBLAZE_64_TLSGOTTPREL", |
"BFD_RELOC_MICROBLAZE_64_TLSTPREL", |
"BFD_RELOC_AARCH64_RELOC_START", |
"BFD_RELOC_AARCH64_NONE", |
"BFD_RELOC_AARCH64_64", |
"BFD_RELOC_AARCH64_32", |
"BFD_RELOC_AARCH64_16", |
"BFD_RELOC_AARCH64_64_PCREL", |
"BFD_RELOC_AARCH64_32_PCREL", |
"BFD_RELOC_AARCH64_16_PCREL", |
"BFD_RELOC_AARCH64_MOVW_G0", |
"BFD_RELOC_AARCH64_MOVW_G0_NC", |
"BFD_RELOC_AARCH64_MOVW_G1", |
"BFD_RELOC_AARCH64_MOVW_G1_NC", |
"BFD_RELOC_AARCH64_MOVW_G2", |
"BFD_RELOC_AARCH64_MOVW_G2_NC", |
"BFD_RELOC_AARCH64_MOVW_G3", |
"BFD_RELOC_AARCH64_MOVW_G0_S", |
"BFD_RELOC_AARCH64_MOVW_G1_S", |
"BFD_RELOC_AARCH64_MOVW_G2_S", |
"BFD_RELOC_AARCH64_LD_LO19_PCREL", |
"BFD_RELOC_AARCH64_ADR_LO21_PCREL", |
"BFD_RELOC_AARCH64_ADR_HI21_PCREL", |
"BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL", |
"BFD_RELOC_AARCH64_ADD_LO12", |
"BFD_RELOC_AARCH64_LDST8_LO12", |
"BFD_RELOC_AARCH64_TSTBR14", |
"BFD_RELOC_AARCH64_BRANCH19", |
"BFD_RELOC_AARCH64_JUMP26", |
"BFD_RELOC_AARCH64_CALL26", |
"BFD_RELOC_AARCH64_LDST16_LO12", |
"BFD_RELOC_AARCH64_LDST32_LO12", |
"BFD_RELOC_AARCH64_LDST64_LO12", |
"BFD_RELOC_AARCH64_LDST128_LO12", |
"BFD_RELOC_AARCH64_GOT_LD_PREL19", |
"BFD_RELOC_AARCH64_ADR_GOT_PAGE", |
"BFD_RELOC_AARCH64_LD64_GOT_LO12_NC", |
"BFD_RELOC_AARCH64_LD32_GOT_LO12_NC", |
"BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21", |
"BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC", |
"BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1", |
"BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC", |
"BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21", |
"BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC", |
"BFD_RELOC_AARCH64_TLSIE_LD32_GOTTPREL_LO12_NC", |
"BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19", |
"BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2", |
"BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1", |
"BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC", |
"BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0", |
"BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC", |
"BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12", |
"BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12", |
"BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC", |
"BFD_RELOC_AARCH64_TLSDESC_LD_PREL19", |
"BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21", |
"BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21", |
"BFD_RELOC_AARCH64_TLSDESC_LD64_LO12_NC", |
"BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC", |
"BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC", |
"BFD_RELOC_AARCH64_TLSDESC_OFF_G1", |
"BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC", |
"BFD_RELOC_AARCH64_TLSDESC_LDR", |
"BFD_RELOC_AARCH64_TLSDESC_ADD", |
"BFD_RELOC_AARCH64_TLSDESC_CALL", |
"BFD_RELOC_AARCH64_COPY", |
"BFD_RELOC_AARCH64_GLOB_DAT", |
"BFD_RELOC_AARCH64_JUMP_SLOT", |
"BFD_RELOC_AARCH64_RELATIVE", |
"BFD_RELOC_AARCH64_TLS_DTPMOD", |
"BFD_RELOC_AARCH64_TLS_DTPREL", |
"BFD_RELOC_AARCH64_TLS_TPREL", |
"BFD_RELOC_AARCH64_TLSDESC", |
"BFD_RELOC_AARCH64_IRELATIVE", |
"BFD_RELOC_AARCH64_RELOC_END", |
"BFD_RELOC_AARCH64_GAS_INTERNAL_FIXUP", |
"BFD_RELOC_AARCH64_LDST_LO12", |
"BFD_RELOC_AARCH64_LD_GOT_LO12_NC", |
"BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_LO12_NC", |
"BFD_RELOC_AARCH64_TLSDESC_LD_LO12_NC", |
"BFD_RELOC_TILEPRO_COPY", |
"BFD_RELOC_TILEPRO_GLOB_DAT", |
"BFD_RELOC_TILEPRO_JMP_SLOT", |
"BFD_RELOC_TILEPRO_RELATIVE", |
"BFD_RELOC_TILEPRO_BROFF_X1", |
"BFD_RELOC_TILEPRO_JOFFLONG_X1", |
"BFD_RELOC_TILEPRO_JOFFLONG_X1_PLT", |
"BFD_RELOC_TILEPRO_IMM8_X0", |
"BFD_RELOC_TILEPRO_IMM8_Y0", |
"BFD_RELOC_TILEPRO_IMM8_X1", |
"BFD_RELOC_TILEPRO_IMM8_Y1", |
"BFD_RELOC_TILEPRO_DEST_IMM8_X1", |
"BFD_RELOC_TILEPRO_MT_IMM15_X1", |
"BFD_RELOC_TILEPRO_MF_IMM15_X1", |
"BFD_RELOC_TILEPRO_IMM16_X0", |
"BFD_RELOC_TILEPRO_IMM16_X1", |
"BFD_RELOC_TILEPRO_IMM16_X0_LO", |
"BFD_RELOC_TILEPRO_IMM16_X1_LO", |
"BFD_RELOC_TILEPRO_IMM16_X0_HI", |
"BFD_RELOC_TILEPRO_IMM16_X1_HI", |
"BFD_RELOC_TILEPRO_IMM16_X0_HA", |
"BFD_RELOC_TILEPRO_IMM16_X1_HA", |
"BFD_RELOC_TILEPRO_IMM16_X0_PCREL", |
"BFD_RELOC_TILEPRO_IMM16_X1_PCREL", |
"BFD_RELOC_TILEPRO_IMM16_X0_LO_PCREL", |
"BFD_RELOC_TILEPRO_IMM16_X1_LO_PCREL", |
"BFD_RELOC_TILEPRO_IMM16_X0_HI_PCREL", |
"BFD_RELOC_TILEPRO_IMM16_X1_HI_PCREL", |
"BFD_RELOC_TILEPRO_IMM16_X0_HA_PCREL", |
"BFD_RELOC_TILEPRO_IMM16_X1_HA_PCREL", |
"BFD_RELOC_TILEPRO_IMM16_X0_GOT", |
"BFD_RELOC_TILEPRO_IMM16_X1_GOT", |
"BFD_RELOC_TILEPRO_IMM16_X0_GOT_LO", |
"BFD_RELOC_TILEPRO_IMM16_X1_GOT_LO", |
"BFD_RELOC_TILEPRO_IMM16_X0_GOT_HI", |
"BFD_RELOC_TILEPRO_IMM16_X1_GOT_HI", |
"BFD_RELOC_TILEPRO_IMM16_X0_GOT_HA", |
"BFD_RELOC_TILEPRO_IMM16_X1_GOT_HA", |
"BFD_RELOC_TILEPRO_MMSTART_X0", |
"BFD_RELOC_TILEPRO_MMEND_X0", |
"BFD_RELOC_TILEPRO_MMSTART_X1", |
"BFD_RELOC_TILEPRO_MMEND_X1", |
"BFD_RELOC_TILEPRO_SHAMT_X0", |
"BFD_RELOC_TILEPRO_SHAMT_X1", |
"BFD_RELOC_TILEPRO_SHAMT_Y0", |
"BFD_RELOC_TILEPRO_SHAMT_Y1", |
"BFD_RELOC_TILEPRO_TLS_GD_CALL", |
"BFD_RELOC_TILEPRO_IMM8_X0_TLS_GD_ADD", |
"BFD_RELOC_TILEPRO_IMM8_X1_TLS_GD_ADD", |
"BFD_RELOC_TILEPRO_IMM8_Y0_TLS_GD_ADD", |
"BFD_RELOC_TILEPRO_IMM8_Y1_TLS_GD_ADD", |
"BFD_RELOC_TILEPRO_TLS_IE_LOAD", |
"BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD", |
"BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD", |
"BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD_LO", |
"BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD_LO", |
"BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD_HI", |
"BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD_HI", |
"BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD_HA", |
"BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD_HA", |
"BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE", |
"BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE", |
"BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE_LO", |
"BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE_LO", |
"BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE_HI", |
"BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE_HI", |
"BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE_HA", |
"BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE_HA", |
"BFD_RELOC_TILEPRO_TLS_DTPMOD32", |
"BFD_RELOC_TILEPRO_TLS_DTPOFF32", |
"BFD_RELOC_TILEPRO_TLS_TPOFF32", |
"BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE", |
"BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE", |
"BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_LO", |
"BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_LO", |
"BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_HI", |
"BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_HI", |
"BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_HA", |
"BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_HA", |
"BFD_RELOC_TILEGX_HW0", |
"BFD_RELOC_TILEGX_HW1", |
"BFD_RELOC_TILEGX_HW2", |
"BFD_RELOC_TILEGX_HW3", |
"BFD_RELOC_TILEGX_HW0_LAST", |
"BFD_RELOC_TILEGX_HW1_LAST", |
"BFD_RELOC_TILEGX_HW2_LAST", |
"BFD_RELOC_TILEGX_COPY", |
"BFD_RELOC_TILEGX_GLOB_DAT", |
"BFD_RELOC_TILEGX_JMP_SLOT", |
"BFD_RELOC_TILEGX_RELATIVE", |
"BFD_RELOC_TILEGX_BROFF_X1", |
"BFD_RELOC_TILEGX_JUMPOFF_X1", |
"BFD_RELOC_TILEGX_JUMPOFF_X1_PLT", |
"BFD_RELOC_TILEGX_IMM8_X0", |
"BFD_RELOC_TILEGX_IMM8_Y0", |
"BFD_RELOC_TILEGX_IMM8_X1", |
"BFD_RELOC_TILEGX_IMM8_Y1", |
"BFD_RELOC_TILEGX_DEST_IMM8_X1", |
"BFD_RELOC_TILEGX_MT_IMM14_X1", |
"BFD_RELOC_TILEGX_MF_IMM14_X1", |
"BFD_RELOC_TILEGX_MMSTART_X0", |
"BFD_RELOC_TILEGX_MMEND_X0", |
"BFD_RELOC_TILEGX_SHAMT_X0", |
"BFD_RELOC_TILEGX_SHAMT_X1", |
"BFD_RELOC_TILEGX_SHAMT_Y0", |
"BFD_RELOC_TILEGX_SHAMT_Y1", |
"BFD_RELOC_TILEGX_IMM16_X0_HW0", |
"BFD_RELOC_TILEGX_IMM16_X1_HW0", |
"BFD_RELOC_TILEGX_IMM16_X0_HW1", |
"BFD_RELOC_TILEGX_IMM16_X1_HW1", |
"BFD_RELOC_TILEGX_IMM16_X0_HW2", |
"BFD_RELOC_TILEGX_IMM16_X1_HW2", |
"BFD_RELOC_TILEGX_IMM16_X0_HW3", |
"BFD_RELOC_TILEGX_IMM16_X1_HW3", |
"BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST", |
"BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST", |
"BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST", |
"BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST", |
"BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST", |
"BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST", |
"BFD_RELOC_TILEGX_IMM16_X0_HW0_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X1_HW0_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X0_HW1_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X1_HW1_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X0_HW2_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X1_HW2_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X0_HW3_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X1_HW3_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X0_HW0_GOT", |
"BFD_RELOC_TILEGX_IMM16_X1_HW0_GOT", |
"BFD_RELOC_TILEGX_IMM16_X0_HW0_PLT_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X1_HW0_PLT_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X0_HW1_PLT_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X1_HW1_PLT_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X0_HW2_PLT_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X1_HW2_PLT_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_GOT", |
"BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_GOT", |
"BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_GOT", |
"BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_GOT", |
"BFD_RELOC_TILEGX_IMM16_X0_HW3_PLT_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X1_HW3_PLT_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_GD", |
"BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_GD", |
"BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_LE", |
"BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_LE", |
"BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_LE", |
"BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_TLS_LE", |
"BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_LE", |
"BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_LE", |
"BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_GD", |
"BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_TLS_GD", |
"BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_GD", |
"BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_GD", |
"BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_IE", |
"BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_IE", |
"BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL", |
"BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_IE", |
"BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_TLS_IE", |
"BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_IE", |
"BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_IE", |
"BFD_RELOC_TILEGX_TLS_DTPMOD64", |
"BFD_RELOC_TILEGX_TLS_DTPOFF64", |
"BFD_RELOC_TILEGX_TLS_TPOFF64", |
"BFD_RELOC_TILEGX_TLS_DTPMOD32", |
"BFD_RELOC_TILEGX_TLS_DTPOFF32", |
"BFD_RELOC_TILEGX_TLS_TPOFF32", |
"BFD_RELOC_TILEGX_TLS_GD_CALL", |
"BFD_RELOC_TILEGX_IMM8_X0_TLS_GD_ADD", |
"BFD_RELOC_TILEGX_IMM8_X1_TLS_GD_ADD", |
"BFD_RELOC_TILEGX_IMM8_Y0_TLS_GD_ADD", |
"BFD_RELOC_TILEGX_IMM8_Y1_TLS_GD_ADD", |
"BFD_RELOC_TILEGX_TLS_IE_LOAD", |
"BFD_RELOC_TILEGX_IMM8_X0_TLS_ADD", |
"BFD_RELOC_TILEGX_IMM8_X1_TLS_ADD", |
"BFD_RELOC_TILEGX_IMM8_Y0_TLS_ADD", |
"BFD_RELOC_TILEGX_IMM8_Y1_TLS_ADD", |
"BFD_RELOC_EPIPHANY_SIMM8", |
"BFD_RELOC_EPIPHANY_SIMM24", |
"BFD_RELOC_EPIPHANY_HIGH", |
"BFD_RELOC_EPIPHANY_LOW", |
"BFD_RELOC_EPIPHANY_SIMM11", |
"BFD_RELOC_EPIPHANY_IMM11", |
"BFD_RELOC_EPIPHANY_IMM8", |
"@@overflow: BFD_RELOC_UNUSED@@", |
}; |
#endif |
reloc_howto_type *bfd_default_reloc_type_lookup |
(bfd *abfd, bfd_reloc_code_real_type code); |
bfd_boolean bfd_generic_relax_section |
(bfd *abfd, |
asection *section, |
struct bfd_link_info *, |
bfd_boolean *); |
bfd_boolean bfd_generic_gc_sections |
(bfd *, struct bfd_link_info *); |
bfd_boolean bfd_generic_lookup_section_flags |
(struct bfd_link_info *, struct flag_info *, asection *); |
bfd_boolean bfd_generic_merge_sections |
(bfd *, struct bfd_link_info *); |
bfd_byte *bfd_generic_get_relocated_section_contents |
(bfd *abfd, |
struct bfd_link_info *link_info, |
struct bfd_link_order *link_order, |
bfd_byte *data, |
bfd_boolean relocatable, |
asymbol **symbols); |
/* Extracted from archures.c. */ |
extern const bfd_arch_info_type bfd_default_arch_struct; |
bfd_boolean bfd_default_set_arch_mach |
(bfd *abfd, enum bfd_architecture arch, unsigned long mach); |
const bfd_arch_info_type *bfd_default_compatible |
(const bfd_arch_info_type *a, const bfd_arch_info_type *b); |
bfd_boolean bfd_default_scan |
(const struct bfd_arch_info *info, const char *string); |
void *bfd_arch_default_fill (bfd_size_type count, |
bfd_boolean is_bigendian, |
bfd_boolean code); |
/* Extracted from elf.c. */ |
/contrib/toolchain/binutils/bfd/libcoff.h |
---|
0,0 → 1,967 |
/* DO NOT EDIT! -*- buffer-read-only: t -*- This file is automatically |
generated from "libcoff-in.h" and "coffcode.h". |
Run "make headers" in your build bfd/ to regenerate. */ |
/* BFD COFF object file private structure. |
Copyright 1990-2013 Free Software Foundation, Inc. |
Written by Cygnus Support. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "bfdlink.h" |
/* Object file tdata; access macros. */ |
#define coff_data(bfd) ((bfd)->tdata.coff_obj_data) |
#define obj_pe(bfd) (coff_data (bfd)->pe) |
#define obj_symbols(bfd) (coff_data (bfd)->symbols) |
#define obj_sym_filepos(bfd) (coff_data (bfd)->sym_filepos) |
#define obj_relocbase(bfd) (coff_data (bfd)->relocbase) |
#define obj_raw_syments(bfd) (coff_data (bfd)->raw_syments) |
#define obj_raw_syment_count(bfd) (coff_data (bfd)->raw_syment_count) |
#define obj_convert(bfd) (coff_data (bfd)->conversion_table) |
#define obj_conv_table_size(bfd) (coff_data (bfd)->conv_table_size) |
#define obj_coff_external_syms(bfd) (coff_data (bfd)->external_syms) |
#define obj_coff_keep_syms(bfd) (coff_data (bfd)->keep_syms) |
#define obj_coff_strings(bfd) (coff_data (bfd)->strings) |
#define obj_coff_keep_strings(bfd) (coff_data (bfd)->keep_strings) |
#define obj_coff_sym_hashes(bfd) (coff_data (bfd)->sym_hashes) |
#define obj_coff_strings_written(bfd) (coff_data (bfd)->strings_written) |
#define obj_coff_local_toc_table(bfd) (coff_data (bfd)->local_toc_sym_map) |
/* `Tdata' information kept for COFF files. */ |
typedef struct coff_tdata |
{ |
struct coff_symbol_struct *symbols; /* Symtab for input bfd. */ |
unsigned int *conversion_table; |
int conv_table_size; |
file_ptr sym_filepos; |
struct coff_ptr_struct *raw_syments; |
unsigned long raw_syment_count; |
/* These are only valid once writing has begun. */ |
long int relocbase; |
/* These members communicate important constants about the symbol table |
to GDB's symbol-reading code. These `constants' unfortunately vary |
from coff implementation to implementation... */ |
unsigned local_n_btmask; |
unsigned local_n_btshft; |
unsigned local_n_tmask; |
unsigned local_n_tshift; |
unsigned local_symesz; |
unsigned local_auxesz; |
unsigned local_linesz; |
/* The unswapped external symbols. May be NULL. Read by |
_bfd_coff_get_external_symbols. */ |
void * external_syms; |
/* If this is TRUE, the external_syms may not be freed. */ |
bfd_boolean keep_syms; |
/* The string table. May be NULL. Read by |
_bfd_coff_read_string_table. */ |
char *strings; |
/* If this is TRUE, the strings may not be freed. */ |
bfd_boolean keep_strings; |
/* If this is TRUE, the strings have been written out already. */ |
bfd_boolean strings_written; |
/* Is this a PE format coff file? */ |
int pe; |
/* Used by the COFF backend linker. */ |
struct coff_link_hash_entry **sym_hashes; |
/* Used by the pe linker for PowerPC. */ |
int *local_toc_sym_map; |
struct bfd_link_info *link_info; |
/* Used by coff_find_nearest_line. */ |
void * line_info; |
/* A place to stash dwarf2 info for this bfd. */ |
void * dwarf2_find_line_info; |
/* The timestamp from the COFF file header. */ |
long timestamp; |
/* Copy of some of the f_flags bits in the COFF filehdr structure, |
used by ARM code. */ |
flagword flags; |
/* coff-stgo32 EXE stub header after BFD tdata has been allocated. Its data |
is kept in internal_filehdr.go32stub beforehand. */ |
char *go32stub; |
} coff_data_type; |
/* Tdata for pe image files. */ |
typedef struct pe_tdata |
{ |
coff_data_type coff; |
struct internal_extra_pe_aouthdr pe_opthdr; |
int dll; |
int has_reloc_section; |
int dont_strip_reloc; |
bfd_boolean insert_timestamp; |
bfd_boolean (*in_reloc_p) (bfd *, reloc_howto_type *); |
flagword real_flags; |
} pe_data_type; |
#define pe_data(bfd) ((bfd)->tdata.pe_obj_data) |
/* Tdata for XCOFF files. */ |
struct xcoff_tdata |
{ |
/* Basic COFF information. */ |
coff_data_type coff; |
/* TRUE if this is an XCOFF64 file. */ |
bfd_boolean xcoff64; |
/* TRUE if a large a.out header should be generated. */ |
bfd_boolean full_aouthdr; |
/* TOC value. */ |
bfd_vma toc; |
/* Index of section holding TOC. */ |
int sntoc; |
/* Index of section holding entry point. */ |
int snentry; |
/* .text alignment from optional header. */ |
int text_align_power; |
/* .data alignment from optional header. */ |
int data_align_power; |
/* modtype from optional header. */ |
short modtype; |
/* cputype from optional header. */ |
short cputype; |
/* maxdata from optional header. */ |
bfd_vma maxdata; |
/* maxstack from optional header. */ |
bfd_vma maxstack; |
/* Used by the XCOFF backend linker. */ |
asection **csects; |
long *debug_indices; |
unsigned int *lineno_counts; |
unsigned int import_file_id; |
}; |
#define xcoff_data(abfd) ((abfd)->tdata.xcoff_obj_data) |
/* We take the address of the first element of an asymbol to ensure that the |
macro is only ever applied to an asymbol. */ |
#define coffsymbol(asymbol) ((coff_symbol_type *)(&((asymbol)->the_bfd))) |
/* The used_by_bfd field of a section may be set to a pointer to this |
structure. */ |
struct coff_section_tdata |
{ |
/* The relocs, swapped into COFF internal form. This may be NULL. */ |
struct internal_reloc *relocs; |
/* If this is TRUE, the relocs entry may not be freed. */ |
bfd_boolean keep_relocs; |
/* The section contents. This may be NULL. */ |
bfd_byte *contents; |
/* If this is TRUE, the contents entry may not be freed. */ |
bfd_boolean keep_contents; |
/* Information cached by coff_find_nearest_line. */ |
bfd_vma offset; |
unsigned int i; |
const char *function; |
/* Optional information about a COMDAT entry; NULL if not COMDAT. */ |
struct coff_comdat_info *comdat; |
int line_base; |
/* A pointer used for .stab linking optimizations. */ |
void * stab_info; |
/* Available for individual backends. */ |
void * tdata; |
}; |
/* An accessor macro for the coff_section_tdata structure. */ |
#define coff_section_data(abfd, sec) \ |
((struct coff_section_tdata *) (sec)->used_by_bfd) |
/* Tdata for sections in XCOFF files. This is used by the linker. */ |
struct xcoff_section_tdata |
{ |
/* Used for XCOFF csects created by the linker; points to the real |
XCOFF section which contains this csect. */ |
asection *enclosing; |
/* The lineno_count field for the enclosing section, because we are |
going to clobber it there. */ |
unsigned int lineno_count; |
/* The first and last symbol indices for symbols used by this csect. */ |
unsigned long first_symndx; |
unsigned long last_symndx; |
}; |
/* An accessor macro the xcoff_section_tdata structure. */ |
#define xcoff_section_data(abfd, sec) \ |
((struct xcoff_section_tdata *) coff_section_data ((abfd), (sec))->tdata) |
/* Tdata for sections in PE files. */ |
struct pei_section_tdata |
{ |
/* The virtual size of the section. */ |
bfd_size_type virt_size; |
/* The PE section flags. */ |
long pe_flags; |
}; |
/* An accessor macro for the pei_section_tdata structure. */ |
#define pei_section_data(abfd, sec) \ |
((struct pei_section_tdata *) coff_section_data ((abfd), (sec))->tdata) |
/* COFF linker hash table entries. */ |
struct coff_link_hash_entry |
{ |
struct bfd_link_hash_entry root; |
/* Symbol index in output file. Set to -1 initially. Set to -2 if |
there is a reloc against this symbol. */ |
long indx; |
/* Symbol type. */ |
unsigned short type; |
/* Symbol class. */ |
unsigned char symbol_class; |
/* Number of auxiliary entries. */ |
char numaux; |
/* BFD to take auxiliary entries from. */ |
bfd *auxbfd; |
/* Pointer to array of auxiliary entries, if any. */ |
union internal_auxent *aux; |
/* Flag word; legal values follow. */ |
unsigned short coff_link_hash_flags; |
/* Symbol is a PE section symbol. */ |
#define COFF_LINK_HASH_PE_SECTION_SYMBOL (01) |
}; |
/* COFF linker hash table. */ |
struct coff_link_hash_table |
{ |
struct bfd_link_hash_table root; |
/* A pointer to information used to link stabs in sections. */ |
struct stab_info stab_info; |
}; |
/* Look up an entry in a COFF linker hash table. */ |
#define coff_link_hash_lookup(table, string, create, copy, follow) \ |
((struct coff_link_hash_entry *) \ |
bfd_link_hash_lookup (&(table)->root, (string), (create), \ |
(copy), (follow))) |
/* Traverse a COFF linker hash table. */ |
#define coff_link_hash_traverse(table, func, info) \ |
(bfd_link_hash_traverse \ |
(&(table)->root, \ |
(bfd_boolean (*) (struct bfd_link_hash_entry *, void *)) (func), \ |
(info))) |
/* Get the COFF linker hash table from a link_info structure. */ |
#define coff_hash_table(p) ((struct coff_link_hash_table *) ((p)->hash)) |
/* Functions in coffgen.c. */ |
extern const bfd_target *coff_object_p |
(bfd *); |
extern struct bfd_section *coff_section_from_bfd_index |
(bfd *, int); |
extern long coff_get_symtab_upper_bound |
(bfd *); |
extern long coff_canonicalize_symtab |
(bfd *, asymbol **); |
extern int coff_count_linenumbers |
(bfd *); |
extern struct coff_symbol_struct *coff_symbol_from |
(bfd *, asymbol *); |
extern bfd_boolean coff_renumber_symbols |
(bfd *, int *); |
extern void coff_mangle_symbols |
(bfd *); |
extern bfd_boolean coff_write_symbols |
(bfd *); |
extern bfd_boolean coff_write_alien_symbol |
(bfd *, asymbol *, struct internal_syment *, bfd_vma *, |
bfd_size_type *, asection **, bfd_size_type *); |
extern bfd_boolean coff_write_linenumbers |
(bfd *); |
extern alent *coff_get_lineno |
(bfd *, asymbol *); |
extern asymbol *coff_section_symbol |
(bfd *, char *); |
extern bfd_boolean _bfd_coff_get_external_symbols |
(bfd *); |
extern const char *_bfd_coff_read_string_table |
(bfd *); |
extern bfd_boolean _bfd_coff_free_symbols |
(bfd *); |
extern struct coff_ptr_struct *coff_get_normalized_symtab |
(bfd *); |
extern long coff_get_reloc_upper_bound |
(bfd *, sec_ptr); |
extern asymbol *coff_make_empty_symbol |
(bfd *); |
extern void coff_print_symbol |
(bfd *, void * filep, asymbol *, bfd_print_symbol_type); |
extern void coff_get_symbol_info |
(bfd *, asymbol *, symbol_info *ret); |
extern bfd_boolean _bfd_coff_is_local_label_name |
(bfd *, const char *); |
extern asymbol *coff_bfd_make_debug_symbol |
(bfd *, void *, unsigned long); |
extern bfd_boolean coff_find_nearest_line |
(bfd *, asection *, asymbol **, bfd_vma, const char **, |
const char **, unsigned int *); |
extern bfd_boolean coff_find_nearest_line_discriminator |
(bfd *, asection *, asymbol **, bfd_vma, const char **, |
const char **, unsigned int *, unsigned int *); |
struct dwarf_debug_section; |
extern bfd_boolean coff_find_nearest_line_with_names |
(bfd *, const struct dwarf_debug_section *, asection *, asymbol **, |
bfd_vma, const char **, const char **, unsigned int *); |
extern bfd_boolean coff_find_inliner_info |
(bfd *, const char **, const char **, unsigned int *); |
extern int coff_sizeof_headers |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean bfd_coff_reloc16_relax_section |
(bfd *, asection *, struct bfd_link_info *, bfd_boolean *); |
extern bfd_byte *bfd_coff_reloc16_get_relocated_section_contents |
(bfd *, struct bfd_link_info *, struct bfd_link_order *, |
bfd_byte *, bfd_boolean, asymbol **); |
extern bfd_vma bfd_coff_reloc16_get_value |
(arelent *, struct bfd_link_info *, asection *); |
extern void bfd_perform_slip |
(bfd *, unsigned int, asection *, bfd_vma); |
/* Functions and types in cofflink.c. */ |
#define STRING_SIZE_SIZE 4 |
/* We use a hash table to merge identical enum, struct, and union |
definitions in the linker. */ |
/* Information we keep for a single element (an enum value, a |
structure or union field) in the debug merge hash table. */ |
struct coff_debug_merge_element |
{ |
/* Next element. */ |
struct coff_debug_merge_element *next; |
/* Name. */ |
const char *name; |
/* Type. */ |
unsigned int type; |
/* Symbol index for complex type. */ |
long tagndx; |
}; |
/* A linked list of debug merge entries for a given name. */ |
struct coff_debug_merge_type |
{ |
/* Next type with the same name. */ |
struct coff_debug_merge_type *next; |
/* Class of type. */ |
int type_class; |
/* Symbol index where this type is defined. */ |
long indx; |
/* List of elements. */ |
struct coff_debug_merge_element *elements; |
}; |
/* Information we store in the debug merge hash table. */ |
struct coff_debug_merge_hash_entry |
{ |
struct bfd_hash_entry root; |
/* A list of types with this name. */ |
struct coff_debug_merge_type *types; |
}; |
/* The debug merge hash table. */ |
struct coff_debug_merge_hash_table |
{ |
struct bfd_hash_table root; |
}; |
/* Initialize a COFF debug merge hash table. */ |
#define coff_debug_merge_hash_table_init(table) \ |
(bfd_hash_table_init (&(table)->root, _bfd_coff_debug_merge_hash_newfunc, \ |
sizeof (struct coff_debug_merge_hash_entry))) |
/* Free a COFF debug merge hash table. */ |
#define coff_debug_merge_hash_table_free(table) \ |
(bfd_hash_table_free (&(table)->root)) |
/* Look up an entry in a COFF debug merge hash table. */ |
#define coff_debug_merge_hash_lookup(table, string, create, copy) \ |
((struct coff_debug_merge_hash_entry *) \ |
bfd_hash_lookup (&(table)->root, (string), (create), (copy))) |
/* Information we keep for each section in the output file when doing |
a relocatable link. */ |
struct coff_link_section_info |
{ |
/* The relocs to be output. */ |
struct internal_reloc *relocs; |
/* For each reloc against a global symbol whose index was not known |
when the reloc was handled, the global hash table entry. */ |
struct coff_link_hash_entry **rel_hashes; |
}; |
/* Information that we pass around while doing the final link step. */ |
struct coff_final_link_info |
{ |
/* General link information. */ |
struct bfd_link_info *info; |
/* Output BFD. */ |
bfd *output_bfd; |
/* Used to indicate failure in traversal routine. */ |
bfd_boolean failed; |
/* If doing "task linking" set only during the time when we want the |
global symbol writer to convert the storage class of defined global |
symbols from global to static. */ |
bfd_boolean global_to_static; |
/* Hash table for long symbol names. */ |
struct bfd_strtab_hash *strtab; |
/* When doing a relocatable link, an array of information kept for |
each output section, indexed by the target_index field. */ |
struct coff_link_section_info *section_info; |
/* Symbol index of last C_FILE symbol (-1 if none). */ |
long last_file_index; |
/* Contents of last C_FILE symbol. */ |
struct internal_syment last_file; |
/* Symbol index of first aux entry of last .bf symbol with an empty |
endndx field (-1 if none). */ |
long last_bf_index; |
/* Contents of last_bf_index aux entry. */ |
union internal_auxent last_bf; |
/* Hash table used to merge debug information. */ |
struct coff_debug_merge_hash_table debug_merge; |
/* Buffer large enough to hold swapped symbols of any input file. */ |
struct internal_syment *internal_syms; |
/* Buffer large enough to hold sections of symbols of any input file. */ |
asection **sec_ptrs; |
/* Buffer large enough to hold output indices of symbols of any |
input file. */ |
long *sym_indices; |
/* Buffer large enough to hold output symbols for any input file. */ |
bfd_byte *outsyms; |
/* Buffer large enough to hold external line numbers for any input |
section. */ |
bfd_byte *linenos; |
/* Buffer large enough to hold any input section. */ |
bfd_byte *contents; |
/* Buffer large enough to hold external relocs of any input section. */ |
bfd_byte *external_relocs; |
/* Buffer large enough to hold swapped relocs of any input section. */ |
struct internal_reloc *internal_relocs; |
}; |
/* Most COFF variants have no way to record the alignment of a |
section. This struct is used to set a specific alignment based on |
the name of the section. */ |
struct coff_section_alignment_entry |
{ |
/* The section name. */ |
const char *name; |
/* This is either (unsigned int) -1, indicating that the section |
name must match exactly, or it is the number of letters which |
must match at the start of the name. */ |
unsigned int comparison_length; |
/* These macros may be used to fill in the first two fields in a |
structure initialization. */ |
#define COFF_SECTION_NAME_EXACT_MATCH(name) (name), ((unsigned int) -1) |
#define COFF_SECTION_NAME_PARTIAL_MATCH(name) (name), (sizeof (name) - 1) |
/* Only use this entry if the default section alignment for this |
target is at least that much (as a power of two). If this field |
is COFF_ALIGNMENT_FIELD_EMPTY, it should be ignored. */ |
unsigned int default_alignment_min; |
/* Only use this entry if the default section alignment for this |
target is no greater than this (as a power of two). If this |
field is COFF_ALIGNMENT_FIELD_EMPTY, it should be ignored. */ |
unsigned int default_alignment_max; |
#define COFF_ALIGNMENT_FIELD_EMPTY ((unsigned int) -1) |
/* The desired alignment for this section (as a power of two). */ |
unsigned int alignment_power; |
}; |
extern struct bfd_hash_entry *_bfd_coff_link_hash_newfunc |
(struct bfd_hash_entry *, struct bfd_hash_table *, const char *); |
extern bfd_boolean _bfd_coff_link_hash_table_init |
(struct coff_link_hash_table *, bfd *, |
struct bfd_hash_entry *(*) (struct bfd_hash_entry *, |
struct bfd_hash_table *, |
const char *), |
unsigned int); |
extern struct bfd_link_hash_table *_bfd_coff_link_hash_table_create |
(bfd *); |
extern const char *_bfd_coff_internal_syment_name |
(bfd *, const struct internal_syment *, char *); |
extern bfd_boolean _bfd_coff_section_already_linked |
(bfd *, asection *, struct bfd_link_info *); |
extern bfd_boolean _bfd_coff_link_add_symbols |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean _bfd_coff_final_link |
(bfd *, struct bfd_link_info *); |
extern struct internal_reloc *_bfd_coff_read_internal_relocs |
(bfd *, asection *, bfd_boolean, bfd_byte *, bfd_boolean, |
struct internal_reloc *); |
extern bfd_boolean _bfd_coff_generic_relocate_section |
(bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, |
struct internal_reloc *, struct internal_syment *, asection **); |
extern struct bfd_hash_entry *_bfd_coff_debug_merge_hash_newfunc |
(struct bfd_hash_entry *, struct bfd_hash_table *, const char *); |
extern bfd_boolean _bfd_coff_write_global_sym |
(struct bfd_hash_entry *, void *); |
extern bfd_boolean _bfd_coff_write_task_globals |
(struct coff_link_hash_entry *, void *); |
extern bfd_boolean _bfd_coff_link_input_bfd |
(struct coff_final_link_info *, bfd *); |
extern bfd_boolean _bfd_coff_reloc_link_order |
(bfd *, struct coff_final_link_info *, asection *, |
struct bfd_link_order *); |
#define coff_get_section_contents_in_window \ |
_bfd_generic_get_section_contents_in_window |
/* Functions in xcofflink.c. */ |
extern long _bfd_xcoff_get_dynamic_symtab_upper_bound |
(bfd *); |
extern long _bfd_xcoff_canonicalize_dynamic_symtab |
(bfd *, asymbol **); |
extern long _bfd_xcoff_get_dynamic_reloc_upper_bound |
(bfd *); |
extern long _bfd_xcoff_canonicalize_dynamic_reloc |
(bfd *, arelent **, asymbol **); |
extern struct bfd_link_hash_table *_bfd_xcoff_bfd_link_hash_table_create |
(bfd *); |
extern void _bfd_xcoff_bfd_link_hash_table_free |
(struct bfd_link_hash_table *); |
extern bfd_boolean _bfd_xcoff_bfd_link_add_symbols |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean _bfd_xcoff_bfd_final_link |
(bfd *, struct bfd_link_info *); |
extern bfd_boolean _bfd_xcoff_define_common_symbol |
(bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *); |
extern bfd_boolean _bfd_ppc_xcoff_relocate_section |
(bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, |
struct internal_reloc *, struct internal_syment *, asection **); |
/* Functions in coff-ppc.c. FIXME: These are called by pe.em in the |
linker, and so should start with bfd and be declared in bfd.h. */ |
extern bfd_boolean ppc_allocate_toc_section |
(struct bfd_link_info *); |
extern bfd_boolean ppc_process_before_allocation |
(bfd *, struct bfd_link_info *); |
/* Extracted from coffcode.h. */ |
typedef struct coff_ptr_struct |
{ |
/* Remembers the offset from the first symbol in the file for |
this symbol. Generated by coff_renumber_symbols. */ |
unsigned int offset; |
/* Should the value of this symbol be renumbered. Used for |
XCOFF C_BSTAT symbols. Set by coff_slurp_symbol_table. */ |
unsigned int fix_value : 1; |
/* Should the tag field of this symbol be renumbered. |
Created by coff_pointerize_aux. */ |
unsigned int fix_tag : 1; |
/* Should the endidx field of this symbol be renumbered. |
Created by coff_pointerize_aux. */ |
unsigned int fix_end : 1; |
/* Should the x_csect.x_scnlen field be renumbered. |
Created by coff_pointerize_aux. */ |
unsigned int fix_scnlen : 1; |
/* Fix up an XCOFF C_BINCL/C_EINCL symbol. The value is the |
index into the line number entries. Set by coff_slurp_symbol_table. */ |
unsigned int fix_line : 1; |
/* The container for the symbol structure as read and translated |
from the file. */ |
union |
{ |
union internal_auxent auxent; |
struct internal_syment syment; |
} u; |
} combined_entry_type; |
/* Each canonical asymbol really looks like this: */ |
typedef struct coff_symbol_struct |
{ |
/* The actual symbol which the rest of BFD works with */ |
asymbol symbol; |
/* A pointer to the hidden information for this symbol */ |
combined_entry_type *native; |
/* A pointer to the linenumber information for this symbol */ |
struct lineno_cache_entry *lineno; |
/* Have the line numbers been relocated yet ? */ |
bfd_boolean done_lineno; |
} coff_symbol_type; |
/* COFF symbol classifications. */ |
enum coff_symbol_classification |
{ |
/* Global symbol. */ |
COFF_SYMBOL_GLOBAL, |
/* Common symbol. */ |
COFF_SYMBOL_COMMON, |
/* Undefined symbol. */ |
COFF_SYMBOL_UNDEFINED, |
/* Local symbol. */ |
COFF_SYMBOL_LOCAL, |
/* PE section symbol. */ |
COFF_SYMBOL_PE_SECTION |
}; |
typedef struct |
{ |
void (*_bfd_coff_swap_aux_in) |
(bfd *, void *, int, int, int, int, void *); |
void (*_bfd_coff_swap_sym_in) |
(bfd *, void *, void *); |
void (*_bfd_coff_swap_lineno_in) |
(bfd *, void *, void *); |
unsigned int (*_bfd_coff_swap_aux_out) |
(bfd *, void *, int, int, int, int, void *); |
unsigned int (*_bfd_coff_swap_sym_out) |
(bfd *, void *, void *); |
unsigned int (*_bfd_coff_swap_lineno_out) |
(bfd *, void *, void *); |
unsigned int (*_bfd_coff_swap_reloc_out) |
(bfd *, void *, void *); |
unsigned int (*_bfd_coff_swap_filehdr_out) |
(bfd *, void *, void *); |
unsigned int (*_bfd_coff_swap_aouthdr_out) |
(bfd *, void *, void *); |
unsigned int (*_bfd_coff_swap_scnhdr_out) |
(bfd *, void *, void *); |
unsigned int _bfd_filhsz; |
unsigned int _bfd_aoutsz; |
unsigned int _bfd_scnhsz; |
unsigned int _bfd_symesz; |
unsigned int _bfd_auxesz; |
unsigned int _bfd_relsz; |
unsigned int _bfd_linesz; |
unsigned int _bfd_filnmlen; |
bfd_boolean _bfd_coff_long_filenames; |
bfd_boolean _bfd_coff_long_section_names; |
bfd_boolean (*_bfd_coff_set_long_section_names) |
(bfd *, int); |
unsigned int _bfd_coff_default_section_alignment_power; |
bfd_boolean _bfd_coff_force_symnames_in_strings; |
unsigned int _bfd_coff_debug_string_prefix_length; |
void (*_bfd_coff_swap_filehdr_in) |
(bfd *, void *, void *); |
void (*_bfd_coff_swap_aouthdr_in) |
(bfd *, void *, void *); |
void (*_bfd_coff_swap_scnhdr_in) |
(bfd *, void *, void *); |
void (*_bfd_coff_swap_reloc_in) |
(bfd *abfd, void *, void *); |
bfd_boolean (*_bfd_coff_bad_format_hook) |
(bfd *, void *); |
bfd_boolean (*_bfd_coff_set_arch_mach_hook) |
(bfd *, void *); |
void * (*_bfd_coff_mkobject_hook) |
(bfd *, void *, void *); |
bfd_boolean (*_bfd_styp_to_sec_flags_hook) |
(bfd *, void *, const char *, asection *, flagword *); |
void (*_bfd_set_alignment_hook) |
(bfd *, asection *, void *); |
bfd_boolean (*_bfd_coff_slurp_symbol_table) |
(bfd *); |
bfd_boolean (*_bfd_coff_symname_in_debug) |
(bfd *, struct internal_syment *); |
bfd_boolean (*_bfd_coff_pointerize_aux_hook) |
(bfd *, combined_entry_type *, combined_entry_type *, |
unsigned int, combined_entry_type *); |
bfd_boolean (*_bfd_coff_print_aux) |
(bfd *, FILE *, combined_entry_type *, combined_entry_type *, |
combined_entry_type *, unsigned int); |
void (*_bfd_coff_reloc16_extra_cases) |
(bfd *, struct bfd_link_info *, struct bfd_link_order *, arelent *, |
bfd_byte *, unsigned int *, unsigned int *); |
int (*_bfd_coff_reloc16_estimate) |
(bfd *, asection *, arelent *, unsigned int, |
struct bfd_link_info *); |
enum coff_symbol_classification (*_bfd_coff_classify_symbol) |
(bfd *, struct internal_syment *); |
bfd_boolean (*_bfd_coff_compute_section_file_positions) |
(bfd *); |
bfd_boolean (*_bfd_coff_start_final_link) |
(bfd *, struct bfd_link_info *); |
bfd_boolean (*_bfd_coff_relocate_section) |
(bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, |
struct internal_reloc *, struct internal_syment *, asection **); |
reloc_howto_type *(*_bfd_coff_rtype_to_howto) |
(bfd *, asection *, struct internal_reloc *, |
struct coff_link_hash_entry *, struct internal_syment *, |
bfd_vma *); |
bfd_boolean (*_bfd_coff_adjust_symndx) |
(bfd *, struct bfd_link_info *, bfd *, asection *, |
struct internal_reloc *, bfd_boolean *); |
bfd_boolean (*_bfd_coff_link_add_one_symbol) |
(struct bfd_link_info *, bfd *, const char *, flagword, |
asection *, bfd_vma, const char *, bfd_boolean, bfd_boolean, |
struct bfd_link_hash_entry **); |
bfd_boolean (*_bfd_coff_link_output_has_begun) |
(bfd *, struct coff_final_link_info *); |
bfd_boolean (*_bfd_coff_final_link_postscript) |
(bfd *, struct coff_final_link_info *); |
bfd_boolean (*_bfd_coff_print_pdata) |
(bfd *, void *); |
} bfd_coff_backend_data; |
#define coff_backend_info(abfd) \ |
((bfd_coff_backend_data *) (abfd)->xvec->backend_data) |
#define bfd_coff_swap_aux_in(a,e,t,c,ind,num,i) \ |
((coff_backend_info (a)->_bfd_coff_swap_aux_in) (a,e,t,c,ind,num,i)) |
#define bfd_coff_swap_sym_in(a,e,i) \ |
((coff_backend_info (a)->_bfd_coff_swap_sym_in) (a,e,i)) |
#define bfd_coff_swap_lineno_in(a,e,i) \ |
((coff_backend_info ( a)->_bfd_coff_swap_lineno_in) (a,e,i)) |
#define bfd_coff_swap_reloc_out(abfd, i, o) \ |
((coff_backend_info (abfd)->_bfd_coff_swap_reloc_out) (abfd, i, o)) |
#define bfd_coff_swap_lineno_out(abfd, i, o) \ |
((coff_backend_info (abfd)->_bfd_coff_swap_lineno_out) (abfd, i, o)) |
#define bfd_coff_swap_aux_out(a,i,t,c,ind,num,o) \ |
((coff_backend_info (a)->_bfd_coff_swap_aux_out) (a,i,t,c,ind,num,o)) |
#define bfd_coff_swap_sym_out(abfd, i,o) \ |
((coff_backend_info (abfd)->_bfd_coff_swap_sym_out) (abfd, i, o)) |
#define bfd_coff_swap_scnhdr_out(abfd, i,o) \ |
((coff_backend_info (abfd)->_bfd_coff_swap_scnhdr_out) (abfd, i, o)) |
#define bfd_coff_swap_filehdr_out(abfd, i,o) \ |
((coff_backend_info (abfd)->_bfd_coff_swap_filehdr_out) (abfd, i, o)) |
#define bfd_coff_swap_aouthdr_out(abfd, i,o) \ |
((coff_backend_info (abfd)->_bfd_coff_swap_aouthdr_out) (abfd, i, o)) |
#define bfd_coff_filhsz(abfd) (coff_backend_info (abfd)->_bfd_filhsz) |
#define bfd_coff_aoutsz(abfd) (coff_backend_info (abfd)->_bfd_aoutsz) |
#define bfd_coff_scnhsz(abfd) (coff_backend_info (abfd)->_bfd_scnhsz) |
#define bfd_coff_symesz(abfd) (coff_backend_info (abfd)->_bfd_symesz) |
#define bfd_coff_auxesz(abfd) (coff_backend_info (abfd)->_bfd_auxesz) |
#define bfd_coff_relsz(abfd) (coff_backend_info (abfd)->_bfd_relsz) |
#define bfd_coff_linesz(abfd) (coff_backend_info (abfd)->_bfd_linesz) |
#define bfd_coff_filnmlen(abfd) (coff_backend_info (abfd)->_bfd_filnmlen) |
#define bfd_coff_long_filenames(abfd) \ |
(coff_backend_info (abfd)->_bfd_coff_long_filenames) |
#define bfd_coff_long_section_names(abfd) \ |
(coff_backend_info (abfd)->_bfd_coff_long_section_names) |
#define bfd_coff_set_long_section_names(abfd, enable) \ |
((coff_backend_info (abfd)->_bfd_coff_set_long_section_names) (abfd, enable)) |
#define bfd_coff_default_section_alignment_power(abfd) \ |
(coff_backend_info (abfd)->_bfd_coff_default_section_alignment_power) |
#define bfd_coff_swap_filehdr_in(abfd, i,o) \ |
((coff_backend_info (abfd)->_bfd_coff_swap_filehdr_in) (abfd, i, o)) |
#define bfd_coff_swap_aouthdr_in(abfd, i,o) \ |
((coff_backend_info (abfd)->_bfd_coff_swap_aouthdr_in) (abfd, i, o)) |
#define bfd_coff_swap_scnhdr_in(abfd, i,o) \ |
((coff_backend_info (abfd)->_bfd_coff_swap_scnhdr_in) (abfd, i, o)) |
#define bfd_coff_swap_reloc_in(abfd, i, o) \ |
((coff_backend_info (abfd)->_bfd_coff_swap_reloc_in) (abfd, i, o)) |
#define bfd_coff_bad_format_hook(abfd, filehdr) \ |
((coff_backend_info (abfd)->_bfd_coff_bad_format_hook) (abfd, filehdr)) |
#define bfd_coff_set_arch_mach_hook(abfd, filehdr)\ |
((coff_backend_info (abfd)->_bfd_coff_set_arch_mach_hook) (abfd, filehdr)) |
#define bfd_coff_mkobject_hook(abfd, filehdr, aouthdr)\ |
((coff_backend_info (abfd)->_bfd_coff_mkobject_hook)\ |
(abfd, filehdr, aouthdr)) |
#define bfd_coff_styp_to_sec_flags_hook(abfd, scnhdr, name, section, flags_ptr)\ |
((coff_backend_info (abfd)->_bfd_styp_to_sec_flags_hook)\ |
(abfd, scnhdr, name, section, flags_ptr)) |
#define bfd_coff_set_alignment_hook(abfd, sec, scnhdr)\ |
((coff_backend_info (abfd)->_bfd_set_alignment_hook) (abfd, sec, scnhdr)) |
#define bfd_coff_slurp_symbol_table(abfd)\ |
((coff_backend_info (abfd)->_bfd_coff_slurp_symbol_table) (abfd)) |
#define bfd_coff_symname_in_debug(abfd, sym)\ |
((coff_backend_info (abfd)->_bfd_coff_symname_in_debug) (abfd, sym)) |
#define bfd_coff_force_symnames_in_strings(abfd)\ |
(coff_backend_info (abfd)->_bfd_coff_force_symnames_in_strings) |
#define bfd_coff_debug_string_prefix_length(abfd)\ |
(coff_backend_info (abfd)->_bfd_coff_debug_string_prefix_length) |
#define bfd_coff_print_aux(abfd, file, base, symbol, aux, indaux)\ |
((coff_backend_info (abfd)->_bfd_coff_print_aux)\ |
(abfd, file, base, symbol, aux, indaux)) |
#define bfd_coff_reloc16_extra_cases(abfd, link_info, link_order,\ |
reloc, data, src_ptr, dst_ptr)\ |
((coff_backend_info (abfd)->_bfd_coff_reloc16_extra_cases)\ |
(abfd, link_info, link_order, reloc, data, src_ptr, dst_ptr)) |
#define bfd_coff_reloc16_estimate(abfd, section, reloc, shrink, link_info)\ |
((coff_backend_info (abfd)->_bfd_coff_reloc16_estimate)\ |
(abfd, section, reloc, shrink, link_info)) |
#define bfd_coff_classify_symbol(abfd, sym)\ |
((coff_backend_info (abfd)->_bfd_coff_classify_symbol)\ |
(abfd, sym)) |
#define bfd_coff_compute_section_file_positions(abfd)\ |
((coff_backend_info (abfd)->_bfd_coff_compute_section_file_positions)\ |
(abfd)) |
#define bfd_coff_start_final_link(obfd, info)\ |
((coff_backend_info (obfd)->_bfd_coff_start_final_link)\ |
(obfd, info)) |
#define bfd_coff_relocate_section(obfd,info,ibfd,o,con,rel,isyms,secs)\ |
((coff_backend_info (ibfd)->_bfd_coff_relocate_section)\ |
(obfd, info, ibfd, o, con, rel, isyms, secs)) |
#define bfd_coff_rtype_to_howto(abfd, sec, rel, h, sym, addendp)\ |
((coff_backend_info (abfd)->_bfd_coff_rtype_to_howto)\ |
(abfd, sec, rel, h, sym, addendp)) |
#define bfd_coff_adjust_symndx(obfd, info, ibfd, sec, rel, adjustedp)\ |
((coff_backend_info (abfd)->_bfd_coff_adjust_symndx)\ |
(obfd, info, ibfd, sec, rel, adjustedp)) |
#define bfd_coff_link_add_one_symbol(info, abfd, name, flags, section,\ |
value, string, cp, coll, hashp)\ |
((coff_backend_info (abfd)->_bfd_coff_link_add_one_symbol)\ |
(info, abfd, name, flags, section, value, string, cp, coll, hashp)) |
#define bfd_coff_link_output_has_begun(a,p) \ |
((coff_backend_info (a)->_bfd_coff_link_output_has_begun) (a, p)) |
#define bfd_coff_final_link_postscript(a,p) \ |
((coff_backend_info (a)->_bfd_coff_final_link_postscript) (a, p)) |
#define bfd_coff_have_print_pdata(a) \ |
(coff_backend_info (a)->_bfd_coff_print_pdata) |
#define bfd_coff_print_pdata(a,p) \ |
((coff_backend_info (a)->_bfd_coff_print_pdata) (a, p)) |
/* Macro: Returns true if the bfd is a PE executable as opposed to a |
PE object file. */ |
#define bfd_pei_p(abfd) \ |
(CONST_STRNEQ ((abfd)->xvec->name, "pei-")) |
/contrib/toolchain/binutils/bfd/libecoff.h |
---|
0,0 → 1,348 |
/* BFD ECOFF object file private structure. |
Copyright 1993, 1994, 1995, 1996, 1999, 2001, 2002, 2003, 2004, |
2005, 2006, 2007, 2008, 2009, 2010 |
Free Software Foundation, Inc. |
Written by Ian Lance Taylor, Cygnus Support. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "bfdlink.h" |
#ifndef ECOFF_H |
#include "coff/ecoff.h" |
#endif |
/* This is the backend information kept for ECOFF files. This |
structure is constant for a particular backend. The first element |
is the COFF backend data structure, so that ECOFF targets can use |
the generic COFF code. */ |
#define ecoff_backend(abfd) \ |
((struct ecoff_backend_data *) (abfd)->xvec->backend_data) |
struct ecoff_backend_data |
{ |
/* COFF backend information. This must be the first field. */ |
bfd_coff_backend_data coff; |
/* Supported architecture. */ |
enum bfd_architecture arch; |
/* Initial portion of armap string. */ |
const char *armap_start; |
/* The page boundary used to align sections in a demand-paged |
executable file. E.g., 0x1000. */ |
bfd_vma round; |
/* TRUE if the .rdata section is part of the text segment, as on the |
Alpha. FALSE if .rdata is part of the data segment, as on the |
MIPS. */ |
bfd_boolean rdata_in_text; |
/* Bitsize of constructor entries. */ |
unsigned int constructor_bitsize; |
/* Reloc to use for constructor entries. */ |
reloc_howto_type *constructor_reloc; |
/* How to swap debugging information. */ |
struct ecoff_debug_swap debug_swap; |
/* External reloc size. */ |
bfd_size_type external_reloc_size; |
/* Reloc swapping functions. */ |
void (*swap_reloc_in) (bfd *, void *, struct internal_reloc *); |
void (*swap_reloc_out) (bfd *, const struct internal_reloc *, void *); |
/* Backend reloc tweaking. */ |
void (*adjust_reloc_in) |
(bfd *, const struct internal_reloc *, arelent *); |
void (*adjust_reloc_out) |
(bfd *, const arelent *, struct internal_reloc *); |
/* Relocate section contents while linking. */ |
bfd_boolean (*relocate_section) |
(bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, void *); |
/* Do final adjustments to filehdr and aouthdr. */ |
bfd_boolean (*adjust_headers) |
(bfd *, struct internal_filehdr *, struct internal_aouthdr *); |
/* Read an element from an archive at a given file position. This |
is needed because OSF/1 3.2 uses a weird archive format. */ |
bfd *(*get_elt_at_filepos) (bfd *, file_ptr); |
}; |
/* ECOFF targets don't support COFF long section names, so this |
macro is provided to use as an initialiser for the related |
members of the embedded bfd_coff_backend_data struct. */ |
#define ECOFF_NO_LONG_SECTION_NAMES (FALSE), _bfd_ecoff_no_long_sections |
/* This is the target specific information kept for ECOFF files. */ |
#define ecoff_data(abfd) ((abfd)->tdata.ecoff_obj_data) |
typedef struct ecoff_tdata |
{ |
/* The reloc file position, set by |
ecoff_compute_section_file_positions. */ |
file_ptr reloc_filepos; |
/* The symbol table file position, set by _bfd_ecoff_mkobject_hook. */ |
file_ptr sym_filepos; |
/* The start and end of the text segment. Only valid for an |
existing file, not for one we are creating. */ |
unsigned long text_start; |
unsigned long text_end; |
/* The cached gp value. This is used when relocating. */ |
bfd_vma gp; |
/* The maximum size of objects to optimize using gp. This is |
typically set by the -G option to the compiler, assembler or |
linker. */ |
unsigned int gp_size; |
/* The register masks. When linking, all the masks found in the |
input files are combined into the masks of the output file. |
These are not all used for all targets, but that's OK, because |
the relevant ones are the only ones swapped in and out. */ |
unsigned long gprmask; |
unsigned long fprmask; |
unsigned long cprmask[4]; |
/* The ECOFF symbolic debugging information. */ |
struct ecoff_debug_info debug_info; |
/* The unswapped ECOFF symbolic information. */ |
void * raw_syments; |
/* The canonical BFD symbols. */ |
struct ecoff_symbol_struct *canonical_symbols; |
/* A mapping from external symbol numbers to entries in the linker |
hash table, used when linking. */ |
struct ecoff_link_hash_entry **sym_hashes; |
/* A mapping from reloc symbol indices to sections, used when |
linking. */ |
asection **symndx_to_section; |
/* TRUE if this BFD was written by the backend linker. */ |
bfd_boolean linker; |
/* TRUE if a warning that multiple global pointer values are |
needed in the output binary was issued already. */ |
bfd_boolean issued_multiple_gp_warning; |
/* Used by find_nearest_line entry point. The structure could be |
included directly in this one, but there's no point to wasting |
the memory just for the infrequently called find_nearest_line. */ |
struct ecoff_find_line *find_line_info; |
/* Whether the .rdata section is in the text segment for this |
particular ECOFF file. This is not valid until |
ecoff_compute_section_file_positions is called. */ |
bfd_boolean rdata_in_text; |
} ecoff_data_type; |
/* Each canonical asymbol really looks like this. */ |
typedef struct ecoff_symbol_struct |
{ |
/* The actual symbol which the rest of BFD works with */ |
asymbol symbol; |
/* The fdr for this symbol. */ |
FDR *fdr; |
/* TRUE if this is a local symbol rather than an external one. */ |
bfd_boolean local; |
/* A pointer to the unswapped hidden information for this symbol. |
This is either a struct sym_ext or a struct ext_ext, depending on |
the value of the local field above. */ |
void * native; |
} ecoff_symbol_type; |
/* We take the address of the first element of an asymbol to ensure that the |
macro is only ever applied to an asymbol. */ |
#define ecoffsymbol(asymbol) ((ecoff_symbol_type *) (&((asymbol)->the_bfd))) |
/* We need to save the index of an external symbol when we write it |
out so that can set the symbol index correctly when we write out |
the relocs. */ |
#define ecoff_get_sym_index(symbol) ((symbol)->udata.i) |
#define ecoff_set_sym_index(symbol, idx) ((symbol)->udata.i = (idx)) |
/* A pointer to this structure is put in the used_by_bfd pointer of |
a section to keep track of any per-section data. |
The user_by_bfd pointer will be NULL if the information was not |
needed. */ |
struct ecoff_section_tdata |
{ |
/* When producing an executable (i.e., final, non-relocatable link) |
on the Alpha, we may need to use multiple global pointer values |
to span the entire .lita section. In essence, we allow each |
input .lita section to have its own gp value. To support this, |
we need to keep track of the gp values that we picked for each |
input .lita section . */ |
bfd_vma gp; |
}; |
/* An accessor macro for the ecoff_section_tdata structure. */ |
#define ecoff_section_data(abfd, sec) \ |
((struct ecoff_section_tdata *) (sec)->used_by_bfd) |
/* ECOFF linker hash table entries. */ |
struct ecoff_link_hash_entry |
{ |
struct bfd_link_hash_entry root; |
/* Symbol index in output file. */ |
long indx; |
/* BFD that ext field value came from. */ |
bfd *abfd; |
/* ECOFF external symbol information. */ |
EXTR esym; |
/* Nonzero if this symbol has been written out. */ |
char written; |
/* Nonzero if this symbol was referred to as small undefined. */ |
char small; |
}; |
/* ECOFF linker hash table. */ |
struct ecoff_link_hash_table |
{ |
struct bfd_link_hash_table root; |
}; |
/* Make an ECOFF object. */ |
extern bfd_boolean _bfd_ecoff_mkobject (bfd *); |
/* Read in the ECOFF symbolic debugging information. */ |
extern bfd_boolean _bfd_ecoff_slurp_symbolic_info |
(bfd *, asection *, struct ecoff_debug_info *); |
/* Generic ECOFF BFD backend vectors. */ |
extern bfd_boolean _bfd_ecoff_write_object_contents (bfd *); |
#define _bfd_ecoff_close_and_cleanup _bfd_generic_close_and_cleanup |
#define _bfd_ecoff_bfd_free_cached_info _bfd_generic_bfd_free_cached_info |
extern bfd_boolean _bfd_ecoff_new_section_hook |
(bfd *, asection *); |
extern bfd_boolean _bfd_ecoff_get_section_contents |
(bfd *, asection *, void * location, file_ptr, bfd_size_type); |
#define _bfd_ecoff_bfd_link_split_section _bfd_generic_link_split_section |
extern bfd_boolean _bfd_ecoff_bfd_copy_private_bfd_data |
(bfd *, bfd *); |
#define _bfd_ecoff_bfd_copy_private_section_data \ |
_bfd_generic_bfd_copy_private_section_data |
#define _bfd_ecoff_bfd_copy_private_symbol_data \ |
_bfd_generic_bfd_copy_private_symbol_data |
#define _bfd_ecoff_bfd_copy_private_header_data \ |
_bfd_generic_bfd_copy_private_header_data |
#define _bfd_ecoff_bfd_print_private_bfd_data \ |
_bfd_generic_bfd_print_private_bfd_data |
#define _bfd_ecoff_bfd_merge_private_bfd_data \ |
_bfd_generic_bfd_merge_private_bfd_data |
#define _bfd_ecoff_bfd_set_private_flags _bfd_generic_bfd_set_private_flags |
extern bfd_boolean _bfd_ecoff_slurp_armap (bfd *); |
#define _bfd_ecoff_slurp_extended_name_table _bfd_slurp_extended_name_table |
#define _bfd_ecoff_construct_extended_name_table \ |
_bfd_archive_bsd_construct_extended_name_table |
#define _bfd_ecoff_truncate_arname bfd_dont_truncate_arname |
extern bfd_boolean _bfd_ecoff_write_armap |
(bfd *, unsigned int, struct orl *, unsigned int, int); |
#define _bfd_ecoff_read_ar_hdr _bfd_generic_read_ar_hdr |
#define _bfd_ecoff_write_ar_hdr _bfd_generic_write_ar_hdr |
#define _bfd_ecoff_openr_next_archived_file \ |
bfd_generic_openr_next_archived_file |
#define _bfd_ecoff_get_elt_at_index _bfd_generic_get_elt_at_index |
#define _bfd_ecoff_generic_stat_arch_elt bfd_generic_stat_arch_elt |
#define _bfd_ecoff_update_armap_timestamp bfd_true |
#define _bfd_ecoff_bfd_is_target_special_symbol \ |
((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) |
extern long _bfd_ecoff_get_symtab_upper_bound (bfd *); |
extern long _bfd_ecoff_canonicalize_symtab (bfd *, asymbol **); |
extern asymbol *_bfd_ecoff_make_empty_symbol (bfd *); |
extern void _bfd_ecoff_print_symbol |
(bfd *, void *, asymbol *, bfd_print_symbol_type); |
extern void _bfd_ecoff_get_symbol_info |
(bfd *, asymbol *, symbol_info *); |
extern bfd_boolean _bfd_ecoff_bfd_is_local_label_name |
(bfd *, const char *); |
#define _bfd_ecoff_get_lineno _bfd_nosymbols_get_lineno |
extern bfd_boolean _bfd_ecoff_find_nearest_line |
(bfd *, asection *, asymbol **, bfd_vma, const char **, const char **, |
unsigned int *); |
#define _bfd_ecoff_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol |
#define _bfd_ecoff_read_minisymbols _bfd_generic_read_minisymbols |
#define _bfd_ecoff_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol |
#define _bfd_ecoff_find_inliner_info _bfd_nosymbols_find_inliner_info |
#define _bfd_ecoff_get_reloc_upper_bound coff_get_reloc_upper_bound |
extern long _bfd_ecoff_canonicalize_reloc |
(bfd *, asection *, arelent **, asymbol **symbols); |
/* ecoff_bfd_reloc_type_lookup defined by backend. */ |
extern bfd_boolean _bfd_ecoff_set_arch_mach |
(bfd *, enum bfd_architecture, unsigned long); |
extern bfd_boolean _bfd_ecoff_set_section_contents |
(bfd *, asection *, const void * location, file_ptr, bfd_size_type); |
extern int _bfd_ecoff_sizeof_headers (bfd *, struct bfd_link_info *); |
/* ecoff_bfd_get_relocated_section_contents defined by backend. */ |
/* ecoff_bfd_relax_section defined by backend. */ |
extern struct bfd_link_hash_table *_bfd_ecoff_bfd_link_hash_table_create |
(bfd *); |
#define _bfd_ecoff_bfd_link_hash_table_free _bfd_generic_link_hash_table_free |
extern bfd_boolean _bfd_ecoff_bfd_link_add_symbols |
(bfd *, struct bfd_link_info *); |
#define _bfd_ecoff_bfd_link_just_syms _bfd_generic_link_just_syms |
#define _bfd_ecoff_bfd_copy_link_hash_symbol_type \ |
_bfd_generic_copy_link_hash_symbol_type |
extern bfd_boolean _bfd_ecoff_bfd_final_link |
(bfd *, struct bfd_link_info *); |
/* Hook functions for the generic COFF section reading code. */ |
extern void * _bfd_ecoff_mkobject_hook (bfd *, void *, void *); |
#define _bfd_ecoff_set_alignment_hook \ |
((void (*) (bfd *, asection *, void *)) bfd_void) |
extern bfd_boolean _bfd_ecoff_set_arch_mach_hook |
(bfd *, void *); |
extern bfd_boolean _bfd_ecoff_no_long_sections |
(bfd *abfd, int enable); |
extern bfd_boolean _bfd_ecoff_styp_to_sec_flags |
(bfd *, void *, const char *, asection *, flagword *); |
extern bfd_boolean _bfd_ecoff_slurp_symbol_table (bfd *); |
/* ECOFF auxiliary information swapping routines. These are the same |
for all ECOFF targets, so they are defined in ecofflink.c. */ |
extern void _bfd_ecoff_swap_tir_in |
(int, const struct tir_ext *, TIR *); |
extern void _bfd_ecoff_swap_tir_out |
(int, const TIR *, struct tir_ext *); |
extern void _bfd_ecoff_swap_rndx_in |
(int, const struct rndx_ext *, RNDXR *); |
extern void _bfd_ecoff_swap_rndx_out |
(int, const RNDXR *, struct rndx_ext *); |
/contrib/toolchain/binutils/bfd/libpei.h |
---|
0,0 → 1,356 |
/* Support for the generic parts of PE/PEI; common header information. |
Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, |
2006, 2007, 2008, 2009 Free Software Foundation, Inc. |
Written by Cygnus Solutions. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* Most of this hacked by Steve Chamberlain, |
sac@cygnus.com |
PE/PEI rearrangement (and code added): Donn Terry |
Softway Systems, Inc. */ |
/* Hey look, some documentation [and in a place you expect to find it]! |
The main reference for the pei format is "Microsoft Portable Executable |
and Common Object File Format Specification 4.1". Get it if you need to |
do some serious hacking on this code. |
Another reference: |
"Peering Inside the PE: A Tour of the Win32 Portable Executable |
File Format", MSJ 1994, Volume 9. |
The *sole* difference between the pe format and the pei format is that the |
latter has an MSDOS 2.0 .exe header on the front that prints the message |
"This app must be run under Windows." (or some such). |
(FIXME: Whether that statement is *really* true or not is unknown. |
Are there more subtle differences between pe and pei formats? |
For now assume there aren't. If you find one, then for God sakes |
document it here!) |
The Microsoft docs use the word "image" instead of "executable" because |
the former can also refer to a DLL (shared library). Confusion can arise |
because the `i' in `pei' also refers to "image". The `pe' format can |
also create images (i.e. executables), it's just that to run on a win32 |
system you need to use the pei format. |
FIXME: Please add more docs here so the next poor fool that has to hack |
on this code has a chance of getting something accomplished without |
wasting too much time. */ |
#ifndef GET_FCN_LNNOPTR |
#define GET_FCN_LNNOPTR(abfd, ext) \ |
H_GET_32 (abfd, ext->x_sym.x_fcnary.x_fcn.x_lnnoptr) |
#endif |
#ifndef GET_FCN_ENDNDX |
#define GET_FCN_ENDNDX(abfd, ext) \ |
H_GET_32 (abfd, ext->x_sym.x_fcnary.x_fcn.x_endndx) |
#endif |
#ifndef PUT_FCN_LNNOPTR |
#define PUT_FCN_LNNOPTR(abfd, in, ext) \ |
H_PUT_32(abfd, in, ext->x_sym.x_fcnary.x_fcn.x_lnnoptr) |
#endif |
#ifndef PUT_FCN_ENDNDX |
#define PUT_FCN_ENDNDX(abfd, in, ext) \ |
H_PUT_32(abfd, in, ext->x_sym.x_fcnary.x_fcn.x_endndx) |
#endif |
#ifndef GET_LNSZ_LNNO |
#define GET_LNSZ_LNNO(abfd, ext) \ |
H_GET_16 (abfd, ext->x_sym.x_misc.x_lnsz.x_lnno) |
#endif |
#ifndef GET_LNSZ_SIZE |
#define GET_LNSZ_SIZE(abfd, ext) \ |
H_GET_16 (abfd, ext->x_sym.x_misc.x_lnsz.x_size) |
#endif |
#ifndef PUT_LNSZ_LNNO |
#define PUT_LNSZ_LNNO(abfd, in, ext) \ |
H_PUT_16(abfd, in, ext->x_sym.x_misc.x_lnsz.x_lnno) |
#endif |
#ifndef PUT_LNSZ_SIZE |
#define PUT_LNSZ_SIZE(abfd, in, ext) \ |
H_PUT_16(abfd, in, ext->x_sym.x_misc.x_lnsz.x_size) |
#endif |
#ifndef GET_SCN_SCNLEN |
#define GET_SCN_SCNLEN(abfd, ext) \ |
H_GET_32 (abfd, ext->x_scn.x_scnlen) |
#endif |
#ifndef GET_SCN_NRELOC |
#define GET_SCN_NRELOC(abfd, ext) \ |
H_GET_16 (abfd, ext->x_scn.x_nreloc) |
#endif |
#ifndef GET_SCN_NLINNO |
#define GET_SCN_NLINNO(abfd, ext) \ |
H_GET_16 (abfd, ext->x_scn.x_nlinno) |
#endif |
#ifndef PUT_SCN_SCNLEN |
#define PUT_SCN_SCNLEN(abfd, in, ext) \ |
H_PUT_32(abfd, in, ext->x_scn.x_scnlen) |
#endif |
#ifndef PUT_SCN_NRELOC |
#define PUT_SCN_NRELOC(abfd, in, ext) \ |
H_PUT_16(abfd, in, ext->x_scn.x_nreloc) |
#endif |
#ifndef PUT_SCN_NLINNO |
#define PUT_SCN_NLINNO(abfd, in, ext) \ |
H_PUT_16(abfd,in, ext->x_scn.x_nlinno) |
#endif |
#ifndef GET_LINENO_LNNO |
#define GET_LINENO_LNNO(abfd, ext) \ |
H_GET_16 (abfd, ext->l_lnno); |
#endif |
#ifndef PUT_LINENO_LNNO |
#define PUT_LINENO_LNNO(abfd, val, ext) \ |
H_PUT_16(abfd,val, ext->l_lnno); |
#endif |
/* The f_symptr field in the filehdr is sometimes 64 bits. */ |
#ifndef GET_FILEHDR_SYMPTR |
#define GET_FILEHDR_SYMPTR H_GET_32 |
#endif |
#ifndef PUT_FILEHDR_SYMPTR |
#define PUT_FILEHDR_SYMPTR H_PUT_32 |
#endif |
/* Some fields in the aouthdr are sometimes 64 bits. */ |
#ifndef GET_AOUTHDR_TSIZE |
#define GET_AOUTHDR_TSIZE H_GET_32 |
#endif |
#ifndef PUT_AOUTHDR_TSIZE |
#define PUT_AOUTHDR_TSIZE H_PUT_32 |
#endif |
#ifndef GET_AOUTHDR_DSIZE |
#define GET_AOUTHDR_DSIZE H_GET_32 |
#endif |
#ifndef PUT_AOUTHDR_DSIZE |
#define PUT_AOUTHDR_DSIZE H_PUT_32 |
#endif |
#ifndef GET_AOUTHDR_BSIZE |
#define GET_AOUTHDR_BSIZE H_GET_32 |
#endif |
#ifndef PUT_AOUTHDR_BSIZE |
#define PUT_AOUTHDR_BSIZE H_PUT_32 |
#endif |
#ifndef GET_AOUTHDR_ENTRY |
#define GET_AOUTHDR_ENTRY H_GET_32 |
#endif |
#ifndef PUT_AOUTHDR_ENTRY |
#define PUT_AOUTHDR_ENTRY H_PUT_32 |
#endif |
#ifndef GET_AOUTHDR_TEXT_START |
#define GET_AOUTHDR_TEXT_START H_GET_32 |
#endif |
#ifndef PUT_AOUTHDR_TEXT_START |
#define PUT_AOUTHDR_TEXT_START H_PUT_32 |
#endif |
#ifndef GET_AOUTHDR_DATA_START |
#define GET_AOUTHDR_DATA_START H_GET_32 |
#endif |
#ifndef PUT_AOUTHDR_DATA_START |
#define PUT_AOUTHDR_DATA_START H_PUT_32 |
#endif |
/* Some fields in the scnhdr are sometimes 64 bits. */ |
#ifndef GET_SCNHDR_PADDR |
#define GET_SCNHDR_PADDR H_GET_32 |
#endif |
#ifndef PUT_SCNHDR_PADDR |
#define PUT_SCNHDR_PADDR H_PUT_32 |
#endif |
#ifndef GET_SCNHDR_VADDR |
#define GET_SCNHDR_VADDR H_GET_32 |
#endif |
#ifndef PUT_SCNHDR_VADDR |
#define PUT_SCNHDR_VADDR H_PUT_32 |
#endif |
#ifndef GET_SCNHDR_SIZE |
#define GET_SCNHDR_SIZE H_GET_32 |
#endif |
#ifndef PUT_SCNHDR_SIZE |
#define PUT_SCNHDR_SIZE H_PUT_32 |
#endif |
#ifndef GET_SCNHDR_SCNPTR |
#define GET_SCNHDR_SCNPTR H_GET_32 |
#endif |
#ifndef PUT_SCNHDR_SCNPTR |
#define PUT_SCNHDR_SCNPTR H_PUT_32 |
#endif |
#ifndef GET_SCNHDR_RELPTR |
#define GET_SCNHDR_RELPTR H_GET_32 |
#endif |
#ifndef PUT_SCNHDR_RELPTR |
#define PUT_SCNHDR_RELPTR H_PUT_32 |
#endif |
#ifndef GET_SCNHDR_LNNOPTR |
#define GET_SCNHDR_LNNOPTR H_GET_32 |
#endif |
#ifndef PUT_SCNHDR_LNNOPTR |
#define PUT_SCNHDR_LNNOPTR H_PUT_32 |
#endif |
#ifdef COFF_WITH_pex64 |
#define GET_OPTHDR_IMAGE_BASE H_GET_64 |
#define PUT_OPTHDR_IMAGE_BASE H_PUT_64 |
#define GET_OPTHDR_SIZE_OF_STACK_RESERVE H_GET_64 |
#define PUT_OPTHDR_SIZE_OF_STACK_RESERVE H_PUT_64 |
#define GET_OPTHDR_SIZE_OF_STACK_COMMIT H_GET_64 |
#define PUT_OPTHDR_SIZE_OF_STACK_COMMIT H_PUT_64 |
#define GET_OPTHDR_SIZE_OF_HEAP_RESERVE H_GET_64 |
#define PUT_OPTHDR_SIZE_OF_HEAP_RESERVE H_PUT_64 |
#define GET_OPTHDR_SIZE_OF_HEAP_COMMIT H_GET_64 |
#define PUT_OPTHDR_SIZE_OF_HEAP_COMMIT H_PUT_64 |
#define GET_PDATA_ENTRY bfd_get_32 |
#define _bfd_XX_bfd_copy_private_bfd_data_common _bfd_pex64_bfd_copy_private_bfd_data_common |
#define _bfd_XX_bfd_copy_private_section_data _bfd_pex64_bfd_copy_private_section_data |
#define _bfd_XX_get_symbol_info _bfd_pex64_get_symbol_info |
#define _bfd_XX_only_swap_filehdr_out _bfd_pex64_only_swap_filehdr_out |
#define _bfd_XX_print_private_bfd_data_common _bfd_pex64_print_private_bfd_data_common |
#define _bfd_XXi_final_link_postscript _bfd_pex64i_final_link_postscript |
#define _bfd_XXi_only_swap_filehdr_out _bfd_pex64i_only_swap_filehdr_out |
#define _bfd_XXi_swap_aouthdr_in _bfd_pex64i_swap_aouthdr_in |
#define _bfd_XXi_swap_aouthdr_out _bfd_pex64i_swap_aouthdr_out |
#define _bfd_XXi_swap_aux_in _bfd_pex64i_swap_aux_in |
#define _bfd_XXi_swap_aux_out _bfd_pex64i_swap_aux_out |
#define _bfd_XXi_swap_lineno_in _bfd_pex64i_swap_lineno_in |
#define _bfd_XXi_swap_lineno_out _bfd_pex64i_swap_lineno_out |
#define _bfd_XXi_swap_scnhdr_out _bfd_pex64i_swap_scnhdr_out |
#define _bfd_XXi_swap_sym_in _bfd_pex64i_swap_sym_in |
#define _bfd_XXi_swap_sym_out _bfd_pex64i_swap_sym_out |
#elif defined COFF_WITH_pep |
#define GET_OPTHDR_IMAGE_BASE H_GET_64 |
#define PUT_OPTHDR_IMAGE_BASE H_PUT_64 |
#define GET_OPTHDR_SIZE_OF_STACK_RESERVE H_GET_64 |
#define PUT_OPTHDR_SIZE_OF_STACK_RESERVE H_PUT_64 |
#define GET_OPTHDR_SIZE_OF_STACK_COMMIT H_GET_64 |
#define PUT_OPTHDR_SIZE_OF_STACK_COMMIT H_PUT_64 |
#define GET_OPTHDR_SIZE_OF_HEAP_RESERVE H_GET_64 |
#define PUT_OPTHDR_SIZE_OF_HEAP_RESERVE H_PUT_64 |
#define GET_OPTHDR_SIZE_OF_HEAP_COMMIT H_GET_64 |
#define PUT_OPTHDR_SIZE_OF_HEAP_COMMIT H_PUT_64 |
#define GET_PDATA_ENTRY bfd_get_64 |
#define _bfd_XX_bfd_copy_private_bfd_data_common _bfd_pep_bfd_copy_private_bfd_data_common |
#define _bfd_XX_bfd_copy_private_section_data _bfd_pep_bfd_copy_private_section_data |
#define _bfd_XX_get_symbol_info _bfd_pep_get_symbol_info |
#define _bfd_XX_only_swap_filehdr_out _bfd_pep_only_swap_filehdr_out |
#define _bfd_XX_print_private_bfd_data_common _bfd_pep_print_private_bfd_data_common |
#define _bfd_XXi_final_link_postscript _bfd_pepi_final_link_postscript |
#define _bfd_XXi_only_swap_filehdr_out _bfd_pepi_only_swap_filehdr_out |
#define _bfd_XXi_swap_aouthdr_in _bfd_pepi_swap_aouthdr_in |
#define _bfd_XXi_swap_aouthdr_out _bfd_pepi_swap_aouthdr_out |
#define _bfd_XXi_swap_aux_in _bfd_pepi_swap_aux_in |
#define _bfd_XXi_swap_aux_out _bfd_pepi_swap_aux_out |
#define _bfd_XXi_swap_lineno_in _bfd_pepi_swap_lineno_in |
#define _bfd_XXi_swap_lineno_out _bfd_pepi_swap_lineno_out |
#define _bfd_XXi_swap_scnhdr_out _bfd_pepi_swap_scnhdr_out |
#define _bfd_XXi_swap_sym_in _bfd_pepi_swap_sym_in |
#define _bfd_XXi_swap_sym_out _bfd_pepi_swap_sym_out |
#else /* !COFF_WITH_pep */ |
#define GET_OPTHDR_IMAGE_BASE H_GET_32 |
#define PUT_OPTHDR_IMAGE_BASE H_PUT_32 |
#define GET_OPTHDR_SIZE_OF_STACK_RESERVE H_GET_32 |
#define PUT_OPTHDR_SIZE_OF_STACK_RESERVE H_PUT_32 |
#define GET_OPTHDR_SIZE_OF_STACK_COMMIT H_GET_32 |
#define PUT_OPTHDR_SIZE_OF_STACK_COMMIT H_PUT_32 |
#define GET_OPTHDR_SIZE_OF_HEAP_RESERVE H_GET_32 |
#define PUT_OPTHDR_SIZE_OF_HEAP_RESERVE H_PUT_32 |
#define GET_OPTHDR_SIZE_OF_HEAP_COMMIT H_GET_32 |
#define PUT_OPTHDR_SIZE_OF_HEAP_COMMIT H_PUT_32 |
#define GET_PDATA_ENTRY bfd_get_32 |
#define _bfd_XX_bfd_copy_private_bfd_data_common _bfd_pe_bfd_copy_private_bfd_data_common |
#define _bfd_XX_bfd_copy_private_section_data _bfd_pe_bfd_copy_private_section_data |
#define _bfd_XX_get_symbol_info _bfd_pe_get_symbol_info |
#define _bfd_XX_only_swap_filehdr_out _bfd_pe_only_swap_filehdr_out |
#define _bfd_XX_print_private_bfd_data_common _bfd_pe_print_private_bfd_data_common |
#define _bfd_XXi_final_link_postscript _bfd_pei_final_link_postscript |
#define _bfd_XXi_only_swap_filehdr_out _bfd_pei_only_swap_filehdr_out |
#define _bfd_XXi_swap_aouthdr_in _bfd_pei_swap_aouthdr_in |
#define _bfd_XXi_swap_aouthdr_out _bfd_pei_swap_aouthdr_out |
#define _bfd_XXi_swap_aux_in _bfd_pei_swap_aux_in |
#define _bfd_XXi_swap_aux_out _bfd_pei_swap_aux_out |
#define _bfd_XXi_swap_lineno_in _bfd_pei_swap_lineno_in |
#define _bfd_XXi_swap_lineno_out _bfd_pei_swap_lineno_out |
#define _bfd_XXi_swap_scnhdr_out _bfd_pei_swap_scnhdr_out |
#define _bfd_XXi_swap_sym_in _bfd_pei_swap_sym_in |
#define _bfd_XXi_swap_sym_out _bfd_pei_swap_sym_out |
#endif /* !COFF_WITH_pep */ |
/* These functions are architecture dependent, and are in peicode.h: |
coff_swap_reloc_in |
int coff_swap_reloc_out |
coff_swap_filehdr_in |
coff_swap_scnhdr_in |
pe_mkobject |
pe_mkobject_hook */ |
/* The functions described below are common across all PE/PEI |
implementations architecture types, and actually appear in |
peigen.c. */ |
#define coff_swap_sym_in _bfd_XXi_swap_sym_in |
#define coff_swap_sym_out _bfd_XXi_swap_sym_out |
#define coff_swap_aux_in _bfd_XXi_swap_aux_in |
#define coff_swap_aux_out _bfd_XXi_swap_aux_out |
#define coff_swap_lineno_in _bfd_XXi_swap_lineno_in |
#define coff_swap_lineno_out _bfd_XXi_swap_lineno_out |
#define coff_swap_aouthdr_in _bfd_XXi_swap_aouthdr_in |
#define coff_swap_aouthdr_out _bfd_XXi_swap_aouthdr_out |
#define coff_swap_scnhdr_out _bfd_XXi_swap_scnhdr_out |
#ifndef coff_final_link_postscript |
#define coff_final_link_postscript _bfd_XXi_final_link_postscript |
#endif |
void _bfd_XXi_swap_sym_in (bfd *, void *, void *); |
unsigned _bfd_XXi_swap_sym_out (bfd *, void *, void *); |
void _bfd_XXi_swap_aux_in (bfd *, void *, int, int, int, int, void *); |
unsigned _bfd_XXi_swap_aux_out (bfd *, void *, int, int, int, int, void *); |
void _bfd_XXi_swap_lineno_in (bfd *, void *, void *); |
unsigned _bfd_XXi_swap_lineno_out (bfd *, void *, void *); |
void _bfd_XXi_swap_aouthdr_in (bfd *, void *, void *); |
unsigned _bfd_XXi_swap_aouthdr_out (bfd *, void *, void *); |
unsigned _bfd_XXi_swap_scnhdr_out (bfd *, void *, void *); |
bfd_boolean _bfd_XX_print_private_bfd_data_common (bfd *, void *); |
bfd_boolean _bfd_XX_bfd_copy_private_bfd_data_common (bfd *, bfd *); |
void _bfd_XX_get_symbol_info (bfd *, asymbol *, symbol_info *); |
bfd_boolean _bfd_XXi_final_link_postscript (bfd *, struct coff_final_link_info *); |
/* The following are needed only for ONE of pe or pei, but don't |
otherwise vary; peicode.h fixes up ifdefs but we provide the |
prototype. */ |
unsigned _bfd_XX_only_swap_filehdr_out (bfd *, void *, void *); |
unsigned _bfd_XXi_only_swap_filehdr_out (bfd *, void *, void *); |
bfd_boolean _bfd_XX_bfd_copy_private_section_data (bfd *, asection *, bfd *, asection *); |
bfd_boolean _bfd_pe_print_ce_compressed_pdata (bfd *, void *); |
bfd_boolean _bfd_pe64_print_ce_compressed_pdata (bfd *, void *); |
bfd_boolean _bfd_pex64_print_ce_compressed_pdata (bfd *, void *); |
bfd_boolean _bfd_pep_print_ce_compressed_pdata (bfd *, void *); |
/contrib/toolchain/binutils/bfd/linker.c |
---|
0,0 → 1,3431 |
/* linker.c -- BFD linker routines |
Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, |
2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 |
Free Software Foundation, Inc. |
Written by Steve Chamberlain and Ian Lance Taylor, Cygnus Support |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
#include "bfdlink.h" |
#include "genlink.h" |
/* |
SECTION |
Linker Functions |
@cindex Linker |
The linker uses three special entry points in the BFD target |
vector. It is not necessary to write special routines for |
these entry points when creating a new BFD back end, since |
generic versions are provided. However, writing them can |
speed up linking and make it use significantly less runtime |
memory. |
The first routine creates a hash table used by the other |
routines. The second routine adds the symbols from an object |
file to the hash table. The third routine takes all the |
object files and links them together to create the output |
file. These routines are designed so that the linker proper |
does not need to know anything about the symbols in the object |
files that it is linking. The linker merely arranges the |
sections as directed by the linker script and lets BFD handle |
the details of symbols and relocs. |
The second routine and third routines are passed a pointer to |
a <<struct bfd_link_info>> structure (defined in |
<<bfdlink.h>>) which holds information relevant to the link, |
including the linker hash table (which was created by the |
first routine) and a set of callback functions to the linker |
proper. |
The generic linker routines are in <<linker.c>>, and use the |
header file <<genlink.h>>. As of this writing, the only back |
ends which have implemented versions of these routines are |
a.out (in <<aoutx.h>>) and ECOFF (in <<ecoff.c>>). The a.out |
routines are used as examples throughout this section. |
@menu |
@* Creating a Linker Hash Table:: |
@* Adding Symbols to the Hash Table:: |
@* Performing the Final Link:: |
@end menu |
INODE |
Creating a Linker Hash Table, Adding Symbols to the Hash Table, Linker Functions, Linker Functions |
SUBSECTION |
Creating a linker hash table |
@cindex _bfd_link_hash_table_create in target vector |
@cindex target vector (_bfd_link_hash_table_create) |
The linker routines must create a hash table, which must be |
derived from <<struct bfd_link_hash_table>> described in |
<<bfdlink.c>>. @xref{Hash Tables}, for information on how to |
create a derived hash table. This entry point is called using |
the target vector of the linker output file. |
The <<_bfd_link_hash_table_create>> entry point must allocate |
and initialize an instance of the desired hash table. If the |
back end does not require any additional information to be |
stored with the entries in the hash table, the entry point may |
simply create a <<struct bfd_link_hash_table>>. Most likely, |
however, some additional information will be needed. |
For example, with each entry in the hash table the a.out |
linker keeps the index the symbol has in the final output file |
(this index number is used so that when doing a relocatable |
link the symbol index used in the output file can be quickly |
filled in when copying over a reloc). The a.out linker code |
defines the required structures and functions for a hash table |
derived from <<struct bfd_link_hash_table>>. The a.out linker |
hash table is created by the function |
<<NAME(aout,link_hash_table_create)>>; it simply allocates |
space for the hash table, initializes it, and returns a |
pointer to it. |
When writing the linker routines for a new back end, you will |
generally not know exactly which fields will be required until |
you have finished. You should simply create a new hash table |
which defines no additional fields, and then simply add fields |
as they become necessary. |
INODE |
Adding Symbols to the Hash Table, Performing the Final Link, Creating a Linker Hash Table, Linker Functions |
SUBSECTION |
Adding symbols to the hash table |
@cindex _bfd_link_add_symbols in target vector |
@cindex target vector (_bfd_link_add_symbols) |
The linker proper will call the <<_bfd_link_add_symbols>> |
entry point for each object file or archive which is to be |
linked (typically these are the files named on the command |
line, but some may also come from the linker script). The |
entry point is responsible for examining the file. For an |
object file, BFD must add any relevant symbol information to |
the hash table. For an archive, BFD must determine which |
elements of the archive should be used and adding them to the |
link. |
The a.out version of this entry point is |
<<NAME(aout,link_add_symbols)>>. |
@menu |
@* Differing file formats:: |
@* Adding symbols from an object file:: |
@* Adding symbols from an archive:: |
@end menu |
INODE |
Differing file formats, Adding symbols from an object file, Adding Symbols to the Hash Table, Adding Symbols to the Hash Table |
SUBSUBSECTION |
Differing file formats |
Normally all the files involved in a link will be of the same |
format, but it is also possible to link together different |
format object files, and the back end must support that. The |
<<_bfd_link_add_symbols>> entry point is called via the target |
vector of the file to be added. This has an important |
consequence: the function may not assume that the hash table |
is the type created by the corresponding |
<<_bfd_link_hash_table_create>> vector. All the |
<<_bfd_link_add_symbols>> function can assume about the hash |
table is that it is derived from <<struct |
bfd_link_hash_table>>. |
Sometimes the <<_bfd_link_add_symbols>> function must store |
some information in the hash table entry to be used by the |
<<_bfd_final_link>> function. In such a case the output bfd |
xvec must be checked to make sure that the hash table was |
created by an object file of the same format. |
The <<_bfd_final_link>> routine must be prepared to handle a |
hash entry without any extra information added by the |
<<_bfd_link_add_symbols>> function. A hash entry without |
extra information will also occur when the linker script |
directs the linker to create a symbol. Note that, regardless |
of how a hash table entry is added, all the fields will be |
initialized to some sort of null value by the hash table entry |
initialization function. |
See <<ecoff_link_add_externals>> for an example of how to |
check the output bfd before saving information (in this |
case, the ECOFF external symbol debugging information) in a |
hash table entry. |
INODE |
Adding symbols from an object file, Adding symbols from an archive, Differing file formats, Adding Symbols to the Hash Table |
SUBSUBSECTION |
Adding symbols from an object file |
When the <<_bfd_link_add_symbols>> routine is passed an object |
file, it must add all externally visible symbols in that |
object file to the hash table. The actual work of adding the |
symbol to the hash table is normally handled by the function |
<<_bfd_generic_link_add_one_symbol>>. The |
<<_bfd_link_add_symbols>> routine is responsible for reading |
all the symbols from the object file and passing the correct |
information to <<_bfd_generic_link_add_one_symbol>>. |
The <<_bfd_link_add_symbols>> routine should not use |
<<bfd_canonicalize_symtab>> to read the symbols. The point of |
providing this routine is to avoid the overhead of converting |
the symbols into generic <<asymbol>> structures. |
@findex _bfd_generic_link_add_one_symbol |
<<_bfd_generic_link_add_one_symbol>> handles the details of |
combining common symbols, warning about multiple definitions, |
and so forth. It takes arguments which describe the symbol to |
add, notably symbol flags, a section, and an offset. The |
symbol flags include such things as <<BSF_WEAK>> or |
<<BSF_INDIRECT>>. The section is a section in the object |
file, or something like <<bfd_und_section_ptr>> for an undefined |
symbol or <<bfd_com_section_ptr>> for a common symbol. |
If the <<_bfd_final_link>> routine is also going to need to |
read the symbol information, the <<_bfd_link_add_symbols>> |
routine should save it somewhere attached to the object file |
BFD. However, the information should only be saved if the |
<<keep_memory>> field of the <<info>> argument is TRUE, so |
that the <<-no-keep-memory>> linker switch is effective. |
The a.out function which adds symbols from an object file is |
<<aout_link_add_object_symbols>>, and most of the interesting |
work is in <<aout_link_add_symbols>>. The latter saves |
pointers to the hash tables entries created by |
<<_bfd_generic_link_add_one_symbol>> indexed by symbol number, |
so that the <<_bfd_final_link>> routine does not have to call |
the hash table lookup routine to locate the entry. |
INODE |
Adding symbols from an archive, , Adding symbols from an object file, Adding Symbols to the Hash Table |
SUBSUBSECTION |
Adding symbols from an archive |
When the <<_bfd_link_add_symbols>> routine is passed an |
archive, it must look through the symbols defined by the |
archive and decide which elements of the archive should be |
included in the link. For each such element it must call the |
<<add_archive_element>> linker callback, and it must add the |
symbols from the object file to the linker hash table. (The |
callback may in fact indicate that a replacement BFD should be |
used, in which case the symbols from that BFD should be added |
to the linker hash table instead.) |
@findex _bfd_generic_link_add_archive_symbols |
In most cases the work of looking through the symbols in the |
archive should be done by the |
<<_bfd_generic_link_add_archive_symbols>> function. This |
function builds a hash table from the archive symbol table and |
looks through the list of undefined symbols to see which |
elements should be included. |
<<_bfd_generic_link_add_archive_symbols>> is passed a function |
to call to make the final decision about adding an archive |
element to the link and to do the actual work of adding the |
symbols to the linker hash table. |
The function passed to |
<<_bfd_generic_link_add_archive_symbols>> must read the |
symbols of the archive element and decide whether the archive |
element should be included in the link. If the element is to |
be included, the <<add_archive_element>> linker callback |
routine must be called with the element as an argument, and |
the element's symbols must be added to the linker hash table |
just as though the element had itself been passed to the |
<<_bfd_link_add_symbols>> function. The <<add_archive_element>> |
callback has the option to indicate that it would like to |
replace the element archive with a substitute BFD, in which |
case it is the symbols of that substitute BFD that must be |
added to the linker hash table instead. |
When the a.out <<_bfd_link_add_symbols>> function receives an |
archive, it calls <<_bfd_generic_link_add_archive_symbols>> |
passing <<aout_link_check_archive_element>> as the function |
argument. <<aout_link_check_archive_element>> calls |
<<aout_link_check_ar_symbols>>. If the latter decides to add |
the element (an element is only added if it provides a real, |
non-common, definition for a previously undefined or common |
symbol) it calls the <<add_archive_element>> callback and then |
<<aout_link_check_archive_element>> calls |
<<aout_link_add_symbols>> to actually add the symbols to the |
linker hash table - possibly those of a substitute BFD, if the |
<<add_archive_element>> callback avails itself of that option. |
The ECOFF back end is unusual in that it does not normally |
call <<_bfd_generic_link_add_archive_symbols>>, because ECOFF |
archives already contain a hash table of symbols. The ECOFF |
back end searches the archive itself to avoid the overhead of |
creating a new hash table. |
INODE |
Performing the Final Link, , Adding Symbols to the Hash Table, Linker Functions |
SUBSECTION |
Performing the final link |
@cindex _bfd_link_final_link in target vector |
@cindex target vector (_bfd_final_link) |
When all the input files have been processed, the linker calls |
the <<_bfd_final_link>> entry point of the output BFD. This |
routine is responsible for producing the final output file, |
which has several aspects. It must relocate the contents of |
the input sections and copy the data into the output sections. |
It must build an output symbol table including any local |
symbols from the input files and the global symbols from the |
hash table. When producing relocatable output, it must |
modify the input relocs and write them into the output file. |
There may also be object format dependent work to be done. |
The linker will also call the <<write_object_contents>> entry |
point when the BFD is closed. The two entry points must work |
together in order to produce the correct output file. |
The details of how this works are inevitably dependent upon |
the specific object file format. The a.out |
<<_bfd_final_link>> routine is <<NAME(aout,final_link)>>. |
@menu |
@* Information provided by the linker:: |
@* Relocating the section contents:: |
@* Writing the symbol table:: |
@end menu |
INODE |
Information provided by the linker, Relocating the section contents, Performing the Final Link, Performing the Final Link |
SUBSUBSECTION |
Information provided by the linker |
Before the linker calls the <<_bfd_final_link>> entry point, |
it sets up some data structures for the function to use. |
The <<input_bfds>> field of the <<bfd_link_info>> structure |
will point to a list of all the input files included in the |
link. These files are linked through the <<link_next>> field |
of the <<bfd>> structure. |
Each section in the output file will have a list of |
<<link_order>> structures attached to the <<map_head.link_order>> |
field (the <<link_order>> structure is defined in |
<<bfdlink.h>>). These structures describe how to create the |
contents of the output section in terms of the contents of |
various input sections, fill constants, and, eventually, other |
types of information. They also describe relocs that must be |
created by the BFD backend, but do not correspond to any input |
file; this is used to support -Ur, which builds constructors |
while generating a relocatable object file. |
INODE |
Relocating the section contents, Writing the symbol table, Information provided by the linker, Performing the Final Link |
SUBSUBSECTION |
Relocating the section contents |
The <<_bfd_final_link>> function should look through the |
<<link_order>> structures attached to each section of the |
output file. Each <<link_order>> structure should either be |
handled specially, or it should be passed to the function |
<<_bfd_default_link_order>> which will do the right thing |
(<<_bfd_default_link_order>> is defined in <<linker.c>>). |
For efficiency, a <<link_order>> of type |
<<bfd_indirect_link_order>> whose associated section belongs |
to a BFD of the same format as the output BFD must be handled |
specially. This type of <<link_order>> describes part of an |
output section in terms of a section belonging to one of the |
input files. The <<_bfd_final_link>> function should read the |
contents of the section and any associated relocs, apply the |
relocs to the section contents, and write out the modified |
section contents. If performing a relocatable link, the |
relocs themselves must also be modified and written out. |
@findex _bfd_relocate_contents |
@findex _bfd_final_link_relocate |
The functions <<_bfd_relocate_contents>> and |
<<_bfd_final_link_relocate>> provide some general support for |
performing the actual relocations, notably overflow checking. |
Their arguments include information about the symbol the |
relocation is against and a <<reloc_howto_type>> argument |
which describes the relocation to perform. These functions |
are defined in <<reloc.c>>. |
The a.out function which handles reading, relocating, and |
writing section contents is <<aout_link_input_section>>. The |
actual relocation is done in <<aout_link_input_section_std>> |
and <<aout_link_input_section_ext>>. |
INODE |
Writing the symbol table, , Relocating the section contents, Performing the Final Link |
SUBSUBSECTION |
Writing the symbol table |
The <<_bfd_final_link>> function must gather all the symbols |
in the input files and write them out. It must also write out |
all the symbols in the global hash table. This must be |
controlled by the <<strip>> and <<discard>> fields of the |
<<bfd_link_info>> structure. |
The local symbols of the input files will not have been |
entered into the linker hash table. The <<_bfd_final_link>> |
routine must consider each input file and include the symbols |
in the output file. It may be convenient to do this when |
looking through the <<link_order>> structures, or it may be |
done by stepping through the <<input_bfds>> list. |
The <<_bfd_final_link>> routine must also traverse the global |
hash table to gather all the externally visible symbols. It |
is possible that most of the externally visible symbols may be |
written out when considering the symbols of each input file, |
but it is still necessary to traverse the hash table since the |
linker script may have defined some symbols that are not in |
any of the input files. |
The <<strip>> field of the <<bfd_link_info>> structure |
controls which symbols are written out. The possible values |
are listed in <<bfdlink.h>>. If the value is <<strip_some>>, |
then the <<keep_hash>> field of the <<bfd_link_info>> |
structure is a hash table of symbols to keep; each symbol |
should be looked up in this hash table, and only symbols which |
are present should be included in the output file. |
If the <<strip>> field of the <<bfd_link_info>> structure |
permits local symbols to be written out, the <<discard>> field |
is used to further controls which local symbols are included |
in the output file. If the value is <<discard_l>>, then all |
local symbols which begin with a certain prefix are discarded; |
this is controlled by the <<bfd_is_local_label_name>> entry point. |
The a.out backend handles symbols by calling |
<<aout_link_write_symbols>> on each input BFD and then |
traversing the global hash table with the function |
<<aout_link_write_other_symbol>>. It builds a string table |
while writing out the symbols, which is written to the output |
file at the end of <<NAME(aout,final_link)>>. |
*/ |
static bfd_boolean generic_link_add_object_symbols |
(bfd *, struct bfd_link_info *, bfd_boolean collect); |
static bfd_boolean generic_link_add_symbols |
(bfd *, struct bfd_link_info *, bfd_boolean); |
static bfd_boolean generic_link_check_archive_element_no_collect |
(bfd *, struct bfd_link_info *, bfd_boolean *); |
static bfd_boolean generic_link_check_archive_element_collect |
(bfd *, struct bfd_link_info *, bfd_boolean *); |
static bfd_boolean generic_link_check_archive_element |
(bfd *, struct bfd_link_info *, bfd_boolean *, bfd_boolean); |
static bfd_boolean generic_link_add_symbol_list |
(bfd *, struct bfd_link_info *, bfd_size_type count, asymbol **, |
bfd_boolean); |
static bfd_boolean generic_add_output_symbol |
(bfd *, size_t *psymalloc, asymbol *); |
static bfd_boolean default_data_link_order |
(bfd *, struct bfd_link_info *, asection *, struct bfd_link_order *); |
static bfd_boolean default_indirect_link_order |
(bfd *, struct bfd_link_info *, asection *, struct bfd_link_order *, |
bfd_boolean); |
/* The link hash table structure is defined in bfdlink.h. It provides |
a base hash table which the backend specific hash tables are built |
upon. */ |
/* Routine to create an entry in the link hash table. */ |
struct bfd_hash_entry * |
_bfd_link_hash_newfunc (struct bfd_hash_entry *entry, |
struct bfd_hash_table *table, |
const char *string) |
{ |
/* Allocate the structure if it has not already been allocated by a |
subclass. */ |
if (entry == NULL) |
{ |
entry = (struct bfd_hash_entry *) |
bfd_hash_allocate (table, sizeof (struct bfd_link_hash_entry)); |
if (entry == NULL) |
return entry; |
} |
/* Call the allocation method of the superclass. */ |
entry = bfd_hash_newfunc (entry, table, string); |
if (entry) |
{ |
struct bfd_link_hash_entry *h = (struct bfd_link_hash_entry *) entry; |
/* Initialize the local fields. */ |
memset ((char *) &h->root + sizeof (h->root), 0, |
sizeof (*h) - sizeof (h->root)); |
} |
return entry; |
} |
/* Initialize a link hash table. The BFD argument is the one |
responsible for creating this table. */ |
bfd_boolean |
_bfd_link_hash_table_init |
(struct bfd_link_hash_table *table, |
bfd *abfd ATTRIBUTE_UNUSED, |
struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *, |
struct bfd_hash_table *, |
const char *), |
unsigned int entsize) |
{ |
table->undefs = NULL; |
table->undefs_tail = NULL; |
table->type = bfd_link_generic_hash_table; |
return bfd_hash_table_init (&table->table, newfunc, entsize); |
} |
/* Look up a symbol in a link hash table. If follow is TRUE, we |
follow bfd_link_hash_indirect and bfd_link_hash_warning links to |
the real symbol. */ |
struct bfd_link_hash_entry * |
bfd_link_hash_lookup (struct bfd_link_hash_table *table, |
const char *string, |
bfd_boolean create, |
bfd_boolean copy, |
bfd_boolean follow) |
{ |
struct bfd_link_hash_entry *ret; |
ret = ((struct bfd_link_hash_entry *) |
bfd_hash_lookup (&table->table, string, create, copy)); |
if (follow && ret != NULL) |
{ |
while (ret->type == bfd_link_hash_indirect |
|| ret->type == bfd_link_hash_warning) |
ret = ret->u.i.link; |
} |
return ret; |
} |
/* Look up a symbol in the main linker hash table if the symbol might |
be wrapped. This should only be used for references to an |
undefined symbol, not for definitions of a symbol. */ |
struct bfd_link_hash_entry * |
bfd_wrapped_link_hash_lookup (bfd *abfd, |
struct bfd_link_info *info, |
const char *string, |
bfd_boolean create, |
bfd_boolean copy, |
bfd_boolean follow) |
{ |
bfd_size_type amt; |
if (info->wrap_hash != NULL) |
{ |
const char *l; |
char prefix = '\0'; |
l = string; |
if (*l == bfd_get_symbol_leading_char (abfd) || *l == info->wrap_char) |
{ |
prefix = *l; |
++l; |
} |
#undef WRAP |
#define WRAP "__wrap_" |
if (bfd_hash_lookup (info->wrap_hash, l, FALSE, FALSE) != NULL) |
{ |
char *n; |
struct bfd_link_hash_entry *h; |
/* This symbol is being wrapped. We want to replace all |
references to SYM with references to __wrap_SYM. */ |
amt = strlen (l) + sizeof WRAP + 1; |
n = (char *) bfd_malloc (amt); |
if (n == NULL) |
return NULL; |
n[0] = prefix; |
n[1] = '\0'; |
strcat (n, WRAP); |
strcat (n, l); |
h = bfd_link_hash_lookup (info->hash, n, create, TRUE, follow); |
free (n); |
return h; |
} |
#undef WRAP |
#undef REAL |
#define REAL "__real_" |
if (*l == '_' |
&& CONST_STRNEQ (l, REAL) |
&& bfd_hash_lookup (info->wrap_hash, l + sizeof REAL - 1, |
FALSE, FALSE) != NULL) |
{ |
char *n; |
struct bfd_link_hash_entry *h; |
/* This is a reference to __real_SYM, where SYM is being |
wrapped. We want to replace all references to __real_SYM |
with references to SYM. */ |
amt = strlen (l + sizeof REAL - 1) + 2; |
n = (char *) bfd_malloc (amt); |
if (n == NULL) |
return NULL; |
n[0] = prefix; |
n[1] = '\0'; |
strcat (n, l + sizeof REAL - 1); |
h = bfd_link_hash_lookup (info->hash, n, create, TRUE, follow); |
free (n); |
return h; |
} |
#undef REAL |
} |
return bfd_link_hash_lookup (info->hash, string, create, copy, follow); |
} |
/* Traverse a generic link hash table. Differs from bfd_hash_traverse |
in the treatment of warning symbols. When warning symbols are |
created they replace the real symbol, so you don't get to see the |
real symbol in a bfd_hash_travere. This traversal calls func with |
the real symbol. */ |
void |
bfd_link_hash_traverse |
(struct bfd_link_hash_table *htab, |
bfd_boolean (*func) (struct bfd_link_hash_entry *, void *), |
void *info) |
{ |
unsigned int i; |
htab->table.frozen = 1; |
for (i = 0; i < htab->table.size; i++) |
{ |
struct bfd_link_hash_entry *p; |
p = (struct bfd_link_hash_entry *) htab->table.table[i]; |
for (; p != NULL; p = (struct bfd_link_hash_entry *) p->root.next) |
if (!(*func) (p->type == bfd_link_hash_warning ? p->u.i.link : p, info)) |
goto out; |
} |
out: |
htab->table.frozen = 0; |
} |
/* Add a symbol to the linker hash table undefs list. */ |
void |
bfd_link_add_undef (struct bfd_link_hash_table *table, |
struct bfd_link_hash_entry *h) |
{ |
BFD_ASSERT (h->u.undef.next == NULL); |
if (table->undefs_tail != NULL) |
table->undefs_tail->u.undef.next = h; |
if (table->undefs == NULL) |
table->undefs = h; |
table->undefs_tail = h; |
} |
/* The undefs list was designed so that in normal use we don't need to |
remove entries. However, if symbols on the list are changed from |
bfd_link_hash_undefined to either bfd_link_hash_undefweak or |
bfd_link_hash_new for some reason, then they must be removed from the |
list. Failure to do so might result in the linker attempting to add |
the symbol to the list again at a later stage. */ |
void |
bfd_link_repair_undef_list (struct bfd_link_hash_table *table) |
{ |
struct bfd_link_hash_entry **pun; |
pun = &table->undefs; |
while (*pun != NULL) |
{ |
struct bfd_link_hash_entry *h = *pun; |
if (h->type == bfd_link_hash_new |
|| h->type == bfd_link_hash_undefweak) |
{ |
*pun = h->u.undef.next; |
h->u.undef.next = NULL; |
if (h == table->undefs_tail) |
{ |
if (pun == &table->undefs) |
table->undefs_tail = NULL; |
else |
/* pun points at an u.undef.next field. Go back to |
the start of the link_hash_entry. */ |
table->undefs_tail = (struct bfd_link_hash_entry *) |
((char *) pun - ((char *) &h->u.undef.next - (char *) h)); |
break; |
} |
} |
else |
pun = &h->u.undef.next; |
} |
} |
/* Routine to create an entry in a generic link hash table. */ |
struct bfd_hash_entry * |
_bfd_generic_link_hash_newfunc (struct bfd_hash_entry *entry, |
struct bfd_hash_table *table, |
const char *string) |
{ |
/* Allocate the structure if it has not already been allocated by a |
subclass. */ |
if (entry == NULL) |
{ |
entry = (struct bfd_hash_entry *) |
bfd_hash_allocate (table, sizeof (struct generic_link_hash_entry)); |
if (entry == NULL) |
return entry; |
} |
/* Call the allocation method of the superclass. */ |
entry = _bfd_link_hash_newfunc (entry, table, string); |
if (entry) |
{ |
struct generic_link_hash_entry *ret; |
/* Set local fields. */ |
ret = (struct generic_link_hash_entry *) entry; |
ret->written = FALSE; |
ret->sym = NULL; |
} |
return entry; |
} |
/* Create a generic link hash table. */ |
struct bfd_link_hash_table * |
_bfd_generic_link_hash_table_create (bfd *abfd) |
{ |
struct generic_link_hash_table *ret; |
bfd_size_type amt = sizeof (struct generic_link_hash_table); |
ret = (struct generic_link_hash_table *) bfd_malloc (amt); |
if (ret == NULL) |
return NULL; |
if (! _bfd_link_hash_table_init (&ret->root, abfd, |
_bfd_generic_link_hash_newfunc, |
sizeof (struct generic_link_hash_entry))) |
{ |
free (ret); |
return NULL; |
} |
return &ret->root; |
} |
void |
_bfd_generic_link_hash_table_free (struct bfd_link_hash_table *hash) |
{ |
struct generic_link_hash_table *ret |
= (struct generic_link_hash_table *) hash; |
bfd_hash_table_free (&ret->root.table); |
free (ret); |
} |
/* Grab the symbols for an object file when doing a generic link. We |
store the symbols in the outsymbols field. We need to keep them |
around for the entire link to ensure that we only read them once. |
If we read them multiple times, we might wind up with relocs and |
the hash table pointing to different instances of the symbol |
structure. */ |
bfd_boolean |
bfd_generic_link_read_symbols (bfd *abfd) |
{ |
if (bfd_get_outsymbols (abfd) == NULL) |
{ |
long symsize; |
long symcount; |
symsize = bfd_get_symtab_upper_bound (abfd); |
if (symsize < 0) |
return FALSE; |
bfd_get_outsymbols (abfd) = (struct bfd_symbol **) bfd_alloc (abfd, |
symsize); |
if (bfd_get_outsymbols (abfd) == NULL && symsize != 0) |
return FALSE; |
symcount = bfd_canonicalize_symtab (abfd, bfd_get_outsymbols (abfd)); |
if (symcount < 0) |
return FALSE; |
bfd_get_symcount (abfd) = symcount; |
} |
return TRUE; |
} |
/* Generic function to add symbols to from an object file to the |
global hash table. This version does not automatically collect |
constructors by name. */ |
bfd_boolean |
_bfd_generic_link_add_symbols (bfd *abfd, struct bfd_link_info *info) |
{ |
return generic_link_add_symbols (abfd, info, FALSE); |
} |
/* Generic function to add symbols from an object file to the global |
hash table. This version automatically collects constructors by |
name, as the collect2 program does. It should be used for any |
target which does not provide some other mechanism for setting up |
constructors and destructors; these are approximately those targets |
for which gcc uses collect2 and do not support stabs. */ |
bfd_boolean |
_bfd_generic_link_add_symbols_collect (bfd *abfd, struct bfd_link_info *info) |
{ |
return generic_link_add_symbols (abfd, info, TRUE); |
} |
/* Indicate that we are only retrieving symbol values from this |
section. We want the symbols to act as though the values in the |
file are absolute. */ |
void |
_bfd_generic_link_just_syms (asection *sec, |
struct bfd_link_info *info ATTRIBUTE_UNUSED) |
{ |
sec->sec_info_type = SEC_INFO_TYPE_JUST_SYMS; |
sec->output_section = bfd_abs_section_ptr; |
sec->output_offset = sec->vma; |
} |
/* Copy the type of a symbol assiciated with a linker hast table entry. |
Override this so that symbols created in linker scripts get their |
type from the RHS of the assignment. |
The default implementation does nothing. */ |
void |
_bfd_generic_copy_link_hash_symbol_type (bfd *abfd ATTRIBUTE_UNUSED, |
struct bfd_link_hash_entry * hdest ATTRIBUTE_UNUSED, |
struct bfd_link_hash_entry * hsrc ATTRIBUTE_UNUSED) |
{ |
} |
/* Add symbols from an object file to the global hash table. */ |
static bfd_boolean |
generic_link_add_symbols (bfd *abfd, |
struct bfd_link_info *info, |
bfd_boolean collect) |
{ |
bfd_boolean ret; |
switch (bfd_get_format (abfd)) |
{ |
case bfd_object: |
ret = generic_link_add_object_symbols (abfd, info, collect); |
break; |
case bfd_archive: |
ret = (_bfd_generic_link_add_archive_symbols |
(abfd, info, |
(collect |
? generic_link_check_archive_element_collect |
: generic_link_check_archive_element_no_collect))); |
break; |
default: |
bfd_set_error (bfd_error_wrong_format); |
ret = FALSE; |
} |
return ret; |
} |
/* Add symbols from an object file to the global hash table. */ |
static bfd_boolean |
generic_link_add_object_symbols (bfd *abfd, |
struct bfd_link_info *info, |
bfd_boolean collect) |
{ |
bfd_size_type symcount; |
struct bfd_symbol **outsyms; |
if (!bfd_generic_link_read_symbols (abfd)) |
return FALSE; |
symcount = _bfd_generic_link_get_symcount (abfd); |
outsyms = _bfd_generic_link_get_symbols (abfd); |
return generic_link_add_symbol_list (abfd, info, symcount, outsyms, collect); |
} |
/* We build a hash table of all symbols defined in an archive. */ |
/* An archive symbol may be defined by multiple archive elements. |
This linked list is used to hold the elements. */ |
struct archive_list |
{ |
struct archive_list *next; |
unsigned int indx; |
}; |
/* An entry in an archive hash table. */ |
struct archive_hash_entry |
{ |
struct bfd_hash_entry root; |
/* Where the symbol is defined. */ |
struct archive_list *defs; |
}; |
/* An archive hash table itself. */ |
struct archive_hash_table |
{ |
struct bfd_hash_table table; |
}; |
/* Create a new entry for an archive hash table. */ |
static struct bfd_hash_entry * |
archive_hash_newfunc (struct bfd_hash_entry *entry, |
struct bfd_hash_table *table, |
const char *string) |
{ |
struct archive_hash_entry *ret = (struct archive_hash_entry *) entry; |
/* Allocate the structure if it has not already been allocated by a |
subclass. */ |
if (ret == NULL) |
ret = (struct archive_hash_entry *) |
bfd_hash_allocate (table, sizeof (struct archive_hash_entry)); |
if (ret == NULL) |
return NULL; |
/* Call the allocation method of the superclass. */ |
ret = ((struct archive_hash_entry *) |
bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); |
if (ret) |
{ |
/* Initialize the local fields. */ |
ret->defs = NULL; |
} |
return &ret->root; |
} |
/* Initialize an archive hash table. */ |
static bfd_boolean |
archive_hash_table_init |
(struct archive_hash_table *table, |
struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *, |
struct bfd_hash_table *, |
const char *), |
unsigned int entsize) |
{ |
return bfd_hash_table_init (&table->table, newfunc, entsize); |
} |
/* Look up an entry in an archive hash table. */ |
#define archive_hash_lookup(t, string, create, copy) \ |
((struct archive_hash_entry *) \ |
bfd_hash_lookup (&(t)->table, (string), (create), (copy))) |
/* Allocate space in an archive hash table. */ |
#define archive_hash_allocate(t, size) bfd_hash_allocate (&(t)->table, (size)) |
/* Free an archive hash table. */ |
#define archive_hash_table_free(t) bfd_hash_table_free (&(t)->table) |
/* Generic function to add symbols from an archive file to the global |
hash file. This function presumes that the archive symbol table |
has already been read in (this is normally done by the |
bfd_check_format entry point). It looks through the undefined and |
common symbols and searches the archive symbol table for them. If |
it finds an entry, it includes the associated object file in the |
link. |
The old linker looked through the archive symbol table for |
undefined symbols. We do it the other way around, looking through |
undefined symbols for symbols defined in the archive. The |
advantage of the newer scheme is that we only have to look through |
the list of undefined symbols once, whereas the old method had to |
re-search the symbol table each time a new object file was added. |
The CHECKFN argument is used to see if an object file should be |
included. CHECKFN should set *PNEEDED to TRUE if the object file |
should be included, and must also call the bfd_link_info |
add_archive_element callback function and handle adding the symbols |
to the global hash table. CHECKFN must notice if the callback |
indicates a substitute BFD, and arrange to add those symbols instead |
if it does so. CHECKFN should only return FALSE if some sort of |
error occurs. |
For some formats, such as a.out, it is possible to look through an |
object file but not actually include it in the link. The |
archive_pass field in a BFD is used to avoid checking the symbols |
of an object files too many times. When an object is included in |
the link, archive_pass is set to -1. If an object is scanned but |
not included, archive_pass is set to the pass number. The pass |
number is incremented each time a new object file is included. The |
pass number is used because when a new object file is included it |
may create new undefined symbols which cause a previously examined |
object file to be included. */ |
bfd_boolean |
_bfd_generic_link_add_archive_symbols |
(bfd *abfd, |
struct bfd_link_info *info, |
bfd_boolean (*checkfn) (bfd *, struct bfd_link_info *, bfd_boolean *)) |
{ |
carsym *arsyms; |
carsym *arsym_end; |
register carsym *arsym; |
int pass; |
struct archive_hash_table arsym_hash; |
unsigned int indx; |
struct bfd_link_hash_entry **pundef; |
if (! bfd_has_map (abfd)) |
{ |
/* An empty archive is a special case. */ |
if (bfd_openr_next_archived_file (abfd, NULL) == NULL) |
return TRUE; |
bfd_set_error (bfd_error_no_armap); |
return FALSE; |
} |
arsyms = bfd_ardata (abfd)->symdefs; |
arsym_end = arsyms + bfd_ardata (abfd)->symdef_count; |
/* In order to quickly determine whether an symbol is defined in |
this archive, we build a hash table of the symbols. */ |
if (! archive_hash_table_init (&arsym_hash, archive_hash_newfunc, |
sizeof (struct archive_hash_entry))) |
return FALSE; |
for (arsym = arsyms, indx = 0; arsym < arsym_end; arsym++, indx++) |
{ |
struct archive_hash_entry *arh; |
struct archive_list *l, **pp; |
arh = archive_hash_lookup (&arsym_hash, arsym->name, TRUE, FALSE); |
if (arh == NULL) |
goto error_return; |
l = ((struct archive_list *) |
archive_hash_allocate (&arsym_hash, sizeof (struct archive_list))); |
if (l == NULL) |
goto error_return; |
l->indx = indx; |
for (pp = &arh->defs; *pp != NULL; pp = &(*pp)->next) |
; |
*pp = l; |
l->next = NULL; |
} |
/* The archive_pass field in the archive itself is used to |
initialize PASS, sine we may search the same archive multiple |
times. */ |
pass = abfd->archive_pass + 1; |
/* New undefined symbols are added to the end of the list, so we |
only need to look through it once. */ |
pundef = &info->hash->undefs; |
while (*pundef != NULL) |
{ |
struct bfd_link_hash_entry *h; |
struct archive_hash_entry *arh; |
struct archive_list *l; |
h = *pundef; |
/* When a symbol is defined, it is not necessarily removed from |
the list. */ |
if (h->type != bfd_link_hash_undefined |
&& h->type != bfd_link_hash_common) |
{ |
/* Remove this entry from the list, for general cleanliness |
and because we are going to look through the list again |
if we search any more libraries. We can't remove the |
entry if it is the tail, because that would lose any |
entries we add to the list later on (it would also cause |
us to lose track of whether the symbol has been |
referenced). */ |
if (*pundef != info->hash->undefs_tail) |
*pundef = (*pundef)->u.undef.next; |
else |
pundef = &(*pundef)->u.undef.next; |
continue; |
} |
/* Look for this symbol in the archive symbol map. */ |
arh = archive_hash_lookup (&arsym_hash, h->root.string, FALSE, FALSE); |
if (arh == NULL) |
{ |
/* If we haven't found the exact symbol we're looking for, |
let's look for its import thunk */ |
if (info->pei386_auto_import) |
{ |
bfd_size_type amt = strlen (h->root.string) + 10; |
char *buf = (char *) bfd_malloc (amt); |
if (buf == NULL) |
return FALSE; |
sprintf (buf, "__imp_%s", h->root.string); |
arh = archive_hash_lookup (&arsym_hash, buf, FALSE, FALSE); |
free(buf); |
} |
if (arh == NULL) |
{ |
pundef = &(*pundef)->u.undef.next; |
continue; |
} |
} |
/* Look at all the objects which define this symbol. */ |
for (l = arh->defs; l != NULL; l = l->next) |
{ |
bfd *element; |
bfd_boolean needed; |
/* If the symbol has gotten defined along the way, quit. */ |
if (h->type != bfd_link_hash_undefined |
&& h->type != bfd_link_hash_common) |
break; |
element = bfd_get_elt_at_index (abfd, l->indx); |
if (element == NULL) |
goto error_return; |
/* If we've already included this element, or if we've |
already checked it on this pass, continue. */ |
if (element->archive_pass == -1 |
|| element->archive_pass == pass) |
continue; |
/* If we can't figure this element out, just ignore it. */ |
if (! bfd_check_format (element, bfd_object)) |
{ |
element->archive_pass = -1; |
continue; |
} |
/* CHECKFN will see if this element should be included, and |
go ahead and include it if appropriate. */ |
if (! (*checkfn) (element, info, &needed)) |
goto error_return; |
if (! needed) |
element->archive_pass = pass; |
else |
{ |
element->archive_pass = -1; |
/* Increment the pass count to show that we may need to |
recheck object files which were already checked. */ |
++pass; |
} |
} |
pundef = &(*pundef)->u.undef.next; |
} |
archive_hash_table_free (&arsym_hash); |
/* Save PASS in case we are called again. */ |
abfd->archive_pass = pass; |
return TRUE; |
error_return: |
archive_hash_table_free (&arsym_hash); |
return FALSE; |
} |
/* See if we should include an archive element. This version is used |
when we do not want to automatically collect constructors based on |
the symbol name, presumably because we have some other mechanism |
for finding them. */ |
static bfd_boolean |
generic_link_check_archive_element_no_collect ( |
bfd *abfd, |
struct bfd_link_info *info, |
bfd_boolean *pneeded) |
{ |
return generic_link_check_archive_element (abfd, info, pneeded, FALSE); |
} |
/* See if we should include an archive element. This version is used |
when we want to automatically collect constructors based on the |
symbol name, as collect2 does. */ |
static bfd_boolean |
generic_link_check_archive_element_collect (bfd *abfd, |
struct bfd_link_info *info, |
bfd_boolean *pneeded) |
{ |
return generic_link_check_archive_element (abfd, info, pneeded, TRUE); |
} |
/* See if we should include an archive element. Optionally collect |
constructors. */ |
static bfd_boolean |
generic_link_check_archive_element (bfd *abfd, |
struct bfd_link_info *info, |
bfd_boolean *pneeded, |
bfd_boolean collect) |
{ |
asymbol **pp, **ppend; |
*pneeded = FALSE; |
if (!bfd_generic_link_read_symbols (abfd)) |
return FALSE; |
pp = _bfd_generic_link_get_symbols (abfd); |
ppend = pp + _bfd_generic_link_get_symcount (abfd); |
for (; pp < ppend; pp++) |
{ |
asymbol *p; |
struct bfd_link_hash_entry *h; |
p = *pp; |
/* We are only interested in globally visible symbols. */ |
if (! bfd_is_com_section (p->section) |
&& (p->flags & (BSF_GLOBAL | BSF_INDIRECT | BSF_WEAK)) == 0) |
continue; |
/* We are only interested if we know something about this |
symbol, and it is undefined or common. An undefined weak |
symbol (type bfd_link_hash_undefweak) is not considered to be |
a reference when pulling files out of an archive. See the |
SVR4 ABI, p. 4-27. */ |
h = bfd_link_hash_lookup (info->hash, bfd_asymbol_name (p), FALSE, |
FALSE, TRUE); |
if (h == NULL |
|| (h->type != bfd_link_hash_undefined |
&& h->type != bfd_link_hash_common)) |
continue; |
/* P is a symbol we are looking for. */ |
if (! bfd_is_com_section (p->section)) |
{ |
bfd_size_type symcount; |
asymbol **symbols; |
bfd *oldbfd = abfd; |
/* This object file defines this symbol, so pull it in. */ |
if (!(*info->callbacks |
->add_archive_element) (info, abfd, bfd_asymbol_name (p), |
&abfd)) |
return FALSE; |
/* Potentially, the add_archive_element hook may have set a |
substitute BFD for us. */ |
if (abfd != oldbfd |
&& !bfd_generic_link_read_symbols (abfd)) |
return FALSE; |
symcount = _bfd_generic_link_get_symcount (abfd); |
symbols = _bfd_generic_link_get_symbols (abfd); |
if (! generic_link_add_symbol_list (abfd, info, symcount, |
symbols, collect)) |
return FALSE; |
*pneeded = TRUE; |
return TRUE; |
} |
/* P is a common symbol. */ |
if (h->type == bfd_link_hash_undefined) |
{ |
bfd *symbfd; |
bfd_vma size; |
unsigned int power; |
symbfd = h->u.undef.abfd; |
if (symbfd == NULL) |
{ |
/* This symbol was created as undefined from outside |
BFD. We assume that we should link in the object |
file. This is for the -u option in the linker. */ |
if (!(*info->callbacks |
->add_archive_element) (info, abfd, bfd_asymbol_name (p), |
&abfd)) |
return FALSE; |
/* Potentially, the add_archive_element hook may have set a |
substitute BFD for us. But no symbols are going to get |
registered by anything we're returning to from here. */ |
*pneeded = TRUE; |
return TRUE; |
} |
/* Turn the symbol into a common symbol but do not link in |
the object file. This is how a.out works. Object |
formats that require different semantics must implement |
this function differently. This symbol is already on the |
undefs list. We add the section to a common section |
attached to symbfd to ensure that it is in a BFD which |
will be linked in. */ |
h->type = bfd_link_hash_common; |
h->u.c.p = (struct bfd_link_hash_common_entry *) |
bfd_hash_allocate (&info->hash->table, |
sizeof (struct bfd_link_hash_common_entry)); |
if (h->u.c.p == NULL) |
return FALSE; |
size = bfd_asymbol_value (p); |
h->u.c.size = size; |
power = bfd_log2 (size); |
if (power > 4) |
power = 4; |
h->u.c.p->alignment_power = power; |
if (p->section == bfd_com_section_ptr) |
h->u.c.p->section = bfd_make_section_old_way (symbfd, "COMMON"); |
else |
h->u.c.p->section = bfd_make_section_old_way (symbfd, |
p->section->name); |
h->u.c.p->section->flags |= SEC_ALLOC; |
} |
else |
{ |
/* Adjust the size of the common symbol if necessary. This |
is how a.out works. Object formats that require |
different semantics must implement this function |
differently. */ |
if (bfd_asymbol_value (p) > h->u.c.size) |
h->u.c.size = bfd_asymbol_value (p); |
} |
} |
/* This archive element is not needed. */ |
return TRUE; |
} |
/* Add the symbols from an object file to the global hash table. ABFD |
is the object file. INFO is the linker information. SYMBOL_COUNT |
is the number of symbols. SYMBOLS is the list of symbols. COLLECT |
is TRUE if constructors should be automatically collected by name |
as is done by collect2. */ |
static bfd_boolean |
generic_link_add_symbol_list (bfd *abfd, |
struct bfd_link_info *info, |
bfd_size_type symbol_count, |
asymbol **symbols, |
bfd_boolean collect) |
{ |
asymbol **pp, **ppend; |
pp = symbols; |
ppend = symbols + symbol_count; |
for (; pp < ppend; pp++) |
{ |
asymbol *p; |
p = *pp; |
if ((p->flags & (BSF_INDIRECT |
| BSF_WARNING |
| BSF_GLOBAL |
| BSF_CONSTRUCTOR |
| BSF_WEAK)) != 0 |
|| bfd_is_und_section (bfd_get_section (p)) |
|| bfd_is_com_section (bfd_get_section (p)) |
|| bfd_is_ind_section (bfd_get_section (p))) |
{ |
const char *name; |
const char *string; |
struct generic_link_hash_entry *h; |
struct bfd_link_hash_entry *bh; |
string = name = bfd_asymbol_name (p); |
if (((p->flags & BSF_INDIRECT) != 0 |
|| bfd_is_ind_section (p->section)) |
&& pp + 1 < ppend) |
{ |
pp++; |
string = bfd_asymbol_name (*pp); |
} |
else if ((p->flags & BSF_WARNING) != 0 |
&& pp + 1 < ppend) |
{ |
/* The name of P is actually the warning string, and the |
next symbol is the one to warn about. */ |
pp++; |
name = bfd_asymbol_name (*pp); |
} |
bh = NULL; |
if (! (_bfd_generic_link_add_one_symbol |
(info, abfd, name, p->flags, bfd_get_section (p), |
p->value, string, FALSE, collect, &bh))) |
return FALSE; |
h = (struct generic_link_hash_entry *) bh; |
/* If this is a constructor symbol, and the linker didn't do |
anything with it, then we want to just pass the symbol |
through to the output file. This will happen when |
linking with -r. */ |
if ((p->flags & BSF_CONSTRUCTOR) != 0 |
&& (h == NULL || h->root.type == bfd_link_hash_new)) |
{ |
p->udata.p = NULL; |
continue; |
} |
/* Save the BFD symbol so that we don't lose any backend |
specific information that may be attached to it. We only |
want this one if it gives more information than the |
existing one; we don't want to replace a defined symbol |
with an undefined one. This routine may be called with a |
hash table other than the generic hash table, so we only |
do this if we are certain that the hash table is a |
generic one. */ |
if (info->output_bfd->xvec == abfd->xvec) |
{ |
if (h->sym == NULL |
|| (! bfd_is_und_section (bfd_get_section (p)) |
&& (! bfd_is_com_section (bfd_get_section (p)) |
|| bfd_is_und_section (bfd_get_section (h->sym))))) |
{ |
h->sym = p; |
/* BSF_OLD_COMMON is a hack to support COFF reloc |
reading, and it should go away when the COFF |
linker is switched to the new version. */ |
if (bfd_is_com_section (bfd_get_section (p))) |
p->flags |= BSF_OLD_COMMON; |
} |
} |
/* Store a back pointer from the symbol to the hash |
table entry for the benefit of relaxation code until |
it gets rewritten to not use asymbol structures. |
Setting this is also used to check whether these |
symbols were set up by the generic linker. */ |
p->udata.p = h; |
} |
} |
return TRUE; |
} |
/* We use a state table to deal with adding symbols from an object |
file. The first index into the state table describes the symbol |
from the object file. The second index into the state table is the |
type of the symbol in the hash table. */ |
/* The symbol from the object file is turned into one of these row |
values. */ |
enum link_row |
{ |
UNDEF_ROW, /* Undefined. */ |
UNDEFW_ROW, /* Weak undefined. */ |
DEF_ROW, /* Defined. */ |
DEFW_ROW, /* Weak defined. */ |
COMMON_ROW, /* Common. */ |
INDR_ROW, /* Indirect. */ |
WARN_ROW, /* Warning. */ |
SET_ROW /* Member of set. */ |
}; |
/* apparently needed for Hitachi 3050R(HI-UX/WE2)? */ |
#undef FAIL |
/* The actions to take in the state table. */ |
enum link_action |
{ |
FAIL, /* Abort. */ |
UND, /* Mark symbol undefined. */ |
WEAK, /* Mark symbol weak undefined. */ |
DEF, /* Mark symbol defined. */ |
DEFW, /* Mark symbol weak defined. */ |
COM, /* Mark symbol common. */ |
REF, /* Mark defined symbol referenced. */ |
CREF, /* Possibly warn about common reference to defined symbol. */ |
CDEF, /* Define existing common symbol. */ |
NOACT, /* No action. */ |
BIG, /* Mark symbol common using largest size. */ |
MDEF, /* Multiple definition error. */ |
MIND, /* Multiple indirect symbols. */ |
IND, /* Make indirect symbol. */ |
CIND, /* Make indirect symbol from existing common symbol. */ |
SET, /* Add value to set. */ |
MWARN, /* Make warning symbol. */ |
WARN, /* Issue warning. */ |
CWARN, /* Warn if referenced, else MWARN. */ |
CYCLE, /* Repeat with symbol pointed to. */ |
REFC, /* Mark indirect symbol referenced and then CYCLE. */ |
WARNC /* Issue warning and then CYCLE. */ |
}; |
/* The state table itself. The first index is a link_row and the |
second index is a bfd_link_hash_type. */ |
static const enum link_action link_action[8][8] = |
{ |
/* current\prev new undef undefw def defw com indr warn */ |
/* UNDEF_ROW */ {UND, NOACT, UND, REF, REF, NOACT, REFC, WARNC }, |
/* UNDEFW_ROW */ {WEAK, NOACT, NOACT, REF, REF, NOACT, REFC, WARNC }, |
/* DEF_ROW */ {DEF, DEF, DEF, MDEF, DEF, CDEF, MDEF, CYCLE }, |
/* DEFW_ROW */ {DEFW, DEFW, DEFW, NOACT, NOACT, NOACT, NOACT, CYCLE }, |
/* COMMON_ROW */ {COM, COM, COM, CREF, COM, BIG, REFC, WARNC }, |
/* INDR_ROW */ {IND, IND, IND, MDEF, IND, CIND, MIND, CYCLE }, |
/* WARN_ROW */ {MWARN, WARN, WARN, CWARN, CWARN, WARN, CWARN, NOACT }, |
/* SET_ROW */ {SET, SET, SET, SET, SET, SET, CYCLE, CYCLE } |
}; |
/* Most of the entries in the LINK_ACTION table are straightforward, |
but a few are somewhat subtle. |
A reference to an indirect symbol (UNDEF_ROW/indr or |
UNDEFW_ROW/indr) is counted as a reference both to the indirect |
symbol and to the symbol the indirect symbol points to. |
A reference to a warning symbol (UNDEF_ROW/warn or UNDEFW_ROW/warn) |
causes the warning to be issued. |
A common definition of an indirect symbol (COMMON_ROW/indr) is |
treated as a multiple definition error. Likewise for an indirect |
definition of a common symbol (INDR_ROW/com). |
An indirect definition of a warning (INDR_ROW/warn) does not cause |
the warning to be issued. |
If a warning is created for an indirect symbol (WARN_ROW/indr) no |
warning is created for the symbol the indirect symbol points to. |
Adding an entry to a set does not count as a reference to a set, |
and no warning is issued (SET_ROW/warn). */ |
/* Return the BFD in which a hash entry has been defined, if known. */ |
static bfd * |
hash_entry_bfd (struct bfd_link_hash_entry *h) |
{ |
while (h->type == bfd_link_hash_warning) |
h = h->u.i.link; |
switch (h->type) |
{ |
default: |
return NULL; |
case bfd_link_hash_undefined: |
case bfd_link_hash_undefweak: |
return h->u.undef.abfd; |
case bfd_link_hash_defined: |
case bfd_link_hash_defweak: |
return h->u.def.section->owner; |
case bfd_link_hash_common: |
return h->u.c.p->section->owner; |
} |
/*NOTREACHED*/ |
} |
/* Add a symbol to the global hash table. |
ABFD is the BFD the symbol comes from. |
NAME is the name of the symbol. |
FLAGS is the BSF_* bits associated with the symbol. |
SECTION is the section in which the symbol is defined; this may be |
bfd_und_section_ptr or bfd_com_section_ptr. |
VALUE is the value of the symbol, relative to the section. |
STRING is used for either an indirect symbol, in which case it is |
the name of the symbol to indirect to, or a warning symbol, in |
which case it is the warning string. |
COPY is TRUE if NAME or STRING must be copied into locally |
allocated memory if they need to be saved. |
COLLECT is TRUE if we should automatically collect gcc constructor |
or destructor names as collect2 does. |
HASHP, if not NULL, is a place to store the created hash table |
entry; if *HASHP is not NULL, the caller has already looked up |
the hash table entry, and stored it in *HASHP. */ |
bfd_boolean |
_bfd_generic_link_add_one_symbol (struct bfd_link_info *info, |
bfd *abfd, |
const char *name, |
flagword flags, |
asection *section, |
bfd_vma value, |
const char *string, |
bfd_boolean copy, |
bfd_boolean collect, |
struct bfd_link_hash_entry **hashp) |
{ |
enum link_row row; |
struct bfd_link_hash_entry *h; |
bfd_boolean cycle; |
BFD_ASSERT (section != NULL); |
if (bfd_is_ind_section (section) |
|| (flags & BSF_INDIRECT) != 0) |
row = INDR_ROW; |
else if ((flags & BSF_WARNING) != 0) |
row = WARN_ROW; |
else if ((flags & BSF_CONSTRUCTOR) != 0) |
row = SET_ROW; |
else if (bfd_is_und_section (section)) |
{ |
if ((flags & BSF_WEAK) != 0) |
row = UNDEFW_ROW; |
else |
row = UNDEF_ROW; |
} |
else if ((flags & BSF_WEAK) != 0) |
row = DEFW_ROW; |
else if (bfd_is_com_section (section)) |
row = COMMON_ROW; |
else |
row = DEF_ROW; |
if (hashp != NULL && *hashp != NULL) |
h = *hashp; |
else |
{ |
if (row == UNDEF_ROW || row == UNDEFW_ROW) |
h = bfd_wrapped_link_hash_lookup (abfd, info, name, TRUE, copy, FALSE); |
else |
h = bfd_link_hash_lookup (info->hash, name, TRUE, copy, FALSE); |
if (h == NULL) |
{ |
if (hashp != NULL) |
*hashp = NULL; |
return FALSE; |
} |
} |
if (info->notice_all |
|| (info->notice_hash != NULL |
&& bfd_hash_lookup (info->notice_hash, name, FALSE, FALSE) != NULL)) |
{ |
if (! (*info->callbacks->notice) (info, h, |
abfd, section, value, flags, string)) |
return FALSE; |
} |
if (hashp != NULL) |
*hashp = h; |
do |
{ |
enum link_action action; |
cycle = FALSE; |
action = link_action[(int) row][(int) h->type]; |
switch (action) |
{ |
case FAIL: |
abort (); |
case NOACT: |
/* Do nothing. */ |
break; |
case UND: |
/* Make a new undefined symbol. */ |
h->type = bfd_link_hash_undefined; |
h->u.undef.abfd = abfd; |
bfd_link_add_undef (info->hash, h); |
break; |
case WEAK: |
/* Make a new weak undefined symbol. */ |
h->type = bfd_link_hash_undefweak; |
h->u.undef.abfd = abfd; |
break; |
case CDEF: |
/* We have found a definition for a symbol which was |
previously common. */ |
BFD_ASSERT (h->type == bfd_link_hash_common); |
if (! ((*info->callbacks->multiple_common) |
(info, h, abfd, bfd_link_hash_defined, 0))) |
return FALSE; |
/* Fall through. */ |
case DEF: |
case DEFW: |
{ |
enum bfd_link_hash_type oldtype; |
/* Define a symbol. */ |
oldtype = h->type; |
if (action == DEFW) |
h->type = bfd_link_hash_defweak; |
else |
h->type = bfd_link_hash_defined; |
h->u.def.section = section; |
h->u.def.value = value; |
/* If we have been asked to, we act like collect2 and |
identify all functions that might be global |
constructors and destructors and pass them up in a |
callback. We only do this for certain object file |
types, since many object file types can handle this |
automatically. */ |
if (collect && name[0] == '_') |
{ |
const char *s; |
/* A constructor or destructor name starts like this: |
_+GLOBAL_[_.$][ID][_.$] where the first [_.$] and |
the second are the same character (we accept any |
character there, in case a new object file format |
comes along with even worse naming restrictions). */ |
#define CONS_PREFIX "GLOBAL_" |
#define CONS_PREFIX_LEN (sizeof CONS_PREFIX - 1) |
s = name + 1; |
while (*s == '_') |
++s; |
if (s[0] == 'G' && CONST_STRNEQ (s, CONS_PREFIX)) |
{ |
char c; |
c = s[CONS_PREFIX_LEN + 1]; |
if ((c == 'I' || c == 'D') |
&& s[CONS_PREFIX_LEN] == s[CONS_PREFIX_LEN + 2]) |
{ |
/* If this is a definition of a symbol which |
was previously weakly defined, we are in |
trouble. We have already added a |
constructor entry for the weak defined |
symbol, and now we are trying to add one |
for the new symbol. Fortunately, this case |
should never arise in practice. */ |
if (oldtype == bfd_link_hash_defweak) |
abort (); |
if (! ((*info->callbacks->constructor) |
(info, c == 'I', |
h->root.string, abfd, section, value))) |
return FALSE; |
} |
} |
} |
} |
break; |
case COM: |
/* We have found a common definition for a symbol. */ |
if (h->type == bfd_link_hash_new) |
bfd_link_add_undef (info->hash, h); |
h->type = bfd_link_hash_common; |
h->u.c.p = (struct bfd_link_hash_common_entry *) |
bfd_hash_allocate (&info->hash->table, |
sizeof (struct bfd_link_hash_common_entry)); |
if (h->u.c.p == NULL) |
return FALSE; |
h->u.c.size = value; |
/* Select a default alignment based on the size. This may |
be overridden by the caller. */ |
{ |
unsigned int power; |
power = bfd_log2 (value); |
if (power > 4) |
power = 4; |
h->u.c.p->alignment_power = power; |
} |
/* The section of a common symbol is only used if the common |
symbol is actually allocated. It basically provides a |
hook for the linker script to decide which output section |
the common symbols should be put in. In most cases, the |
section of a common symbol will be bfd_com_section_ptr, |
the code here will choose a common symbol section named |
"COMMON", and the linker script will contain *(COMMON) in |
the appropriate place. A few targets use separate common |
sections for small symbols, and they require special |
handling. */ |
if (section == bfd_com_section_ptr) |
{ |
h->u.c.p->section = bfd_make_section_old_way (abfd, "COMMON"); |
h->u.c.p->section->flags |= SEC_ALLOC; |
} |
else if (section->owner != abfd) |
{ |
h->u.c.p->section = bfd_make_section_old_way (abfd, |
section->name); |
h->u.c.p->section->flags |= SEC_ALLOC; |
} |
else |
h->u.c.p->section = section; |
break; |
case REF: |
/* A reference to a defined symbol. */ |
if (h->u.undef.next == NULL && info->hash->undefs_tail != h) |
h->u.undef.next = h; |
break; |
case BIG: |
/* We have found a common definition for a symbol which |
already had a common definition. Use the maximum of the |
two sizes, and use the section required by the larger symbol. */ |
BFD_ASSERT (h->type == bfd_link_hash_common); |
if (! ((*info->callbacks->multiple_common) |
(info, h, abfd, bfd_link_hash_common, value))) |
return FALSE; |
if (value > h->u.c.size) |
{ |
unsigned int power; |
h->u.c.size = value; |
/* Select a default alignment based on the size. This may |
be overridden by the caller. */ |
power = bfd_log2 (value); |
if (power > 4) |
power = 4; |
h->u.c.p->alignment_power = power; |
/* Some systems have special treatment for small commons, |
hence we want to select the section used by the larger |
symbol. This makes sure the symbol does not go in a |
small common section if it is now too large. */ |
if (section == bfd_com_section_ptr) |
{ |
h->u.c.p->section |
= bfd_make_section_old_way (abfd, "COMMON"); |
h->u.c.p->section->flags |= SEC_ALLOC; |
} |
else if (section->owner != abfd) |
{ |
h->u.c.p->section |
= bfd_make_section_old_way (abfd, section->name); |
h->u.c.p->section->flags |= SEC_ALLOC; |
} |
else |
h->u.c.p->section = section; |
} |
break; |
case CREF: |
/* We have found a common definition for a symbol which |
was already defined. */ |
if (! ((*info->callbacks->multiple_common) |
(info, h, abfd, bfd_link_hash_common, value))) |
return FALSE; |
break; |
case MIND: |
/* Multiple indirect symbols. This is OK if they both point |
to the same symbol. */ |
if (strcmp (h->u.i.link->root.string, string) == 0) |
break; |
/* Fall through. */ |
case MDEF: |
/* Handle a multiple definition. */ |
if (! ((*info->callbacks->multiple_definition) |
(info, h, abfd, section, value))) |
return FALSE; |
break; |
case CIND: |
/* Create an indirect symbol from an existing common symbol. */ |
BFD_ASSERT (h->type == bfd_link_hash_common); |
if (! ((*info->callbacks->multiple_common) |
(info, h, abfd, bfd_link_hash_indirect, 0))) |
return FALSE; |
/* Fall through. */ |
case IND: |
/* Create an indirect symbol. */ |
{ |
struct bfd_link_hash_entry *inh; |
/* STRING is the name of the symbol we want to indirect |
to. */ |
inh = bfd_wrapped_link_hash_lookup (abfd, info, string, TRUE, |
copy, FALSE); |
if (inh == NULL) |
return FALSE; |
if (inh->type == bfd_link_hash_indirect |
&& inh->u.i.link == h) |
{ |
(*_bfd_error_handler) |
(_("%B: indirect symbol `%s' to `%s' is a loop"), |
abfd, name, string); |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
if (inh->type == bfd_link_hash_new) |
{ |
inh->type = bfd_link_hash_undefined; |
inh->u.undef.abfd = abfd; |
bfd_link_add_undef (info->hash, inh); |
} |
/* If the indirect symbol has been referenced, we need to |
push the reference down to the symbol we are |
referencing. */ |
if (h->type != bfd_link_hash_new) |
{ |
row = UNDEF_ROW; |
cycle = TRUE; |
} |
h->type = bfd_link_hash_indirect; |
h->u.i.link = inh; |
} |
break; |
case SET: |
/* Add an entry to a set. */ |
if (! (*info->callbacks->add_to_set) (info, h, BFD_RELOC_CTOR, |
abfd, section, value)) |
return FALSE; |
break; |
case WARNC: |
/* Issue a warning and cycle. */ |
if (h->u.i.warning != NULL) |
{ |
if (! (*info->callbacks->warning) (info, h->u.i.warning, |
h->root.string, abfd, |
NULL, 0)) |
return FALSE; |
/* Only issue a warning once. */ |
h->u.i.warning = NULL; |
} |
/* Fall through. */ |
case CYCLE: |
/* Try again with the referenced symbol. */ |
h = h->u.i.link; |
cycle = TRUE; |
break; |
case REFC: |
/* A reference to an indirect symbol. */ |
if (h->u.undef.next == NULL && info->hash->undefs_tail != h) |
h->u.undef.next = h; |
h = h->u.i.link; |
cycle = TRUE; |
break; |
case WARN: |
/* Issue a warning. */ |
if (! (*info->callbacks->warning) (info, string, h->root.string, |
hash_entry_bfd (h), NULL, 0)) |
return FALSE; |
break; |
case CWARN: |
/* Warn if this symbol has been referenced already, |
otherwise add a warning. A symbol has been referenced if |
the u.undef.next field is not NULL, or it is the tail of the |
undefined symbol list. The REF case above helps to |
ensure this. */ |
if (h->u.undef.next != NULL || info->hash->undefs_tail == h) |
{ |
if (! (*info->callbacks->warning) (info, string, h->root.string, |
hash_entry_bfd (h), NULL, 0)) |
return FALSE; |
break; |
} |
/* Fall through. */ |
case MWARN: |
/* Make a warning symbol. */ |
{ |
struct bfd_link_hash_entry *sub; |
/* STRING is the warning to give. */ |
sub = ((struct bfd_link_hash_entry *) |
((*info->hash->table.newfunc) |
(NULL, &info->hash->table, h->root.string))); |
if (sub == NULL) |
return FALSE; |
*sub = *h; |
sub->type = bfd_link_hash_warning; |
sub->u.i.link = h; |
if (! copy) |
sub->u.i.warning = string; |
else |
{ |
char *w; |
size_t len = strlen (string) + 1; |
w = (char *) bfd_hash_allocate (&info->hash->table, len); |
if (w == NULL) |
return FALSE; |
memcpy (w, string, len); |
sub->u.i.warning = w; |
} |
bfd_hash_replace (&info->hash->table, |
(struct bfd_hash_entry *) h, |
(struct bfd_hash_entry *) sub); |
if (hashp != NULL) |
*hashp = sub; |
} |
break; |
} |
} |
while (cycle); |
return TRUE; |
} |
/* Generic final link routine. */ |
bfd_boolean |
_bfd_generic_final_link (bfd *abfd, struct bfd_link_info *info) |
{ |
bfd *sub; |
asection *o; |
struct bfd_link_order *p; |
size_t outsymalloc; |
struct generic_write_global_symbol_info wginfo; |
bfd_get_outsymbols (abfd) = NULL; |
bfd_get_symcount (abfd) = 0; |
outsymalloc = 0; |
/* Mark all sections which will be included in the output file. */ |
for (o = abfd->sections; o != NULL; o = o->next) |
for (p = o->map_head.link_order; p != NULL; p = p->next) |
if (p->type == bfd_indirect_link_order) |
p->u.indirect.section->linker_mark = TRUE; |
/* Build the output symbol table. */ |
for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) |
if (! _bfd_generic_link_output_symbols (abfd, sub, info, &outsymalloc)) |
return FALSE; |
/* Accumulate the global symbols. */ |
wginfo.info = info; |
wginfo.output_bfd = abfd; |
wginfo.psymalloc = &outsymalloc; |
_bfd_generic_link_hash_traverse (_bfd_generic_hash_table (info), |
_bfd_generic_link_write_global_symbol, |
&wginfo); |
/* Make sure we have a trailing NULL pointer on OUTSYMBOLS. We |
shouldn't really need one, since we have SYMCOUNT, but some old |
code still expects one. */ |
if (! generic_add_output_symbol (abfd, &outsymalloc, NULL)) |
return FALSE; |
if (info->relocatable) |
{ |
/* Allocate space for the output relocs for each section. */ |
for (o = abfd->sections; o != NULL; o = o->next) |
{ |
o->reloc_count = 0; |
for (p = o->map_head.link_order; p != NULL; p = p->next) |
{ |
if (p->type == bfd_section_reloc_link_order |
|| p->type == bfd_symbol_reloc_link_order) |
++o->reloc_count; |
else if (p->type == bfd_indirect_link_order) |
{ |
asection *input_section; |
bfd *input_bfd; |
long relsize; |
arelent **relocs; |
asymbol **symbols; |
long reloc_count; |
input_section = p->u.indirect.section; |
input_bfd = input_section->owner; |
relsize = bfd_get_reloc_upper_bound (input_bfd, |
input_section); |
if (relsize < 0) |
return FALSE; |
relocs = (arelent **) bfd_malloc (relsize); |
if (!relocs && relsize != 0) |
return FALSE; |
symbols = _bfd_generic_link_get_symbols (input_bfd); |
reloc_count = bfd_canonicalize_reloc (input_bfd, |
input_section, |
relocs, |
symbols); |
free (relocs); |
if (reloc_count < 0) |
return FALSE; |
BFD_ASSERT ((unsigned long) reloc_count |
== input_section->reloc_count); |
o->reloc_count += reloc_count; |
} |
} |
if (o->reloc_count > 0) |
{ |
bfd_size_type amt; |
amt = o->reloc_count; |
amt *= sizeof (arelent *); |
o->orelocation = (struct reloc_cache_entry **) bfd_alloc (abfd, amt); |
if (!o->orelocation) |
return FALSE; |
o->flags |= SEC_RELOC; |
/* Reset the count so that it can be used as an index |
when putting in the output relocs. */ |
o->reloc_count = 0; |
} |
} |
} |
/* Handle all the link order information for the sections. */ |
for (o = abfd->sections; o != NULL; o = o->next) |
{ |
for (p = o->map_head.link_order; p != NULL; p = p->next) |
{ |
switch (p->type) |
{ |
case bfd_section_reloc_link_order: |
case bfd_symbol_reloc_link_order: |
if (! _bfd_generic_reloc_link_order (abfd, info, o, p)) |
return FALSE; |
break; |
case bfd_indirect_link_order: |
if (! default_indirect_link_order (abfd, info, o, p, TRUE)) |
return FALSE; |
break; |
default: |
if (! _bfd_default_link_order (abfd, info, o, p)) |
return FALSE; |
break; |
} |
} |
} |
return TRUE; |
} |
/* Add an output symbol to the output BFD. */ |
static bfd_boolean |
generic_add_output_symbol (bfd *output_bfd, size_t *psymalloc, asymbol *sym) |
{ |
if (bfd_get_symcount (output_bfd) >= *psymalloc) |
{ |
asymbol **newsyms; |
bfd_size_type amt; |
if (*psymalloc == 0) |
*psymalloc = 124; |
else |
*psymalloc *= 2; |
amt = *psymalloc; |
amt *= sizeof (asymbol *); |
newsyms = (asymbol **) bfd_realloc (bfd_get_outsymbols (output_bfd), amt); |
if (newsyms == NULL) |
return FALSE; |
bfd_get_outsymbols (output_bfd) = newsyms; |
} |
bfd_get_outsymbols (output_bfd) [bfd_get_symcount (output_bfd)] = sym; |
if (sym != NULL) |
++ bfd_get_symcount (output_bfd); |
return TRUE; |
} |
/* Handle the symbols for an input BFD. */ |
bfd_boolean |
_bfd_generic_link_output_symbols (bfd *output_bfd, |
bfd *input_bfd, |
struct bfd_link_info *info, |
size_t *psymalloc) |
{ |
asymbol **sym_ptr; |
asymbol **sym_end; |
if (!bfd_generic_link_read_symbols (input_bfd)) |
return FALSE; |
/* Create a filename symbol if we are supposed to. */ |
if (info->create_object_symbols_section != NULL) |
{ |
asection *sec; |
for (sec = input_bfd->sections; sec != NULL; sec = sec->next) |
{ |
if (sec->output_section == info->create_object_symbols_section) |
{ |
asymbol *newsym; |
newsym = bfd_make_empty_symbol (input_bfd); |
if (!newsym) |
return FALSE; |
newsym->name = input_bfd->filename; |
newsym->value = 0; |
newsym->flags = BSF_LOCAL | BSF_FILE; |
newsym->section = sec; |
if (! generic_add_output_symbol (output_bfd, psymalloc, |
newsym)) |
return FALSE; |
break; |
} |
} |
} |
/* Adjust the values of the globally visible symbols, and write out |
local symbols. */ |
sym_ptr = _bfd_generic_link_get_symbols (input_bfd); |
sym_end = sym_ptr + _bfd_generic_link_get_symcount (input_bfd); |
for (; sym_ptr < sym_end; sym_ptr++) |
{ |
asymbol *sym; |
struct generic_link_hash_entry *h; |
bfd_boolean output; |
h = NULL; |
sym = *sym_ptr; |
if ((sym->flags & (BSF_INDIRECT |
| BSF_WARNING |
| BSF_GLOBAL |
| BSF_CONSTRUCTOR |
| BSF_WEAK)) != 0 |
|| bfd_is_und_section (bfd_get_section (sym)) |
|| bfd_is_com_section (bfd_get_section (sym)) |
|| bfd_is_ind_section (bfd_get_section (sym))) |
{ |
if (sym->udata.p != NULL) |
h = (struct generic_link_hash_entry *) sym->udata.p; |
else if ((sym->flags & BSF_CONSTRUCTOR) != 0) |
{ |
/* This case normally means that the main linker code |
deliberately ignored this constructor symbol. We |
should just pass it through. This will screw up if |
the constructor symbol is from a different, |
non-generic, object file format, but the case will |
only arise when linking with -r, which will probably |
fail anyhow, since there will be no way to represent |
the relocs in the output format being used. */ |
h = NULL; |
} |
else if (bfd_is_und_section (bfd_get_section (sym))) |
h = ((struct generic_link_hash_entry *) |
bfd_wrapped_link_hash_lookup (output_bfd, info, |
bfd_asymbol_name (sym), |
FALSE, FALSE, TRUE)); |
else |
h = _bfd_generic_link_hash_lookup (_bfd_generic_hash_table (info), |
bfd_asymbol_name (sym), |
FALSE, FALSE, TRUE); |
if (h != NULL) |
{ |
/* Force all references to this symbol to point to |
the same area in memory. It is possible that |
this routine will be called with a hash table |
other than a generic hash table, so we double |
check that. */ |
if (info->output_bfd->xvec == input_bfd->xvec) |
{ |
if (h->sym != NULL) |
*sym_ptr = sym = h->sym; |
} |
switch (h->root.type) |
{ |
default: |
case bfd_link_hash_new: |
abort (); |
case bfd_link_hash_undefined: |
break; |
case bfd_link_hash_undefweak: |
sym->flags |= BSF_WEAK; |
break; |
case bfd_link_hash_indirect: |
h = (struct generic_link_hash_entry *) h->root.u.i.link; |
/* fall through */ |
case bfd_link_hash_defined: |
sym->flags |= BSF_GLOBAL; |
sym->flags &=~ BSF_CONSTRUCTOR; |
sym->value = h->root.u.def.value; |
sym->section = h->root.u.def.section; |
break; |
case bfd_link_hash_defweak: |
sym->flags |= BSF_WEAK; |
sym->flags &=~ BSF_CONSTRUCTOR; |
sym->value = h->root.u.def.value; |
sym->section = h->root.u.def.section; |
break; |
case bfd_link_hash_common: |
sym->value = h->root.u.c.size; |
sym->flags |= BSF_GLOBAL; |
if (! bfd_is_com_section (sym->section)) |
{ |
BFD_ASSERT (bfd_is_und_section (sym->section)); |
sym->section = bfd_com_section_ptr; |
} |
/* We do not set the section of the symbol to |
h->root.u.c.p->section. That value was saved so |
that we would know where to allocate the symbol |
if it was defined. In this case the type is |
still bfd_link_hash_common, so we did not define |
it, so we do not want to use that section. */ |
break; |
} |
} |
} |
/* This switch is straight from the old code in |
write_file_locals in ldsym.c. */ |
if (info->strip == strip_all |
|| (info->strip == strip_some |
&& bfd_hash_lookup (info->keep_hash, bfd_asymbol_name (sym), |
FALSE, FALSE) == NULL)) |
output = FALSE; |
else if ((sym->flags & (BSF_GLOBAL | BSF_WEAK)) != 0) |
{ |
/* If this symbol is marked as occurring now, rather |
than at the end, output it now. This is used for |
COFF C_EXT FCN symbols. FIXME: There must be a |
better way. */ |
if (bfd_asymbol_bfd (sym) == input_bfd |
&& (sym->flags & BSF_NOT_AT_END) != 0) |
output = TRUE; |
else |
output = FALSE; |
} |
else if (bfd_is_ind_section (sym->section)) |
output = FALSE; |
else if ((sym->flags & BSF_DEBUGGING) != 0) |
{ |
if (info->strip == strip_none) |
output = TRUE; |
else |
output = FALSE; |
} |
else if (bfd_is_und_section (sym->section) |
|| bfd_is_com_section (sym->section)) |
output = FALSE; |
else if ((sym->flags & BSF_LOCAL) != 0) |
{ |
if ((sym->flags & BSF_WARNING) != 0) |
output = FALSE; |
else |
{ |
switch (info->discard) |
{ |
default: |
case discard_all: |
output = FALSE; |
break; |
case discard_sec_merge: |
output = TRUE; |
if (info->relocatable |
|| ! (sym->section->flags & SEC_MERGE)) |
break; |
/* FALLTHROUGH */ |
case discard_l: |
if (bfd_is_local_label (input_bfd, sym)) |
output = FALSE; |
else |
output = TRUE; |
break; |
case discard_none: |
output = TRUE; |
break; |
} |
} |
} |
else if ((sym->flags & BSF_CONSTRUCTOR)) |
{ |
if (info->strip != strip_all) |
output = TRUE; |
else |
output = FALSE; |
} |
else if (sym->flags == 0 |
&& (sym->section->owner->flags & BFD_PLUGIN) != 0) |
/* LTO doesn't set symbol information. We get here with the |
generic linker for a symbol that was "common" but no longer |
needs to be global. */ |
output = FALSE; |
else |
abort (); |
/* If this symbol is in a section which is not being included |
in the output file, then we don't want to output the |
symbol. */ |
if (!bfd_is_abs_section (sym->section) |
&& bfd_section_removed_from_list (output_bfd, |
sym->section->output_section)) |
output = FALSE; |
if (output) |
{ |
if (! generic_add_output_symbol (output_bfd, psymalloc, sym)) |
return FALSE; |
if (h != NULL) |
h->written = TRUE; |
} |
} |
return TRUE; |
} |
/* Set the section and value of a generic BFD symbol based on a linker |
hash table entry. */ |
static void |
set_symbol_from_hash (asymbol *sym, struct bfd_link_hash_entry *h) |
{ |
switch (h->type) |
{ |
default: |
abort (); |
break; |
case bfd_link_hash_new: |
/* This can happen when a constructor symbol is seen but we are |
not building constructors. */ |
if (sym->section != NULL) |
{ |
BFD_ASSERT ((sym->flags & BSF_CONSTRUCTOR) != 0); |
} |
else |
{ |
sym->flags |= BSF_CONSTRUCTOR; |
sym->section = bfd_abs_section_ptr; |
sym->value = 0; |
} |
break; |
case bfd_link_hash_undefined: |
sym->section = bfd_und_section_ptr; |
sym->value = 0; |
break; |
case bfd_link_hash_undefweak: |
sym->section = bfd_und_section_ptr; |
sym->value = 0; |
sym->flags |= BSF_WEAK; |
break; |
case bfd_link_hash_defined: |
sym->section = h->u.def.section; |
sym->value = h->u.def.value; |
break; |
case bfd_link_hash_defweak: |
sym->flags |= BSF_WEAK; |
sym->section = h->u.def.section; |
sym->value = h->u.def.value; |
break; |
case bfd_link_hash_common: |
sym->value = h->u.c.size; |
if (sym->section == NULL) |
sym->section = bfd_com_section_ptr; |
else if (! bfd_is_com_section (sym->section)) |
{ |
BFD_ASSERT (bfd_is_und_section (sym->section)); |
sym->section = bfd_com_section_ptr; |
} |
/* Do not set the section; see _bfd_generic_link_output_symbols. */ |
break; |
case bfd_link_hash_indirect: |
case bfd_link_hash_warning: |
/* FIXME: What should we do here? */ |
break; |
} |
} |
/* Write out a global symbol, if it hasn't already been written out. |
This is called for each symbol in the hash table. */ |
bfd_boolean |
_bfd_generic_link_write_global_symbol (struct generic_link_hash_entry *h, |
void *data) |
{ |
struct generic_write_global_symbol_info *wginfo = |
(struct generic_write_global_symbol_info *) data; |
asymbol *sym; |
if (h->written) |
return TRUE; |
h->written = TRUE; |
if (wginfo->info->strip == strip_all |
|| (wginfo->info->strip == strip_some |
&& bfd_hash_lookup (wginfo->info->keep_hash, h->root.root.string, |
FALSE, FALSE) == NULL)) |
return TRUE; |
if (h->sym != NULL) |
sym = h->sym; |
else |
{ |
sym = bfd_make_empty_symbol (wginfo->output_bfd); |
if (!sym) |
return FALSE; |
sym->name = h->root.root.string; |
sym->flags = 0; |
} |
set_symbol_from_hash (sym, &h->root); |
sym->flags |= BSF_GLOBAL; |
if (! generic_add_output_symbol (wginfo->output_bfd, wginfo->psymalloc, |
sym)) |
{ |
/* FIXME: No way to return failure. */ |
abort (); |
} |
return TRUE; |
} |
/* Create a relocation. */ |
bfd_boolean |
_bfd_generic_reloc_link_order (bfd *abfd, |
struct bfd_link_info *info, |
asection *sec, |
struct bfd_link_order *link_order) |
{ |
arelent *r; |
if (! info->relocatable) |
abort (); |
if (sec->orelocation == NULL) |
abort (); |
r = (arelent *) bfd_alloc (abfd, sizeof (arelent)); |
if (r == NULL) |
return FALSE; |
r->address = link_order->offset; |
r->howto = bfd_reloc_type_lookup (abfd, link_order->u.reloc.p->reloc); |
if (r->howto == 0) |
{ |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
/* Get the symbol to use for the relocation. */ |
if (link_order->type == bfd_section_reloc_link_order) |
r->sym_ptr_ptr = link_order->u.reloc.p->u.section->symbol_ptr_ptr; |
else |
{ |
struct generic_link_hash_entry *h; |
h = ((struct generic_link_hash_entry *) |
bfd_wrapped_link_hash_lookup (abfd, info, |
link_order->u.reloc.p->u.name, |
FALSE, FALSE, TRUE)); |
if (h == NULL |
|| ! h->written) |
{ |
if (! ((*info->callbacks->unattached_reloc) |
(info, link_order->u.reloc.p->u.name, NULL, NULL, 0))) |
return FALSE; |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
r->sym_ptr_ptr = &h->sym; |
} |
/* If this is an inplace reloc, write the addend to the object file. |
Otherwise, store it in the reloc addend. */ |
if (! r->howto->partial_inplace) |
r->addend = link_order->u.reloc.p->addend; |
else |
{ |
bfd_size_type size; |
bfd_reloc_status_type rstat; |
bfd_byte *buf; |
bfd_boolean ok; |
file_ptr loc; |
size = bfd_get_reloc_size (r->howto); |
buf = (bfd_byte *) bfd_zmalloc (size); |
if (buf == NULL) |
return FALSE; |
rstat = _bfd_relocate_contents (r->howto, abfd, |
(bfd_vma) link_order->u.reloc.p->addend, |
buf); |
switch (rstat) |
{ |
case bfd_reloc_ok: |
break; |
default: |
case bfd_reloc_outofrange: |
abort (); |
case bfd_reloc_overflow: |
if (! ((*info->callbacks->reloc_overflow) |
(info, NULL, |
(link_order->type == bfd_section_reloc_link_order |
? bfd_section_name (abfd, link_order->u.reloc.p->u.section) |
: link_order->u.reloc.p->u.name), |
r->howto->name, link_order->u.reloc.p->addend, |
NULL, NULL, 0))) |
{ |
free (buf); |
return FALSE; |
} |
break; |
} |
loc = link_order->offset * bfd_octets_per_byte (abfd); |
ok = bfd_set_section_contents (abfd, sec, buf, loc, size); |
free (buf); |
if (! ok) |
return FALSE; |
r->addend = 0; |
} |
sec->orelocation[sec->reloc_count] = r; |
++sec->reloc_count; |
return TRUE; |
} |
/* Allocate a new link_order for a section. */ |
struct bfd_link_order * |
bfd_new_link_order (bfd *abfd, asection *section) |
{ |
bfd_size_type amt = sizeof (struct bfd_link_order); |
struct bfd_link_order *new_lo; |
new_lo = (struct bfd_link_order *) bfd_zalloc (abfd, amt); |
if (!new_lo) |
return NULL; |
new_lo->type = bfd_undefined_link_order; |
if (section->map_tail.link_order != NULL) |
section->map_tail.link_order->next = new_lo; |
else |
section->map_head.link_order = new_lo; |
section->map_tail.link_order = new_lo; |
return new_lo; |
} |
/* Default link order processing routine. Note that we can not handle |
the reloc_link_order types here, since they depend upon the details |
of how the particular backends generates relocs. */ |
bfd_boolean |
_bfd_default_link_order (bfd *abfd, |
struct bfd_link_info *info, |
asection *sec, |
struct bfd_link_order *link_order) |
{ |
switch (link_order->type) |
{ |
case bfd_undefined_link_order: |
case bfd_section_reloc_link_order: |
case bfd_symbol_reloc_link_order: |
default: |
abort (); |
case bfd_indirect_link_order: |
return default_indirect_link_order (abfd, info, sec, link_order, |
FALSE); |
case bfd_data_link_order: |
return default_data_link_order (abfd, info, sec, link_order); |
} |
} |
/* Default routine to handle a bfd_data_link_order. */ |
static bfd_boolean |
default_data_link_order (bfd *abfd, |
struct bfd_link_info *info ATTRIBUTE_UNUSED, |
asection *sec, |
struct bfd_link_order *link_order) |
{ |
bfd_size_type size; |
size_t fill_size; |
bfd_byte *fill; |
file_ptr loc; |
bfd_boolean result; |
BFD_ASSERT ((sec->flags & SEC_HAS_CONTENTS) != 0); |
size = link_order->size; |
if (size == 0) |
return TRUE; |
fill = link_order->u.data.contents; |
fill_size = link_order->u.data.size; |
if (fill_size == 0) |
{ |
fill = abfd->arch_info->fill (size, bfd_big_endian (abfd), |
(sec->flags & SEC_CODE) != 0); |
if (fill == NULL) |
return FALSE; |
} |
else if (fill_size < size) |
{ |
bfd_byte *p; |
fill = (bfd_byte *) bfd_malloc (size); |
if (fill == NULL) |
return FALSE; |
p = fill; |
if (fill_size == 1) |
memset (p, (int) link_order->u.data.contents[0], (size_t) size); |
else |
{ |
do |
{ |
memcpy (p, link_order->u.data.contents, fill_size); |
p += fill_size; |
size -= fill_size; |
} |
while (size >= fill_size); |
if (size != 0) |
memcpy (p, link_order->u.data.contents, (size_t) size); |
size = link_order->size; |
} |
} |
loc = link_order->offset * bfd_octets_per_byte (abfd); |
result = bfd_set_section_contents (abfd, sec, fill, loc, size); |
if (fill != link_order->u.data.contents) |
free (fill); |
return result; |
} |
/* Default routine to handle a bfd_indirect_link_order. */ |
static bfd_boolean |
default_indirect_link_order (bfd *output_bfd, |
struct bfd_link_info *info, |
asection *output_section, |
struct bfd_link_order *link_order, |
bfd_boolean generic_linker) |
{ |
asection *input_section; |
bfd *input_bfd; |
bfd_byte *contents = NULL; |
bfd_byte *new_contents; |
bfd_size_type sec_size; |
file_ptr loc; |
BFD_ASSERT ((output_section->flags & SEC_HAS_CONTENTS) != 0); |
input_section = link_order->u.indirect.section; |
input_bfd = input_section->owner; |
if (input_section->size == 0) |
return TRUE; |
BFD_ASSERT (input_section->output_section == output_section); |
BFD_ASSERT (input_section->output_offset == link_order->offset); |
BFD_ASSERT (input_section->size == link_order->size); |
if (info->relocatable |
&& input_section->reloc_count > 0 |
&& output_section->orelocation == NULL) |
{ |
/* Space has not been allocated for the output relocations. |
This can happen when we are called by a specific backend |
because somebody is attempting to link together different |
types of object files. Handling this case correctly is |
difficult, and sometimes impossible. */ |
(*_bfd_error_handler) |
(_("Attempt to do relocatable link with %s input and %s output"), |
bfd_get_target (input_bfd), bfd_get_target (output_bfd)); |
bfd_set_error (bfd_error_wrong_format); |
return FALSE; |
} |
if (! generic_linker) |
{ |
asymbol **sympp; |
asymbol **symppend; |
/* Get the canonical symbols. The generic linker will always |
have retrieved them by this point, but we are being called by |
a specific linker, presumably because we are linking |
different types of object files together. */ |
if (!bfd_generic_link_read_symbols (input_bfd)) |
return FALSE; |
/* Since we have been called by a specific linker, rather than |
the generic linker, the values of the symbols will not be |
right. They will be the values as seen in the input file, |
not the values of the final link. We need to fix them up |
before we can relocate the section. */ |
sympp = _bfd_generic_link_get_symbols (input_bfd); |
symppend = sympp + _bfd_generic_link_get_symcount (input_bfd); |
for (; sympp < symppend; sympp++) |
{ |
asymbol *sym; |
struct bfd_link_hash_entry *h; |
sym = *sympp; |
if ((sym->flags & (BSF_INDIRECT |
| BSF_WARNING |
| BSF_GLOBAL |
| BSF_CONSTRUCTOR |
| BSF_WEAK)) != 0 |
|| bfd_is_und_section (bfd_get_section (sym)) |
|| bfd_is_com_section (bfd_get_section (sym)) |
|| bfd_is_ind_section (bfd_get_section (sym))) |
{ |
/* sym->udata may have been set by |
generic_link_add_symbol_list. */ |
if (sym->udata.p != NULL) |
h = (struct bfd_link_hash_entry *) sym->udata.p; |
else if (bfd_is_und_section (bfd_get_section (sym))) |
h = bfd_wrapped_link_hash_lookup (output_bfd, info, |
bfd_asymbol_name (sym), |
FALSE, FALSE, TRUE); |
else |
h = bfd_link_hash_lookup (info->hash, |
bfd_asymbol_name (sym), |
FALSE, FALSE, TRUE); |
if (h != NULL) |
set_symbol_from_hash (sym, h); |
} |
} |
} |
if ((output_section->flags & (SEC_GROUP | SEC_LINKER_CREATED)) == SEC_GROUP |
&& input_section->size != 0) |
{ |
/* Group section contents are set by bfd_elf_set_group_contents. */ |
if (!output_bfd->output_has_begun) |
{ |
/* FIXME: This hack ensures bfd_elf_set_group_contents is called. */ |
if (!bfd_set_section_contents (output_bfd, output_section, "", 0, 1)) |
goto error_return; |
} |
new_contents = output_section->contents; |
BFD_ASSERT (new_contents != NULL); |
BFD_ASSERT (input_section->output_offset == 0); |
} |
else |
{ |
/* Get and relocate the section contents. */ |
sec_size = (input_section->rawsize > input_section->size |
? input_section->rawsize |
: input_section->size); |
contents = (bfd_byte *) bfd_malloc (sec_size); |
if (contents == NULL && sec_size != 0) |
goto error_return; |
new_contents = (bfd_get_relocated_section_contents |
(output_bfd, info, link_order, contents, |
info->relocatable, |
_bfd_generic_link_get_symbols (input_bfd))); |
if (!new_contents) |
goto error_return; |
} |
/* Output the section contents. */ |
loc = input_section->output_offset * bfd_octets_per_byte (output_bfd); |
if (! bfd_set_section_contents (output_bfd, output_section, |
new_contents, loc, input_section->size)) |
goto error_return; |
if (contents != NULL) |
free (contents); |
return TRUE; |
error_return: |
if (contents != NULL) |
free (contents); |
return FALSE; |
} |
/* A little routine to count the number of relocs in a link_order |
list. */ |
unsigned int |
_bfd_count_link_order_relocs (struct bfd_link_order *link_order) |
{ |
register unsigned int c; |
register struct bfd_link_order *l; |
c = 0; |
for (l = link_order; l != NULL; l = l->next) |
{ |
if (l->type == bfd_section_reloc_link_order |
|| l->type == bfd_symbol_reloc_link_order) |
++c; |
} |
return c; |
} |
/* |
FUNCTION |
bfd_link_split_section |
SYNOPSIS |
bfd_boolean bfd_link_split_section (bfd *abfd, asection *sec); |
DESCRIPTION |
Return nonzero if @var{sec} should be split during a |
reloceatable or final link. |
.#define bfd_link_split_section(abfd, sec) \ |
. BFD_SEND (abfd, _bfd_link_split_section, (abfd, sec)) |
. |
*/ |
bfd_boolean |
_bfd_generic_link_split_section (bfd *abfd ATTRIBUTE_UNUSED, |
asection *sec ATTRIBUTE_UNUSED) |
{ |
return FALSE; |
} |
/* |
FUNCTION |
bfd_section_already_linked |
SYNOPSIS |
bfd_boolean bfd_section_already_linked (bfd *abfd, |
asection *sec, |
struct bfd_link_info *info); |
DESCRIPTION |
Check if @var{data} has been already linked during a reloceatable |
or final link. Return TRUE if it has. |
.#define bfd_section_already_linked(abfd, sec, info) \ |
. BFD_SEND (abfd, _section_already_linked, (abfd, sec, info)) |
. |
*/ |
/* Sections marked with the SEC_LINK_ONCE flag should only be linked |
once into the output. This routine checks each section, and |
arrange to discard it if a section of the same name has already |
been linked. This code assumes that all relevant sections have the |
SEC_LINK_ONCE flag set; that is, it does not depend solely upon the |
section name. bfd_section_already_linked is called via |
bfd_map_over_sections. */ |
/* The hash table. */ |
static struct bfd_hash_table _bfd_section_already_linked_table; |
/* Support routines for the hash table used by section_already_linked, |
initialize the table, traverse, lookup, fill in an entry and remove |
the table. */ |
void |
bfd_section_already_linked_table_traverse |
(bfd_boolean (*func) (struct bfd_section_already_linked_hash_entry *, |
void *), void *info) |
{ |
bfd_hash_traverse (&_bfd_section_already_linked_table, |
(bfd_boolean (*) (struct bfd_hash_entry *, |
void *)) func, |
info); |
} |
struct bfd_section_already_linked_hash_entry * |
bfd_section_already_linked_table_lookup (const char *name) |
{ |
return ((struct bfd_section_already_linked_hash_entry *) |
bfd_hash_lookup (&_bfd_section_already_linked_table, name, |
TRUE, FALSE)); |
} |
bfd_boolean |
bfd_section_already_linked_table_insert |
(struct bfd_section_already_linked_hash_entry *already_linked_list, |
asection *sec) |
{ |
struct bfd_section_already_linked *l; |
/* Allocate the memory from the same obstack as the hash table is |
kept in. */ |
l = (struct bfd_section_already_linked *) |
bfd_hash_allocate (&_bfd_section_already_linked_table, sizeof *l); |
if (l == NULL) |
return FALSE; |
l->sec = sec; |
l->next = already_linked_list->entry; |
already_linked_list->entry = l; |
return TRUE; |
} |
static struct bfd_hash_entry * |
already_linked_newfunc (struct bfd_hash_entry *entry ATTRIBUTE_UNUSED, |
struct bfd_hash_table *table, |
const char *string ATTRIBUTE_UNUSED) |
{ |
struct bfd_section_already_linked_hash_entry *ret = |
(struct bfd_section_already_linked_hash_entry *) |
bfd_hash_allocate (table, sizeof *ret); |
if (ret == NULL) |
return NULL; |
ret->entry = NULL; |
return &ret->root; |
} |
bfd_boolean |
bfd_section_already_linked_table_init (void) |
{ |
return bfd_hash_table_init_n (&_bfd_section_already_linked_table, |
already_linked_newfunc, |
sizeof (struct bfd_section_already_linked_hash_entry), |
42); |
} |
void |
bfd_section_already_linked_table_free (void) |
{ |
bfd_hash_table_free (&_bfd_section_already_linked_table); |
} |
/* Report warnings as appropriate for duplicate section SEC. |
Return FALSE if we decide to keep SEC after all. */ |
bfd_boolean |
_bfd_handle_already_linked (asection *sec, |
struct bfd_section_already_linked *l, |
struct bfd_link_info *info) |
{ |
switch (sec->flags & SEC_LINK_DUPLICATES) |
{ |
default: |
abort (); |
case SEC_LINK_DUPLICATES_DISCARD: |
/* If we found an LTO IR match for this comdat group on |
the first pass, replace it with the LTO output on the |
second pass. We can't simply choose real object |
files over IR because the first pass may contain a |
mix of LTO and normal objects and we must keep the |
first match, be it IR or real. */ |
if (info->loading_lto_outputs |
&& (l->sec->owner->flags & BFD_PLUGIN) != 0) |
{ |
l->sec = sec; |
return FALSE; |
} |
break; |
case SEC_LINK_DUPLICATES_ONE_ONLY: |
info->callbacks->einfo |
(_("%B: ignoring duplicate section `%A'\n"), |
sec->owner, sec); |
break; |
case SEC_LINK_DUPLICATES_SAME_SIZE: |
if ((l->sec->owner->flags & BFD_PLUGIN) != 0) |
; |
else if (sec->size != l->sec->size) |
info->callbacks->einfo |
(_("%B: duplicate section `%A' has different size\n"), |
sec->owner, sec); |
break; |
case SEC_LINK_DUPLICATES_SAME_CONTENTS: |
if ((l->sec->owner->flags & BFD_PLUGIN) != 0) |
; |
else if (sec->size != l->sec->size) |
info->callbacks->einfo |
(_("%B: duplicate section `%A' has different size\n"), |
sec->owner, sec); |
else if (sec->size != 0) |
{ |
bfd_byte *sec_contents, *l_sec_contents = NULL; |
if (!bfd_malloc_and_get_section (sec->owner, sec, &sec_contents)) |
info->callbacks->einfo |
(_("%B: could not read contents of section `%A'\n"), |
sec->owner, sec); |
else if (!bfd_malloc_and_get_section (l->sec->owner, l->sec, |
&l_sec_contents)) |
info->callbacks->einfo |
(_("%B: could not read contents of section `%A'\n"), |
l->sec->owner, l->sec); |
else if (memcmp (sec_contents, l_sec_contents, sec->size) != 0) |
info->callbacks->einfo |
(_("%B: duplicate section `%A' has different contents\n"), |
sec->owner, sec); |
if (sec_contents) |
free (sec_contents); |
if (l_sec_contents) |
free (l_sec_contents); |
} |
break; |
} |
/* Set the output_section field so that lang_add_section |
does not create a lang_input_section structure for this |
section. Since there might be a symbol in the section |
being discarded, we must retain a pointer to the section |
which we are really going to use. */ |
sec->output_section = bfd_abs_section_ptr; |
sec->kept_section = l->sec; |
return TRUE; |
} |
/* This is used on non-ELF inputs. */ |
bfd_boolean |
_bfd_generic_section_already_linked (bfd *abfd ATTRIBUTE_UNUSED, |
asection *sec, |
struct bfd_link_info *info) |
{ |
const char *name; |
struct bfd_section_already_linked *l; |
struct bfd_section_already_linked_hash_entry *already_linked_list; |
if ((sec->flags & SEC_LINK_ONCE) == 0) |
return FALSE; |
/* The generic linker doesn't handle section groups. */ |
if ((sec->flags & SEC_GROUP) != 0) |
return FALSE; |
/* FIXME: When doing a relocatable link, we may have trouble |
copying relocations in other sections that refer to local symbols |
in the section being discarded. Those relocations will have to |
be converted somehow; as of this writing I'm not sure that any of |
the backends handle that correctly. |
It is tempting to instead not discard link once sections when |
doing a relocatable link (technically, they should be discarded |
whenever we are building constructors). However, that fails, |
because the linker winds up combining all the link once sections |
into a single large link once section, which defeats the purpose |
of having link once sections in the first place. */ |
name = bfd_get_section_name (abfd, sec); |
already_linked_list = bfd_section_already_linked_table_lookup (name); |
l = already_linked_list->entry; |
if (l != NULL) |
{ |
/* The section has already been linked. See if we should |
issue a warning. */ |
return _bfd_handle_already_linked (sec, l, info); |
} |
/* This is the first section with this name. Record it. */ |
if (!bfd_section_already_linked_table_insert (already_linked_list, sec)) |
info->callbacks->einfo (_("%F%P: already_linked_table: %E\n")); |
return FALSE; |
} |
/* Choose a neighbouring section to S in OBFD that will be output, or |
the absolute section if ADDR is out of bounds of the neighbours. */ |
asection * |
_bfd_nearby_section (bfd *obfd, asection *s, bfd_vma addr) |
{ |
asection *next, *prev, *best; |
/* Find preceding kept section. */ |
for (prev = s->prev; prev != NULL; prev = prev->prev) |
if ((prev->flags & SEC_EXCLUDE) == 0 |
&& !bfd_section_removed_from_list (obfd, prev)) |
break; |
/* Find following kept section. Start at prev->next because |
other sections may have been added after S was removed. */ |
if (s->prev != NULL) |
next = s->prev->next; |
else |
next = s->owner->sections; |
for (; next != NULL; next = next->next) |
if ((next->flags & SEC_EXCLUDE) == 0 |
&& !bfd_section_removed_from_list (obfd, next)) |
break; |
/* Choose better of two sections, based on flags. The idea |
is to choose a section that will be in the same segment |
as S would have been if it was kept. */ |
best = next; |
if (prev == NULL) |
{ |
if (next == NULL) |
best = bfd_abs_section_ptr; |
} |
else if (next == NULL) |
best = prev; |
else if (((prev->flags ^ next->flags) |
& (SEC_ALLOC | SEC_THREAD_LOCAL | SEC_LOAD)) != 0) |
{ |
if (((next->flags ^ s->flags) |
& (SEC_ALLOC | SEC_THREAD_LOCAL)) != 0 |
/* We prefer to choose a loaded section. Section S |
doesn't have SEC_LOAD set (it being excluded, that |
part of the flag processing didn't happen) so we |
can't compare that flag to those of NEXT and PREV. */ |
|| ((prev->flags & SEC_LOAD) != 0 |
&& (next->flags & SEC_LOAD) == 0)) |
best = prev; |
} |
else if (((prev->flags ^ next->flags) & SEC_READONLY) != 0) |
{ |
if (((next->flags ^ s->flags) & SEC_READONLY) != 0) |
best = prev; |
} |
else if (((prev->flags ^ next->flags) & SEC_CODE) != 0) |
{ |
if (((next->flags ^ s->flags) & SEC_CODE) != 0) |
best = prev; |
} |
else |
{ |
/* Flags we care about are the same. Prefer the following |
section if that will result in a positive valued sym. */ |
if (addr < next->vma) |
best = prev; |
} |
return best; |
} |
/* Convert symbols in excluded output sections to use a kept section. */ |
static bfd_boolean |
fix_syms (struct bfd_link_hash_entry *h, void *data) |
{ |
bfd *obfd = (bfd *) data; |
if (h->type == bfd_link_hash_defined |
|| h->type == bfd_link_hash_defweak) |
{ |
asection *s = h->u.def.section; |
if (s != NULL |
&& s->output_section != NULL |
&& (s->output_section->flags & SEC_EXCLUDE) != 0 |
&& bfd_section_removed_from_list (obfd, s->output_section)) |
{ |
asection *op; |
h->u.def.value += s->output_offset + s->output_section->vma; |
op = _bfd_nearby_section (obfd, s->output_section, h->u.def.value); |
h->u.def.value -= op->vma; |
h->u.def.section = op; |
} |
} |
return TRUE; |
} |
void |
_bfd_fix_excluded_sec_syms (bfd *obfd, struct bfd_link_info *info) |
{ |
bfd_link_hash_traverse (info->hash, fix_syms, obfd); |
} |
/* |
FUNCTION |
bfd_generic_define_common_symbol |
SYNOPSIS |
bfd_boolean bfd_generic_define_common_symbol |
(bfd *output_bfd, struct bfd_link_info *info, |
struct bfd_link_hash_entry *h); |
DESCRIPTION |
Convert common symbol @var{h} into a defined symbol. |
Return TRUE on success and FALSE on failure. |
.#define bfd_define_common_symbol(output_bfd, info, h) \ |
. BFD_SEND (output_bfd, _bfd_define_common_symbol, (output_bfd, info, h)) |
. |
*/ |
bfd_boolean |
bfd_generic_define_common_symbol (bfd *output_bfd, |
struct bfd_link_info *info ATTRIBUTE_UNUSED, |
struct bfd_link_hash_entry *h) |
{ |
unsigned int power_of_two; |
bfd_vma alignment, size; |
asection *section; |
BFD_ASSERT (h != NULL && h->type == bfd_link_hash_common); |
size = h->u.c.size; |
power_of_two = h->u.c.p->alignment_power; |
section = h->u.c.p->section; |
/* Increase the size of the section to align the common symbol. |
The alignment must be a power of two. */ |
alignment = bfd_octets_per_byte (output_bfd) << power_of_two; |
BFD_ASSERT (alignment != 0 && (alignment & -alignment) == alignment); |
section->size += alignment - 1; |
section->size &= -alignment; |
/* Adjust the section's overall alignment if necessary. */ |
if (power_of_two > section->alignment_power) |
section->alignment_power = power_of_two; |
/* Change the symbol from common to defined. */ |
h->type = bfd_link_hash_defined; |
h->u.def.section = section; |
h->u.def.value = section->size; |
/* Increase the size of the section. */ |
section->size += size; |
/* Make sure the section is allocated in memory, and make sure that |
it is no longer a common section. */ |
section->flags |= SEC_ALLOC; |
section->flags &= ~SEC_IS_COMMON; |
return TRUE; |
} |
/* |
FUNCTION |
bfd_find_version_for_sym |
SYNOPSIS |
struct bfd_elf_version_tree * bfd_find_version_for_sym |
(struct bfd_elf_version_tree *verdefs, |
const char *sym_name, bfd_boolean *hide); |
DESCRIPTION |
Search an elf version script tree for symbol versioning |
info and export / don't-export status for a given symbol. |
Return non-NULL on success and NULL on failure; also sets |
the output @samp{hide} boolean parameter. |
*/ |
struct bfd_elf_version_tree * |
bfd_find_version_for_sym (struct bfd_elf_version_tree *verdefs, |
const char *sym_name, |
bfd_boolean *hide) |
{ |
struct bfd_elf_version_tree *t; |
struct bfd_elf_version_tree *local_ver, *global_ver, *exist_ver; |
struct bfd_elf_version_tree *star_local_ver, *star_global_ver; |
local_ver = NULL; |
global_ver = NULL; |
star_local_ver = NULL; |
star_global_ver = NULL; |
exist_ver = NULL; |
for (t = verdefs; t != NULL; t = t->next) |
{ |
if (t->globals.list != NULL) |
{ |
struct bfd_elf_version_expr *d = NULL; |
while ((d = (*t->match) (&t->globals, d, sym_name)) != NULL) |
{ |
if (d->literal || strcmp (d->pattern, "*") != 0) |
global_ver = t; |
else |
star_global_ver = t; |
if (d->symver) |
exist_ver = t; |
d->script = 1; |
/* If the match is a wildcard pattern, keep looking for |
a more explicit, perhaps even local, match. */ |
if (d->literal) |
break; |
} |
if (d != NULL) |
break; |
} |
if (t->locals.list != NULL) |
{ |
struct bfd_elf_version_expr *d = NULL; |
while ((d = (*t->match) (&t->locals, d, sym_name)) != NULL) |
{ |
if (d->literal || strcmp (d->pattern, "*") != 0) |
local_ver = t; |
else |
star_local_ver = t; |
/* If the match is a wildcard pattern, keep looking for |
a more explicit, perhaps even global, match. */ |
if (d->literal) |
{ |
/* An exact match overrides a global wildcard. */ |
global_ver = NULL; |
star_global_ver = NULL; |
break; |
} |
} |
if (d != NULL) |
break; |
} |
} |
if (global_ver == NULL && local_ver == NULL) |
global_ver = star_global_ver; |
if (global_ver != NULL) |
{ |
/* If we already have a versioned symbol that matches the |
node for this symbol, then we don't want to create a |
duplicate from the unversioned symbol. Instead hide the |
unversioned symbol. */ |
*hide = exist_ver == global_ver; |
return global_ver; |
} |
if (local_ver == NULL) |
local_ver = star_local_ver; |
if (local_ver != NULL) |
{ |
*hide = TRUE; |
return local_ver; |
} |
return NULL; |
} |
/* |
FUNCTION |
bfd_hide_sym_by_version |
SYNOPSIS |
bfd_boolean bfd_hide_sym_by_version |
(struct bfd_elf_version_tree *verdefs, const char *sym_name); |
DESCRIPTION |
Search an elf version script tree for symbol versioning |
info for a given symbol. Return TRUE if the symbol is hidden. |
*/ |
bfd_boolean |
bfd_hide_sym_by_version (struct bfd_elf_version_tree *verdefs, |
const char *sym_name) |
{ |
bfd_boolean hidden = FALSE; |
bfd_find_version_for_sym (verdefs, sym_name, &hidden); |
return hidden; |
} |
/contrib/toolchain/binutils/bfd/merge.c |
---|
0,0 → 1,901 |
/* SEC_MERGE support. |
Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 |
Free Software Foundation, Inc. |
Written by Jakub Jelinek <jakub@redhat.com>. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* This file contains support for merging duplicate entities within sections, |
as used in ELF SHF_MERGE. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
#include "hashtab.h" |
#include "libiberty.h" |
struct sec_merge_sec_info; |
/* An entry in the section merge hash table. */ |
struct sec_merge_hash_entry |
{ |
struct bfd_hash_entry root; |
/* Length of this entry. This includes the zero terminator. */ |
unsigned int len; |
/* Start of this string needs to be aligned to |
alignment octets (not 1 << align). */ |
unsigned int alignment; |
union |
{ |
/* Index within the merged section. */ |
bfd_size_type index; |
/* Entry this is a suffix of (if alignment is 0). */ |
struct sec_merge_hash_entry *suffix; |
} u; |
/* Which section is it in. */ |
struct sec_merge_sec_info *secinfo; |
/* Next entity in the hash table. */ |
struct sec_merge_hash_entry *next; |
}; |
/* The section merge hash table. */ |
struct sec_merge_hash |
{ |
struct bfd_hash_table table; |
/* Next available index. */ |
bfd_size_type size; |
/* First entity in the SEC_MERGE sections of this type. */ |
struct sec_merge_hash_entry *first; |
/* Last entity in the SEC_MERGE sections of this type. */ |
struct sec_merge_hash_entry *last; |
/* Entity size. */ |
unsigned int entsize; |
/* Are entries fixed size or zero terminated strings? */ |
bfd_boolean strings; |
}; |
struct sec_merge_info |
{ |
/* Chain of sec_merge_infos. */ |
struct sec_merge_info *next; |
/* Chain of sec_merge_sec_infos. */ |
struct sec_merge_sec_info *chain; |
/* A hash table used to hold section content. */ |
struct sec_merge_hash *htab; |
}; |
struct sec_merge_sec_info |
{ |
/* Chain of sec_merge_sec_infos. */ |
struct sec_merge_sec_info *next; |
/* The corresponding section. */ |
asection *sec; |
/* Pointer to merge_info pointing to us. */ |
void **psecinfo; |
/* A hash table used to hold section content. */ |
struct sec_merge_hash *htab; |
/* First string in this section. */ |
struct sec_merge_hash_entry *first_str; |
/* Original section content. */ |
unsigned char contents[1]; |
}; |
/* Routine to create an entry in a section merge hashtab. */ |
static struct bfd_hash_entry * |
sec_merge_hash_newfunc (struct bfd_hash_entry *entry, |
struct bfd_hash_table *table, const char *string) |
{ |
/* Allocate the structure if it has not already been allocated by a |
subclass. */ |
if (entry == NULL) |
entry = (struct bfd_hash_entry *) |
bfd_hash_allocate (table, sizeof (struct sec_merge_hash_entry)); |
if (entry == NULL) |
return NULL; |
/* Call the allocation method of the superclass. */ |
entry = bfd_hash_newfunc (entry, table, string); |
if (entry != NULL) |
{ |
/* Initialize the local fields. */ |
struct sec_merge_hash_entry *ret = (struct sec_merge_hash_entry *) entry; |
ret->u.suffix = NULL; |
ret->alignment = 0; |
ret->secinfo = NULL; |
ret->next = NULL; |
} |
return entry; |
} |
/* Look up an entry in a section merge hash table. */ |
static struct sec_merge_hash_entry * |
sec_merge_hash_lookup (struct sec_merge_hash *table, const char *string, |
unsigned int alignment, bfd_boolean create) |
{ |
const unsigned char *s; |
unsigned long hash; |
unsigned int c; |
struct sec_merge_hash_entry *hashp; |
unsigned int len, i; |
unsigned int _index; |
hash = 0; |
len = 0; |
s = (const unsigned char *) string; |
if (table->strings) |
{ |
if (table->entsize == 1) |
{ |
while ((c = *s++) != '\0') |
{ |
hash += c + (c << 17); |
hash ^= hash >> 2; |
++len; |
} |
hash += len + (len << 17); |
} |
else |
{ |
for (;;) |
{ |
for (i = 0; i < table->entsize; ++i) |
if (s[i] != '\0') |
break; |
if (i == table->entsize) |
break; |
for (i = 0; i < table->entsize; ++i) |
{ |
c = *s++; |
hash += c + (c << 17); |
hash ^= hash >> 2; |
} |
++len; |
} |
hash += len + (len << 17); |
len *= table->entsize; |
} |
hash ^= hash >> 2; |
len += table->entsize; |
} |
else |
{ |
for (i = 0; i < table->entsize; ++i) |
{ |
c = *s++; |
hash += c + (c << 17); |
hash ^= hash >> 2; |
} |
len = table->entsize; |
} |
_index = hash % table->table.size; |
for (hashp = (struct sec_merge_hash_entry *) table->table.table[_index]; |
hashp != NULL; |
hashp = (struct sec_merge_hash_entry *) hashp->root.next) |
{ |
if (hashp->root.hash == hash |
&& len == hashp->len |
&& memcmp (hashp->root.string, string, len) == 0) |
{ |
/* If the string we found does not have at least the required |
alignment, we need to insert another copy. */ |
if (hashp->alignment < alignment) |
{ |
if (create) |
{ |
/* Mark the less aligned copy as deleted. */ |
hashp->len = 0; |
hashp->alignment = 0; |
} |
break; |
} |
return hashp; |
} |
} |
if (! create) |
return NULL; |
hashp = ((struct sec_merge_hash_entry *) |
bfd_hash_insert (&table->table, string, hash)); |
if (hashp == NULL) |
return NULL; |
hashp->len = len; |
hashp->alignment = alignment; |
return hashp; |
} |
/* Create a new hash table. */ |
static struct sec_merge_hash * |
sec_merge_init (unsigned int entsize, bfd_boolean strings) |
{ |
struct sec_merge_hash *table; |
table = (struct sec_merge_hash *) bfd_malloc (sizeof (struct sec_merge_hash)); |
if (table == NULL) |
return NULL; |
if (! bfd_hash_table_init_n (&table->table, sec_merge_hash_newfunc, |
sizeof (struct sec_merge_hash_entry), 16699)) |
{ |
free (table); |
return NULL; |
} |
table->size = 0; |
table->first = NULL; |
table->last = NULL; |
table->entsize = entsize; |
table->strings = strings; |
return table; |
} |
/* Get the index of an entity in a hash table, adding it if it is not |
already present. */ |
static struct sec_merge_hash_entry * |
sec_merge_add (struct sec_merge_hash *tab, const char *str, |
unsigned int alignment, struct sec_merge_sec_info *secinfo) |
{ |
struct sec_merge_hash_entry *entry; |
entry = sec_merge_hash_lookup (tab, str, alignment, TRUE); |
if (entry == NULL) |
return NULL; |
if (entry->secinfo == NULL) |
{ |
tab->size++; |
entry->secinfo = secinfo; |
if (tab->first == NULL) |
tab->first = entry; |
else |
tab->last->next = entry; |
tab->last = entry; |
} |
return entry; |
} |
static bfd_boolean |
sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry) |
{ |
struct sec_merge_sec_info *secinfo = entry->secinfo; |
asection *sec = secinfo->sec; |
char *pad = NULL; |
bfd_size_type off = 0; |
int alignment_power = sec->output_section->alignment_power; |
if (alignment_power) |
{ |
pad = (char *) bfd_zmalloc ((bfd_size_type) 1 << alignment_power); |
if (pad == NULL) |
return FALSE; |
} |
for (; entry != NULL && entry->secinfo == secinfo; entry = entry->next) |
{ |
const char *str; |
bfd_size_type len; |
len = -off & (entry->alignment - 1); |
if (len != 0) |
{ |
if (bfd_bwrite (pad, len, abfd) != len) |
goto err; |
off += len; |
} |
str = entry->root.string; |
len = entry->len; |
if (bfd_bwrite (str, len, abfd) != len) |
goto err; |
off += len; |
} |
/* Trailing alignment needed? */ |
off = sec->size - off; |
if (off != 0 |
&& bfd_bwrite (pad, off, abfd) != off) |
goto err; |
if (pad != NULL) |
free (pad); |
return TRUE; |
err: |
if (pad != NULL) |
free (pad); |
return FALSE; |
} |
/* Register a SEC_MERGE section as a candidate for merging. |
This function is called for all non-dynamic SEC_MERGE input sections. */ |
bfd_boolean |
_bfd_add_merge_section (bfd *abfd, void **psinfo, asection *sec, |
void **psecinfo) |
{ |
struct sec_merge_info *sinfo; |
struct sec_merge_sec_info *secinfo; |
unsigned int align; |
bfd_size_type amt; |
bfd_byte *contents; |
if ((abfd->flags & DYNAMIC) != 0 |
|| (sec->flags & SEC_MERGE) == 0) |
abort (); |
if (sec->size == 0 |
|| (sec->flags & SEC_EXCLUDE) != 0 |
|| sec->entsize == 0) |
return TRUE; |
if ((sec->flags & SEC_RELOC) != 0) |
{ |
/* We aren't prepared to handle relocations in merged sections. */ |
return TRUE; |
} |
align = sec->alignment_power; |
if ((sec->entsize < (unsigned) 1 << align |
&& ((sec->entsize & (sec->entsize - 1)) |
|| !(sec->flags & SEC_STRINGS))) |
|| (sec->entsize > (unsigned) 1 << align |
&& (sec->entsize & (((unsigned) 1 << align) - 1)))) |
{ |
/* Sanity check. If string character size is smaller than |
alignment, then we require character size to be a power |
of 2, otherwise character size must be integer multiple |
of alignment. For non-string constants, alignment must |
be smaller than or equal to entity size and entity size |
must be integer multiple of alignment. */ |
return TRUE; |
} |
for (sinfo = (struct sec_merge_info *) *psinfo; sinfo; sinfo = sinfo->next) |
if ((secinfo = sinfo->chain) |
&& ! ((secinfo->sec->flags ^ sec->flags) & (SEC_MERGE | SEC_STRINGS)) |
&& secinfo->sec->entsize == sec->entsize |
&& secinfo->sec->alignment_power == sec->alignment_power |
&& secinfo->sec->output_section == sec->output_section) |
break; |
if (sinfo == NULL) |
{ |
/* Initialize the information we need to keep track of. */ |
sinfo = (struct sec_merge_info *) |
bfd_alloc (abfd, sizeof (struct sec_merge_info)); |
if (sinfo == NULL) |
goto error_return; |
sinfo->next = (struct sec_merge_info *) *psinfo; |
sinfo->chain = NULL; |
*psinfo = sinfo; |
sinfo->htab = sec_merge_init (sec->entsize, (sec->flags & SEC_STRINGS)); |
if (sinfo->htab == NULL) |
goto error_return; |
} |
/* Read the section from abfd. */ |
amt = sizeof (struct sec_merge_sec_info) - 1 + sec->size; |
if (sec->flags & SEC_STRINGS) |
/* Some versions of gcc may emit a string without a zero terminator. |
See http://gcc.gnu.org/ml/gcc-patches/2006-06/msg01004.html |
Allocate space for an extra zero. */ |
amt += sec->entsize; |
*psecinfo = bfd_alloc (abfd, amt); |
if (*psecinfo == NULL) |
goto error_return; |
secinfo = (struct sec_merge_sec_info *) *psecinfo; |
if (sinfo->chain) |
{ |
secinfo->next = sinfo->chain->next; |
sinfo->chain->next = secinfo; |
} |
else |
secinfo->next = secinfo; |
sinfo->chain = secinfo; |
secinfo->sec = sec; |
secinfo->psecinfo = psecinfo; |
secinfo->htab = sinfo->htab; |
secinfo->first_str = NULL; |
sec->rawsize = sec->size; |
if (sec->flags & SEC_STRINGS) |
memset (secinfo->contents + sec->size, 0, sec->entsize); |
contents = secinfo->contents; |
if (! bfd_get_full_section_contents (sec->owner, sec, &contents)) |
goto error_return; |
return TRUE; |
error_return: |
*psecinfo = NULL; |
return FALSE; |
} |
/* Record one section into the hash table. */ |
static bfd_boolean |
record_section (struct sec_merge_info *sinfo, |
struct sec_merge_sec_info *secinfo) |
{ |
asection *sec = secinfo->sec; |
struct sec_merge_hash_entry *entry; |
bfd_boolean nul; |
unsigned char *p, *end; |
bfd_vma mask, eltalign; |
unsigned int align, i; |
align = sec->alignment_power; |
end = secinfo->contents + sec->size; |
nul = FALSE; |
mask = ((bfd_vma) 1 << align) - 1; |
if (sec->flags & SEC_STRINGS) |
{ |
for (p = secinfo->contents; p < end; ) |
{ |
eltalign = p - secinfo->contents; |
eltalign = ((eltalign ^ (eltalign - 1)) + 1) >> 1; |
if (!eltalign || eltalign > mask) |
eltalign = mask + 1; |
entry = sec_merge_add (sinfo->htab, (char *) p, (unsigned) eltalign, |
secinfo); |
if (! entry) |
goto error_return; |
p += entry->len; |
if (sec->entsize == 1) |
{ |
while (p < end && *p == 0) |
{ |
if (!nul && !((p - secinfo->contents) & mask)) |
{ |
nul = TRUE; |
entry = sec_merge_add (sinfo->htab, "", |
(unsigned) mask + 1, secinfo); |
if (! entry) |
goto error_return; |
} |
p++; |
} |
} |
else |
{ |
while (p < end) |
{ |
for (i = 0; i < sec->entsize; i++) |
if (p[i] != '\0') |
break; |
if (i != sec->entsize) |
break; |
if (!nul && !((p - secinfo->contents) & mask)) |
{ |
nul = TRUE; |
entry = sec_merge_add (sinfo->htab, (char *) p, |
(unsigned) mask + 1, secinfo); |
if (! entry) |
goto error_return; |
} |
p += sec->entsize; |
} |
} |
} |
} |
else |
{ |
for (p = secinfo->contents; p < end; p += sec->entsize) |
{ |
entry = sec_merge_add (sinfo->htab, (char *) p, 1, secinfo); |
if (! entry) |
goto error_return; |
} |
} |
return TRUE; |
error_return: |
for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next) |
*secinfo->psecinfo = NULL; |
return FALSE; |
} |
static int |
strrevcmp (const void *a, const void *b) |
{ |
struct sec_merge_hash_entry *A = *(struct sec_merge_hash_entry **) a; |
struct sec_merge_hash_entry *B = *(struct sec_merge_hash_entry **) b; |
unsigned int lenA = A->len; |
unsigned int lenB = B->len; |
const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1; |
const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1; |
int l = lenA < lenB ? lenA : lenB; |
while (l) |
{ |
if (*s != *t) |
return (int) *s - (int) *t; |
s--; |
t--; |
l--; |
} |
return lenA - lenB; |
} |
/* Like strrevcmp, but for the case where all strings have the same |
alignment > entsize. */ |
static int |
strrevcmp_align (const void *a, const void *b) |
{ |
struct sec_merge_hash_entry *A = *(struct sec_merge_hash_entry **) a; |
struct sec_merge_hash_entry *B = *(struct sec_merge_hash_entry **) b; |
unsigned int lenA = A->len; |
unsigned int lenB = B->len; |
const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1; |
const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1; |
int l = lenA < lenB ? lenA : lenB; |
int tail_align = (lenA & (A->alignment - 1)) - (lenB & (A->alignment - 1)); |
if (tail_align != 0) |
return tail_align; |
while (l) |
{ |
if (*s != *t) |
return (int) *s - (int) *t; |
s--; |
t--; |
l--; |
} |
return lenA - lenB; |
} |
static inline int |
is_suffix (const struct sec_merge_hash_entry *A, |
const struct sec_merge_hash_entry *B) |
{ |
if (A->len <= B->len) |
/* B cannot be a suffix of A unless A is equal to B, which is guaranteed |
not to be equal by the hash table. */ |
return 0; |
return memcmp (A->root.string + (A->len - B->len), |
B->root.string, B->len) == 0; |
} |
/* This is a helper function for _bfd_merge_sections. It attempts to |
merge strings matching suffixes of longer strings. */ |
static void |
merge_strings (struct sec_merge_info *sinfo) |
{ |
struct sec_merge_hash_entry **array, **a, *e; |
struct sec_merge_sec_info *secinfo; |
bfd_size_type size, amt; |
unsigned int alignment = 0; |
/* Now sort the strings */ |
amt = sinfo->htab->size * sizeof (struct sec_merge_hash_entry *); |
array = (struct sec_merge_hash_entry **) bfd_malloc (amt); |
if (array == NULL) |
goto alloc_failure; |
for (e = sinfo->htab->first, a = array; e; e = e->next) |
if (e->alignment) |
{ |
*a++ = e; |
/* Adjust the length to not include the zero terminator. */ |
e->len -= sinfo->htab->entsize; |
if (alignment != e->alignment) |
{ |
if (alignment == 0) |
alignment = e->alignment; |
else |
alignment = (unsigned) -1; |
} |
} |
sinfo->htab->size = a - array; |
if (sinfo->htab->size != 0) |
{ |
qsort (array, (size_t) sinfo->htab->size, |
sizeof (struct sec_merge_hash_entry *), |
(alignment != (unsigned) -1 && alignment > sinfo->htab->entsize |
? strrevcmp_align : strrevcmp)); |
/* Loop over the sorted array and merge suffixes */ |
e = *--a; |
e->len += sinfo->htab->entsize; |
while (--a >= array) |
{ |
struct sec_merge_hash_entry *cmp = *a; |
cmp->len += sinfo->htab->entsize; |
if (e->alignment >= cmp->alignment |
&& !((e->len - cmp->len) & (cmp->alignment - 1)) |
&& is_suffix (e, cmp)) |
{ |
cmp->u.suffix = e; |
cmp->alignment = 0; |
} |
else |
e = cmp; |
} |
} |
alloc_failure: |
if (array) |
free (array); |
/* Now assign positions to the strings we want to keep. */ |
size = 0; |
secinfo = sinfo->htab->first->secinfo; |
for (e = sinfo->htab->first; e; e = e->next) |
{ |
if (e->secinfo != secinfo) |
{ |
secinfo->sec->size = size; |
secinfo = e->secinfo; |
} |
if (e->alignment) |
{ |
if (e->secinfo->first_str == NULL) |
{ |
e->secinfo->first_str = e; |
size = 0; |
} |
size = (size + e->alignment - 1) & ~((bfd_vma) e->alignment - 1); |
e->u.index = size; |
size += e->len; |
} |
} |
secinfo->sec->size = size; |
if (secinfo->sec->alignment_power != 0) |
{ |
bfd_size_type align = (bfd_size_type) 1 << secinfo->sec->alignment_power; |
secinfo->sec->size = (secinfo->sec->size + align - 1) & -align; |
} |
/* And now adjust the rest, removing them from the chain (but not hashtable) |
at the same time. */ |
for (a = &sinfo->htab->first, e = *a; e; e = e->next) |
if (e->alignment) |
a = &e->next; |
else |
{ |
*a = e->next; |
if (e->len) |
{ |
e->secinfo = e->u.suffix->secinfo; |
e->alignment = e->u.suffix->alignment; |
e->u.index = e->u.suffix->u.index + (e->u.suffix->len - e->len); |
} |
} |
} |
/* This function is called once after all SEC_MERGE sections are registered |
with _bfd_merge_section. */ |
bfd_boolean |
_bfd_merge_sections (bfd *abfd, |
struct bfd_link_info *info ATTRIBUTE_UNUSED, |
void *xsinfo, |
void (*remove_hook) (bfd *, asection *)) |
{ |
struct sec_merge_info *sinfo; |
for (sinfo = (struct sec_merge_info *) xsinfo; sinfo; sinfo = sinfo->next) |
{ |
struct sec_merge_sec_info * secinfo; |
if (! sinfo->chain) |
continue; |
/* Move sinfo->chain to head of the chain, terminate it. */ |
secinfo = sinfo->chain; |
sinfo->chain = secinfo->next; |
secinfo->next = NULL; |
/* Record the sections into the hash table. */ |
for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next) |
if (secinfo->sec->flags & SEC_EXCLUDE) |
{ |
*secinfo->psecinfo = NULL; |
if (remove_hook) |
(*remove_hook) (abfd, secinfo->sec); |
} |
else if (! record_section (sinfo, secinfo)) |
break; |
if (secinfo) |
continue; |
if (sinfo->htab->first == NULL) |
continue; |
if (sinfo->htab->strings) |
merge_strings (sinfo); |
else |
{ |
struct sec_merge_hash_entry *e; |
bfd_size_type size = 0; |
/* Things are much simpler for non-strings. |
Just assign them slots in the section. */ |
secinfo = NULL; |
for (e = sinfo->htab->first; e; e = e->next) |
{ |
if (e->secinfo->first_str == NULL) |
{ |
if (secinfo) |
secinfo->sec->size = size; |
e->secinfo->first_str = e; |
size = 0; |
} |
size = (size + e->alignment - 1) |
& ~((bfd_vma) e->alignment - 1); |
e->u.index = size; |
size += e->len; |
secinfo = e->secinfo; |
} |
secinfo->sec->size = size; |
} |
/* Finally remove all input sections which have not made it into |
the hash table at all. */ |
for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next) |
if (secinfo->first_str == NULL) |
secinfo->sec->flags |= SEC_EXCLUDE | SEC_KEEP; |
} |
return TRUE; |
} |
/* Write out the merged section. */ |
bfd_boolean |
_bfd_write_merged_section (bfd *output_bfd, asection *sec, void *psecinfo) |
{ |
struct sec_merge_sec_info *secinfo; |
file_ptr pos; |
secinfo = (struct sec_merge_sec_info *) psecinfo; |
if (!secinfo) |
return FALSE; |
if (secinfo->first_str == NULL) |
return TRUE; |
/* FIXME: octets_per_byte. */ |
pos = sec->output_section->filepos + sec->output_offset; |
if (bfd_seek (output_bfd, pos, SEEK_SET) != 0) |
return FALSE; |
if (! sec_merge_emit (output_bfd, secinfo->first_str)) |
return FALSE; |
return TRUE; |
} |
/* Adjust an address in the SEC_MERGE section. Given OFFSET within |
*PSEC, this returns the new offset in the adjusted SEC_MERGE |
section and writes the new section back into *PSEC. */ |
bfd_vma |
_bfd_merged_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED, asection **psec, |
void *psecinfo, bfd_vma offset) |
{ |
struct sec_merge_sec_info *secinfo; |
struct sec_merge_hash_entry *entry; |
unsigned char *p; |
asection *sec = *psec; |
secinfo = (struct sec_merge_sec_info *) psecinfo; |
if (!secinfo) |
return offset; |
if (offset >= sec->rawsize) |
{ |
if (offset > sec->rawsize) |
{ |
(*_bfd_error_handler) |
(_("%s: access beyond end of merged section (%ld)"), |
bfd_get_filename (sec->owner), (long) offset); |
} |
return secinfo->first_str ? sec->size : 0; |
} |
if (secinfo->htab->strings) |
{ |
if (sec->entsize == 1) |
{ |
p = secinfo->contents + offset - 1; |
while (p >= secinfo->contents && *p) |
--p; |
++p; |
} |
else |
{ |
p = secinfo->contents + (offset / sec->entsize) * sec->entsize; |
p -= sec->entsize; |
while (p >= secinfo->contents) |
{ |
unsigned int i; |
for (i = 0; i < sec->entsize; ++i) |
if (p[i] != '\0') |
break; |
if (i == sec->entsize) |
break; |
p -= sec->entsize; |
} |
p += sec->entsize; |
} |
} |
else |
{ |
p = secinfo->contents + (offset / sec->entsize) * sec->entsize; |
} |
entry = sec_merge_hash_lookup (secinfo->htab, (char *) p, 0, FALSE); |
if (!entry) |
{ |
if (! secinfo->htab->strings) |
abort (); |
/* This should only happen if somebody points into the padding |
after a NUL character but before next entity. */ |
if (*p) |
abort (); |
if (! secinfo->htab->first) |
abort (); |
entry = secinfo->htab->first; |
p = (secinfo->contents + (offset / sec->entsize + 1) * sec->entsize |
- entry->len); |
} |
*psec = entry->secinfo->sec; |
return entry->u.index + (secinfo->contents + offset - p); |
} |
/* Tidy up when done. */ |
void |
_bfd_merge_sections_free (void *xsinfo) |
{ |
struct sec_merge_info *sinfo; |
for (sinfo = (struct sec_merge_info *) xsinfo; sinfo; sinfo = sinfo->next) |
{ |
bfd_hash_table_free (&sinfo->htab->table); |
free (sinfo->htab); |
} |
} |
/contrib/toolchain/binutils/bfd/opncls.c |
---|
0,0 → 1,1652 |
/* opncls.c -- open and close a BFD. |
Copyright 1990-2013 Free Software Foundation, Inc. |
Written by Cygnus Support. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "objalloc.h" |
#include "libbfd.h" |
#include "libiberty.h" |
#ifndef S_IXUSR |
#define S_IXUSR 0100 /* Execute by owner. */ |
#endif |
#ifndef S_IXGRP |
#define S_IXGRP 0010 /* Execute by group. */ |
#endif |
#ifndef S_IXOTH |
#define S_IXOTH 0001 /* Execute by others. */ |
#endif |
/* Counters used to initialize the bfd identifier. */ |
static unsigned int bfd_id_counter = 0; |
static unsigned int bfd_reserved_id_counter = 0; |
/* |
CODE_FRAGMENT |
.{* Set to N to open the next N BFDs using an alternate id space. *} |
.extern unsigned int bfd_use_reserved_id; |
*/ |
unsigned int bfd_use_reserved_id = 0; |
/* fdopen is a loser -- we should use stdio exclusively. Unfortunately |
if we do that we can't use fcntl. */ |
/* Return a new BFD. All BFD's are allocated through this routine. */ |
bfd * |
_bfd_new_bfd (void) |
{ |
bfd *nbfd; |
nbfd = (bfd *) bfd_zmalloc (sizeof (bfd)); |
if (nbfd == NULL) |
return NULL; |
if (bfd_use_reserved_id) |
{ |
nbfd->id = --bfd_reserved_id_counter; |
--bfd_use_reserved_id; |
} |
else |
nbfd->id = bfd_id_counter++; |
nbfd->memory = objalloc_create (); |
if (nbfd->memory == NULL) |
{ |
bfd_set_error (bfd_error_no_memory); |
free (nbfd); |
return NULL; |
} |
nbfd->arch_info = &bfd_default_arch_struct; |
nbfd->direction = no_direction; |
nbfd->iostream = NULL; |
nbfd->where = 0; |
if (!bfd_hash_table_init_n (& nbfd->section_htab, bfd_section_hash_newfunc, |
sizeof (struct section_hash_entry), 13)) |
{ |
free (nbfd); |
return NULL; |
} |
nbfd->sections = NULL; |
nbfd->section_last = NULL; |
nbfd->format = bfd_unknown; |
nbfd->my_archive = NULL; |
nbfd->origin = 0; |
nbfd->opened_once = FALSE; |
nbfd->output_has_begun = FALSE; |
nbfd->section_count = 0; |
nbfd->usrdata = NULL; |
nbfd->cacheable = FALSE; |
nbfd->flags = BFD_NO_FLAGS; |
nbfd->mtime_set = FALSE; |
return nbfd; |
} |
static const struct bfd_iovec opncls_iovec; |
/* Allocate a new BFD as a member of archive OBFD. */ |
bfd * |
_bfd_new_bfd_contained_in (bfd *obfd) |
{ |
bfd *nbfd; |
nbfd = _bfd_new_bfd (); |
if (nbfd == NULL) |
return NULL; |
nbfd->xvec = obfd->xvec; |
nbfd->iovec = obfd->iovec; |
if (obfd->iovec == &opncls_iovec) |
nbfd->iostream = obfd->iostream; |
nbfd->my_archive = obfd; |
nbfd->direction = read_direction; |
nbfd->target_defaulted = obfd->target_defaulted; |
return nbfd; |
} |
/* Delete a BFD. */ |
static void |
_bfd_delete_bfd (bfd *abfd) |
{ |
if (abfd->memory) |
{ |
bfd_hash_table_free (&abfd->section_htab); |
objalloc_free ((struct objalloc *) abfd->memory); |
} |
free (abfd->arelt_data); |
free (abfd); |
} |
/* Free objalloc memory. */ |
bfd_boolean |
_bfd_free_cached_info (bfd *abfd) |
{ |
if (abfd->memory) |
{ |
bfd_hash_table_free (&abfd->section_htab); |
objalloc_free ((struct objalloc *) abfd->memory); |
abfd->sections = NULL; |
abfd->section_last = NULL; |
abfd->outsymbols = NULL; |
abfd->tdata.any = NULL; |
abfd->usrdata = NULL; |
abfd->memory = NULL; |
} |
return TRUE; |
} |
/* |
SECTION |
Opening and closing BFDs |
SUBSECTION |
Functions for opening and closing |
*/ |
/* |
FUNCTION |
bfd_fopen |
SYNOPSIS |
bfd *bfd_fopen (const char *filename, const char *target, |
const char *mode, int fd); |
DESCRIPTION |
Open the file @var{filename} with the target @var{target}. |
Return a pointer to the created BFD. If @var{fd} is not -1, |
then <<fdopen>> is used to open the file; otherwise, <<fopen>> |
is used. @var{mode} is passed directly to <<fopen>> or |
<<fdopen>>. |
Calls <<bfd_find_target>>, so @var{target} is interpreted as by |
that function. |
The new BFD is marked as cacheable iff @var{fd} is -1. |
If <<NULL>> is returned then an error has occured. Possible errors |
are <<bfd_error_no_memory>>, <<bfd_error_invalid_target>> or |
<<system_call>> error. |
On error, @var{fd} is always closed. |
*/ |
bfd * |
bfd_fopen (const char *filename, const char *target, const char *mode, int fd) |
{ |
bfd *nbfd; |
const bfd_target *target_vec; |
nbfd = _bfd_new_bfd (); |
if (nbfd == NULL) |
{ |
if (fd != -1) |
close (fd); |
return NULL; |
} |
target_vec = bfd_find_target (target, nbfd); |
if (target_vec == NULL) |
{ |
if (fd != -1) |
close (fd); |
_bfd_delete_bfd (nbfd); |
return NULL; |
} |
#ifdef HAVE_FDOPEN |
if (fd != -1) |
nbfd->iostream = fdopen (fd, mode); |
else |
#endif |
nbfd->iostream = real_fopen (filename, mode); |
if (nbfd->iostream == NULL) |
{ |
bfd_set_error (bfd_error_system_call); |
_bfd_delete_bfd (nbfd); |
return NULL; |
} |
/* OK, put everything where it belongs. */ |
nbfd->filename = filename; |
/* Figure out whether the user is opening the file for reading, |
writing, or both, by looking at the MODE argument. */ |
if ((mode[0] == 'r' || mode[0] == 'w' || mode[0] == 'a') |
&& mode[1] == '+') |
nbfd->direction = both_direction; |
else if (mode[0] == 'r') |
nbfd->direction = read_direction; |
else |
nbfd->direction = write_direction; |
if (! bfd_cache_init (nbfd)) |
{ |
_bfd_delete_bfd (nbfd); |
return NULL; |
} |
nbfd->opened_once = TRUE; |
/* If we opened the file by name, mark it cacheable; we can close it |
and reopen it later. However, if a file descriptor was provided, |
then it may have been opened with special flags that make it |
unsafe to close and reopen the file. */ |
if (fd == -1) |
(void) bfd_set_cacheable (nbfd, TRUE); |
return nbfd; |
} |
/* |
FUNCTION |
bfd_openr |
SYNOPSIS |
bfd *bfd_openr (const char *filename, const char *target); |
DESCRIPTION |
Open the file @var{filename} (using <<fopen>>) with the target |
@var{target}. Return a pointer to the created BFD. |
Calls <<bfd_find_target>>, so @var{target} is interpreted as by |
that function. |
If <<NULL>> is returned then an error has occured. Possible errors |
are <<bfd_error_no_memory>>, <<bfd_error_invalid_target>> or |
<<system_call>> error. |
*/ |
bfd * |
bfd_openr (const char *filename, const char *target) |
{ |
return bfd_fopen (filename, target, FOPEN_RB, -1); |
} |
/* Don't try to `optimize' this function: |
o - We lock using stack space so that interrupting the locking |
won't cause a storage leak. |
o - We open the file stream last, since we don't want to have to |
close it if anything goes wrong. Closing the stream means closing |
the file descriptor too, even though we didn't open it. */ |
/* |
FUNCTION |
bfd_fdopenr |
SYNOPSIS |
bfd *bfd_fdopenr (const char *filename, const char *target, int fd); |
DESCRIPTION |
<<bfd_fdopenr>> is to <<bfd_fopenr>> much like <<fdopen>> is to |
<<fopen>>. It opens a BFD on a file already described by the |
@var{fd} supplied. |
When the file is later <<bfd_close>>d, the file descriptor will |
be closed. If the caller desires that this file descriptor be |
cached by BFD (opened as needed, closed as needed to free |
descriptors for other opens), with the supplied @var{fd} used as |
an initial file descriptor (but subject to closure at any time), |
call bfd_set_cacheable(bfd, 1) on the returned BFD. The default |
is to assume no caching; the file descriptor will remain open |
until <<bfd_close>>, and will not be affected by BFD operations |
on other files. |
Possible errors are <<bfd_error_no_memory>>, |
<<bfd_error_invalid_target>> and <<bfd_error_system_call>>. |
On error, @var{fd} is closed. |
*/ |
bfd * |
bfd_fdopenr (const char *filename, const char *target, int fd) |
{ |
const char *mode; |
#if defined(HAVE_FCNTL) && defined(F_GETFL) |
int fdflags; |
#endif |
#if ! defined(HAVE_FCNTL) || ! defined(F_GETFL) |
mode = FOPEN_RUB; /* Assume full access. */ |
#else |
fdflags = fcntl (fd, F_GETFL, NULL); |
if (fdflags == -1) |
{ |
int save = errno; |
close (fd); |
errno = save; |
bfd_set_error (bfd_error_system_call); |
return NULL; |
} |
/* (O_ACCMODE) parens are to avoid Ultrix header file bug. */ |
switch (fdflags & (O_ACCMODE)) |
{ |
case O_RDONLY: mode = FOPEN_RB; break; |
case O_WRONLY: mode = FOPEN_RUB; break; |
case O_RDWR: mode = FOPEN_RUB; break; |
default: abort (); |
} |
#endif |
return bfd_fopen (filename, target, mode, fd); |
} |
/* |
FUNCTION |
bfd_openstreamr |
SYNOPSIS |
bfd *bfd_openstreamr (const char *, const char *, void *); |
DESCRIPTION |
Open a BFD for read access on an existing stdio stream. When |
the BFD is passed to <<bfd_close>>, the stream will be closed. |
*/ |
bfd * |
bfd_openstreamr (const char *filename, const char *target, void *streamarg) |
{ |
FILE *stream = (FILE *) streamarg; |
bfd *nbfd; |
const bfd_target *target_vec; |
nbfd = _bfd_new_bfd (); |
if (nbfd == NULL) |
return NULL; |
target_vec = bfd_find_target (target, nbfd); |
if (target_vec == NULL) |
{ |
_bfd_delete_bfd (nbfd); |
return NULL; |
} |
nbfd->iostream = stream; |
nbfd->filename = filename; |
nbfd->direction = read_direction; |
if (! bfd_cache_init (nbfd)) |
{ |
_bfd_delete_bfd (nbfd); |
return NULL; |
} |
return nbfd; |
} |
/* |
FUNCTION |
bfd_openr_iovec |
SYNOPSIS |
bfd *bfd_openr_iovec (const char *filename, const char *target, |
void *(*open_func) (struct bfd *nbfd, |
void *open_closure), |
void *open_closure, |
file_ptr (*pread_func) (struct bfd *nbfd, |
void *stream, |
void *buf, |
file_ptr nbytes, |
file_ptr offset), |
int (*close_func) (struct bfd *nbfd, |
void *stream), |
int (*stat_func) (struct bfd *abfd, |
void *stream, |
struct stat *sb)); |
DESCRIPTION |
Create and return a BFD backed by a read-only @var{stream}. |
The @var{stream} is created using @var{open_func}, accessed using |
@var{pread_func} and destroyed using @var{close_func}. |
Calls <<bfd_find_target>>, so @var{target} is interpreted as by |
that function. |
Calls @var{open_func} (which can call <<bfd_zalloc>> and |
<<bfd_get_filename>>) to obtain the read-only stream backing |
the BFD. @var{open_func} either succeeds returning the |
non-<<NULL>> @var{stream}, or fails returning <<NULL>> |
(setting <<bfd_error>>). |
Calls @var{pread_func} to request @var{nbytes} of data from |
@var{stream} starting at @var{offset} (e.g., via a call to |
<<bfd_read>>). @var{pread_func} either succeeds returning the |
number of bytes read (which can be less than @var{nbytes} when |
end-of-file), or fails returning -1 (setting <<bfd_error>>). |
Calls @var{close_func} when the BFD is later closed using |
<<bfd_close>>. @var{close_func} either succeeds returning 0, or |
fails returning -1 (setting <<bfd_error>>). |
Calls @var{stat_func} to fill in a stat structure for bfd_stat, |
bfd_get_size, and bfd_get_mtime calls. @var{stat_func} returns 0 |
on success, or returns -1 on failure (setting <<bfd_error>>). |
If <<bfd_openr_iovec>> returns <<NULL>> then an error has |
occurred. Possible errors are <<bfd_error_no_memory>>, |
<<bfd_error_invalid_target>> and <<bfd_error_system_call>>. |
*/ |
struct opncls |
{ |
void *stream; |
file_ptr (*pread) (struct bfd *abfd, void *stream, void *buf, |
file_ptr nbytes, file_ptr offset); |
int (*close) (struct bfd *abfd, void *stream); |
int (*stat) (struct bfd *abfd, void *stream, struct stat *sb); |
file_ptr where; |
}; |
static file_ptr |
opncls_btell (struct bfd *abfd) |
{ |
struct opncls *vec = (struct opncls *) abfd->iostream; |
return vec->where; |
} |
static int |
opncls_bseek (struct bfd *abfd, file_ptr offset, int whence) |
{ |
struct opncls *vec = (struct opncls *) abfd->iostream; |
switch (whence) |
{ |
case SEEK_SET: vec->where = offset; break; |
case SEEK_CUR: vec->where += offset; break; |
case SEEK_END: return -1; |
} |
return 0; |
} |
static file_ptr |
opncls_bread (struct bfd *abfd, void *buf, file_ptr nbytes) |
{ |
struct opncls *vec = (struct opncls *) abfd->iostream; |
file_ptr nread = (vec->pread) (abfd, vec->stream, buf, nbytes, vec->where); |
if (nread < 0) |
return nread; |
vec->where += nread; |
return nread; |
} |
static file_ptr |
opncls_bwrite (struct bfd *abfd ATTRIBUTE_UNUSED, |
const void *where ATTRIBUTE_UNUSED, |
file_ptr nbytes ATTRIBUTE_UNUSED) |
{ |
return -1; |
} |
static int |
opncls_bclose (struct bfd *abfd) |
{ |
struct opncls *vec = (struct opncls *) abfd->iostream; |
/* Since the VEC's memory is bound to the bfd deleting the bfd will |
free it. */ |
int status = 0; |
if (vec->close != NULL) |
status = (vec->close) (abfd, vec->stream); |
abfd->iostream = NULL; |
return status; |
} |
static int |
opncls_bflush (struct bfd *abfd ATTRIBUTE_UNUSED) |
{ |
return 0; |
} |
static int |
opncls_bstat (struct bfd *abfd, struct stat *sb) |
{ |
struct opncls *vec = (struct opncls *) abfd->iostream; |
memset (sb, 0, sizeof (*sb)); |
if (vec->stat == NULL) |
return 0; |
return (vec->stat) (abfd, vec->stream, sb); |
} |
static void * |
opncls_bmmap (struct bfd *abfd ATTRIBUTE_UNUSED, |
void *addr ATTRIBUTE_UNUSED, |
bfd_size_type len ATTRIBUTE_UNUSED, |
int prot ATTRIBUTE_UNUSED, |
int flags ATTRIBUTE_UNUSED, |
file_ptr offset ATTRIBUTE_UNUSED, |
void **map_addr ATTRIBUTE_UNUSED, |
bfd_size_type *map_len ATTRIBUTE_UNUSED) |
{ |
return (void *) -1; |
} |
static const struct bfd_iovec opncls_iovec = { |
&opncls_bread, &opncls_bwrite, &opncls_btell, &opncls_bseek, |
&opncls_bclose, &opncls_bflush, &opncls_bstat, &opncls_bmmap |
}; |
bfd * |
bfd_openr_iovec (const char *filename, const char *target, |
void *(*open_p) (struct bfd *, void *), |
void *open_closure, |
file_ptr (*pread_p) (struct bfd *, void *, void *, |
file_ptr, file_ptr), |
int (*close_p) (struct bfd *, void *), |
int (*stat_p) (struct bfd *, void *, struct stat *)) |
{ |
bfd *nbfd; |
const bfd_target *target_vec; |
struct opncls *vec; |
void *stream; |
nbfd = _bfd_new_bfd (); |
if (nbfd == NULL) |
return NULL; |
target_vec = bfd_find_target (target, nbfd); |
if (target_vec == NULL) |
{ |
_bfd_delete_bfd (nbfd); |
return NULL; |
} |
nbfd->filename = filename; |
nbfd->direction = read_direction; |
/* `open_p (...)' would get expanded by an the open(2) syscall macro. */ |
stream = (*open_p) (nbfd, open_closure); |
if (stream == NULL) |
{ |
_bfd_delete_bfd (nbfd); |
return NULL; |
} |
vec = (struct opncls *) bfd_zalloc (nbfd, sizeof (struct opncls)); |
vec->stream = stream; |
vec->pread = pread_p; |
vec->close = close_p; |
vec->stat = stat_p; |
nbfd->iovec = &opncls_iovec; |
nbfd->iostream = vec; |
return nbfd; |
} |
/* bfd_openw -- open for writing. |
Returns a pointer to a freshly-allocated BFD on success, or NULL. |
See comment by bfd_fdopenr before you try to modify this function. */ |
/* |
FUNCTION |
bfd_openw |
SYNOPSIS |
bfd *bfd_openw (const char *filename, const char *target); |
DESCRIPTION |
Create a BFD, associated with file @var{filename}, using the |
file format @var{target}, and return a pointer to it. |
Possible errors are <<bfd_error_system_call>>, <<bfd_error_no_memory>>, |
<<bfd_error_invalid_target>>. |
*/ |
bfd * |
bfd_openw (const char *filename, const char *target) |
{ |
bfd *nbfd; |
const bfd_target *target_vec; |
/* nbfd has to point to head of malloc'ed block so that bfd_close may |
reclaim it correctly. */ |
nbfd = _bfd_new_bfd (); |
if (nbfd == NULL) |
return NULL; |
target_vec = bfd_find_target (target, nbfd); |
if (target_vec == NULL) |
{ |
_bfd_delete_bfd (nbfd); |
return NULL; |
} |
nbfd->filename = filename; |
nbfd->direction = write_direction; |
if (bfd_open_file (nbfd) == NULL) |
{ |
/* File not writeable, etc. */ |
bfd_set_error (bfd_error_system_call); |
_bfd_delete_bfd (nbfd); |
return NULL; |
} |
return nbfd; |
} |
static inline void |
_maybe_make_executable (bfd * abfd) |
{ |
/* If the file was open for writing and is now executable, |
make it so. */ |
if (abfd->direction == write_direction |
&& (abfd->flags & (EXEC_P | DYNAMIC)) != 0) |
{ |
struct stat buf; |
if (stat (abfd->filename, &buf) == 0 |
/* Do not attempt to change non-regular files. This is |
here especially for configure scripts and kernel builds |
which run tests with "ld [...] -o /dev/null". */ |
&& S_ISREG(buf.st_mode)) |
{ |
unsigned int mask = umask (0); |
umask (mask); |
chmod (abfd->filename, |
(0777 |
& (buf.st_mode | ((S_IXUSR | S_IXGRP | S_IXOTH) &~ mask)))); |
} |
} |
} |
/* |
FUNCTION |
bfd_close |
SYNOPSIS |
bfd_boolean bfd_close (bfd *abfd); |
DESCRIPTION |
Close a BFD. If the BFD was open for writing, then pending |
operations are completed and the file written out and closed. |
If the created file is executable, then <<chmod>> is called |
to mark it as such. |
All memory attached to the BFD is released. |
The file descriptor associated with the BFD is closed (even |
if it was passed in to BFD by <<bfd_fdopenr>>). |
RETURNS |
<<TRUE>> is returned if all is ok, otherwise <<FALSE>>. |
*/ |
bfd_boolean |
bfd_close (bfd *abfd) |
{ |
bfd_boolean ret; |
if (bfd_write_p (abfd)) |
{ |
if (! BFD_SEND_FMT (abfd, _bfd_write_contents, (abfd))) |
return FALSE; |
} |
if (! BFD_SEND (abfd, _close_and_cleanup, (abfd))) |
return FALSE; |
ret = abfd->iovec->bclose (abfd) == 0; |
if (ret) |
_maybe_make_executable (abfd); |
_bfd_delete_bfd (abfd); |
return ret; |
} |
/* |
FUNCTION |
bfd_close_all_done |
SYNOPSIS |
bfd_boolean bfd_close_all_done (bfd *); |
DESCRIPTION |
Close a BFD. Differs from <<bfd_close>> since it does not |
complete any pending operations. This routine would be used |
if the application had just used BFD for swapping and didn't |
want to use any of the writing code. |
If the created file is executable, then <<chmod>> is called |
to mark it as such. |
All memory attached to the BFD is released. |
RETURNS |
<<TRUE>> is returned if all is ok, otherwise <<FALSE>>. |
*/ |
bfd_boolean |
bfd_close_all_done (bfd *abfd) |
{ |
bfd_boolean ret; |
ret = bfd_cache_close (abfd); |
if (ret) |
_maybe_make_executable (abfd); |
_bfd_delete_bfd (abfd); |
return ret; |
} |
/* |
FUNCTION |
bfd_create |
SYNOPSIS |
bfd *bfd_create (const char *filename, bfd *templ); |
DESCRIPTION |
Create a new BFD in the manner of <<bfd_openw>>, but without |
opening a file. The new BFD takes the target from the target |
used by @var{templ}. The format is always set to <<bfd_object>>. |
*/ |
bfd * |
bfd_create (const char *filename, bfd *templ) |
{ |
bfd *nbfd; |
nbfd = _bfd_new_bfd (); |
if (nbfd == NULL) |
return NULL; |
nbfd->filename = filename; |
if (templ) |
nbfd->xvec = templ->xvec; |
nbfd->direction = no_direction; |
bfd_set_format (nbfd, bfd_object); |
return nbfd; |
} |
/* |
FUNCTION |
bfd_make_writable |
SYNOPSIS |
bfd_boolean bfd_make_writable (bfd *abfd); |
DESCRIPTION |
Takes a BFD as created by <<bfd_create>> and converts it |
into one like as returned by <<bfd_openw>>. It does this |
by converting the BFD to BFD_IN_MEMORY. It's assumed that |
you will call <<bfd_make_readable>> on this bfd later. |
RETURNS |
<<TRUE>> is returned if all is ok, otherwise <<FALSE>>. |
*/ |
bfd_boolean |
bfd_make_writable (bfd *abfd) |
{ |
struct bfd_in_memory *bim; |
if (abfd->direction != no_direction) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
bim = (struct bfd_in_memory *) bfd_malloc (sizeof (struct bfd_in_memory)); |
if (bim == NULL) |
return FALSE; /* bfd_error already set. */ |
abfd->iostream = bim; |
/* bfd_bwrite will grow these as needed. */ |
bim->size = 0; |
bim->buffer = 0; |
abfd->flags |= BFD_IN_MEMORY; |
abfd->iovec = &_bfd_memory_iovec; |
abfd->origin = 0; |
abfd->direction = write_direction; |
abfd->where = 0; |
return TRUE; |
} |
/* |
FUNCTION |
bfd_make_readable |
SYNOPSIS |
bfd_boolean bfd_make_readable (bfd *abfd); |
DESCRIPTION |
Takes a BFD as created by <<bfd_create>> and |
<<bfd_make_writable>> and converts it into one like as |
returned by <<bfd_openr>>. It does this by writing the |
contents out to the memory buffer, then reversing the |
direction. |
RETURNS |
<<TRUE>> is returned if all is ok, otherwise <<FALSE>>. */ |
bfd_boolean |
bfd_make_readable (bfd *abfd) |
{ |
if (abfd->direction != write_direction || !(abfd->flags & BFD_IN_MEMORY)) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
if (! BFD_SEND_FMT (abfd, _bfd_write_contents, (abfd))) |
return FALSE; |
if (! BFD_SEND (abfd, _close_and_cleanup, (abfd))) |
return FALSE; |
abfd->arch_info = &bfd_default_arch_struct; |
abfd->where = 0; |
abfd->format = bfd_unknown; |
abfd->my_archive = NULL; |
abfd->origin = 0; |
abfd->opened_once = FALSE; |
abfd->output_has_begun = FALSE; |
abfd->section_count = 0; |
abfd->usrdata = NULL; |
abfd->cacheable = FALSE; |
abfd->flags |= BFD_IN_MEMORY; |
abfd->mtime_set = FALSE; |
abfd->target_defaulted = TRUE; |
abfd->direction = read_direction; |
abfd->sections = 0; |
abfd->symcount = 0; |
abfd->outsymbols = 0; |
abfd->tdata.any = 0; |
bfd_section_list_clear (abfd); |
bfd_check_format (abfd, bfd_object); |
return TRUE; |
} |
/* |
FUNCTION |
bfd_alloc |
SYNOPSIS |
void *bfd_alloc (bfd *abfd, bfd_size_type wanted); |
DESCRIPTION |
Allocate a block of @var{wanted} bytes of memory attached to |
<<abfd>> and return a pointer to it. |
*/ |
void * |
bfd_alloc (bfd *abfd, bfd_size_type size) |
{ |
void *ret; |
if (size != (unsigned long) size) |
{ |
bfd_set_error (bfd_error_no_memory); |
return NULL; |
} |
ret = objalloc_alloc ((struct objalloc *) abfd->memory, (unsigned long) size); |
if (ret == NULL) |
bfd_set_error (bfd_error_no_memory); |
return ret; |
} |
/* |
INTERNAL_FUNCTION |
bfd_alloc2 |
SYNOPSIS |
void *bfd_alloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size); |
DESCRIPTION |
Allocate a block of @var{nmemb} elements of @var{size} bytes each |
of memory attached to <<abfd>> and return a pointer to it. |
*/ |
void * |
bfd_alloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size) |
{ |
void *ret; |
if ((nmemb | size) >= HALF_BFD_SIZE_TYPE |
&& size != 0 |
&& nmemb > ~(bfd_size_type) 0 / size) |
{ |
bfd_set_error (bfd_error_no_memory); |
return NULL; |
} |
size *= nmemb; |
if (size != (unsigned long) size) |
{ |
bfd_set_error (bfd_error_no_memory); |
return NULL; |
} |
ret = objalloc_alloc ((struct objalloc *) abfd->memory, (unsigned long) size); |
if (ret == NULL) |
bfd_set_error (bfd_error_no_memory); |
return ret; |
} |
/* |
FUNCTION |
bfd_zalloc |
SYNOPSIS |
void *bfd_zalloc (bfd *abfd, bfd_size_type wanted); |
DESCRIPTION |
Allocate a block of @var{wanted} bytes of zeroed memory |
attached to <<abfd>> and return a pointer to it. |
*/ |
void * |
bfd_zalloc (bfd *abfd, bfd_size_type size) |
{ |
void *res; |
res = bfd_alloc (abfd, size); |
if (res) |
memset (res, 0, (size_t) size); |
return res; |
} |
/* |
INTERNAL_FUNCTION |
bfd_zalloc2 |
SYNOPSIS |
void *bfd_zalloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size); |
DESCRIPTION |
Allocate a block of @var{nmemb} elements of @var{size} bytes each |
of zeroed memory attached to <<abfd>> and return a pointer to it. |
*/ |
void * |
bfd_zalloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size) |
{ |
void *res; |
if ((nmemb | size) >= HALF_BFD_SIZE_TYPE |
&& size != 0 |
&& nmemb > ~(bfd_size_type) 0 / size) |
{ |
bfd_set_error (bfd_error_no_memory); |
return NULL; |
} |
size *= nmemb; |
res = bfd_alloc (abfd, size); |
if (res) |
memset (res, 0, (size_t) size); |
return res; |
} |
/* Free a block allocated for a BFD. |
Note: Also frees all more recently allocated blocks! */ |
void |
bfd_release (bfd *abfd, void *block) |
{ |
objalloc_free_block ((struct objalloc *) abfd->memory, block); |
} |
/* |
GNU Extension: separate debug-info files |
The idea here is that a special section called .gnu_debuglink might be |
embedded in a binary file, which indicates that some *other* file |
contains the real debugging information. This special section contains a |
filename and CRC32 checksum, which we read and resolve to another file, |
if it exists. |
This facilitates "optional" provision of debugging information, without |
having to provide two complete copies of every binary object (with and |
without debug symbols). */ |
#define GNU_DEBUGLINK ".gnu_debuglink" |
#define GNU_DEBUGALTLINK ".gnu_debugaltlink" |
/* |
FUNCTION |
bfd_calc_gnu_debuglink_crc32 |
SYNOPSIS |
unsigned long bfd_calc_gnu_debuglink_crc32 |
(unsigned long crc, const unsigned char *buf, bfd_size_type len); |
DESCRIPTION |
Computes a CRC value as used in the .gnu_debuglink section. |
Advances the previously computed @var{crc} value by computing |
and adding in the crc32 for @var{len} bytes of @var{buf}. |
RETURNS |
Return the updated CRC32 value. |
*/ |
unsigned long |
bfd_calc_gnu_debuglink_crc32 (unsigned long crc, |
const unsigned char *buf, |
bfd_size_type len) |
{ |
static const unsigned long crc32_table[256] = |
{ |
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, |
0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, |
0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, |
0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, |
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, |
0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, |
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, |
0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, |
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, |
0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, |
0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, |
0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, |
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, |
0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, |
0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, |
0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, |
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, |
0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, |
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, |
0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, |
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, |
0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, |
0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, |
0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, |
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, |
0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, |
0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, |
0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, |
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, |
0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, |
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, |
0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, |
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, |
0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, |
0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, |
0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, |
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, |
0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, |
0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, |
0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, |
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, |
0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, |
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, |
0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, |
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, |
0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, |
0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, |
0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, |
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, |
0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, |
0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, |
0x2d02ef8d |
}; |
const unsigned char *end; |
crc = ~crc & 0xffffffff; |
for (end = buf + len; buf < end; ++ buf) |
crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); |
return ~crc & 0xffffffff; |
} |
/* |
FUNCTION |
bfd_get_debug_link_info |
SYNOPSIS |
char *bfd_get_debug_link_info (bfd *abfd, unsigned long *crc32_out); |
DESCRIPTION |
fetch the filename and CRC32 value for any separate debuginfo |
associated with @var{abfd}. Return NULL if no such info found, |
otherwise return filename and update @var{crc32_out}. The |
returned filename is allocated with @code{malloc}; freeing it |
is the responsibility of the caller. |
*/ |
char * |
bfd_get_debug_link_info (bfd *abfd, unsigned long *crc32_out) |
{ |
asection *sect; |
unsigned long crc32; |
bfd_byte *contents; |
int crc_offset; |
char *name; |
BFD_ASSERT (abfd); |
BFD_ASSERT (crc32_out); |
sect = bfd_get_section_by_name (abfd, GNU_DEBUGLINK); |
if (sect == NULL) |
return NULL; |
if (!bfd_malloc_and_get_section (abfd, sect, &contents)) |
{ |
if (contents != NULL) |
free (contents); |
return NULL; |
} |
/* Crc value is stored after the filename, aligned up to 4 bytes. */ |
name = (char *) contents; |
crc_offset = strlen (name) + 1; |
crc_offset = (crc_offset + 3) & ~3; |
crc32 = bfd_get_32 (abfd, contents + crc_offset); |
*crc32_out = crc32; |
return name; |
} |
/* |
FUNCTION |
bfd_get_alt_debug_link_info |
SYNOPSIS |
char *bfd_get_alt_debug_link_info (bfd *abfd, unsigned long *crc32_out); |
DESCRIPTION |
Fetch the filename and BuildID value for any alternate debuginfo |
associated with @var{abfd}. Return NULL if no such info found, |
otherwise return filename and update @var{buildid_out}. The |
returned filename is allocated with @code{malloc}; freeing it |
is the responsibility of the caller. |
*/ |
char * |
bfd_get_alt_debug_link_info (bfd * abfd, unsigned long * buildid_out) |
{ |
asection *sect; |
bfd_byte *contents; |
int buildid_offset; |
char *name; |
BFD_ASSERT (abfd); |
BFD_ASSERT (buildid_out); |
sect = bfd_get_section_by_name (abfd, GNU_DEBUGALTLINK); |
if (sect == NULL) |
return NULL; |
if (!bfd_malloc_and_get_section (abfd, sect, & contents)) |
{ |
if (contents != NULL) |
free (contents); |
return NULL; |
} |
/* BuildID value is stored after the filename, aligned up to 4 bytes. */ |
name = (char *) contents; |
buildid_offset = strlen (name) + 1; |
buildid_offset = (buildid_offset + 3) & ~3; |
* buildid_out = bfd_get_32 (abfd, contents + buildid_offset); |
return name; |
} |
/* |
INTERNAL_FUNCTION |
separate_debug_file_exists |
SYNOPSIS |
bfd_boolean separate_debug_file_exists |
(char *name, unsigned long crc32); |
DESCRIPTION |
Checks to see if @var{name} is a file and if its contents |
match @var{crc32}. |
*/ |
static bfd_boolean |
separate_debug_file_exists (const char *name, const unsigned long crc) |
{ |
static unsigned char buffer [8 * 1024]; |
unsigned long file_crc = 0; |
FILE *f; |
bfd_size_type count; |
BFD_ASSERT (name); |
f = real_fopen (name, FOPEN_RB); |
if (f == NULL) |
return FALSE; |
while ((count = fread (buffer, 1, sizeof (buffer), f)) > 0) |
file_crc = bfd_calc_gnu_debuglink_crc32 (file_crc, buffer, count); |
fclose (f); |
return crc == file_crc; |
} |
/* |
INTERNAL_FUNCTION |
separate_alt_debug_file_exists |
SYNOPSIS |
bfd_boolean separate_alt_debug_file_exists |
(char *name, unsigned long crc32); |
DESCRIPTION |
Checks to see if @var{name} is a file and if its BuildID |
matches @var{buildid}. |
*/ |
static bfd_boolean |
separate_alt_debug_file_exists (const char *name, |
const unsigned long buildid ATTRIBUTE_UNUSED) |
{ |
FILE *f; |
BFD_ASSERT (name); |
f = real_fopen (name, FOPEN_RB); |
if (f == NULL) |
return FALSE; |
/* FIXME: Add code to check buildid. */ |
fclose (f); |
return TRUE; |
} |
/* |
INTERNAL_FUNCTION |
find_separate_debug_file |
SYNOPSIS |
char *find_separate_debug_file (bfd *abfd); |
DESCRIPTION |
Searches @var{abfd} for a section called @var{section_name} which |
is expected to contain a reference to a file containing separate |
debugging information. The function scans various locations in |
the filesystem, including the file tree rooted at |
@var{debug_file_directory}, and returns the first matching |
filename that it finds. If @var{check_crc} is TRUE then the |
contents of the file must also match the CRC value contained in |
@var{section_name}. Returns NULL if no valid file could be found. |
*/ |
typedef char * (* get_func_type) (bfd *, unsigned long *); |
typedef bfd_boolean (* check_func_type) (const char *, const unsigned long); |
static char * |
find_separate_debug_file (bfd * abfd, |
const char * debug_file_directory, |
get_func_type get_func, |
check_func_type check_func) |
{ |
char *base; |
char *dir; |
char *debugfile; |
char *canon_dir; |
unsigned long crc32; |
size_t dirlen; |
size_t canon_dirlen; |
BFD_ASSERT (abfd); |
if (debug_file_directory == NULL) |
debug_file_directory = "."; |
/* BFD may have been opened from a stream. */ |
if (abfd->filename == NULL) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return NULL; |
} |
base = get_func (abfd, & crc32); |
if (base == NULL) |
return NULL; |
if (base[0] == '\0') |
{ |
free (base); |
bfd_set_error (bfd_error_no_debug_section); |
return NULL; |
} |
for (dirlen = strlen (abfd->filename); dirlen > 0; dirlen--) |
if (IS_DIR_SEPARATOR (abfd->filename[dirlen - 1])) |
break; |
dir = (char *) bfd_malloc (dirlen + 1); |
if (dir == NULL) |
{ |
free (base); |
return NULL; |
} |
memcpy (dir, abfd->filename, dirlen); |
dir[dirlen] = '\0'; |
/* Compute the canonical name of the bfd object with all symbolic links |
resolved, for use in the global debugfile directory. */ |
canon_dir = lrealpath (abfd->filename); |
for (canon_dirlen = strlen (canon_dir); canon_dirlen > 0; canon_dirlen--) |
if (IS_DIR_SEPARATOR (canon_dir[canon_dirlen - 1])) |
break; |
canon_dir[canon_dirlen] = '\0'; |
debugfile = (char *) |
bfd_malloc (strlen (debug_file_directory) + 1 |
+ (canon_dirlen > dirlen ? canon_dirlen : dirlen) |
+ strlen (".debug/") |
+ strlen (base) |
+ 1); |
if (debugfile == NULL) |
goto found; /* Actually this returns NULL. */ |
/* First try in the same directory as the original file: */ |
strcpy (debugfile, dir); |
strcat (debugfile, base); |
if (check_func (debugfile, crc32)) |
goto found; |
/* Then try in a subdirectory called .debug. */ |
strcpy (debugfile, dir); |
strcat (debugfile, ".debug/"); |
strcat (debugfile, base); |
if (check_func (debugfile, crc32)) |
goto found; |
/* Then try in the global debugfile directory. */ |
strcpy (debugfile, debug_file_directory); |
dirlen = strlen (debug_file_directory) - 1; |
if (dirlen > 0 |
&& debug_file_directory[dirlen] != '/' |
&& canon_dir[0] != '/') |
strcat (debugfile, "/"); |
strcat (debugfile, canon_dir); |
strcat (debugfile, base); |
if (check_func (debugfile, crc32)) |
goto found; |
/* Failed to find the file. */ |
free (debugfile); |
debugfile = NULL; |
found: |
free (base); |
free (dir); |
free (canon_dir); |
return debugfile; |
} |
/* |
FUNCTION |
bfd_follow_gnu_debuglink |
SYNOPSIS |
char *bfd_follow_gnu_debuglink (bfd *abfd, const char *dir); |
DESCRIPTION |
Takes a BFD and searches it for a .gnu_debuglink section. If this |
section is found, it examines the section for the name and checksum |
of a '.debug' file containing auxiliary debugging information. It |
then searches the filesystem for this .debug file in some standard |
locations, including the directory tree rooted at @var{dir}, and if |
found returns the full filename. |
If @var{dir} is NULL, it will search a default path configured into |
libbfd at build time. [XXX this feature is not currently |
implemented]. |
RETURNS |
<<NULL>> on any errors or failure to locate the .debug file, |
otherwise a pointer to a heap-allocated string containing the |
filename. The caller is responsible for freeing this string. |
*/ |
char * |
bfd_follow_gnu_debuglink (bfd *abfd, const char *dir) |
{ |
return find_separate_debug_file (abfd, dir, |
bfd_get_debug_link_info, |
separate_debug_file_exists); |
} |
/* |
FUNCTION |
bfd_follow_gnu_debugaltlink |
SYNOPSIS |
char *bfd_follow_gnu_debugaltlink (bfd *abfd, const char *dir); |
DESCRIPTION |
Takes a BFD and searches it for a .gnu_debugaltlink section. If this |
section is found, it examines the section for the name of a file |
containing auxiliary debugging information. It then searches the |
filesystem for this file in a set of standard locations, including |
the directory tree rooted at @var{dir}, and if found returns the |
full filename. |
If @var{dir} is NULL, it will search a default path configured into |
libbfd at build time. [FIXME: This feature is not currently |
implemented]. |
RETURNS |
<<NULL>> on any errors or failure to locate the debug file, |
otherwise a pointer to a heap-allocated string containing the |
filename. The caller is responsible for freeing this string. |
*/ |
char * |
bfd_follow_gnu_debugaltlink (bfd *abfd, const char *dir) |
{ |
return find_separate_debug_file (abfd, dir, |
bfd_get_alt_debug_link_info, |
separate_alt_debug_file_exists); |
} |
/* |
FUNCTION |
bfd_create_gnu_debuglink_section |
SYNOPSIS |
struct bfd_section *bfd_create_gnu_debuglink_section |
(bfd *abfd, const char *filename); |
DESCRIPTION |
Takes a @var{BFD} and adds a .gnu_debuglink section to it. The section is sized |
to be big enough to contain a link to the specified @var{filename}. |
RETURNS |
A pointer to the new section is returned if all is ok. Otherwise <<NULL>> is |
returned and bfd_error is set. |
*/ |
asection * |
bfd_create_gnu_debuglink_section (bfd *abfd, const char *filename) |
{ |
asection *sect; |
bfd_size_type debuglink_size; |
flagword flags; |
if (abfd == NULL || filename == NULL) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return NULL; |
} |
/* Strip off any path components in filename. */ |
filename = lbasename (filename); |
sect = bfd_get_section_by_name (abfd, GNU_DEBUGLINK); |
if (sect) |
{ |
/* Section already exists. */ |
bfd_set_error (bfd_error_invalid_operation); |
return NULL; |
} |
flags = SEC_HAS_CONTENTS | SEC_READONLY | SEC_DEBUGGING; |
sect = bfd_make_section_with_flags (abfd, GNU_DEBUGLINK, flags); |
if (sect == NULL) |
return NULL; |
debuglink_size = strlen (filename) + 1; |
debuglink_size += 3; |
debuglink_size &= ~3; |
debuglink_size += 4; |
if (! bfd_set_section_size (abfd, sect, debuglink_size)) |
/* XXX Should we delete the section from the bfd ? */ |
return NULL; |
return sect; |
} |
/* |
FUNCTION |
bfd_fill_in_gnu_debuglink_section |
SYNOPSIS |
bfd_boolean bfd_fill_in_gnu_debuglink_section |
(bfd *abfd, struct bfd_section *sect, const char *filename); |
DESCRIPTION |
Takes a @var{BFD} and containing a .gnu_debuglink section @var{SECT} |
and fills in the contents of the section to contain a link to the |
specified @var{filename}. The filename should be relative to the |
current directory. |
RETURNS |
<<TRUE>> is returned if all is ok. Otherwise <<FALSE>> is returned |
and bfd_error is set. |
*/ |
bfd_boolean |
bfd_fill_in_gnu_debuglink_section (bfd *abfd, |
struct bfd_section *sect, |
const char *filename) |
{ |
bfd_size_type debuglink_size; |
unsigned long crc32; |
char * contents; |
bfd_size_type crc_offset; |
FILE * handle; |
static unsigned char buffer[8 * 1024]; |
size_t count; |
size_t filelen; |
if (abfd == NULL || sect == NULL || filename == NULL) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
/* Make sure that we can read the file. |
XXX - Should we attempt to locate the debug info file using the same |
algorithm as gdb ? At the moment, since we are creating the |
.gnu_debuglink section, we insist upon the user providing us with a |
correct-for-section-creation-time path, but this need not conform to |
the gdb location algorithm. */ |
handle = real_fopen (filename, FOPEN_RB); |
if (handle == NULL) |
{ |
bfd_set_error (bfd_error_system_call); |
return FALSE; |
} |
crc32 = 0; |
while ((count = fread (buffer, 1, sizeof buffer, handle)) > 0) |
crc32 = bfd_calc_gnu_debuglink_crc32 (crc32, buffer, count); |
fclose (handle); |
/* Strip off any path components in filename, |
now that we no longer need them. */ |
filename = lbasename (filename); |
filelen = strlen (filename); |
debuglink_size = filelen + 1; |
debuglink_size += 3; |
debuglink_size &= ~3; |
debuglink_size += 4; |
contents = (char *) bfd_malloc (debuglink_size); |
if (contents == NULL) |
{ |
/* XXX Should we delete the section from the bfd ? */ |
return FALSE; |
} |
crc_offset = debuglink_size - 4; |
memcpy (contents, filename, filelen); |
memset (contents + filelen, 0, crc_offset - filelen); |
bfd_put_32 (abfd, crc32, contents + crc_offset); |
if (! bfd_set_section_contents (abfd, sect, contents, 0, debuglink_size)) |
{ |
/* XXX Should we delete the section from the bfd ? */ |
free (contents); |
return FALSE; |
} |
return TRUE; |
} |
/contrib/toolchain/binutils/bfd/pe-i386.c |
---|
0,0 → 1,46 |
/* BFD back-end for Intel 386 PECOFF files. |
Copyright 1995, 1996, 1999, 2001, 2002, 2004, 2005, 2006, 2007 |
Free Software Foundation, Inc. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#define TARGET_SYM i386pe_vec |
#define TARGET_NAME "pe-i386" |
#define COFF_WITH_PE |
#define PCRELOFFSET TRUE |
#define TARGET_UNDERSCORE '_' |
#define COFF_LONG_SECTION_NAMES |
#define COFF_SUPPORT_GNU_LINKONCE |
#define COFF_LONG_FILENAMES |
#define COFF_SECTION_ALIGNMENT_ENTRIES \ |
{ COFF_SECTION_NAME_PARTIAL_MATCH (".idata"), \ |
COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ |
{ COFF_SECTION_NAME_EXACT_MATCH (".pdata"), \ |
COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ |
{ COFF_SECTION_NAME_PARTIAL_MATCH (".debug"), \ |
COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 }, \ |
{ COFF_SECTION_NAME_PARTIAL_MATCH (".zdebug"), \ |
COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 }, \ |
{ COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.wi."), \ |
COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 } |
#include "coff-i386.c" |
/contrib/toolchain/binutils/bfd/peicode.h |
---|
0,0 → 1,1350 |
/* Support for the generic parts of PE/PEI, for BFD. |
Copyright 1995-2013 Free Software Foundation, Inc. |
Written by Cygnus Solutions. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* Most of this hacked by Steve Chamberlain, |
sac@cygnus.com |
PE/PEI rearrangement (and code added): Donn Terry |
Softway Systems, Inc. */ |
/* Hey look, some documentation [and in a place you expect to find it]! |
The main reference for the pei format is "Microsoft Portable Executable |
and Common Object File Format Specification 4.1". Get it if you need to |
do some serious hacking on this code. |
Another reference: |
"Peering Inside the PE: A Tour of the Win32 Portable Executable |
File Format", MSJ 1994, Volume 9. |
The *sole* difference between the pe format and the pei format is that the |
latter has an MSDOS 2.0 .exe header on the front that prints the message |
"This app must be run under Windows." (or some such). |
(FIXME: Whether that statement is *really* true or not is unknown. |
Are there more subtle differences between pe and pei formats? |
For now assume there aren't. If you find one, then for God sakes |
document it here!) |
The Microsoft docs use the word "image" instead of "executable" because |
the former can also refer to a DLL (shared library). Confusion can arise |
because the `i' in `pei' also refers to "image". The `pe' format can |
also create images (i.e. executables), it's just that to run on a win32 |
system you need to use the pei format. |
FIXME: Please add more docs here so the next poor fool that has to hack |
on this code has a chance of getting something accomplished without |
wasting too much time. */ |
#include "libpei.h" |
static bfd_boolean (*pe_saved_coff_bfd_print_private_bfd_data) (bfd *, void *) = |
#ifndef coff_bfd_print_private_bfd_data |
NULL; |
#else |
coff_bfd_print_private_bfd_data; |
#undef coff_bfd_print_private_bfd_data |
#endif |
static bfd_boolean pe_print_private_bfd_data (bfd *, void *); |
#define coff_bfd_print_private_bfd_data pe_print_private_bfd_data |
static bfd_boolean (*pe_saved_coff_bfd_copy_private_bfd_data) (bfd *, bfd *) = |
#ifndef coff_bfd_copy_private_bfd_data |
NULL; |
#else |
coff_bfd_copy_private_bfd_data; |
#undef coff_bfd_copy_private_bfd_data |
#endif |
static bfd_boolean pe_bfd_copy_private_bfd_data (bfd *, bfd *); |
#define coff_bfd_copy_private_bfd_data pe_bfd_copy_private_bfd_data |
#define coff_mkobject pe_mkobject |
#define coff_mkobject_hook pe_mkobject_hook |
#ifdef COFF_IMAGE_WITH_PE |
/* This structure contains static variables used by the ILF code. */ |
typedef asection * asection_ptr; |
typedef struct |
{ |
bfd * abfd; |
bfd_byte * data; |
struct bfd_in_memory * bim; |
unsigned short magic; |
arelent * reltab; |
unsigned int relcount; |
coff_symbol_type * sym_cache; |
coff_symbol_type * sym_ptr; |
unsigned int sym_index; |
unsigned int * sym_table; |
unsigned int * table_ptr; |
combined_entry_type * native_syms; |
combined_entry_type * native_ptr; |
coff_symbol_type ** sym_ptr_table; |
coff_symbol_type ** sym_ptr_ptr; |
unsigned int sec_index; |
char * string_table; |
char * string_ptr; |
char * end_string_ptr; |
SYMENT * esym_table; |
SYMENT * esym_ptr; |
struct internal_reloc * int_reltab; |
} |
pe_ILF_vars; |
#endif /* COFF_IMAGE_WITH_PE */ |
const bfd_target *coff_real_object_p |
(bfd *, unsigned, struct internal_filehdr *, struct internal_aouthdr *); |
#ifndef NO_COFF_RELOCS |
static void |
coff_swap_reloc_in (bfd * abfd, void * src, void * dst) |
{ |
RELOC *reloc_src = (RELOC *) src; |
struct internal_reloc *reloc_dst = (struct internal_reloc *) dst; |
reloc_dst->r_vaddr = H_GET_32 (abfd, reloc_src->r_vaddr); |
reloc_dst->r_symndx = H_GET_S32 (abfd, reloc_src->r_symndx); |
reloc_dst->r_type = H_GET_16 (abfd, reloc_src->r_type); |
#ifdef SWAP_IN_RELOC_OFFSET |
reloc_dst->r_offset = SWAP_IN_RELOC_OFFSET (abfd, reloc_src->r_offset); |
#endif |
} |
static unsigned int |
coff_swap_reloc_out (bfd * abfd, void * src, void * dst) |
{ |
struct internal_reloc *reloc_src = (struct internal_reloc *) src; |
struct external_reloc *reloc_dst = (struct external_reloc *) dst; |
H_PUT_32 (abfd, reloc_src->r_vaddr, reloc_dst->r_vaddr); |
H_PUT_32 (abfd, reloc_src->r_symndx, reloc_dst->r_symndx); |
H_PUT_16 (abfd, reloc_src->r_type, reloc_dst->r_type); |
#ifdef SWAP_OUT_RELOC_OFFSET |
SWAP_OUT_RELOC_OFFSET (abfd, reloc_src->r_offset, reloc_dst->r_offset); |
#endif |
#ifdef SWAP_OUT_RELOC_EXTRA |
SWAP_OUT_RELOC_EXTRA (abfd, reloc_src, reloc_dst); |
#endif |
return RELSZ; |
} |
#endif /* not NO_COFF_RELOCS */ |
#ifdef COFF_IMAGE_WITH_PE |
#undef FILHDR |
#define FILHDR struct external_PEI_IMAGE_hdr |
#endif |
static void |
coff_swap_filehdr_in (bfd * abfd, void * src, void * dst) |
{ |
FILHDR *filehdr_src = (FILHDR *) src; |
struct internal_filehdr *filehdr_dst = (struct internal_filehdr *) dst; |
filehdr_dst->f_magic = H_GET_16 (abfd, filehdr_src->f_magic); |
filehdr_dst->f_nscns = H_GET_16 (abfd, filehdr_src->f_nscns); |
filehdr_dst->f_timdat = H_GET_32 (abfd, filehdr_src->f_timdat); |
filehdr_dst->f_nsyms = H_GET_32 (abfd, filehdr_src->f_nsyms); |
filehdr_dst->f_flags = H_GET_16 (abfd, filehdr_src->f_flags); |
filehdr_dst->f_symptr = H_GET_32 (abfd, filehdr_src->f_symptr); |
/* Other people's tools sometimes generate headers with an nsyms but |
a zero symptr. */ |
if (filehdr_dst->f_nsyms != 0 && filehdr_dst->f_symptr == 0) |
{ |
filehdr_dst->f_nsyms = 0; |
filehdr_dst->f_flags |= F_LSYMS; |
} |
filehdr_dst->f_opthdr = H_GET_16 (abfd, filehdr_src-> f_opthdr); |
} |
#ifdef COFF_IMAGE_WITH_PE |
# define coff_swap_filehdr_out _bfd_XXi_only_swap_filehdr_out |
#elif defined COFF_WITH_pex64 |
# define coff_swap_filehdr_out _bfd_pex64_only_swap_filehdr_out |
#elif defined COFF_WITH_pep |
# define coff_swap_filehdr_out _bfd_pep_only_swap_filehdr_out |
#else |
# define coff_swap_filehdr_out _bfd_pe_only_swap_filehdr_out |
#endif |
static void |
coff_swap_scnhdr_in (bfd * abfd, void * ext, void * in) |
{ |
SCNHDR *scnhdr_ext = (SCNHDR *) ext; |
struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in; |
memcpy (scnhdr_int->s_name, scnhdr_ext->s_name, sizeof (scnhdr_int->s_name)); |
scnhdr_int->s_vaddr = GET_SCNHDR_VADDR (abfd, scnhdr_ext->s_vaddr); |
scnhdr_int->s_paddr = GET_SCNHDR_PADDR (abfd, scnhdr_ext->s_paddr); |
scnhdr_int->s_size = GET_SCNHDR_SIZE (abfd, scnhdr_ext->s_size); |
scnhdr_int->s_scnptr = GET_SCNHDR_SCNPTR (abfd, scnhdr_ext->s_scnptr); |
scnhdr_int->s_relptr = GET_SCNHDR_RELPTR (abfd, scnhdr_ext->s_relptr); |
scnhdr_int->s_lnnoptr = GET_SCNHDR_LNNOPTR (abfd, scnhdr_ext->s_lnnoptr); |
scnhdr_int->s_flags = H_GET_32 (abfd, scnhdr_ext->s_flags); |
/* MS handles overflow of line numbers by carrying into the reloc |
field (it appears). Since it's supposed to be zero for PE |
*IMAGE* format, that's safe. This is still a bit iffy. */ |
#ifdef COFF_IMAGE_WITH_PE |
scnhdr_int->s_nlnno = (H_GET_16 (abfd, scnhdr_ext->s_nlnno) |
+ (H_GET_16 (abfd, scnhdr_ext->s_nreloc) << 16)); |
scnhdr_int->s_nreloc = 0; |
#else |
scnhdr_int->s_nreloc = H_GET_16 (abfd, scnhdr_ext->s_nreloc); |
scnhdr_int->s_nlnno = H_GET_16 (abfd, scnhdr_ext->s_nlnno); |
#endif |
if (scnhdr_int->s_vaddr != 0) |
{ |
scnhdr_int->s_vaddr += pe_data (abfd)->pe_opthdr.ImageBase; |
/* Do not cut upper 32-bits for 64-bit vma. */ |
#ifndef COFF_WITH_pex64 |
scnhdr_int->s_vaddr &= 0xffffffff; |
#endif |
} |
#ifndef COFF_NO_HACK_SCNHDR_SIZE |
/* If this section holds uninitialized data and is from an object file |
or from an executable image that has not initialized the field, |
or if the image is an executable file and the physical size is padded, |
use the virtual size (stored in s_paddr) instead. */ |
if (scnhdr_int->s_paddr > 0 |
&& (((scnhdr_int->s_flags & IMAGE_SCN_CNT_UNINITIALIZED_DATA) != 0 |
&& (! bfd_pei_p (abfd) || scnhdr_int->s_size == 0)) |
|| (bfd_pei_p (abfd) && (scnhdr_int->s_size > scnhdr_int->s_paddr)))) |
/* This code used to set scnhdr_int->s_paddr to 0. However, |
coff_set_alignment_hook stores s_paddr in virt_size, which |
only works if it correctly holds the virtual size of the |
section. */ |
scnhdr_int->s_size = scnhdr_int->s_paddr; |
#endif |
} |
static bfd_boolean |
pe_mkobject (bfd * abfd) |
{ |
pe_data_type *pe; |
bfd_size_type amt = sizeof (pe_data_type); |
abfd->tdata.pe_obj_data = (struct pe_tdata *) bfd_zalloc (abfd, amt); |
if (abfd->tdata.pe_obj_data == 0) |
return FALSE; |
pe = pe_data (abfd); |
pe->coff.pe = 1; |
/* in_reloc_p is architecture dependent. */ |
pe->in_reloc_p = in_reloc_p; |
return TRUE; |
} |
/* Create the COFF backend specific information. */ |
static void * |
pe_mkobject_hook (bfd * abfd, |
void * filehdr, |
void * aouthdr ATTRIBUTE_UNUSED) |
{ |
struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; |
pe_data_type *pe; |
if (! pe_mkobject (abfd)) |
return NULL; |
pe = pe_data (abfd); |
pe->coff.sym_filepos = internal_f->f_symptr; |
/* These members communicate important constants about the symbol |
table to GDB's symbol-reading code. These `constants' |
unfortunately vary among coff implementations... */ |
pe->coff.local_n_btmask = N_BTMASK; |
pe->coff.local_n_btshft = N_BTSHFT; |
pe->coff.local_n_tmask = N_TMASK; |
pe->coff.local_n_tshift = N_TSHIFT; |
pe->coff.local_symesz = SYMESZ; |
pe->coff.local_auxesz = AUXESZ; |
pe->coff.local_linesz = LINESZ; |
pe->coff.timestamp = internal_f->f_timdat; |
obj_raw_syment_count (abfd) = |
obj_conv_table_size (abfd) = |
internal_f->f_nsyms; |
pe->real_flags = internal_f->f_flags; |
if ((internal_f->f_flags & F_DLL) != 0) |
pe->dll = 1; |
if ((internal_f->f_flags & IMAGE_FILE_DEBUG_STRIPPED) == 0) |
abfd->flags |= HAS_DEBUG; |
#ifdef COFF_IMAGE_WITH_PE |
if (aouthdr) |
pe->pe_opthdr = ((struct internal_aouthdr *) aouthdr)->pe; |
#endif |
#ifdef ARM |
if (! _bfd_coff_arm_set_private_flags (abfd, internal_f->f_flags)) |
coff_data (abfd) ->flags = 0; |
#endif |
return (void *) pe; |
} |
static bfd_boolean |
pe_print_private_bfd_data (bfd *abfd, void * vfile) |
{ |
FILE *file = (FILE *) vfile; |
if (!_bfd_XX_print_private_bfd_data_common (abfd, vfile)) |
return FALSE; |
if (pe_saved_coff_bfd_print_private_bfd_data == NULL) |
return TRUE; |
fputc ('\n', file); |
return pe_saved_coff_bfd_print_private_bfd_data (abfd, vfile); |
} |
/* Copy any private info we understand from the input bfd |
to the output bfd. */ |
static bfd_boolean |
pe_bfd_copy_private_bfd_data (bfd *ibfd, bfd *obfd) |
{ |
/* PR binutils/716: Copy the large address aware flag. |
XXX: Should we be copying other flags or other fields in the pe_data() |
structure ? */ |
if (pe_data (obfd) != NULL |
&& pe_data (ibfd) != NULL |
&& pe_data (ibfd)->real_flags & IMAGE_FILE_LARGE_ADDRESS_AWARE) |
pe_data (obfd)->real_flags |= IMAGE_FILE_LARGE_ADDRESS_AWARE; |
if (!_bfd_XX_bfd_copy_private_bfd_data_common (ibfd, obfd)) |
return FALSE; |
if (pe_saved_coff_bfd_copy_private_bfd_data) |
return pe_saved_coff_bfd_copy_private_bfd_data (ibfd, obfd); |
return TRUE; |
} |
#define coff_bfd_copy_private_section_data \ |
_bfd_XX_bfd_copy_private_section_data |
#define coff_get_symbol_info _bfd_XX_get_symbol_info |
#ifdef COFF_IMAGE_WITH_PE |
/* Code to handle Microsoft's Image Library Format. |
Also known as LINK6 format. |
Documentation about this format can be found at: |
http://msdn.microsoft.com/library/specs/pecoff_section8.htm */ |
/* The following constants specify the sizes of the various data |
structures that we have to create in order to build a bfd describing |
an ILF object file. The final "+ 1" in the definitions of SIZEOF_IDATA6 |
and SIZEOF_IDATA7 below is to allow for the possibility that we might |
need a padding byte in order to ensure 16 bit alignment for the section's |
contents. |
The value for SIZEOF_ILF_STRINGS is computed as follows: |
There will be NUM_ILF_SECTIONS section symbols. Allow 9 characters |
per symbol for their names (longest section name is .idata$x). |
There will be two symbols for the imported value, one the symbol name |
and one with _imp__ prefixed. Allowing for the terminating nul's this |
is strlen (symbol_name) * 2 + 8 + 21 + strlen (source_dll). |
The strings in the string table must start STRING__SIZE_SIZE bytes into |
the table in order to for the string lookup code in coffgen/coffcode to |
work. */ |
#define NUM_ILF_RELOCS 8 |
#define NUM_ILF_SECTIONS 6 |
#define NUM_ILF_SYMS (2 + NUM_ILF_SECTIONS) |
#define SIZEOF_ILF_SYMS (NUM_ILF_SYMS * sizeof (* vars.sym_cache)) |
#define SIZEOF_ILF_SYM_TABLE (NUM_ILF_SYMS * sizeof (* vars.sym_table)) |
#define SIZEOF_ILF_NATIVE_SYMS (NUM_ILF_SYMS * sizeof (* vars.native_syms)) |
#define SIZEOF_ILF_SYM_PTR_TABLE (NUM_ILF_SYMS * sizeof (* vars.sym_ptr_table)) |
#define SIZEOF_ILF_EXT_SYMS (NUM_ILF_SYMS * sizeof (* vars.esym_table)) |
#define SIZEOF_ILF_RELOCS (NUM_ILF_RELOCS * sizeof (* vars.reltab)) |
#define SIZEOF_ILF_INT_RELOCS (NUM_ILF_RELOCS * sizeof (* vars.int_reltab)) |
#define SIZEOF_ILF_STRINGS (strlen (symbol_name) * 2 + 8 \ |
+ 21 + strlen (source_dll) \ |
+ NUM_ILF_SECTIONS * 9 \ |
+ STRING_SIZE_SIZE) |
#define SIZEOF_IDATA2 (5 * 4) |
/* For PEx64 idata4 & 5 have thumb size of 8 bytes. */ |
#ifdef COFF_WITH_pex64 |
#define SIZEOF_IDATA4 (2 * 4) |
#define SIZEOF_IDATA5 (2 * 4) |
#else |
#define SIZEOF_IDATA4 (1 * 4) |
#define SIZEOF_IDATA5 (1 * 4) |
#endif |
#define SIZEOF_IDATA6 (2 + strlen (symbol_name) + 1 + 1) |
#define SIZEOF_IDATA7 (strlen (source_dll) + 1 + 1) |
#define SIZEOF_ILF_SECTIONS (NUM_ILF_SECTIONS * sizeof (struct coff_section_tdata)) |
#define ILF_DATA_SIZE \ |
+ SIZEOF_ILF_SYMS \ |
+ SIZEOF_ILF_SYM_TABLE \ |
+ SIZEOF_ILF_NATIVE_SYMS \ |
+ SIZEOF_ILF_SYM_PTR_TABLE \ |
+ SIZEOF_ILF_EXT_SYMS \ |
+ SIZEOF_ILF_RELOCS \ |
+ SIZEOF_ILF_INT_RELOCS \ |
+ SIZEOF_ILF_STRINGS \ |
+ SIZEOF_IDATA2 \ |
+ SIZEOF_IDATA4 \ |
+ SIZEOF_IDATA5 \ |
+ SIZEOF_IDATA6 \ |
+ SIZEOF_IDATA7 \ |
+ SIZEOF_ILF_SECTIONS \ |
+ MAX_TEXT_SECTION_SIZE |
/* Create an empty relocation against the given symbol. */ |
static void |
pe_ILF_make_a_symbol_reloc (pe_ILF_vars * vars, |
bfd_vma address, |
bfd_reloc_code_real_type reloc, |
struct bfd_symbol ** sym, |
unsigned int sym_index) |
{ |
arelent * entry; |
struct internal_reloc * internal; |
entry = vars->reltab + vars->relcount; |
internal = vars->int_reltab + vars->relcount; |
entry->address = address; |
entry->addend = 0; |
entry->howto = bfd_reloc_type_lookup (vars->abfd, reloc); |
entry->sym_ptr_ptr = sym; |
internal->r_vaddr = address; |
internal->r_symndx = sym_index; |
internal->r_type = entry->howto->type; |
vars->relcount ++; |
BFD_ASSERT (vars->relcount <= NUM_ILF_RELOCS); |
} |
/* Create an empty relocation against the given section. */ |
static void |
pe_ILF_make_a_reloc (pe_ILF_vars * vars, |
bfd_vma address, |
bfd_reloc_code_real_type reloc, |
asection_ptr sec) |
{ |
pe_ILF_make_a_symbol_reloc (vars, address, reloc, sec->symbol_ptr_ptr, |
coff_section_data (vars->abfd, sec)->i); |
} |
/* Move the queued relocs into the given section. */ |
static void |
pe_ILF_save_relocs (pe_ILF_vars * vars, |
asection_ptr sec) |
{ |
/* Make sure that there is somewhere to store the internal relocs. */ |
if (coff_section_data (vars->abfd, sec) == NULL) |
/* We should probably return an error indication here. */ |
abort (); |
coff_section_data (vars->abfd, sec)->relocs = vars->int_reltab; |
coff_section_data (vars->abfd, sec)->keep_relocs = TRUE; |
sec->relocation = vars->reltab; |
sec->reloc_count = vars->relcount; |
sec->flags |= SEC_RELOC; |
vars->reltab += vars->relcount; |
vars->int_reltab += vars->relcount; |
vars->relcount = 0; |
BFD_ASSERT ((bfd_byte *) vars->int_reltab < (bfd_byte *) vars->string_table); |
} |
/* Create a global symbol and add it to the relevant tables. */ |
static void |
pe_ILF_make_a_symbol (pe_ILF_vars * vars, |
const char * prefix, |
const char * symbol_name, |
asection_ptr section, |
flagword extra_flags) |
{ |
coff_symbol_type * sym; |
combined_entry_type * ent; |
SYMENT * esym; |
unsigned short sclass; |
if (extra_flags & BSF_LOCAL) |
sclass = C_STAT; |
else |
sclass = C_EXT; |
#ifdef THUMBPEMAGIC |
if (vars->magic == THUMBPEMAGIC) |
{ |
if (extra_flags & BSF_FUNCTION) |
sclass = C_THUMBEXTFUNC; |
else if (extra_flags & BSF_LOCAL) |
sclass = C_THUMBSTAT; |
else |
sclass = C_THUMBEXT; |
} |
#endif |
BFD_ASSERT (vars->sym_index < NUM_ILF_SYMS); |
sym = vars->sym_ptr; |
ent = vars->native_ptr; |
esym = vars->esym_ptr; |
/* Copy the symbol's name into the string table. */ |
sprintf (vars->string_ptr, "%s%s", prefix, symbol_name); |
if (section == NULL) |
section = bfd_und_section_ptr; |
/* Initialise the external symbol. */ |
H_PUT_32 (vars->abfd, vars->string_ptr - vars->string_table, |
esym->e.e.e_offset); |
H_PUT_16 (vars->abfd, section->target_index, esym->e_scnum); |
esym->e_sclass[0] = sclass; |
/* The following initialisations are unnecessary - the memory is |
zero initialised. They are just kept here as reminders. */ |
/* Initialise the internal symbol structure. */ |
ent->u.syment.n_sclass = sclass; |
ent->u.syment.n_scnum = section->target_index; |
ent->u.syment._n._n_n._n_offset = (bfd_hostptr_t) sym; |
sym->symbol.the_bfd = vars->abfd; |
sym->symbol.name = vars->string_ptr; |
sym->symbol.flags = BSF_EXPORT | BSF_GLOBAL | extra_flags; |
sym->symbol.section = section; |
sym->native = ent; |
* vars->table_ptr = vars->sym_index; |
* vars->sym_ptr_ptr = sym; |
/* Adjust pointers for the next symbol. */ |
vars->sym_index ++; |
vars->sym_ptr ++; |
vars->sym_ptr_ptr ++; |
vars->table_ptr ++; |
vars->native_ptr ++; |
vars->esym_ptr ++; |
vars->string_ptr += strlen (symbol_name) + strlen (prefix) + 1; |
BFD_ASSERT (vars->string_ptr < vars->end_string_ptr); |
} |
/* Create a section. */ |
static asection_ptr |
pe_ILF_make_a_section (pe_ILF_vars * vars, |
const char * name, |
unsigned int size, |
flagword extra_flags) |
{ |
asection_ptr sec; |
flagword flags; |
sec = bfd_make_section_old_way (vars->abfd, name); |
if (sec == NULL) |
return NULL; |
flags = SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_KEEP | SEC_IN_MEMORY; |
bfd_set_section_flags (vars->abfd, sec, flags | extra_flags); |
(void) bfd_set_section_alignment (vars->abfd, sec, 2); |
/* Check that we will not run out of space. */ |
BFD_ASSERT (vars->data + size < vars->bim->buffer + vars->bim->size); |
/* Set the section size and contents. The actual |
contents are filled in by our parent. */ |
bfd_set_section_size (vars->abfd, sec, (bfd_size_type) size); |
sec->contents = vars->data; |
sec->target_index = vars->sec_index ++; |
/* Advance data pointer in the vars structure. */ |
vars->data += size; |
/* Skip the padding byte if it was not needed. |
The logic here is that if the string length is odd, |
then the entire string length, including the null byte, |
is even and so the extra, padding byte, is not needed. */ |
if (size & 1) |
vars->data --; |
/* Create a coff_section_tdata structure for our use. */ |
sec->used_by_bfd = (struct coff_section_tdata *) vars->data; |
vars->data += sizeof (struct coff_section_tdata); |
BFD_ASSERT (vars->data <= vars->bim->buffer + vars->bim->size); |
/* Create a symbol to refer to this section. */ |
pe_ILF_make_a_symbol (vars, "", name, sec, BSF_LOCAL); |
/* Cache the index to the symbol in the coff_section_data structure. */ |
coff_section_data (vars->abfd, sec)->i = vars->sym_index - 1; |
return sec; |
} |
/* This structure contains the code that goes into the .text section |
in order to perform a jump into the DLL lookup table. The entries |
in the table are index by the magic number used to represent the |
machine type in the PE file. The contents of the data[] arrays in |
these entries are stolen from the jtab[] arrays in ld/pe-dll.c. |
The SIZE field says how many bytes in the DATA array are actually |
used. The OFFSET field says where in the data array the address |
of the .idata$5 section should be placed. */ |
#define MAX_TEXT_SECTION_SIZE 32 |
typedef struct |
{ |
unsigned short magic; |
unsigned char data[MAX_TEXT_SECTION_SIZE]; |
unsigned int size; |
unsigned int offset; |
} |
jump_table; |
static jump_table jtab[] = |
{ |
#ifdef I386MAGIC |
{ I386MAGIC, |
{ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x90, 0x90 }, |
8, 2 |
}, |
#endif |
#ifdef AMD64MAGIC |
{ AMD64MAGIC, |
{ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x90, 0x90 }, |
8, 2 |
}, |
#endif |
#ifdef MC68MAGIC |
{ MC68MAGIC, |
{ /* XXX fill me in */ }, |
0, 0 |
}, |
#endif |
#ifdef MIPS_ARCH_MAGIC_WINCE |
{ MIPS_ARCH_MAGIC_WINCE, |
{ 0x00, 0x00, 0x08, 0x3c, 0x00, 0x00, 0x08, 0x8d, |
0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 }, |
16, 0 |
}, |
#endif |
#ifdef SH_ARCH_MAGIC_WINCE |
{ SH_ARCH_MAGIC_WINCE, |
{ 0x01, 0xd0, 0x02, 0x60, 0x2b, 0x40, |
0x09, 0x00, 0x00, 0x00, 0x00, 0x00 }, |
12, 8 |
}, |
#endif |
#ifdef ARMPEMAGIC |
{ ARMPEMAGIC, |
{ 0x00, 0xc0, 0x9f, 0xe5, 0x00, 0xf0, |
0x9c, 0xe5, 0x00, 0x00, 0x00, 0x00}, |
12, 8 |
}, |
#endif |
#ifdef THUMBPEMAGIC |
{ THUMBPEMAGIC, |
{ 0x40, 0xb4, 0x02, 0x4e, 0x36, 0x68, 0xb4, 0x46, |
0x40, 0xbc, 0x60, 0x47, 0x00, 0x00, 0x00, 0x00 }, |
16, 12 |
}, |
#endif |
{ 0, { 0 }, 0, 0 } |
}; |
#ifndef NUM_ENTRIES |
#define NUM_ENTRIES(a) (sizeof (a) / sizeof (a)[0]) |
#endif |
/* Build a full BFD from the information supplied in a ILF object. */ |
static bfd_boolean |
pe_ILF_build_a_bfd (bfd * abfd, |
unsigned int magic, |
char * symbol_name, |
char * source_dll, |
unsigned int ordinal, |
unsigned int types) |
{ |
bfd_byte * ptr; |
pe_ILF_vars vars; |
struct internal_filehdr internal_f; |
unsigned int import_type; |
unsigned int import_name_type; |
asection_ptr id4, id5, id6 = NULL, text = NULL; |
coff_symbol_type ** imp_sym; |
unsigned int imp_index; |
/* Decode and verify the types field of the ILF structure. */ |
import_type = types & 0x3; |
import_name_type = (types & 0x1c) >> 2; |
switch (import_type) |
{ |
case IMPORT_CODE: |
case IMPORT_DATA: |
break; |
case IMPORT_CONST: |
/* XXX code yet to be written. */ |
_bfd_error_handler (_("%B: Unhandled import type; %x"), |
abfd, import_type); |
return FALSE; |
default: |
_bfd_error_handler (_("%B: Unrecognised import type; %x"), |
abfd, import_type); |
return FALSE; |
} |
switch (import_name_type) |
{ |
case IMPORT_ORDINAL: |
case IMPORT_NAME: |
case IMPORT_NAME_NOPREFIX: |
case IMPORT_NAME_UNDECORATE: |
break; |
default: |
_bfd_error_handler (_("%B: Unrecognised import name type; %x"), |
abfd, import_name_type); |
return FALSE; |
} |
/* Initialise local variables. |
Note these are kept in a structure rather than being |
declared as statics since bfd frowns on global variables. |
We are going to construct the contents of the BFD in memory, |
so allocate all the space that we will need right now. */ |
vars.bim |
= (struct bfd_in_memory *) bfd_malloc ((bfd_size_type) sizeof (*vars.bim)); |
if (vars.bim == NULL) |
return FALSE; |
ptr = (bfd_byte *) bfd_zmalloc ((bfd_size_type) ILF_DATA_SIZE); |
vars.bim->buffer = ptr; |
vars.bim->size = ILF_DATA_SIZE; |
if (ptr == NULL) |
goto error_return; |
/* Initialise the pointers to regions of the memory and the |
other contents of the pe_ILF_vars structure as well. */ |
vars.sym_cache = (coff_symbol_type *) ptr; |
vars.sym_ptr = (coff_symbol_type *) ptr; |
vars.sym_index = 0; |
ptr += SIZEOF_ILF_SYMS; |
vars.sym_table = (unsigned int *) ptr; |
vars.table_ptr = (unsigned int *) ptr; |
ptr += SIZEOF_ILF_SYM_TABLE; |
vars.native_syms = (combined_entry_type *) ptr; |
vars.native_ptr = (combined_entry_type *) ptr; |
ptr += SIZEOF_ILF_NATIVE_SYMS; |
vars.sym_ptr_table = (coff_symbol_type **) ptr; |
vars.sym_ptr_ptr = (coff_symbol_type **) ptr; |
ptr += SIZEOF_ILF_SYM_PTR_TABLE; |
vars.esym_table = (SYMENT *) ptr; |
vars.esym_ptr = (SYMENT *) ptr; |
ptr += SIZEOF_ILF_EXT_SYMS; |
vars.reltab = (arelent *) ptr; |
vars.relcount = 0; |
ptr += SIZEOF_ILF_RELOCS; |
vars.int_reltab = (struct internal_reloc *) ptr; |
ptr += SIZEOF_ILF_INT_RELOCS; |
vars.string_table = (char *) ptr; |
vars.string_ptr = (char *) ptr + STRING_SIZE_SIZE; |
ptr += SIZEOF_ILF_STRINGS; |
vars.end_string_ptr = (char *) ptr; |
/* The remaining space in bim->buffer is used |
by the pe_ILF_make_a_section() function. */ |
vars.data = ptr; |
vars.abfd = abfd; |
vars.sec_index = 0; |
vars.magic = magic; |
/* Create the initial .idata$<n> sections: |
[.idata$2: Import Directory Table -- not needed] |
.idata$4: Import Lookup Table |
.idata$5: Import Address Table |
Note we do not create a .idata$3 section as this is |
created for us by the linker script. */ |
id4 = pe_ILF_make_a_section (& vars, ".idata$4", SIZEOF_IDATA4, 0); |
id5 = pe_ILF_make_a_section (& vars, ".idata$5", SIZEOF_IDATA5, 0); |
if (id4 == NULL || id5 == NULL) |
goto error_return; |
/* Fill in the contents of these sections. */ |
if (import_name_type == IMPORT_ORDINAL) |
{ |
if (ordinal == 0) |
/* XXX - treat as IMPORT_NAME ??? */ |
abort (); |
#ifdef COFF_WITH_pex64 |
((unsigned int *) id4->contents)[0] = ordinal; |
((unsigned int *) id4->contents)[1] = 0x80000000; |
((unsigned int *) id5->contents)[0] = ordinal; |
((unsigned int *) id5->contents)[1] = 0x80000000; |
#else |
* (unsigned int *) id4->contents = ordinal | 0x80000000; |
* (unsigned int *) id5->contents = ordinal | 0x80000000; |
#endif |
} |
else |
{ |
char * symbol; |
unsigned int len; |
/* Create .idata$6 - the Hint Name Table. */ |
id6 = pe_ILF_make_a_section (& vars, ".idata$6", SIZEOF_IDATA6, 0); |
if (id6 == NULL) |
goto error_return; |
/* If necessary, trim the import symbol name. */ |
symbol = symbol_name; |
/* As used by MS compiler, '_', '@', and '?' are alternative |
forms of USER_LABEL_PREFIX, with '?' for c++ mangled names, |
'@' used for fastcall (in C), '_' everywhere else. Only one |
of these is used for a symbol. We strip this leading char for |
IMPORT_NAME_NOPREFIX and IMPORT_NAME_UNDECORATE as per the |
PE COFF 6.0 spec (section 8.3, Import Name Type). */ |
if (import_name_type != IMPORT_NAME) |
{ |
char c = symbol[0]; |
/* Check that we don't remove for targets with empty |
USER_LABEL_PREFIX the leading underscore. */ |
if ((c == '_' && abfd->xvec->symbol_leading_char != 0) |
|| c == '@' || c == '?') |
symbol++; |
} |
len = strlen (symbol); |
if (import_name_type == IMPORT_NAME_UNDECORATE) |
{ |
/* Truncate at the first '@'. */ |
char *at = strchr (symbol, '@'); |
if (at != NULL) |
len = at - symbol; |
} |
id6->contents[0] = ordinal & 0xff; |
id6->contents[1] = ordinal >> 8; |
memcpy ((char *) id6->contents + 2, symbol, len); |
id6->contents[len + 2] = '\0'; |
} |
if (import_name_type != IMPORT_ORDINAL) |
{ |
pe_ILF_make_a_reloc (&vars, (bfd_vma) 0, BFD_RELOC_RVA, id6); |
pe_ILF_save_relocs (&vars, id4); |
pe_ILF_make_a_reloc (&vars, (bfd_vma) 0, BFD_RELOC_RVA, id6); |
pe_ILF_save_relocs (&vars, id5); |
} |
/* Create extra sections depending upon the type of import we are dealing with. */ |
switch (import_type) |
{ |
int i; |
case IMPORT_CODE: |
/* Create a .text section. |
First we need to look up its contents in the jump table. */ |
for (i = NUM_ENTRIES (jtab); i--;) |
{ |
if (jtab[i].size == 0) |
continue; |
if (jtab[i].magic == magic) |
break; |
} |
/* If we did not find a matching entry something is wrong. */ |
if (i < 0) |
abort (); |
/* Create the .text section. */ |
text = pe_ILF_make_a_section (& vars, ".text", jtab[i].size, SEC_CODE); |
if (text == NULL) |
goto error_return; |
/* Copy in the jump code. */ |
memcpy (text->contents, jtab[i].data, jtab[i].size); |
/* Create an import symbol. */ |
pe_ILF_make_a_symbol (& vars, "__imp_", symbol_name, id5, 0); |
imp_sym = vars.sym_ptr_ptr - 1; |
imp_index = vars.sym_index - 1; |
/* Create a reloc for the data in the text section. */ |
#ifdef MIPS_ARCH_MAGIC_WINCE |
if (magic == MIPS_ARCH_MAGIC_WINCE) |
{ |
pe_ILF_make_a_symbol_reloc (&vars, (bfd_vma) 0, BFD_RELOC_HI16_S, |
(struct bfd_symbol **) imp_sym, |
imp_index); |
pe_ILF_make_a_reloc (&vars, (bfd_vma) 0, BFD_RELOC_LO16, text); |
pe_ILF_make_a_symbol_reloc (&vars, (bfd_vma) 4, BFD_RELOC_LO16, |
(struct bfd_symbol **) imp_sym, |
imp_index); |
} |
else |
#endif |
pe_ILF_make_a_symbol_reloc (&vars, (bfd_vma) jtab[i].offset, |
BFD_RELOC_32, (asymbol **) imp_sym, |
imp_index); |
pe_ILF_save_relocs (& vars, text); |
break; |
case IMPORT_DATA: |
break; |
default: |
/* XXX code not yet written. */ |
abort (); |
} |
/* Initialise the bfd. */ |
memset (& internal_f, 0, sizeof (internal_f)); |
internal_f.f_magic = magic; |
internal_f.f_symptr = 0; |
internal_f.f_nsyms = 0; |
internal_f.f_flags = F_AR32WR | F_LNNO; /* XXX is this correct ? */ |
if ( ! bfd_set_start_address (abfd, (bfd_vma) 0) |
|| ! bfd_coff_set_arch_mach_hook (abfd, & internal_f)) |
goto error_return; |
if (bfd_coff_mkobject_hook (abfd, (void *) & internal_f, NULL) == NULL) |
goto error_return; |
coff_data (abfd)->pe = 1; |
#ifdef THUMBPEMAGIC |
if (vars.magic == THUMBPEMAGIC) |
/* Stop some linker warnings about thumb code not supporting interworking. */ |
coff_data (abfd)->flags |= F_INTERWORK | F_INTERWORK_SET; |
#endif |
/* Switch from file contents to memory contents. */ |
bfd_cache_close (abfd); |
abfd->iostream = (void *) vars.bim; |
abfd->flags |= BFD_IN_MEMORY /* | HAS_LOCALS */; |
abfd->iovec = &_bfd_memory_iovec; |
abfd->where = 0; |
abfd->origin = 0; |
obj_sym_filepos (abfd) = 0; |
/* Now create a symbol describing the imported value. */ |
switch (import_type) |
{ |
case IMPORT_CODE: |
pe_ILF_make_a_symbol (& vars, "", symbol_name, text, |
BSF_NOT_AT_END | BSF_FUNCTION); |
/* Create an import symbol for the DLL, without the |
.dll suffix. */ |
ptr = (bfd_byte *) strrchr (source_dll, '.'); |
if (ptr) |
* ptr = 0; |
pe_ILF_make_a_symbol (& vars, "__IMPORT_DESCRIPTOR_", source_dll, NULL, 0); |
if (ptr) |
* ptr = '.'; |
break; |
case IMPORT_DATA: |
/* Nothing to do here. */ |
break; |
default: |
/* XXX code not yet written. */ |
abort (); |
} |
/* Point the bfd at the symbol table. */ |
obj_symbols (abfd) = vars.sym_cache; |
bfd_get_symcount (abfd) = vars.sym_index; |
obj_raw_syments (abfd) = vars.native_syms; |
obj_raw_syment_count (abfd) = vars.sym_index; |
obj_coff_external_syms (abfd) = (void *) vars.esym_table; |
obj_coff_keep_syms (abfd) = TRUE; |
obj_convert (abfd) = vars.sym_table; |
obj_conv_table_size (abfd) = vars.sym_index; |
obj_coff_strings (abfd) = vars.string_table; |
obj_coff_keep_strings (abfd) = TRUE; |
abfd->flags |= HAS_SYMS; |
return TRUE; |
error_return: |
if (vars.bim->buffer != NULL) |
free (vars.bim->buffer); |
free (vars.bim); |
return FALSE; |
} |
/* We have detected a Image Library Format archive element. |
Decode the element and return the appropriate target. */ |
static const bfd_target * |
pe_ILF_object_p (bfd * abfd) |
{ |
bfd_byte buffer[16]; |
bfd_byte * ptr; |
char * symbol_name; |
char * source_dll; |
unsigned int machine; |
bfd_size_type size; |
unsigned int ordinal; |
unsigned int types; |
unsigned int magic; |
/* Upon entry the first four buyes of the ILF header have |
already been read. Now read the rest of the header. */ |
if (bfd_bread (buffer, (bfd_size_type) 16, abfd) != 16) |
return NULL; |
ptr = buffer; |
/* We do not bother to check the version number. |
version = H_GET_16 (abfd, ptr); */ |
ptr += 2; |
machine = H_GET_16 (abfd, ptr); |
ptr += 2; |
/* Check that the machine type is recognised. */ |
magic = 0; |
switch (machine) |
{ |
case IMAGE_FILE_MACHINE_UNKNOWN: |
case IMAGE_FILE_MACHINE_ALPHA: |
case IMAGE_FILE_MACHINE_ALPHA64: |
case IMAGE_FILE_MACHINE_IA64: |
break; |
case IMAGE_FILE_MACHINE_I386: |
#ifdef I386MAGIC |
magic = I386MAGIC; |
#endif |
break; |
case IMAGE_FILE_MACHINE_AMD64: |
#ifdef AMD64MAGIC |
magic = AMD64MAGIC; |
#endif |
break; |
case IMAGE_FILE_MACHINE_M68K: |
#ifdef MC68AGIC |
magic = MC68MAGIC; |
#endif |
break; |
case IMAGE_FILE_MACHINE_R3000: |
case IMAGE_FILE_MACHINE_R4000: |
case IMAGE_FILE_MACHINE_R10000: |
case IMAGE_FILE_MACHINE_MIPS16: |
case IMAGE_FILE_MACHINE_MIPSFPU: |
case IMAGE_FILE_MACHINE_MIPSFPU16: |
#ifdef MIPS_ARCH_MAGIC_WINCE |
magic = MIPS_ARCH_MAGIC_WINCE; |
#endif |
break; |
case IMAGE_FILE_MACHINE_SH3: |
case IMAGE_FILE_MACHINE_SH4: |
#ifdef SH_ARCH_MAGIC_WINCE |
magic = SH_ARCH_MAGIC_WINCE; |
#endif |
break; |
case IMAGE_FILE_MACHINE_ARM: |
#ifdef ARMPEMAGIC |
magic = ARMPEMAGIC; |
#endif |
break; |
case IMAGE_FILE_MACHINE_THUMB: |
#ifdef THUMBPEMAGIC |
{ |
extern const bfd_target TARGET_LITTLE_SYM; |
if (abfd->xvec == & TARGET_LITTLE_SYM) |
magic = THUMBPEMAGIC; |
} |
#endif |
break; |
case IMAGE_FILE_MACHINE_POWERPC: |
/* We no longer support PowerPC. */ |
default: |
_bfd_error_handler |
(_("%B: Unrecognised machine type (0x%x)" |
" in Import Library Format archive"), |
abfd, machine); |
bfd_set_error (bfd_error_malformed_archive); |
return NULL; |
break; |
} |
if (magic == 0) |
{ |
_bfd_error_handler |
(_("%B: Recognised but unhandled machine type (0x%x)" |
" in Import Library Format archive"), |
abfd, machine); |
bfd_set_error (bfd_error_wrong_format); |
return NULL; |
} |
/* We do not bother to check the date. |
date = H_GET_32 (abfd, ptr); */ |
ptr += 4; |
size = H_GET_32 (abfd, ptr); |
ptr += 4; |
if (size == 0) |
{ |
_bfd_error_handler |
(_("%B: size field is zero in Import Library Format header"), abfd); |
bfd_set_error (bfd_error_malformed_archive); |
return NULL; |
} |
ordinal = H_GET_16 (abfd, ptr); |
ptr += 2; |
types = H_GET_16 (abfd, ptr); |
/* ptr += 2; */ |
/* Now read in the two strings that follow. */ |
ptr = (bfd_byte *) bfd_alloc (abfd, size); |
if (ptr == NULL) |
return NULL; |
if (bfd_bread (ptr, size, abfd) != size) |
{ |
bfd_release (abfd, ptr); |
return NULL; |
} |
symbol_name = (char *) ptr; |
source_dll = symbol_name + strlen (symbol_name) + 1; |
/* Verify that the strings are null terminated. */ |
if (ptr[size - 1] != 0 |
|| (bfd_size_type) ((bfd_byte *) source_dll - ptr) >= size) |
{ |
_bfd_error_handler |
(_("%B: string not null terminated in ILF object file."), abfd); |
bfd_set_error (bfd_error_malformed_archive); |
bfd_release (abfd, ptr); |
return NULL; |
} |
/* Now construct the bfd. */ |
if (! pe_ILF_build_a_bfd (abfd, magic, symbol_name, |
source_dll, ordinal, types)) |
{ |
bfd_release (abfd, ptr); |
return NULL; |
} |
return abfd->xvec; |
} |
static const bfd_target * |
pe_bfd_object_p (bfd * abfd) |
{ |
bfd_byte buffer[4]; |
struct external_PEI_DOS_hdr dos_hdr; |
struct external_PEI_IMAGE_hdr image_hdr; |
struct internal_filehdr internal_f; |
struct internal_aouthdr internal_a; |
file_ptr opt_hdr_size; |
file_ptr offset; |
/* Detect if this a Microsoft Import Library Format element. */ |
if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 |
|| bfd_bread (buffer, (bfd_size_type) 4, abfd) != 4) |
{ |
if (bfd_get_error () != bfd_error_system_call) |
bfd_set_error (bfd_error_wrong_format); |
return NULL; |
} |
if (H_GET_32 (abfd, buffer) == 0xffff0000) |
return pe_ILF_object_p (abfd); |
if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 |
|| bfd_bread (&dos_hdr, (bfd_size_type) sizeof (dos_hdr), abfd) |
!= sizeof (dos_hdr)) |
{ |
if (bfd_get_error () != bfd_error_system_call) |
bfd_set_error (bfd_error_wrong_format); |
return NULL; |
} |
/* There are really two magic numbers involved; the magic number |
that says this is a NT executable (PEI) and the magic number that |
determines the architecture. The former is DOSMAGIC, stored in |
the e_magic field. The latter is stored in the f_magic field. |
If the NT magic number isn't valid, the architecture magic number |
could be mimicked by some other field (specifically, the number |
of relocs in section 3). Since this routine can only be called |
correctly for a PEI file, check the e_magic number here, and, if |
it doesn't match, clobber the f_magic number so that we don't get |
a false match. */ |
if (H_GET_16 (abfd, dos_hdr.e_magic) != DOSMAGIC) |
{ |
bfd_set_error (bfd_error_wrong_format); |
return NULL; |
} |
offset = H_GET_32 (abfd, dos_hdr.e_lfanew); |
if (bfd_seek (abfd, offset, SEEK_SET) != 0 |
|| (bfd_bread (&image_hdr, (bfd_size_type) sizeof (image_hdr), abfd) |
!= sizeof (image_hdr))) |
{ |
if (bfd_get_error () != bfd_error_system_call) |
bfd_set_error (bfd_error_wrong_format); |
return NULL; |
} |
if (H_GET_32 (abfd, image_hdr.nt_signature) != 0x4550) |
{ |
bfd_set_error (bfd_error_wrong_format); |
return NULL; |
} |
/* Swap file header, so that we get the location for calling |
real_object_p. */ |
bfd_coff_swap_filehdr_in (abfd, (PTR)&image_hdr, &internal_f); |
if (! bfd_coff_bad_format_hook (abfd, &internal_f) |
|| internal_f.f_opthdr > bfd_coff_aoutsz (abfd)) |
{ |
bfd_set_error (bfd_error_wrong_format); |
return NULL; |
} |
/* Read the optional header, which has variable size. */ |
opt_hdr_size = internal_f.f_opthdr; |
if (opt_hdr_size != 0) |
{ |
PTR opthdr; |
opthdr = bfd_alloc (abfd, opt_hdr_size); |
if (opthdr == NULL) |
return NULL; |
if (bfd_bread (opthdr, opt_hdr_size, abfd) |
!= (bfd_size_type) opt_hdr_size) |
return NULL; |
bfd_coff_swap_aouthdr_in (abfd, opthdr, (PTR) & internal_a); |
} |
return coff_real_object_p (abfd, internal_f.f_nscns, &internal_f, |
(opt_hdr_size != 0 |
? &internal_a |
: (struct internal_aouthdr *) NULL)); |
} |
#define coff_object_p pe_bfd_object_p |
#endif /* COFF_IMAGE_WITH_PE */ |
/contrib/toolchain/binutils/bfd/peigen.c |
---|
0,0 → 1,2486 |
/* Support for the generic parts of PE/PEI; the common executable parts. |
Copyright 1995-2013 Free Software Foundation, Inc. |
Written by Cygnus Solutions. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* Most of this hacked by Steve Chamberlain <sac@cygnus.com>. |
PE/PEI rearrangement (and code added): Donn Terry |
Softway Systems, Inc. */ |
/* Hey look, some documentation [and in a place you expect to find it]! |
The main reference for the pei format is "Microsoft Portable Executable |
and Common Object File Format Specification 4.1". Get it if you need to |
do some serious hacking on this code. |
Another reference: |
"Peering Inside the PE: A Tour of the Win32 Portable Executable |
File Format", MSJ 1994, Volume 9. |
The *sole* difference between the pe format and the pei format is that the |
latter has an MSDOS 2.0 .exe header on the front that prints the message |
"This app must be run under Windows." (or some such). |
(FIXME: Whether that statement is *really* true or not is unknown. |
Are there more subtle differences between pe and pei formats? |
For now assume there aren't. If you find one, then for God sakes |
document it here!) |
The Microsoft docs use the word "image" instead of "executable" because |
the former can also refer to a DLL (shared library). Confusion can arise |
because the `i' in `pei' also refers to "image". The `pe' format can |
also create images (i.e. executables), it's just that to run on a win32 |
system you need to use the pei format. |
FIXME: Please add more docs here so the next poor fool that has to hack |
on this code has a chance of getting something accomplished without |
wasting too much time. */ |
/* This expands into COFF_WITH_pe, COFF_WITH_pep, or COFF_WITH_pex64 |
depending on whether we're compiling for straight PE or PE+. */ |
#define COFF_WITH_pe |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
#include "coff/internal.h" |
#include "bfdver.h" |
/* NOTE: it's strange to be including an architecture specific header |
in what's supposed to be general (to PE/PEI) code. However, that's |
where the definitions are, and they don't vary per architecture |
within PE/PEI, so we get them from there. FIXME: The lack of |
variance is an assumption which may prove to be incorrect if new |
PE/PEI targets are created. */ |
#if defined COFF_WITH_pex64 |
# include "coff/x86_64.h" |
#elif defined COFF_WITH_pep |
# include "coff/ia64.h" |
#else |
# include "coff/i386.h" |
#endif |
#include "coff/pe.h" |
#include "libcoff.h" |
#include "libpei.h" |
#if defined COFF_WITH_pep || defined COFF_WITH_pex64 |
# undef AOUTSZ |
# define AOUTSZ PEPAOUTSZ |
# define PEAOUTHDR PEPAOUTHDR |
#endif |
/* FIXME: This file has various tests of POWERPC_LE_PE. Those tests |
worked when the code was in peicode.h, but no longer work now that |
the code is in peigen.c. PowerPC NT is said to be dead. If |
anybody wants to revive the code, you will have to figure out how |
to handle those issues. */ |
void |
_bfd_pei_swap_sym_in (bfd * abfd, void * ext1, void * in1) |
{ |
SYMENT *ext = (SYMENT *) ext1; |
struct internal_syment *in = (struct internal_syment *) in1; |
if (ext->e.e_name[0] == 0) |
{ |
in->_n._n_n._n_zeroes = 0; |
in->_n._n_n._n_offset = H_GET_32 (abfd, ext->e.e.e_offset); |
} |
else |
memcpy (in->_n._n_name, ext->e.e_name, SYMNMLEN); |
in->n_value = H_GET_32 (abfd, ext->e_value); |
in->n_scnum = H_GET_16 (abfd, ext->e_scnum); |
if (sizeof (ext->e_type) == 2) |
in->n_type = H_GET_16 (abfd, ext->e_type); |
else |
in->n_type = H_GET_32 (abfd, ext->e_type); |
in->n_sclass = H_GET_8 (abfd, ext->e_sclass); |
in->n_numaux = H_GET_8 (abfd, ext->e_numaux); |
#ifndef STRICT_PE_FORMAT |
/* This is for Gnu-created DLLs. */ |
/* The section symbols for the .idata$ sections have class 0x68 |
(C_SECTION), which MS documentation indicates is a section |
symbol. Unfortunately, the value field in the symbol is simply a |
copy of the .idata section's flags rather than something useful. |
When these symbols are encountered, change the value to 0 so that |
they will be handled somewhat correctly in the bfd code. */ |
if (in->n_sclass == C_SECTION) |
{ |
char namebuf[SYMNMLEN + 1]; |
const char *name = NULL; |
in->n_value = 0x0; |
/* Create synthetic empty sections as needed. DJ */ |
if (in->n_scnum == 0) |
{ |
asection *sec; |
name = _bfd_coff_internal_syment_name (abfd, in, namebuf); |
if (name == NULL) |
/* FIXME: Return error. */ |
abort (); |
sec = bfd_get_section_by_name (abfd, name); |
if (sec != NULL) |
in->n_scnum = sec->target_index; |
} |
if (in->n_scnum == 0) |
{ |
int unused_section_number = 0; |
asection *sec; |
flagword flags; |
for (sec = abfd->sections; sec; sec = sec->next) |
if (unused_section_number <= sec->target_index) |
unused_section_number = sec->target_index + 1; |
if (name == namebuf) |
{ |
name = (const char *) bfd_alloc (abfd, strlen (namebuf) + 1); |
if (name == NULL) |
/* FIXME: Return error. */ |
abort (); |
strcpy ((char *) name, namebuf); |
} |
flags = SEC_HAS_CONTENTS | SEC_ALLOC | SEC_DATA | SEC_LOAD; |
sec = bfd_make_section_anyway_with_flags (abfd, name, flags); |
if (sec == NULL) |
/* FIXME: Return error. */ |
abort (); |
sec->vma = 0; |
sec->lma = 0; |
sec->size = 0; |
sec->filepos = 0; |
sec->rel_filepos = 0; |
sec->reloc_count = 0; |
sec->line_filepos = 0; |
sec->lineno_count = 0; |
sec->userdata = NULL; |
sec->next = NULL; |
sec->alignment_power = 2; |
sec->target_index = unused_section_number; |
in->n_scnum = unused_section_number; |
} |
in->n_sclass = C_STAT; |
} |
#endif |
#ifdef coff_swap_sym_in_hook |
/* This won't work in peigen.c, but since it's for PPC PE, it's not |
worth fixing. */ |
coff_swap_sym_in_hook (abfd, ext1, in1); |
#endif |
} |
unsigned int |
_bfd_pei_swap_sym_out (bfd * abfd, void * inp, void * extp) |
{ |
struct internal_syment *in = (struct internal_syment *) inp; |
SYMENT *ext = (SYMENT *) extp; |
if (in->_n._n_name[0] == 0) |
{ |
H_PUT_32 (abfd, 0, ext->e.e.e_zeroes); |
H_PUT_32 (abfd, in->_n._n_n._n_offset, ext->e.e.e_offset); |
} |
else |
memcpy (ext->e.e_name, in->_n._n_name, SYMNMLEN); |
H_PUT_32 (abfd, in->n_value, ext->e_value); |
H_PUT_16 (abfd, in->n_scnum, ext->e_scnum); |
if (sizeof (ext->e_type) == 2) |
H_PUT_16 (abfd, in->n_type, ext->e_type); |
else |
H_PUT_32 (abfd, in->n_type, ext->e_type); |
H_PUT_8 (abfd, in->n_sclass, ext->e_sclass); |
H_PUT_8 (abfd, in->n_numaux, ext->e_numaux); |
return SYMESZ; |
} |
void |
_bfd_pei_swap_aux_in (bfd * abfd, |
void * ext1, |
int type, |
int in_class, |
int indx ATTRIBUTE_UNUSED, |
int numaux ATTRIBUTE_UNUSED, |
void * in1) |
{ |
AUXENT *ext = (AUXENT *) ext1; |
union internal_auxent *in = (union internal_auxent *) in1; |
switch (in_class) |
{ |
case C_FILE: |
if (ext->x_file.x_fname[0] == 0) |
{ |
in->x_file.x_n.x_zeroes = 0; |
in->x_file.x_n.x_offset = H_GET_32 (abfd, ext->x_file.x_n.x_offset); |
} |
else |
memcpy (in->x_file.x_fname, ext->x_file.x_fname, FILNMLEN); |
return; |
case C_STAT: |
case C_LEAFSTAT: |
case C_HIDDEN: |
if (type == T_NULL) |
{ |
in->x_scn.x_scnlen = GET_SCN_SCNLEN (abfd, ext); |
in->x_scn.x_nreloc = GET_SCN_NRELOC (abfd, ext); |
in->x_scn.x_nlinno = GET_SCN_NLINNO (abfd, ext); |
in->x_scn.x_checksum = H_GET_32 (abfd, ext->x_scn.x_checksum); |
in->x_scn.x_associated = H_GET_16 (abfd, ext->x_scn.x_associated); |
in->x_scn.x_comdat = H_GET_8 (abfd, ext->x_scn.x_comdat); |
return; |
} |
break; |
} |
in->x_sym.x_tagndx.l = H_GET_32 (abfd, ext->x_sym.x_tagndx); |
in->x_sym.x_tvndx = H_GET_16 (abfd, ext->x_sym.x_tvndx); |
if (in_class == C_BLOCK || in_class == C_FCN || ISFCN (type) |
|| ISTAG (in_class)) |
{ |
in->x_sym.x_fcnary.x_fcn.x_lnnoptr = GET_FCN_LNNOPTR (abfd, ext); |
in->x_sym.x_fcnary.x_fcn.x_endndx.l = GET_FCN_ENDNDX (abfd, ext); |
} |
else |
{ |
in->x_sym.x_fcnary.x_ary.x_dimen[0] = |
H_GET_16 (abfd, ext->x_sym.x_fcnary.x_ary.x_dimen[0]); |
in->x_sym.x_fcnary.x_ary.x_dimen[1] = |
H_GET_16 (abfd, ext->x_sym.x_fcnary.x_ary.x_dimen[1]); |
in->x_sym.x_fcnary.x_ary.x_dimen[2] = |
H_GET_16 (abfd, ext->x_sym.x_fcnary.x_ary.x_dimen[2]); |
in->x_sym.x_fcnary.x_ary.x_dimen[3] = |
H_GET_16 (abfd, ext->x_sym.x_fcnary.x_ary.x_dimen[3]); |
} |
if (ISFCN (type)) |
{ |
in->x_sym.x_misc.x_fsize = H_GET_32 (abfd, ext->x_sym.x_misc.x_fsize); |
} |
else |
{ |
in->x_sym.x_misc.x_lnsz.x_lnno = GET_LNSZ_LNNO (abfd, ext); |
in->x_sym.x_misc.x_lnsz.x_size = GET_LNSZ_SIZE (abfd, ext); |
} |
} |
unsigned int |
_bfd_pei_swap_aux_out (bfd * abfd, |
void * inp, |
int type, |
int in_class, |
int indx ATTRIBUTE_UNUSED, |
int numaux ATTRIBUTE_UNUSED, |
void * extp) |
{ |
union internal_auxent *in = (union internal_auxent *) inp; |
AUXENT *ext = (AUXENT *) extp; |
memset (ext, 0, AUXESZ); |
switch (in_class) |
{ |
case C_FILE: |
if (in->x_file.x_fname[0] == 0) |
{ |
H_PUT_32 (abfd, 0, ext->x_file.x_n.x_zeroes); |
H_PUT_32 (abfd, in->x_file.x_n.x_offset, ext->x_file.x_n.x_offset); |
} |
else |
memcpy (ext->x_file.x_fname, in->x_file.x_fname, FILNMLEN); |
return AUXESZ; |
case C_STAT: |
case C_LEAFSTAT: |
case C_HIDDEN: |
if (type == T_NULL) |
{ |
PUT_SCN_SCNLEN (abfd, in->x_scn.x_scnlen, ext); |
PUT_SCN_NRELOC (abfd, in->x_scn.x_nreloc, ext); |
PUT_SCN_NLINNO (abfd, in->x_scn.x_nlinno, ext); |
H_PUT_32 (abfd, in->x_scn.x_checksum, ext->x_scn.x_checksum); |
H_PUT_16 (abfd, in->x_scn.x_associated, ext->x_scn.x_associated); |
H_PUT_8 (abfd, in->x_scn.x_comdat, ext->x_scn.x_comdat); |
return AUXESZ; |
} |
break; |
} |
H_PUT_32 (abfd, in->x_sym.x_tagndx.l, ext->x_sym.x_tagndx); |
H_PUT_16 (abfd, in->x_sym.x_tvndx, ext->x_sym.x_tvndx); |
if (in_class == C_BLOCK || in_class == C_FCN || ISFCN (type) |
|| ISTAG (in_class)) |
{ |
PUT_FCN_LNNOPTR (abfd, in->x_sym.x_fcnary.x_fcn.x_lnnoptr, ext); |
PUT_FCN_ENDNDX (abfd, in->x_sym.x_fcnary.x_fcn.x_endndx.l, ext); |
} |
else |
{ |
H_PUT_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[0], |
ext->x_sym.x_fcnary.x_ary.x_dimen[0]); |
H_PUT_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[1], |
ext->x_sym.x_fcnary.x_ary.x_dimen[1]); |
H_PUT_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[2], |
ext->x_sym.x_fcnary.x_ary.x_dimen[2]); |
H_PUT_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[3], |
ext->x_sym.x_fcnary.x_ary.x_dimen[3]); |
} |
if (ISFCN (type)) |
H_PUT_32 (abfd, in->x_sym.x_misc.x_fsize, ext->x_sym.x_misc.x_fsize); |
else |
{ |
PUT_LNSZ_LNNO (abfd, in->x_sym.x_misc.x_lnsz.x_lnno, ext); |
PUT_LNSZ_SIZE (abfd, in->x_sym.x_misc.x_lnsz.x_size, ext); |
} |
return AUXESZ; |
} |
void |
_bfd_pei_swap_lineno_in (bfd * abfd, void * ext1, void * in1) |
{ |
LINENO *ext = (LINENO *) ext1; |
struct internal_lineno *in = (struct internal_lineno *) in1; |
in->l_addr.l_symndx = H_GET_32 (abfd, ext->l_addr.l_symndx); |
in->l_lnno = GET_LINENO_LNNO (abfd, ext); |
} |
unsigned int |
_bfd_pei_swap_lineno_out (bfd * abfd, void * inp, void * outp) |
{ |
struct internal_lineno *in = (struct internal_lineno *) inp; |
struct external_lineno *ext = (struct external_lineno *) outp; |
H_PUT_32 (abfd, in->l_addr.l_symndx, ext->l_addr.l_symndx); |
PUT_LINENO_LNNO (abfd, in->l_lnno, ext); |
return LINESZ; |
} |
void |
_bfd_pei_swap_aouthdr_in (bfd * abfd, |
void * aouthdr_ext1, |
void * aouthdr_int1) |
{ |
PEAOUTHDR * src = (PEAOUTHDR *) aouthdr_ext1; |
AOUTHDR * aouthdr_ext = (AOUTHDR *) aouthdr_ext1; |
struct internal_aouthdr *aouthdr_int |
= (struct internal_aouthdr *) aouthdr_int1; |
struct internal_extra_pe_aouthdr *a = &aouthdr_int->pe; |
aouthdr_int->magic = H_GET_16 (abfd, aouthdr_ext->magic); |
aouthdr_int->vstamp = H_GET_16 (abfd, aouthdr_ext->vstamp); |
aouthdr_int->tsize = GET_AOUTHDR_TSIZE (abfd, aouthdr_ext->tsize); |
aouthdr_int->dsize = GET_AOUTHDR_DSIZE (abfd, aouthdr_ext->dsize); |
aouthdr_int->bsize = GET_AOUTHDR_BSIZE (abfd, aouthdr_ext->bsize); |
aouthdr_int->entry = GET_AOUTHDR_ENTRY (abfd, aouthdr_ext->entry); |
aouthdr_int->text_start = |
GET_AOUTHDR_TEXT_START (abfd, aouthdr_ext->text_start); |
#if !defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64) |
/* PE32+ does not have data_start member! */ |
aouthdr_int->data_start = |
GET_AOUTHDR_DATA_START (abfd, aouthdr_ext->data_start); |
a->BaseOfData = aouthdr_int->data_start; |
#endif |
a->Magic = aouthdr_int->magic; |
a->MajorLinkerVersion = H_GET_8 (abfd, aouthdr_ext->vstamp); |
a->MinorLinkerVersion = H_GET_8 (abfd, aouthdr_ext->vstamp + 1); |
a->SizeOfCode = aouthdr_int->tsize ; |
a->SizeOfInitializedData = aouthdr_int->dsize ; |
a->SizeOfUninitializedData = aouthdr_int->bsize ; |
a->AddressOfEntryPoint = aouthdr_int->entry; |
a->BaseOfCode = aouthdr_int->text_start; |
a->ImageBase = GET_OPTHDR_IMAGE_BASE (abfd, src->ImageBase); |
a->SectionAlignment = H_GET_32 (abfd, src->SectionAlignment); |
a->FileAlignment = H_GET_32 (abfd, src->FileAlignment); |
a->MajorOperatingSystemVersion = |
H_GET_16 (abfd, src->MajorOperatingSystemVersion); |
a->MinorOperatingSystemVersion = |
H_GET_16 (abfd, src->MinorOperatingSystemVersion); |
a->MajorImageVersion = H_GET_16 (abfd, src->MajorImageVersion); |
a->MinorImageVersion = H_GET_16 (abfd, src->MinorImageVersion); |
a->MajorSubsystemVersion = H_GET_16 (abfd, src->MajorSubsystemVersion); |
a->MinorSubsystemVersion = H_GET_16 (abfd, src->MinorSubsystemVersion); |
a->Reserved1 = H_GET_32 (abfd, src->Reserved1); |
a->SizeOfImage = H_GET_32 (abfd, src->SizeOfImage); |
a->SizeOfHeaders = H_GET_32 (abfd, src->SizeOfHeaders); |
a->CheckSum = H_GET_32 (abfd, src->CheckSum); |
a->Subsystem = H_GET_16 (abfd, src->Subsystem); |
a->DllCharacteristics = H_GET_16 (abfd, src->DllCharacteristics); |
a->SizeOfStackReserve = |
GET_OPTHDR_SIZE_OF_STACK_RESERVE (abfd, src->SizeOfStackReserve); |
a->SizeOfStackCommit = |
GET_OPTHDR_SIZE_OF_STACK_COMMIT (abfd, src->SizeOfStackCommit); |
a->SizeOfHeapReserve = |
GET_OPTHDR_SIZE_OF_HEAP_RESERVE (abfd, src->SizeOfHeapReserve); |
a->SizeOfHeapCommit = |
GET_OPTHDR_SIZE_OF_HEAP_COMMIT (abfd, src->SizeOfHeapCommit); |
a->LoaderFlags = H_GET_32 (abfd, src->LoaderFlags); |
a->NumberOfRvaAndSizes = H_GET_32 (abfd, src->NumberOfRvaAndSizes); |
{ |
int idx; |
for (idx = 0; idx < a->NumberOfRvaAndSizes; idx++) |
{ |
/* If data directory is empty, rva also should be 0. */ |
int size = |
H_GET_32 (abfd, src->DataDirectory[idx][1]); |
a->DataDirectory[idx].Size = size; |
if (size) |
a->DataDirectory[idx].VirtualAddress = |
H_GET_32 (abfd, src->DataDirectory[idx][0]); |
else |
a->DataDirectory[idx].VirtualAddress = 0; |
} |
} |
if (aouthdr_int->entry) |
{ |
aouthdr_int->entry += a->ImageBase; |
#if !defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64) |
aouthdr_int->entry &= 0xffffffff; |
#endif |
} |
if (aouthdr_int->tsize) |
{ |
aouthdr_int->text_start += a->ImageBase; |
#if !defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64) |
aouthdr_int->text_start &= 0xffffffff; |
#endif |
} |
#if !defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64) |
/* PE32+ does not have data_start member! */ |
if (aouthdr_int->dsize) |
{ |
aouthdr_int->data_start += a->ImageBase; |
aouthdr_int->data_start &= 0xffffffff; |
} |
#endif |
#ifdef POWERPC_LE_PE |
/* These three fields are normally set up by ppc_relocate_section. |
In the case of reading a file in, we can pick them up from the |
DataDirectory. */ |
first_thunk_address = a->DataDirectory[PE_IMPORT_ADDRESS_TABLE].VirtualAddress; |
thunk_size = a->DataDirectory[PE_IMPORT_ADDRESS_TABLE].Size; |
import_table_size = a->DataDirectory[PE_IMPORT_TABLE].Size; |
#endif |
} |
/* A support function for below. */ |
static void |
add_data_entry (bfd * abfd, |
struct internal_extra_pe_aouthdr *aout, |
int idx, |
char *name, |
bfd_vma base) |
{ |
asection *sec = bfd_get_section_by_name (abfd, name); |
/* Add import directory information if it exists. */ |
if ((sec != NULL) |
&& (coff_section_data (abfd, sec) != NULL) |
&& (pei_section_data (abfd, sec) != NULL)) |
{ |
/* If data directory is empty, rva also should be 0. */ |
int size = pei_section_data (abfd, sec)->virt_size; |
aout->DataDirectory[idx].Size = size; |
if (size) |
{ |
aout->DataDirectory[idx].VirtualAddress = |
(sec->vma - base) & 0xffffffff; |
sec->flags |= SEC_DATA; |
} |
} |
} |
unsigned int |
_bfd_pei_swap_aouthdr_out (bfd * abfd, void * in, void * out) |
{ |
struct internal_aouthdr *aouthdr_in = (struct internal_aouthdr *) in; |
pe_data_type *pe = pe_data (abfd); |
struct internal_extra_pe_aouthdr *extra = &pe->pe_opthdr; |
PEAOUTHDR *aouthdr_out = (PEAOUTHDR *) out; |
bfd_vma sa, fa, ib; |
IMAGE_DATA_DIRECTORY idata2, idata5, tls; |
sa = extra->SectionAlignment; |
fa = extra->FileAlignment; |
ib = extra->ImageBase; |
idata2 = pe->pe_opthdr.DataDirectory[PE_IMPORT_TABLE]; |
idata5 = pe->pe_opthdr.DataDirectory[PE_IMPORT_ADDRESS_TABLE]; |
tls = pe->pe_opthdr.DataDirectory[PE_TLS_TABLE]; |
if (aouthdr_in->tsize) |
{ |
aouthdr_in->text_start -= ib; |
#if !defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64) |
aouthdr_in->text_start &= 0xffffffff; |
#endif |
} |
if (aouthdr_in->dsize) |
{ |
aouthdr_in->data_start -= ib; |
#if !defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64) |
aouthdr_in->data_start &= 0xffffffff; |
#endif |
} |
if (aouthdr_in->entry) |
{ |
aouthdr_in->entry -= ib; |
#if !defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64) |
aouthdr_in->entry &= 0xffffffff; |
#endif |
} |
#define FA(x) (((x) + fa -1 ) & (- fa)) |
#define SA(x) (((x) + sa -1 ) & (- sa)) |
/* We like to have the sizes aligned. */ |
aouthdr_in->bsize = FA (aouthdr_in->bsize); |
extra->NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES; |
add_data_entry (abfd, extra, 0, ".edata", ib); |
add_data_entry (abfd, extra, 2, ".rsrc", ib); |
add_data_entry (abfd, extra, 3, ".pdata", ib); |
/* In theory we do not need to call add_data_entry for .idata$2 or |
.idata$5. It will be done in bfd_coff_final_link where all the |
required information is available. If however, we are not going |
to perform a final link, eg because we have been invoked by objcopy |
or strip, then we need to make sure that these Data Directory |
entries are initialised properly. |
So - we copy the input values into the output values, and then, if |
a final link is going to be performed, it can overwrite them. */ |
extra->DataDirectory[PE_IMPORT_TABLE] = idata2; |
extra->DataDirectory[PE_IMPORT_ADDRESS_TABLE] = idata5; |
extra->DataDirectory[PE_TLS_TABLE] = tls; |
if (extra->DataDirectory[PE_IMPORT_TABLE].VirtualAddress == 0) |
/* Until other .idata fixes are made (pending patch), the entry for |
.idata is needed for backwards compatibility. FIXME. */ |
add_data_entry (abfd, extra, 1, ".idata", ib); |
/* For some reason, the virtual size (which is what's set by |
add_data_entry) for .reloc is not the same as the size recorded |
in this slot by MSVC; it doesn't seem to cause problems (so far), |
but since it's the best we've got, use it. It does do the right |
thing for .pdata. */ |
if (pe->has_reloc_section) |
add_data_entry (abfd, extra, 5, ".reloc", ib); |
{ |
asection *sec; |
bfd_vma hsize = 0; |
bfd_vma dsize = 0; |
bfd_vma isize = 0; |
bfd_vma tsize = 0; |
for (sec = abfd->sections; sec; sec = sec->next) |
{ |
int rounded = FA (sec->size); |
/* The first non-zero section filepos is the header size. |
Sections without contents will have a filepos of 0. */ |
if (hsize == 0) |
hsize = sec->filepos; |
if (sec->flags & SEC_DATA) |
dsize += rounded; |
if (sec->flags & SEC_CODE) |
tsize += rounded; |
/* The image size is the total VIRTUAL size (which is what is |
in the virt_size field). Files have been seen (from MSVC |
5.0 link.exe) where the file size of the .data segment is |
quite small compared to the virtual size. Without this |
fix, strip munges the file. |
FIXME: We need to handle holes between sections, which may |
happpen when we covert from another format. We just use |
the virtual address and virtual size of the last section |
for the image size. */ |
if (coff_section_data (abfd, sec) != NULL |
&& pei_section_data (abfd, sec) != NULL) |
isize = (sec->vma - extra->ImageBase |
+ SA (FA (pei_section_data (abfd, sec)->virt_size))); |
} |
aouthdr_in->dsize = dsize; |
aouthdr_in->tsize = tsize; |
extra->SizeOfHeaders = hsize; |
extra->SizeOfImage = isize; |
} |
H_PUT_16 (abfd, aouthdr_in->magic, aouthdr_out->standard.magic); |
/* e.g. 219510000 is linker version 2.19 */ |
#define LINKER_VERSION ((short) (BFD_VERSION / 1000000)) |
/* This piece of magic sets the "linker version" field to |
LINKER_VERSION. */ |
H_PUT_16 (abfd, (LINKER_VERSION / 100 + (LINKER_VERSION % 100) * 256), |
aouthdr_out->standard.vstamp); |
PUT_AOUTHDR_TSIZE (abfd, aouthdr_in->tsize, aouthdr_out->standard.tsize); |
PUT_AOUTHDR_DSIZE (abfd, aouthdr_in->dsize, aouthdr_out->standard.dsize); |
PUT_AOUTHDR_BSIZE (abfd, aouthdr_in->bsize, aouthdr_out->standard.bsize); |
PUT_AOUTHDR_ENTRY (abfd, aouthdr_in->entry, aouthdr_out->standard.entry); |
PUT_AOUTHDR_TEXT_START (abfd, aouthdr_in->text_start, |
aouthdr_out->standard.text_start); |
#if !defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64) |
/* PE32+ does not have data_start member! */ |
PUT_AOUTHDR_DATA_START (abfd, aouthdr_in->data_start, |
aouthdr_out->standard.data_start); |
#endif |
PUT_OPTHDR_IMAGE_BASE (abfd, extra->ImageBase, aouthdr_out->ImageBase); |
H_PUT_32 (abfd, extra->SectionAlignment, aouthdr_out->SectionAlignment); |
H_PUT_32 (abfd, extra->FileAlignment, aouthdr_out->FileAlignment); |
H_PUT_16 (abfd, extra->MajorOperatingSystemVersion, |
aouthdr_out->MajorOperatingSystemVersion); |
H_PUT_16 (abfd, extra->MinorOperatingSystemVersion, |
aouthdr_out->MinorOperatingSystemVersion); |
H_PUT_16 (abfd, extra->MajorImageVersion, aouthdr_out->MajorImageVersion); |
H_PUT_16 (abfd, extra->MinorImageVersion, aouthdr_out->MinorImageVersion); |
H_PUT_16 (abfd, extra->MajorSubsystemVersion, |
aouthdr_out->MajorSubsystemVersion); |
H_PUT_16 (abfd, extra->MinorSubsystemVersion, |
aouthdr_out->MinorSubsystemVersion); |
H_PUT_32 (abfd, extra->Reserved1, aouthdr_out->Reserved1); |
H_PUT_32 (abfd, extra->SizeOfImage, aouthdr_out->SizeOfImage); |
H_PUT_32 (abfd, extra->SizeOfHeaders, aouthdr_out->SizeOfHeaders); |
H_PUT_32 (abfd, extra->CheckSum, aouthdr_out->CheckSum); |
H_PUT_16 (abfd, extra->Subsystem, aouthdr_out->Subsystem); |
H_PUT_16 (abfd, extra->DllCharacteristics, aouthdr_out->DllCharacteristics); |
PUT_OPTHDR_SIZE_OF_STACK_RESERVE (abfd, extra->SizeOfStackReserve, |
aouthdr_out->SizeOfStackReserve); |
PUT_OPTHDR_SIZE_OF_STACK_COMMIT (abfd, extra->SizeOfStackCommit, |
aouthdr_out->SizeOfStackCommit); |
PUT_OPTHDR_SIZE_OF_HEAP_RESERVE (abfd, extra->SizeOfHeapReserve, |
aouthdr_out->SizeOfHeapReserve); |
PUT_OPTHDR_SIZE_OF_HEAP_COMMIT (abfd, extra->SizeOfHeapCommit, |
aouthdr_out->SizeOfHeapCommit); |
H_PUT_32 (abfd, extra->LoaderFlags, aouthdr_out->LoaderFlags); |
H_PUT_32 (abfd, extra->NumberOfRvaAndSizes, |
aouthdr_out->NumberOfRvaAndSizes); |
{ |
int idx; |
for (idx = 0; idx < 16; idx++) |
{ |
H_PUT_32 (abfd, extra->DataDirectory[idx].VirtualAddress, |
aouthdr_out->DataDirectory[idx][0]); |
H_PUT_32 (abfd, extra->DataDirectory[idx].Size, |
aouthdr_out->DataDirectory[idx][1]); |
} |
} |
return AOUTSZ; |
} |
unsigned int |
_bfd_pei_only_swap_filehdr_out (bfd * abfd, void * in, void * out) |
{ |
int idx; |
struct internal_filehdr *filehdr_in = (struct internal_filehdr *) in; |
struct external_PEI_filehdr *filehdr_out = (struct external_PEI_filehdr *) out; |
if (pe_data (abfd)->has_reloc_section |
|| pe_data (abfd)->dont_strip_reloc) |
filehdr_in->f_flags &= ~F_RELFLG; |
if (pe_data (abfd)->dll) |
filehdr_in->f_flags |= F_DLL; |
filehdr_in->pe.e_magic = DOSMAGIC; |
filehdr_in->pe.e_cblp = 0x90; |
filehdr_in->pe.e_cp = 0x3; |
filehdr_in->pe.e_crlc = 0x0; |
filehdr_in->pe.e_cparhdr = 0x4; |
filehdr_in->pe.e_minalloc = 0x0; |
filehdr_in->pe.e_maxalloc = 0xffff; |
filehdr_in->pe.e_ss = 0x0; |
filehdr_in->pe.e_sp = 0xb8; |
filehdr_in->pe.e_csum = 0x0; |
filehdr_in->pe.e_ip = 0x0; |
filehdr_in->pe.e_cs = 0x0; |
filehdr_in->pe.e_lfarlc = 0x40; |
filehdr_in->pe.e_ovno = 0x0; |
for (idx = 0; idx < 4; idx++) |
filehdr_in->pe.e_res[idx] = 0x0; |
filehdr_in->pe.e_oemid = 0x0; |
filehdr_in->pe.e_oeminfo = 0x0; |
for (idx = 0; idx < 10; idx++) |
filehdr_in->pe.e_res2[idx] = 0x0; |
filehdr_in->pe.e_lfanew = 0x80; |
/* This next collection of data are mostly just characters. It |
appears to be constant within the headers put on NT exes. */ |
filehdr_in->pe.dos_message[0] = 0x0eba1f0e; |
filehdr_in->pe.dos_message[1] = 0xcd09b400; |
filehdr_in->pe.dos_message[2] = 0x4c01b821; |
filehdr_in->pe.dos_message[3] = 0x685421cd; |
filehdr_in->pe.dos_message[4] = 0x70207369; |
filehdr_in->pe.dos_message[5] = 0x72676f72; |
filehdr_in->pe.dos_message[6] = 0x63206d61; |
filehdr_in->pe.dos_message[7] = 0x6f6e6e61; |
filehdr_in->pe.dos_message[8] = 0x65622074; |
filehdr_in->pe.dos_message[9] = 0x6e757220; |
filehdr_in->pe.dos_message[10] = 0x206e6920; |
filehdr_in->pe.dos_message[11] = 0x20534f44; |
filehdr_in->pe.dos_message[12] = 0x65646f6d; |
filehdr_in->pe.dos_message[13] = 0x0a0d0d2e; |
filehdr_in->pe.dos_message[14] = 0x24; |
filehdr_in->pe.dos_message[15] = 0x0; |
filehdr_in->pe.nt_signature = NT_SIGNATURE; |
H_PUT_16 (abfd, filehdr_in->f_magic, filehdr_out->f_magic); |
H_PUT_16 (abfd, filehdr_in->f_nscns, filehdr_out->f_nscns); |
/* Only use a real timestamp if the option was chosen. */ |
if ((pe_data (abfd)->insert_timestamp)) |
H_PUT_32 (abfd, time(0), filehdr_out->f_timdat); |
PUT_FILEHDR_SYMPTR (abfd, filehdr_in->f_symptr, |
filehdr_out->f_symptr); |
H_PUT_32 (abfd, filehdr_in->f_nsyms, filehdr_out->f_nsyms); |
H_PUT_16 (abfd, filehdr_in->f_opthdr, filehdr_out->f_opthdr); |
H_PUT_16 (abfd, filehdr_in->f_flags, filehdr_out->f_flags); |
/* Put in extra dos header stuff. This data remains essentially |
constant, it just has to be tacked on to the beginning of all exes |
for NT. */ |
H_PUT_16 (abfd, filehdr_in->pe.e_magic, filehdr_out->e_magic); |
H_PUT_16 (abfd, filehdr_in->pe.e_cblp, filehdr_out->e_cblp); |
H_PUT_16 (abfd, filehdr_in->pe.e_cp, filehdr_out->e_cp); |
H_PUT_16 (abfd, filehdr_in->pe.e_crlc, filehdr_out->e_crlc); |
H_PUT_16 (abfd, filehdr_in->pe.e_cparhdr, filehdr_out->e_cparhdr); |
H_PUT_16 (abfd, filehdr_in->pe.e_minalloc, filehdr_out->e_minalloc); |
H_PUT_16 (abfd, filehdr_in->pe.e_maxalloc, filehdr_out->e_maxalloc); |
H_PUT_16 (abfd, filehdr_in->pe.e_ss, filehdr_out->e_ss); |
H_PUT_16 (abfd, filehdr_in->pe.e_sp, filehdr_out->e_sp); |
H_PUT_16 (abfd, filehdr_in->pe.e_csum, filehdr_out->e_csum); |
H_PUT_16 (abfd, filehdr_in->pe.e_ip, filehdr_out->e_ip); |
H_PUT_16 (abfd, filehdr_in->pe.e_cs, filehdr_out->e_cs); |
H_PUT_16 (abfd, filehdr_in->pe.e_lfarlc, filehdr_out->e_lfarlc); |
H_PUT_16 (abfd, filehdr_in->pe.e_ovno, filehdr_out->e_ovno); |
for (idx = 0; idx < 4; idx++) |
H_PUT_16 (abfd, filehdr_in->pe.e_res[idx], filehdr_out->e_res[idx]); |
H_PUT_16 (abfd, filehdr_in->pe.e_oemid, filehdr_out->e_oemid); |
H_PUT_16 (abfd, filehdr_in->pe.e_oeminfo, filehdr_out->e_oeminfo); |
for (idx = 0; idx < 10; idx++) |
H_PUT_16 (abfd, filehdr_in->pe.e_res2[idx], filehdr_out->e_res2[idx]); |
H_PUT_32 (abfd, filehdr_in->pe.e_lfanew, filehdr_out->e_lfanew); |
for (idx = 0; idx < 16; idx++) |
H_PUT_32 (abfd, filehdr_in->pe.dos_message[idx], |
filehdr_out->dos_message[idx]); |
/* Also put in the NT signature. */ |
H_PUT_32 (abfd, filehdr_in->pe.nt_signature, filehdr_out->nt_signature); |
return FILHSZ; |
} |
unsigned int |
_bfd_pe_only_swap_filehdr_out (bfd * abfd, void * in, void * out) |
{ |
struct internal_filehdr *filehdr_in = (struct internal_filehdr *) in; |
FILHDR *filehdr_out = (FILHDR *) out; |
H_PUT_16 (abfd, filehdr_in->f_magic, filehdr_out->f_magic); |
H_PUT_16 (abfd, filehdr_in->f_nscns, filehdr_out->f_nscns); |
H_PUT_32 (abfd, filehdr_in->f_timdat, filehdr_out->f_timdat); |
PUT_FILEHDR_SYMPTR (abfd, filehdr_in->f_symptr, filehdr_out->f_symptr); |
H_PUT_32 (abfd, filehdr_in->f_nsyms, filehdr_out->f_nsyms); |
H_PUT_16 (abfd, filehdr_in->f_opthdr, filehdr_out->f_opthdr); |
H_PUT_16 (abfd, filehdr_in->f_flags, filehdr_out->f_flags); |
return FILHSZ; |
} |
unsigned int |
_bfd_pei_swap_scnhdr_out (bfd * abfd, void * in, void * out) |
{ |
struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in; |
SCNHDR *scnhdr_ext = (SCNHDR *) out; |
unsigned int ret = SCNHSZ; |
bfd_vma ps; |
bfd_vma ss; |
memcpy (scnhdr_ext->s_name, scnhdr_int->s_name, sizeof (scnhdr_int->s_name)); |
PUT_SCNHDR_VADDR (abfd, |
((scnhdr_int->s_vaddr |
- pe_data (abfd)->pe_opthdr.ImageBase) |
& 0xffffffff), |
scnhdr_ext->s_vaddr); |
/* NT wants the size data to be rounded up to the next |
NT_FILE_ALIGNMENT, but zero if it has no content (as in .bss, |
sometimes). */ |
if ((scnhdr_int->s_flags & IMAGE_SCN_CNT_UNINITIALIZED_DATA) != 0) |
{ |
if (bfd_pei_p (abfd)) |
{ |
ps = scnhdr_int->s_size; |
ss = 0; |
} |
else |
{ |
ps = 0; |
ss = scnhdr_int->s_size; |
} |
} |
else |
{ |
if (bfd_pei_p (abfd)) |
ps = scnhdr_int->s_paddr; |
else |
ps = 0; |
ss = scnhdr_int->s_size; |
} |
PUT_SCNHDR_SIZE (abfd, ss, |
scnhdr_ext->s_size); |
/* s_paddr in PE is really the virtual size. */ |
PUT_SCNHDR_PADDR (abfd, ps, scnhdr_ext->s_paddr); |
PUT_SCNHDR_SCNPTR (abfd, scnhdr_int->s_scnptr, |
scnhdr_ext->s_scnptr); |
PUT_SCNHDR_RELPTR (abfd, scnhdr_int->s_relptr, |
scnhdr_ext->s_relptr); |
PUT_SCNHDR_LNNOPTR (abfd, scnhdr_int->s_lnnoptr, |
scnhdr_ext->s_lnnoptr); |
{ |
/* Extra flags must be set when dealing with PE. All sections should also |
have the IMAGE_SCN_MEM_READ (0x40000000) flag set. In addition, the |
.text section must have IMAGE_SCN_MEM_EXECUTE (0x20000000) and the data |
sections (.idata, .data, .bss, .CRT) must have IMAGE_SCN_MEM_WRITE set |
(this is especially important when dealing with the .idata section since |
the addresses for routines from .dlls must be overwritten). If .reloc |
section data is ever generated, we must add IMAGE_SCN_MEM_DISCARDABLE |
(0x02000000). Also, the resource data should also be read and |
writable. */ |
/* FIXME: Alignment is also encoded in this field, at least on PPC and |
ARM-WINCE. Although - how do we get the original alignment field |
back ? */ |
typedef struct |
{ |
const char * section_name; |
unsigned long must_have; |
} |
pe_required_section_flags; |
pe_required_section_flags known_sections [] = |
{ |
{ ".arch", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_ALIGN_8BYTES }, |
{ ".bss", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_WRITE }, |
{ ".data", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE }, |
{ ".edata", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA }, |
{ ".idata", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE }, |
{ ".pdata", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA }, |
{ ".rdata", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA }, |
{ ".reloc", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE }, |
{ ".rsrc", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE }, |
{ ".text" , IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE }, |
{ ".tls", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE }, |
{ ".xdata", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA }, |
{ NULL, 0} |
}; |
pe_required_section_flags * p; |
/* We have defaulted to adding the IMAGE_SCN_MEM_WRITE flag, but now |
we know exactly what this specific section wants so we remove it |
and then allow the must_have field to add it back in if necessary. |
However, we don't remove IMAGE_SCN_MEM_WRITE flag from .text if the |
default WP_TEXT file flag has been cleared. WP_TEXT may be cleared |
by ld --enable-auto-import (if auto-import is actually needed), |
by ld --omagic, or by obcopy --writable-text. */ |
for (p = known_sections; p->section_name; p++) |
if (strcmp (scnhdr_int->s_name, p->section_name) == 0) |
{ |
if (strcmp (scnhdr_int->s_name, ".text") |
|| (bfd_get_file_flags (abfd) & WP_TEXT)) |
scnhdr_int->s_flags &= ~IMAGE_SCN_MEM_WRITE; |
scnhdr_int->s_flags |= p->must_have; |
break; |
} |
H_PUT_32 (abfd, scnhdr_int->s_flags, scnhdr_ext->s_flags); |
} |
if (coff_data (abfd)->link_info |
&& ! coff_data (abfd)->link_info->relocatable |
&& ! coff_data (abfd)->link_info->shared |
&& strcmp (scnhdr_int->s_name, ".text") == 0) |
{ |
/* By inference from looking at MS output, the 32 bit field |
which is the combination of the number_of_relocs and |
number_of_linenos is used for the line number count in |
executables. A 16-bit field won't do for cc1. The MS |
document says that the number of relocs is zero for |
executables, but the 17-th bit has been observed to be there. |
Overflow is not an issue: a 4G-line program will overflow a |
bunch of other fields long before this! */ |
H_PUT_16 (abfd, (scnhdr_int->s_nlnno & 0xffff), scnhdr_ext->s_nlnno); |
H_PUT_16 (abfd, (scnhdr_int->s_nlnno >> 16), scnhdr_ext->s_nreloc); |
} |
else |
{ |
if (scnhdr_int->s_nlnno <= 0xffff) |
H_PUT_16 (abfd, scnhdr_int->s_nlnno, scnhdr_ext->s_nlnno); |
else |
{ |
(*_bfd_error_handler) (_("%s: line number overflow: 0x%lx > 0xffff"), |
bfd_get_filename (abfd), |
scnhdr_int->s_nlnno); |
bfd_set_error (bfd_error_file_truncated); |
H_PUT_16 (abfd, 0xffff, scnhdr_ext->s_nlnno); |
ret = 0; |
} |
/* Although we could encode 0xffff relocs here, we do not, to be |
consistent with other parts of bfd. Also it lets us warn, as |
we should never see 0xffff here w/o having the overflow flag |
set. */ |
if (scnhdr_int->s_nreloc < 0xffff) |
H_PUT_16 (abfd, scnhdr_int->s_nreloc, scnhdr_ext->s_nreloc); |
else |
{ |
/* PE can deal with large #s of relocs, but not here. */ |
H_PUT_16 (abfd, 0xffff, scnhdr_ext->s_nreloc); |
scnhdr_int->s_flags |= IMAGE_SCN_LNK_NRELOC_OVFL; |
H_PUT_32 (abfd, scnhdr_int->s_flags, scnhdr_ext->s_flags); |
} |
} |
return ret; |
} |
static char * dir_names[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] = |
{ |
N_("Export Directory [.edata (or where ever we found it)]"), |
N_("Import Directory [parts of .idata]"), |
N_("Resource Directory [.rsrc]"), |
N_("Exception Directory [.pdata]"), |
N_("Security Directory"), |
N_("Base Relocation Directory [.reloc]"), |
N_("Debug Directory"), |
N_("Description Directory"), |
N_("Special Directory"), |
N_("Thread Storage Directory [.tls]"), |
N_("Load Configuration Directory"), |
N_("Bound Import Directory"), |
N_("Import Address Table Directory"), |
N_("Delay Import Directory"), |
N_("CLR Runtime Header"), |
N_("Reserved") |
}; |
#ifdef POWERPC_LE_PE |
/* The code for the PPC really falls in the "architecture dependent" |
category. However, it's not clear that anyone will ever care, so |
we're ignoring the issue for now; if/when PPC matters, some of this |
may need to go into peicode.h, or arguments passed to enable the |
PPC- specific code. */ |
#endif |
static bfd_boolean |
pe_print_idata (bfd * abfd, void * vfile) |
{ |
FILE *file = (FILE *) vfile; |
bfd_byte *data; |
asection *section; |
bfd_signed_vma adj; |
#ifdef POWERPC_LE_PE |
asection *rel_section = bfd_get_section_by_name (abfd, ".reldata"); |
#endif |
bfd_size_type datasize = 0; |
bfd_size_type dataoff; |
bfd_size_type i; |
int onaline = 20; |
pe_data_type *pe = pe_data (abfd); |
struct internal_extra_pe_aouthdr *extra = &pe->pe_opthdr; |
bfd_vma addr; |
addr = extra->DataDirectory[PE_IMPORT_TABLE].VirtualAddress; |
if (addr == 0 && extra->DataDirectory[PE_IMPORT_TABLE].Size == 0) |
{ |
/* Maybe the extra header isn't there. Look for the section. */ |
section = bfd_get_section_by_name (abfd, ".idata"); |
if (section == NULL) |
return TRUE; |
addr = section->vma; |
datasize = section->size; |
if (datasize == 0) |
return TRUE; |
} |
else |
{ |
addr += extra->ImageBase; |
for (section = abfd->sections; section != NULL; section = section->next) |
{ |
datasize = section->size; |
if (addr >= section->vma && addr < section->vma + datasize) |
break; |
} |
if (section == NULL) |
{ |
fprintf (file, |
_("\nThere is an import table, but the section containing it could not be found\n")); |
return TRUE; |
} |
} |
fprintf (file, _("\nThere is an import table in %s at 0x%lx\n"), |
section->name, (unsigned long) addr); |
dataoff = addr - section->vma; |
#ifdef POWERPC_LE_PE |
if (rel_section != 0 && rel_section->size != 0) |
{ |
/* The toc address can be found by taking the starting address, |
which on the PPC locates a function descriptor. The |
descriptor consists of the function code starting address |
followed by the address of the toc. The starting address we |
get from the bfd, and the descriptor is supposed to be in the |
.reldata section. */ |
bfd_vma loadable_toc_address; |
bfd_vma toc_address; |
bfd_vma start_address; |
bfd_byte *data; |
bfd_vma offset; |
if (!bfd_malloc_and_get_section (abfd, rel_section, &data)) |
{ |
if (data != NULL) |
free (data); |
return FALSE; |
} |
offset = abfd->start_address - rel_section->vma; |
if (offset >= rel_section->size || offset + 8 > rel_section->size) |
{ |
if (data != NULL) |
free (data); |
return FALSE; |
} |
start_address = bfd_get_32 (abfd, data + offset); |
loadable_toc_address = bfd_get_32 (abfd, data + offset + 4); |
toc_address = loadable_toc_address - 32768; |
fprintf (file, |
_("\nFunction descriptor located at the start address: %04lx\n"), |
(unsigned long int) (abfd->start_address)); |
fprintf (file, |
_("\tcode-base %08lx toc (loadable/actual) %08lx/%08lx\n"), |
start_address, loadable_toc_address, toc_address); |
if (data != NULL) |
free (data); |
} |
else |
{ |
fprintf (file, |
_("\nNo reldata section! Function descriptor not decoded.\n")); |
} |
#endif |
fprintf (file, |
_("\nThe Import Tables (interpreted %s section contents)\n"), |
section->name); |
fprintf (file, |
_("\ |
vma: Hint Time Forward DLL First\n\ |
Table Stamp Chain Name Thunk\n")); |
/* Read the whole section. Some of the fields might be before dataoff. */ |
if (!bfd_malloc_and_get_section (abfd, section, &data)) |
{ |
if (data != NULL) |
free (data); |
return FALSE; |
} |
adj = section->vma - extra->ImageBase; |
/* Print all image import descriptors. */ |
for (i = dataoff; i + onaline <= datasize; i += onaline) |
{ |
bfd_vma hint_addr; |
bfd_vma time_stamp; |
bfd_vma forward_chain; |
bfd_vma dll_name; |
bfd_vma first_thunk; |
int idx = 0; |
bfd_size_type j; |
char *dll; |
/* Print (i + extra->DataDirectory[PE_IMPORT_TABLE].VirtualAddress). */ |
fprintf (file, " %08lx\t", (unsigned long) (i + adj)); |
hint_addr = bfd_get_32 (abfd, data + i); |
time_stamp = bfd_get_32 (abfd, data + i + 4); |
forward_chain = bfd_get_32 (abfd, data + i + 8); |
dll_name = bfd_get_32 (abfd, data + i + 12); |
first_thunk = bfd_get_32 (abfd, data + i + 16); |
fprintf (file, "%08lx %08lx %08lx %08lx %08lx\n", |
(unsigned long) hint_addr, |
(unsigned long) time_stamp, |
(unsigned long) forward_chain, |
(unsigned long) dll_name, |
(unsigned long) first_thunk); |
if (hint_addr == 0 && first_thunk == 0) |
break; |
if (dll_name - adj >= section->size) |
break; |
dll = (char *) data + dll_name - adj; |
fprintf (file, _("\n\tDLL Name: %s\n"), dll); |
if (hint_addr != 0) |
{ |
bfd_byte *ft_data; |
asection *ft_section; |
bfd_vma ft_addr; |
bfd_size_type ft_datasize; |
int ft_idx; |
int ft_allocated; |
fprintf (file, _("\tvma: Hint/Ord Member-Name Bound-To\n")); |
idx = hint_addr - adj; |
ft_addr = first_thunk + extra->ImageBase; |
ft_idx = first_thunk - adj; |
ft_data = data + ft_idx; |
ft_datasize = datasize - ft_idx; |
ft_allocated = 0; |
if (first_thunk != hint_addr) |
{ |
/* Find the section which contains the first thunk. */ |
for (ft_section = abfd->sections; |
ft_section != NULL; |
ft_section = ft_section->next) |
{ |
if (ft_addr >= ft_section->vma |
&& ft_addr < ft_section->vma + ft_section->size) |
break; |
} |
if (ft_section == NULL) |
{ |
fprintf (file, |
_("\nThere is a first thunk, but the section containing it could not be found\n")); |
continue; |
} |
/* Now check to see if this section is the same as our current |
section. If it is not then we will have to load its data in. */ |
if (ft_section != section) |
{ |
ft_idx = first_thunk - (ft_section->vma - extra->ImageBase); |
ft_datasize = ft_section->size - ft_idx; |
ft_data = (bfd_byte *) bfd_malloc (ft_datasize); |
if (ft_data == NULL) |
continue; |
/* Read ft_datasize bytes starting at offset ft_idx. */ |
if (!bfd_get_section_contents (abfd, ft_section, ft_data, |
(bfd_vma) ft_idx, ft_datasize)) |
{ |
free (ft_data); |
continue; |
} |
ft_allocated = 1; |
} |
} |
/* Print HintName vector entries. */ |
#ifdef COFF_WITH_pex64 |
for (j = 0; idx + j + 8 <= datasize; j += 8) |
{ |
unsigned long member = bfd_get_32 (abfd, data + idx + j); |
unsigned long member_high = bfd_get_32 (abfd, data + idx + j + 4); |
if (!member && !member_high) |
break; |
if (member_high & 0x80000000) |
fprintf (file, "\t%lx%08lx\t %4lx%08lx <none>", |
member_high,member, member_high & 0x7fffffff, member); |
else |
{ |
int ordinal; |
char *member_name; |
ordinal = bfd_get_16 (abfd, data + member - adj); |
member_name = (char *) data + member - adj + 2; |
fprintf (file, "\t%04lx\t %4d %s",member, ordinal, member_name); |
} |
/* If the time stamp is not zero, the import address |
table holds actual addresses. */ |
if (time_stamp != 0 |
&& first_thunk != 0 |
&& first_thunk != hint_addr |
&& j + 4 <= ft_datasize) |
fprintf (file, "\t%04lx", |
(unsigned long) bfd_get_32 (abfd, ft_data + j)); |
fprintf (file, "\n"); |
} |
#else |
for (j = 0; idx + j + 4 <= datasize; j += 4) |
{ |
unsigned long member = bfd_get_32 (abfd, data + idx + j); |
/* Print single IMAGE_IMPORT_BY_NAME vector. */ |
if (member == 0) |
break; |
if (member & 0x80000000) |
fprintf (file, "\t%04lx\t %4lu <none>", |
member, member & 0x7fffffff); |
else |
{ |
int ordinal; |
char *member_name; |
ordinal = bfd_get_16 (abfd, data + member - adj); |
member_name = (char *) data + member - adj + 2; |
fprintf (file, "\t%04lx\t %4d %s", |
member, ordinal, member_name); |
} |
/* If the time stamp is not zero, the import address |
table holds actual addresses. */ |
if (time_stamp != 0 |
&& first_thunk != 0 |
&& first_thunk != hint_addr |
&& j + 4 <= ft_datasize) |
fprintf (file, "\t%04lx", |
(unsigned long) bfd_get_32 (abfd, ft_data + j)); |
fprintf (file, "\n"); |
} |
#endif |
if (ft_allocated) |
free (ft_data); |
} |
fprintf (file, "\n"); |
} |
free (data); |
return TRUE; |
} |
static bfd_boolean |
pe_print_edata (bfd * abfd, void * vfile) |
{ |
FILE *file = (FILE *) vfile; |
bfd_byte *data; |
asection *section; |
bfd_size_type datasize = 0; |
bfd_size_type dataoff; |
bfd_size_type i; |
bfd_signed_vma adj; |
struct EDT_type |
{ |
long export_flags; /* Reserved - should be zero. */ |
long time_stamp; |
short major_ver; |
short minor_ver; |
bfd_vma name; /* RVA - relative to image base. */ |
long base; /* Ordinal base. */ |
unsigned long num_functions;/* Number in the export address table. */ |
unsigned long num_names; /* Number in the name pointer table. */ |
bfd_vma eat_addr; /* RVA to the export address table. */ |
bfd_vma npt_addr; /* RVA to the Export Name Pointer Table. */ |
bfd_vma ot_addr; /* RVA to the Ordinal Table. */ |
} edt; |
pe_data_type *pe = pe_data (abfd); |
struct internal_extra_pe_aouthdr *extra = &pe->pe_opthdr; |
bfd_vma addr; |
addr = extra->DataDirectory[PE_EXPORT_TABLE].VirtualAddress; |
if (addr == 0 && extra->DataDirectory[PE_EXPORT_TABLE].Size == 0) |
{ |
/* Maybe the extra header isn't there. Look for the section. */ |
section = bfd_get_section_by_name (abfd, ".edata"); |
if (section == NULL) |
return TRUE; |
addr = section->vma; |
dataoff = 0; |
datasize = section->size; |
if (datasize == 0) |
return TRUE; |
} |
else |
{ |
addr += extra->ImageBase; |
for (section = abfd->sections; section != NULL; section = section->next) |
if (addr >= section->vma && addr < section->vma + section->size) |
break; |
if (section == NULL) |
{ |
fprintf (file, |
_("\nThere is an export table, but the section containing it could not be found\n")); |
return TRUE; |
} |
dataoff = addr - section->vma; |
datasize = extra->DataDirectory[PE_EXPORT_TABLE].Size; |
if (datasize > section->size - dataoff) |
{ |
fprintf (file, |
_("\nThere is an export table in %s, but it does not fit into that section\n"), |
section->name); |
return TRUE; |
} |
} |
fprintf (file, _("\nThere is an export table in %s at 0x%lx\n"), |
section->name, (unsigned long) addr); |
data = (bfd_byte *) bfd_malloc (datasize); |
if (data == NULL) |
return FALSE; |
if (! bfd_get_section_contents (abfd, section, data, |
(file_ptr) dataoff, datasize)) |
return FALSE; |
/* Go get Export Directory Table. */ |
edt.export_flags = bfd_get_32 (abfd, data + 0); |
edt.time_stamp = bfd_get_32 (abfd, data + 4); |
edt.major_ver = bfd_get_16 (abfd, data + 8); |
edt.minor_ver = bfd_get_16 (abfd, data + 10); |
edt.name = bfd_get_32 (abfd, data + 12); |
edt.base = bfd_get_32 (abfd, data + 16); |
edt.num_functions = bfd_get_32 (abfd, data + 20); |
edt.num_names = bfd_get_32 (abfd, data + 24); |
edt.eat_addr = bfd_get_32 (abfd, data + 28); |
edt.npt_addr = bfd_get_32 (abfd, data + 32); |
edt.ot_addr = bfd_get_32 (abfd, data + 36); |
adj = section->vma - extra->ImageBase + dataoff; |
/* Dump the EDT first. */ |
fprintf (file, |
_("\nThe Export Tables (interpreted %s section contents)\n\n"), |
section->name); |
fprintf (file, |
_("Export Flags \t\t\t%lx\n"), (unsigned long) edt.export_flags); |
fprintf (file, |
_("Time/Date stamp \t\t%lx\n"), (unsigned long) edt.time_stamp); |
fprintf (file, |
_("Major/Minor \t\t\t%d/%d\n"), edt.major_ver, edt.minor_ver); |
fprintf (file, |
_("Name \t\t\t\t")); |
bfd_fprintf_vma (abfd, file, edt.name); |
fprintf (file, |
" %s\n", data + edt.name - adj); |
fprintf (file, |
_("Ordinal Base \t\t\t%ld\n"), edt.base); |
fprintf (file, |
_("Number in:\n")); |
fprintf (file, |
_("\tExport Address Table \t\t%08lx\n"), |
edt.num_functions); |
fprintf (file, |
_("\t[Name Pointer/Ordinal] Table\t%08lx\n"), edt.num_names); |
fprintf (file, |
_("Table Addresses\n")); |
fprintf (file, |
_("\tExport Address Table \t\t")); |
bfd_fprintf_vma (abfd, file, edt.eat_addr); |
fprintf (file, "\n"); |
fprintf (file, |
_("\tName Pointer Table \t\t")); |
bfd_fprintf_vma (abfd, file, edt.npt_addr); |
fprintf (file, "\n"); |
fprintf (file, |
_("\tOrdinal Table \t\t\t")); |
bfd_fprintf_vma (abfd, file, edt.ot_addr); |
fprintf (file, "\n"); |
/* The next table to find is the Export Address Table. It's basically |
a list of pointers that either locate a function in this dll, or |
forward the call to another dll. Something like: |
typedef union |
{ |
long export_rva; |
long forwarder_rva; |
} export_address_table_entry; */ |
fprintf (file, |
_("\nExport Address Table -- Ordinal Base %ld\n"), |
edt.base); |
for (i = 0; i < edt.num_functions; ++i) |
{ |
bfd_vma eat_member = bfd_get_32 (abfd, |
data + edt.eat_addr + (i * 4) - adj); |
if (eat_member == 0) |
continue; |
if (eat_member - adj <= datasize) |
{ |
/* This rva is to a name (forwarding function) in our section. */ |
/* Should locate a function descriptor. */ |
fprintf (file, |
"\t[%4ld] +base[%4ld] %04lx %s -- %s\n", |
(long) i, |
(long) (i + edt.base), |
(unsigned long) eat_member, |
_("Forwarder RVA"), |
data + eat_member - adj); |
} |
else |
{ |
/* Should locate a function descriptor in the reldata section. */ |
fprintf (file, |
"\t[%4ld] +base[%4ld] %04lx %s\n", |
(long) i, |
(long) (i + edt.base), |
(unsigned long) eat_member, |
_("Export RVA")); |
} |
} |
/* The Export Name Pointer Table is paired with the Export Ordinal Table. */ |
/* Dump them in parallel for clarity. */ |
fprintf (file, |
_("\n[Ordinal/Name Pointer] Table\n")); |
for (i = 0; i < edt.num_names; ++i) |
{ |
bfd_vma name_ptr = bfd_get_32 (abfd, |
data + |
edt.npt_addr |
+ (i*4) - adj); |
char *name = (char *) data + name_ptr - adj; |
bfd_vma ord = bfd_get_16 (abfd, |
data + |
edt.ot_addr |
+ (i*2) - adj); |
fprintf (file, |
"\t[%4ld] %s\n", (long) ord, name); |
} |
free (data); |
return TRUE; |
} |
/* This really is architecture dependent. On IA-64, a .pdata entry |
consists of three dwords containing relative virtual addresses that |
specify the start and end address of the code range the entry |
covers and the address of the corresponding unwind info data. |
On ARM and SH-4, a compressed PDATA structure is used : |
_IMAGE_CE_RUNTIME_FUNCTION_ENTRY, whereas MIPS is documented to use |
_IMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY. |
See http://msdn2.microsoft.com/en-us/library/ms253988(VS.80).aspx . |
This is the version for uncompressed data. */ |
static bfd_boolean |
pe_print_pdata (bfd * abfd, void * vfile) |
{ |
#if defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64) |
# define PDATA_ROW_SIZE (3 * 8) |
#else |
# define PDATA_ROW_SIZE (5 * 4) |
#endif |
FILE *file = (FILE *) vfile; |
bfd_byte *data = 0; |
asection *section = bfd_get_section_by_name (abfd, ".pdata"); |
bfd_size_type datasize = 0; |
bfd_size_type i; |
bfd_size_type start, stop; |
int onaline = PDATA_ROW_SIZE; |
if (section == NULL |
|| coff_section_data (abfd, section) == NULL |
|| pei_section_data (abfd, section) == NULL) |
return TRUE; |
stop = pei_section_data (abfd, section)->virt_size; |
if ((stop % onaline) != 0) |
fprintf (file, |
_("Warning, .pdata section size (%ld) is not a multiple of %d\n"), |
(long) stop, onaline); |
fprintf (file, |
_("\nThe Function Table (interpreted .pdata section contents)\n")); |
#if defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64) |
fprintf (file, |
_(" vma:\t\t\tBegin Address End Address Unwind Info\n")); |
#else |
fprintf (file, _("\ |
vma:\t\tBegin End EH EH PrologEnd Exception\n\ |
\t\tAddress Address Handler Data Address Mask\n")); |
#endif |
datasize = section->size; |
if (datasize == 0) |
return TRUE; |
if (! bfd_malloc_and_get_section (abfd, section, &data)) |
{ |
if (data != NULL) |
free (data); |
return FALSE; |
} |
start = 0; |
for (i = start; i < stop; i += onaline) |
{ |
bfd_vma begin_addr; |
bfd_vma end_addr; |
bfd_vma eh_handler; |
bfd_vma eh_data; |
bfd_vma prolog_end_addr; |
#if !defined(COFF_WITH_pep) || defined(COFF_WITH_pex64) |
int em_data; |
#endif |
if (i + PDATA_ROW_SIZE > stop) |
break; |
begin_addr = GET_PDATA_ENTRY (abfd, data + i ); |
end_addr = GET_PDATA_ENTRY (abfd, data + i + 4); |
eh_handler = GET_PDATA_ENTRY (abfd, data + i + 8); |
eh_data = GET_PDATA_ENTRY (abfd, data + i + 12); |
prolog_end_addr = GET_PDATA_ENTRY (abfd, data + i + 16); |
if (begin_addr == 0 && end_addr == 0 && eh_handler == 0 |
&& eh_data == 0 && prolog_end_addr == 0) |
/* We are probably into the padding of the section now. */ |
break; |
#if !defined(COFF_WITH_pep) || defined(COFF_WITH_pex64) |
em_data = ((eh_handler & 0x1) << 2) | (prolog_end_addr & 0x3); |
#endif |
eh_handler &= ~(bfd_vma) 0x3; |
prolog_end_addr &= ~(bfd_vma) 0x3; |
fputc (' ', file); |
bfd_fprintf_vma (abfd, file, i + section->vma); fputc ('\t', file); |
bfd_fprintf_vma (abfd, file, begin_addr); fputc (' ', file); |
bfd_fprintf_vma (abfd, file, end_addr); fputc (' ', file); |
bfd_fprintf_vma (abfd, file, eh_handler); |
#if !defined(COFF_WITH_pep) || defined(COFF_WITH_pex64) |
fputc (' ', file); |
bfd_fprintf_vma (abfd, file, eh_data); fputc (' ', file); |
bfd_fprintf_vma (abfd, file, prolog_end_addr); |
fprintf (file, " %x", em_data); |
#endif |
#ifdef POWERPC_LE_PE |
if (eh_handler == 0 && eh_data != 0) |
{ |
/* Special bits here, although the meaning may be a little |
mysterious. The only one I know for sure is 0x03 |
Code Significance |
0x00 None |
0x01 Register Save Millicode |
0x02 Register Restore Millicode |
0x03 Glue Code Sequence. */ |
switch (eh_data) |
{ |
case 0x01: |
fprintf (file, _(" Register save millicode")); |
break; |
case 0x02: |
fprintf (file, _(" Register restore millicode")); |
break; |
case 0x03: |
fprintf (file, _(" Glue code sequence")); |
break; |
default: |
break; |
} |
} |
#endif |
fprintf (file, "\n"); |
} |
free (data); |
return TRUE; |
#undef PDATA_ROW_SIZE |
} |
typedef struct sym_cache |
{ |
int symcount; |
asymbol ** syms; |
} sym_cache; |
static asymbol ** |
slurp_symtab (bfd *abfd, sym_cache *psc) |
{ |
asymbol ** sy = NULL; |
long storage; |
if (!(bfd_get_file_flags (abfd) & HAS_SYMS)) |
{ |
psc->symcount = 0; |
return NULL; |
} |
storage = bfd_get_symtab_upper_bound (abfd); |
if (storage < 0) |
return NULL; |
if (storage) |
sy = (asymbol **) bfd_malloc (storage); |
psc->symcount = bfd_canonicalize_symtab (abfd, sy); |
if (psc->symcount < 0) |
return NULL; |
return sy; |
} |
static const char * |
my_symbol_for_address (bfd *abfd, bfd_vma func, sym_cache *psc) |
{ |
int i; |
if (psc->syms == 0) |
psc->syms = slurp_symtab (abfd, psc); |
for (i = 0; i < psc->symcount; i++) |
{ |
if (psc->syms[i]->section->vma + psc->syms[i]->value == func) |
return psc->syms[i]->name; |
} |
return NULL; |
} |
static void |
cleanup_syms (sym_cache *psc) |
{ |
psc->symcount = 0; |
free (psc->syms); |
psc->syms = NULL; |
} |
/* This is the version for "compressed" pdata. */ |
bfd_boolean |
_bfd_pe_print_ce_compressed_pdata (bfd * abfd, void * vfile) |
{ |
# define PDATA_ROW_SIZE (2 * 4) |
FILE *file = (FILE *) vfile; |
bfd_byte *data = NULL; |
asection *section = bfd_get_section_by_name (abfd, ".pdata"); |
bfd_size_type datasize = 0; |
bfd_size_type i; |
bfd_size_type start, stop; |
int onaline = PDATA_ROW_SIZE; |
struct sym_cache cache = {0, 0} ; |
if (section == NULL |
|| coff_section_data (abfd, section) == NULL |
|| pei_section_data (abfd, section) == NULL) |
return TRUE; |
stop = pei_section_data (abfd, section)->virt_size; |
if ((stop % onaline) != 0) |
fprintf (file, |
_("Warning, .pdata section size (%ld) is not a multiple of %d\n"), |
(long) stop, onaline); |
fprintf (file, |
_("\nThe Function Table (interpreted .pdata section contents)\n")); |
fprintf (file, _("\ |
vma:\t\tBegin Prolog Function Flags Exception EH\n\ |
\t\tAddress Length Length 32b exc Handler Data\n")); |
datasize = section->size; |
if (datasize == 0) |
return TRUE; |
if (! bfd_malloc_and_get_section (abfd, section, &data)) |
{ |
if (data != NULL) |
free (data); |
return FALSE; |
} |
start = 0; |
for (i = start; i < stop; i += onaline) |
{ |
bfd_vma begin_addr; |
bfd_vma other_data; |
bfd_vma prolog_length, function_length; |
int flag32bit, exception_flag; |
asection *tsection; |
if (i + PDATA_ROW_SIZE > stop) |
break; |
begin_addr = GET_PDATA_ENTRY (abfd, data + i ); |
other_data = GET_PDATA_ENTRY (abfd, data + i + 4); |
if (begin_addr == 0 && other_data == 0) |
/* We are probably into the padding of the section now. */ |
break; |
prolog_length = (other_data & 0x000000FF); |
function_length = (other_data & 0x3FFFFF00) >> 8; |
flag32bit = (int)((other_data & 0x40000000) >> 30); |
exception_flag = (int)((other_data & 0x80000000) >> 31); |
fputc (' ', file); |
bfd_fprintf_vma (abfd, file, i + section->vma); fputc ('\t', file); |
bfd_fprintf_vma (abfd, file, begin_addr); fputc (' ', file); |
bfd_fprintf_vma (abfd, file, prolog_length); fputc (' ', file); |
bfd_fprintf_vma (abfd, file, function_length); fputc (' ', file); |
fprintf (file, "%2d %2d ", flag32bit, exception_flag); |
/* Get the exception handler's address and the data passed from the |
.text section. This is really the data that belongs with the .pdata |
but got "compressed" out for the ARM and SH4 architectures. */ |
tsection = bfd_get_section_by_name (abfd, ".text"); |
if (tsection && coff_section_data (abfd, tsection) |
&& pei_section_data (abfd, tsection)) |
{ |
bfd_vma eh_off = (begin_addr - 8) - tsection->vma; |
bfd_byte *tdata; |
tdata = (bfd_byte *) bfd_malloc (8); |
if (tdata) |
{ |
if (bfd_get_section_contents (abfd, tsection, tdata, eh_off, 8)) |
{ |
bfd_vma eh, eh_data; |
eh = bfd_get_32 (abfd, tdata); |
eh_data = bfd_get_32 (abfd, tdata + 4); |
fprintf (file, "%08x ", (unsigned int) eh); |
fprintf (file, "%08x", (unsigned int) eh_data); |
if (eh != 0) |
{ |
const char *s = my_symbol_for_address (abfd, eh, &cache); |
if (s) |
fprintf (file, " (%s) ", s); |
} |
} |
free (tdata); |
} |
} |
fprintf (file, "\n"); |
} |
free (data); |
cleanup_syms (& cache); |
return TRUE; |
#undef PDATA_ROW_SIZE |
} |
#define IMAGE_REL_BASED_HIGHADJ 4 |
static const char * const tbl[] = |
{ |
"ABSOLUTE", |
"HIGH", |
"LOW", |
"HIGHLOW", |
"HIGHADJ", |
"MIPS_JMPADDR", |
"SECTION", |
"REL32", |
"RESERVED1", |
"MIPS_JMPADDR16", |
"DIR64", |
"HIGH3ADJ", |
"UNKNOWN", /* MUST be last. */ |
}; |
static bfd_boolean |
pe_print_reloc (bfd * abfd, void * vfile) |
{ |
FILE *file = (FILE *) vfile; |
bfd_byte *data = 0; |
asection *section = bfd_get_section_by_name (abfd, ".reloc"); |
bfd_size_type i; |
bfd_size_type start, stop; |
if (section == NULL) |
return TRUE; |
if (section->size == 0) |
return TRUE; |
fprintf (file, |
_("\n\nPE File Base Relocations (interpreted .reloc section contents)\n")); |
if (! bfd_malloc_and_get_section (abfd, section, &data)) |
{ |
if (data != NULL) |
free (data); |
return FALSE; |
} |
start = 0; |
stop = section->size; |
for (i = start; i < stop;) |
{ |
int j; |
bfd_vma virtual_address; |
long number, size; |
/* The .reloc section is a sequence of blocks, with a header consisting |
of two 32 bit quantities, followed by a number of 16 bit entries. */ |
virtual_address = bfd_get_32 (abfd, data+i); |
size = bfd_get_32 (abfd, data+i+4); |
number = (size - 8) / 2; |
if (size == 0) |
break; |
fprintf (file, |
_("\nVirtual Address: %08lx Chunk size %ld (0x%lx) Number of fixups %ld\n"), |
(unsigned long) virtual_address, size, (unsigned long) size, number); |
for (j = 0; j < number; ++j) |
{ |
unsigned short e = bfd_get_16 (abfd, data + i + 8 + j * 2); |
unsigned int t = (e & 0xF000) >> 12; |
int off = e & 0x0FFF; |
if (t >= sizeof (tbl) / sizeof (tbl[0])) |
t = (sizeof (tbl) / sizeof (tbl[0])) - 1; |
fprintf (file, |
_("\treloc %4d offset %4x [%4lx] %s"), |
j, off, (unsigned long) (off + virtual_address), tbl[t]); |
/* HIGHADJ takes an argument, - the next record *is* the |
low 16 bits of addend. */ |
if (t == IMAGE_REL_BASED_HIGHADJ) |
{ |
fprintf (file, " (%4x)", |
((unsigned int) |
bfd_get_16 (abfd, data + i + 8 + j * 2 + 2))); |
j++; |
} |
fprintf (file, "\n"); |
} |
i += size; |
} |
free (data); |
return TRUE; |
} |
/* Print out the program headers. */ |
bfd_boolean |
_bfd_pe_print_private_bfd_data_common (bfd * abfd, void * vfile) |
{ |
FILE *file = (FILE *) vfile; |
int j; |
pe_data_type *pe = pe_data (abfd); |
struct internal_extra_pe_aouthdr *i = &pe->pe_opthdr; |
const char *subsystem_name = NULL; |
const char *name; |
/* The MS dumpbin program reportedly ands with 0xff0f before |
printing the characteristics field. Not sure why. No reason to |
emulate it here. */ |
fprintf (file, _("\nCharacteristics 0x%x\n"), pe->real_flags); |
#undef PF |
#define PF(x, y) if (pe->real_flags & x) { fprintf (file, "\t%s\n", y); } |
PF (IMAGE_FILE_RELOCS_STRIPPED, "relocations stripped"); |
PF (IMAGE_FILE_EXECUTABLE_IMAGE, "executable"); |
PF (IMAGE_FILE_LINE_NUMS_STRIPPED, "line numbers stripped"); |
PF (IMAGE_FILE_LOCAL_SYMS_STRIPPED, "symbols stripped"); |
PF (IMAGE_FILE_LARGE_ADDRESS_AWARE, "large address aware"); |
PF (IMAGE_FILE_BYTES_REVERSED_LO, "little endian"); |
PF (IMAGE_FILE_32BIT_MACHINE, "32 bit words"); |
PF (IMAGE_FILE_DEBUG_STRIPPED, "debugging information removed"); |
PF (IMAGE_FILE_SYSTEM, "system file"); |
PF (IMAGE_FILE_DLL, "DLL"); |
PF (IMAGE_FILE_BYTES_REVERSED_HI, "big endian"); |
#undef PF |
/* ctime implies '\n'. */ |
{ |
time_t t = pe->coff.timestamp; |
fprintf (file, "\nTime/Date\t\t%s", ctime (&t)); |
} |
#ifndef IMAGE_NT_OPTIONAL_HDR_MAGIC |
# define IMAGE_NT_OPTIONAL_HDR_MAGIC 0x10b |
#endif |
#ifndef IMAGE_NT_OPTIONAL_HDR64_MAGIC |
# define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b |
#endif |
#ifndef IMAGE_NT_OPTIONAL_HDRROM_MAGIC |
# define IMAGE_NT_OPTIONAL_HDRROM_MAGIC 0x107 |
#endif |
switch (i->Magic) |
{ |
case IMAGE_NT_OPTIONAL_HDR_MAGIC: |
name = "PE32"; |
break; |
case IMAGE_NT_OPTIONAL_HDR64_MAGIC: |
name = "PE32+"; |
break; |
case IMAGE_NT_OPTIONAL_HDRROM_MAGIC: |
name = "ROM"; |
break; |
default: |
name = NULL; |
break; |
} |
fprintf (file, "Magic\t\t\t%04x", i->Magic); |
if (name) |
fprintf (file, "\t(%s)",name); |
fprintf (file, "\nMajorLinkerVersion\t%d\n", i->MajorLinkerVersion); |
fprintf (file, "MinorLinkerVersion\t%d\n", i->MinorLinkerVersion); |
fprintf (file, "SizeOfCode\t\t%08lx\n", (unsigned long) i->SizeOfCode); |
fprintf (file, "SizeOfInitializedData\t%08lx\n", |
(unsigned long) i->SizeOfInitializedData); |
fprintf (file, "SizeOfUninitializedData\t%08lx\n", |
(unsigned long) i->SizeOfUninitializedData); |
fprintf (file, "AddressOfEntryPoint\t"); |
bfd_fprintf_vma (abfd, file, i->AddressOfEntryPoint); |
fprintf (file, "\nBaseOfCode\t\t"); |
bfd_fprintf_vma (abfd, file, i->BaseOfCode); |
#if !defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64) |
/* PE32+ does not have BaseOfData member! */ |
fprintf (file, "\nBaseOfData\t\t"); |
bfd_fprintf_vma (abfd, file, i->BaseOfData); |
#endif |
fprintf (file, "\nImageBase\t\t"); |
bfd_fprintf_vma (abfd, file, i->ImageBase); |
fprintf (file, "\nSectionAlignment\t"); |
bfd_fprintf_vma (abfd, file, i->SectionAlignment); |
fprintf (file, "\nFileAlignment\t\t"); |
bfd_fprintf_vma (abfd, file, i->FileAlignment); |
fprintf (file, "\nMajorOSystemVersion\t%d\n", i->MajorOperatingSystemVersion); |
fprintf (file, "MinorOSystemVersion\t%d\n", i->MinorOperatingSystemVersion); |
fprintf (file, "MajorImageVersion\t%d\n", i->MajorImageVersion); |
fprintf (file, "MinorImageVersion\t%d\n", i->MinorImageVersion); |
fprintf (file, "MajorSubsystemVersion\t%d\n", i->MajorSubsystemVersion); |
fprintf (file, "MinorSubsystemVersion\t%d\n", i->MinorSubsystemVersion); |
fprintf (file, "Win32Version\t\t%08lx\n", (unsigned long) i->Reserved1); |
fprintf (file, "SizeOfImage\t\t%08lx\n", (unsigned long) i->SizeOfImage); |
fprintf (file, "SizeOfHeaders\t\t%08lx\n", (unsigned long) i->SizeOfHeaders); |
fprintf (file, "CheckSum\t\t%08lx\n", (unsigned long) i->CheckSum); |
switch (i->Subsystem) |
{ |
case IMAGE_SUBSYSTEM_UNKNOWN: |
subsystem_name = "unspecified"; |
break; |
case IMAGE_SUBSYSTEM_NATIVE: |
subsystem_name = "NT native"; |
break; |
case IMAGE_SUBSYSTEM_WINDOWS_GUI: |
subsystem_name = "Windows GUI"; |
break; |
case IMAGE_SUBSYSTEM_WINDOWS_CUI: |
subsystem_name = "Windows CUI"; |
break; |
case IMAGE_SUBSYSTEM_POSIX_CUI: |
subsystem_name = "POSIX CUI"; |
break; |
case IMAGE_SUBSYSTEM_WINDOWS_CE_GUI: |
subsystem_name = "Wince CUI"; |
break; |
// These are from UEFI Platform Initialization Specification 1.1. |
case IMAGE_SUBSYSTEM_EFI_APPLICATION: |
subsystem_name = "EFI application"; |
break; |
case IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER: |
subsystem_name = "EFI boot service driver"; |
break; |
case IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: |
subsystem_name = "EFI runtime driver"; |
break; |
case IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER: |
subsystem_name = "SAL runtime driver"; |
break; |
// This is from revision 8.0 of the MS PE/COFF spec |
case IMAGE_SUBSYSTEM_XBOX: |
subsystem_name = "XBOX"; |
break; |
// Added default case for clarity - subsystem_name is NULL anyway. |
default: |
subsystem_name = NULL; |
} |
fprintf (file, "Subsystem\t\t%08x", i->Subsystem); |
if (subsystem_name) |
fprintf (file, "\t(%s)", subsystem_name); |
fprintf (file, "\nDllCharacteristics\t%08x\n", i->DllCharacteristics); |
fprintf (file, "SizeOfStackReserve\t"); |
bfd_fprintf_vma (abfd, file, i->SizeOfStackReserve); |
fprintf (file, "\nSizeOfStackCommit\t"); |
bfd_fprintf_vma (abfd, file, i->SizeOfStackCommit); |
fprintf (file, "\nSizeOfHeapReserve\t"); |
bfd_fprintf_vma (abfd, file, i->SizeOfHeapReserve); |
fprintf (file, "\nSizeOfHeapCommit\t"); |
bfd_fprintf_vma (abfd, file, i->SizeOfHeapCommit); |
fprintf (file, "\nLoaderFlags\t\t%08lx\n", (unsigned long) i->LoaderFlags); |
fprintf (file, "NumberOfRvaAndSizes\t%08lx\n", |
(unsigned long) i->NumberOfRvaAndSizes); |
fprintf (file, "\nThe Data Directory\n"); |
for (j = 0; j < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; j++) |
{ |
fprintf (file, "Entry %1x ", j); |
bfd_fprintf_vma (abfd, file, i->DataDirectory[j].VirtualAddress); |
fprintf (file, " %08lx ", (unsigned long) i->DataDirectory[j].Size); |
fprintf (file, "%s\n", dir_names[j]); |
} |
pe_print_idata (abfd, vfile); |
pe_print_edata (abfd, vfile); |
if (bfd_coff_have_print_pdata (abfd)) |
bfd_coff_print_pdata (abfd, vfile); |
else |
pe_print_pdata (abfd, vfile); |
pe_print_reloc (abfd, vfile); |
return TRUE; |
} |
/* Copy any private info we understand from the input bfd |
to the output bfd. */ |
bfd_boolean |
_bfd_pe_bfd_copy_private_bfd_data_common (bfd * ibfd, bfd * obfd) |
{ |
pe_data_type *ipe, *ope; |
/* One day we may try to grok other private data. */ |
if (ibfd->xvec->flavour != bfd_target_coff_flavour |
|| obfd->xvec->flavour != bfd_target_coff_flavour) |
return TRUE; |
ipe = pe_data (ibfd); |
ope = pe_data (obfd); |
/* pe_opthdr is copied in copy_object. */ |
ope->dll = ipe->dll; |
/* Don't copy input subsystem if output is different from input. */ |
if (obfd->xvec != ibfd->xvec) |
ope->pe_opthdr.Subsystem = IMAGE_SUBSYSTEM_UNKNOWN; |
/* For strip: if we removed .reloc, we'll make a real mess of things |
if we don't remove this entry as well. */ |
if (! pe_data (obfd)->has_reloc_section) |
{ |
pe_data (obfd)->pe_opthdr.DataDirectory[PE_BASE_RELOCATION_TABLE].VirtualAddress = 0; |
pe_data (obfd)->pe_opthdr.DataDirectory[PE_BASE_RELOCATION_TABLE].Size = 0; |
} |
/* For PIE, if there is .reloc, we won't add IMAGE_FILE_RELOCS_STRIPPED. |
But there is no .reloc, we make sure that IMAGE_FILE_RELOCS_STRIPPED |
won't be added. */ |
if (! pe_data (ibfd)->has_reloc_section |
&& ! (pe_data (ibfd)->real_flags & IMAGE_FILE_RELOCS_STRIPPED)) |
pe_data (obfd)->dont_strip_reloc = 1; |
return TRUE; |
} |
/* Copy private section data. */ |
bfd_boolean |
_bfd_pe_bfd_copy_private_section_data (bfd *ibfd, |
asection *isec, |
bfd *obfd, |
asection *osec) |
{ |
if (bfd_get_flavour (ibfd) != bfd_target_coff_flavour |
|| bfd_get_flavour (obfd) != bfd_target_coff_flavour) |
return TRUE; |
if (coff_section_data (ibfd, isec) != NULL |
&& pei_section_data (ibfd, isec) != NULL) |
{ |
if (coff_section_data (obfd, osec) == NULL) |
{ |
bfd_size_type amt = sizeof (struct coff_section_tdata); |
osec->used_by_bfd = bfd_zalloc (obfd, amt); |
if (osec->used_by_bfd == NULL) |
return FALSE; |
} |
if (pei_section_data (obfd, osec) == NULL) |
{ |
bfd_size_type amt = sizeof (struct pei_section_tdata); |
coff_section_data (obfd, osec)->tdata = bfd_zalloc (obfd, amt); |
if (coff_section_data (obfd, osec)->tdata == NULL) |
return FALSE; |
} |
pei_section_data (obfd, osec)->virt_size = |
pei_section_data (ibfd, isec)->virt_size; |
pei_section_data (obfd, osec)->pe_flags = |
pei_section_data (ibfd, isec)->pe_flags; |
} |
return TRUE; |
} |
void |
_bfd_pe_get_symbol_info (bfd * abfd, asymbol *symbol, symbol_info *ret) |
{ |
coff_get_symbol_info (abfd, symbol, ret); |
} |
#if !defined(COFF_WITH_pep) && defined(COFF_WITH_pex64) |
static int |
sort_x64_pdata (const void *l, const void *r) |
{ |
const char *lp = (const char *) l; |
const char *rp = (const char *) r; |
bfd_vma vl, vr; |
vl = bfd_getl32 (lp); vr = bfd_getl32 (rp); |
if (vl != vr) |
return (vl < vr ? -1 : 1); |
/* We compare just begin address. */ |
return 0; |
} |
#endif |
/* Handle the .idata section and other things that need symbol table |
access. */ |
bfd_boolean |
_bfd_pei_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo) |
{ |
struct coff_link_hash_entry *h1; |
struct bfd_link_info *info = pfinfo->info; |
bfd_boolean result = TRUE; |
/* There are a few fields that need to be filled in now while we |
have symbol table access. |
The .idata subsections aren't directly available as sections, but |
they are in the symbol table, so get them from there. */ |
/* The import directory. This is the address of .idata$2, with size |
of .idata$2 + .idata$3. */ |
h1 = coff_link_hash_lookup (coff_hash_table (info), |
".idata$2", FALSE, FALSE, TRUE); |
if (h1 != NULL) |
{ |
/* PR ld/2729: We cannot rely upon all the output sections having been |
created properly, so check before referencing them. Issue a warning |
message for any sections tht could not be found. */ |
if ((h1->root.type == bfd_link_hash_defined |
|| h1->root.type == bfd_link_hash_defweak) |
&& h1->root.u.def.section != NULL |
&& h1->root.u.def.section->output_section != NULL) |
pe_data (abfd)->pe_opthdr.DataDirectory[PE_IMPORT_TABLE].VirtualAddress = |
(h1->root.u.def.value |
+ h1->root.u.def.section->output_section->vma |
+ h1->root.u.def.section->output_offset); |
else |
{ |
_bfd_error_handler |
(_("%B: unable to fill in DataDictionary[1] because .idata$2 is missing"), |
abfd); |
result = FALSE; |
} |
h1 = coff_link_hash_lookup (coff_hash_table (info), |
".idata$4", FALSE, FALSE, TRUE); |
if (h1 != NULL |
&& (h1->root.type == bfd_link_hash_defined |
|| h1->root.type == bfd_link_hash_defweak) |
&& h1->root.u.def.section != NULL |
&& h1->root.u.def.section->output_section != NULL) |
pe_data (abfd)->pe_opthdr.DataDirectory[PE_IMPORT_TABLE].Size = |
((h1->root.u.def.value |
+ h1->root.u.def.section->output_section->vma |
+ h1->root.u.def.section->output_offset) |
- pe_data (abfd)->pe_opthdr.DataDirectory[PE_IMPORT_TABLE].VirtualAddress); |
else |
{ |
_bfd_error_handler |
(_("%B: unable to fill in DataDictionary[1] because .idata$4 is missing"), |
abfd); |
result = FALSE; |
} |
/* The import address table. This is the size/address of |
.idata$5. */ |
h1 = coff_link_hash_lookup (coff_hash_table (info), |
".idata$5", FALSE, FALSE, TRUE); |
if (h1 != NULL |
&& (h1->root.type == bfd_link_hash_defined |
|| h1->root.type == bfd_link_hash_defweak) |
&& h1->root.u.def.section != NULL |
&& h1->root.u.def.section->output_section != NULL) |
pe_data (abfd)->pe_opthdr.DataDirectory[PE_IMPORT_ADDRESS_TABLE].VirtualAddress = |
(h1->root.u.def.value |
+ h1->root.u.def.section->output_section->vma |
+ h1->root.u.def.section->output_offset); |
else |
{ |
_bfd_error_handler |
(_("%B: unable to fill in DataDictionary[12] because .idata$5 is missing"), |
abfd); |
result = FALSE; |
} |
h1 = coff_link_hash_lookup (coff_hash_table (info), |
".idata$6", FALSE, FALSE, TRUE); |
if (h1 != NULL |
&& (h1->root.type == bfd_link_hash_defined |
|| h1->root.type == bfd_link_hash_defweak) |
&& h1->root.u.def.section != NULL |
&& h1->root.u.def.section->output_section != NULL) |
pe_data (abfd)->pe_opthdr.DataDirectory[PE_IMPORT_ADDRESS_TABLE].Size = |
((h1->root.u.def.value |
+ h1->root.u.def.section->output_section->vma |
+ h1->root.u.def.section->output_offset) |
- pe_data (abfd)->pe_opthdr.DataDirectory[PE_IMPORT_ADDRESS_TABLE].VirtualAddress); |
else |
{ |
_bfd_error_handler |
(_("%B: unable to fill in DataDictionary[PE_IMPORT_ADDRESS_TABLE (12)] because .idata$6 is missing"), |
abfd); |
result = FALSE; |
} |
} |
else |
{ |
h1 = coff_link_hash_lookup (coff_hash_table (info), |
"__IAT_start__", FALSE, FALSE, TRUE); |
if (h1 != NULL |
&& (h1->root.type == bfd_link_hash_defined |
|| h1->root.type == bfd_link_hash_defweak) |
&& h1->root.u.def.section != NULL |
&& h1->root.u.def.section->output_section != NULL) |
{ |
bfd_vma iat_va; |
iat_va = |
(h1->root.u.def.value |
+ h1->root.u.def.section->output_section->vma |
+ h1->root.u.def.section->output_offset); |
h1 = coff_link_hash_lookup (coff_hash_table (info), |
"__IAT_end__", FALSE, FALSE, TRUE); |
if (h1 != NULL |
&& (h1->root.type == bfd_link_hash_defined |
|| h1->root.type == bfd_link_hash_defweak) |
&& h1->root.u.def.section != NULL |
&& h1->root.u.def.section->output_section != NULL) |
{ |
pe_data (abfd)->pe_opthdr.DataDirectory[PE_IMPORT_ADDRESS_TABLE].Size = |
((h1->root.u.def.value |
+ h1->root.u.def.section->output_section->vma |
+ h1->root.u.def.section->output_offset) |
- iat_va); |
if (pe_data (abfd)->pe_opthdr.DataDirectory[PE_IMPORT_ADDRESS_TABLE].Size != 0) |
pe_data (abfd)->pe_opthdr.DataDirectory[PE_IMPORT_ADDRESS_TABLE].VirtualAddress = |
iat_va - pe_data (abfd)->pe_opthdr.ImageBase; |
} |
else |
{ |
_bfd_error_handler |
(_("%B: unable to fill in DataDictionary[PE_IMPORT_ADDRESS_TABLE(12)]" |
" because .idata$6 is missing"), abfd); |
result = FALSE; |
} |
} |
} |
h1 = coff_link_hash_lookup (coff_hash_table (info), |
(bfd_get_symbol_leading_char(abfd) != 0 |
? "__tls_used" : "_tls_used"), |
FALSE, FALSE, TRUE); |
if (h1 != NULL) |
{ |
if ((h1->root.type == bfd_link_hash_defined |
|| h1->root.type == bfd_link_hash_defweak) |
&& h1->root.u.def.section != NULL |
&& h1->root.u.def.section->output_section != NULL) |
pe_data (abfd)->pe_opthdr.DataDirectory[PE_TLS_TABLE].VirtualAddress = |
(h1->root.u.def.value |
+ h1->root.u.def.section->output_section->vma |
+ h1->root.u.def.section->output_offset |
- pe_data (abfd)->pe_opthdr.ImageBase); |
else |
{ |
_bfd_error_handler |
(_("%B: unable to fill in DataDictionary[9] because __tls_used is missing"), |
abfd); |
result = FALSE; |
} |
/* According to PECOFF sepcifications by Microsoft version 8.2 |
the TLS data directory consists of 4 pointers, followed |
by two 4-byte integer. This implies that the total size |
is different for 32-bit and 64-bit executables. */ |
#if !defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64) |
pe_data (abfd)->pe_opthdr.DataDirectory[PE_TLS_TABLE].Size = 0x18; |
#else |
pe_data (abfd)->pe_opthdr.DataDirectory[PE_TLS_TABLE].Size = 0x28; |
#endif |
} |
/* If there is a .pdata section and we have linked pdata finally, we |
need to sort the entries ascending. */ |
#if !defined(COFF_WITH_pep) && defined(COFF_WITH_pex64) |
{ |
asection *sec = bfd_get_section_by_name (abfd, ".pdata"); |
if (sec) |
{ |
bfd_size_type x = sec->rawsize; |
bfd_byte *tmp_data = NULL; |
if (x) |
tmp_data = bfd_malloc (x); |
if (tmp_data != NULL) |
{ |
if (bfd_get_section_contents (abfd, sec, tmp_data, 0, x)) |
{ |
qsort (tmp_data, |
(size_t) (x / 12), |
12, sort_x64_pdata); |
bfd_set_section_contents (pfinfo->output_bfd, sec, |
tmp_data, 0, x); |
} |
free (tmp_data); |
} |
} |
} |
#endif |
/* If we couldn't find idata$2, we either have an excessively |
trivial program or are in DEEP trouble; we have to assume trivial |
program.... */ |
return result; |
} |
/contrib/toolchain/binutils/bfd/reloc.c |
---|
0,0 → 1,7267 |
/* BFD support for handling relocation entries. |
Copyright 1990-2013 Free Software Foundation, Inc. |
Written by Cygnus Support. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* |
SECTION |
Relocations |
BFD maintains relocations in much the same way it maintains |
symbols: they are left alone until required, then read in |
en-masse and translated into an internal form. A common |
routine <<bfd_perform_relocation>> acts upon the |
canonical form to do the fixup. |
Relocations are maintained on a per section basis, |
while symbols are maintained on a per BFD basis. |
All that a back end has to do to fit the BFD interface is to create |
a <<struct reloc_cache_entry>> for each relocation |
in a particular section, and fill in the right bits of the structures. |
@menu |
@* typedef arelent:: |
@* howto manager:: |
@end menu |
*/ |
/* DO compile in the reloc_code name table from libbfd.h. */ |
#define _BFD_MAKE_TABLE_bfd_reloc_code_real |
#include "sysdep.h" |
#include "bfd.h" |
#include "bfdlink.h" |
#include "libbfd.h" |
/* |
DOCDD |
INODE |
typedef arelent, howto manager, Relocations, Relocations |
SUBSECTION |
typedef arelent |
This is the structure of a relocation entry: |
CODE_FRAGMENT |
. |
.typedef enum bfd_reloc_status |
.{ |
. {* No errors detected. *} |
. bfd_reloc_ok, |
. |
. {* The relocation was performed, but there was an overflow. *} |
. bfd_reloc_overflow, |
. |
. {* The address to relocate was not within the section supplied. *} |
. bfd_reloc_outofrange, |
. |
. {* Used by special functions. *} |
. bfd_reloc_continue, |
. |
. {* Unsupported relocation size requested. *} |
. bfd_reloc_notsupported, |
. |
. {* Unused. *} |
. bfd_reloc_other, |
. |
. {* The symbol to relocate against was undefined. *} |
. bfd_reloc_undefined, |
. |
. {* The relocation was performed, but may not be ok - presently |
. generated only when linking i960 coff files with i960 b.out |
. symbols. If this type is returned, the error_message argument |
. to bfd_perform_relocation will be set. *} |
. bfd_reloc_dangerous |
. } |
. bfd_reloc_status_type; |
. |
. |
.typedef struct reloc_cache_entry |
.{ |
. {* A pointer into the canonical table of pointers. *} |
. struct bfd_symbol **sym_ptr_ptr; |
. |
. {* offset in section. *} |
. bfd_size_type address; |
. |
. {* addend for relocation value. *} |
. bfd_vma addend; |
. |
. {* Pointer to how to perform the required relocation. *} |
. reloc_howto_type *howto; |
. |
.} |
.arelent; |
. |
*/ |
/* |
DESCRIPTION |
Here is a description of each of the fields within an <<arelent>>: |
o <<sym_ptr_ptr>> |
The symbol table pointer points to a pointer to the symbol |
associated with the relocation request. It is the pointer |
into the table returned by the back end's |
<<canonicalize_symtab>> action. @xref{Symbols}. The symbol is |
referenced through a pointer to a pointer so that tools like |
the linker can fix up all the symbols of the same name by |
modifying only one pointer. The relocation routine looks in |
the symbol and uses the base of the section the symbol is |
attached to and the value of the symbol as the initial |
relocation offset. If the symbol pointer is zero, then the |
section provided is looked up. |
o <<address>> |
The <<address>> field gives the offset in bytes from the base of |
the section data which owns the relocation record to the first |
byte of relocatable information. The actual data relocated |
will be relative to this point; for example, a relocation |
type which modifies the bottom two bytes of a four byte word |
would not touch the first byte pointed to in a big endian |
world. |
o <<addend>> |
The <<addend>> is a value provided by the back end to be added (!) |
to the relocation offset. Its interpretation is dependent upon |
the howto. For example, on the 68k the code: |
| char foo[]; |
| main() |
| { |
| return foo[0x12345678]; |
| } |
Could be compiled into: |
| linkw fp,#-4 |
| moveb @@#12345678,d0 |
| extbl d0 |
| unlk fp |
| rts |
This could create a reloc pointing to <<foo>>, but leave the |
offset in the data, something like: |
|RELOCATION RECORDS FOR [.text]: |
|offset type value |
|00000006 32 _foo |
| |
|00000000 4e56 fffc ; linkw fp,#-4 |
|00000004 1039 1234 5678 ; moveb @@#12345678,d0 |
|0000000a 49c0 ; extbl d0 |
|0000000c 4e5e ; unlk fp |
|0000000e 4e75 ; rts |
Using coff and an 88k, some instructions don't have enough |
space in them to represent the full address range, and |
pointers have to be loaded in two parts. So you'd get something like: |
| or.u r13,r0,hi16(_foo+0x12345678) |
| ld.b r2,r13,lo16(_foo+0x12345678) |
| jmp r1 |
This should create two relocs, both pointing to <<_foo>>, and with |
0x12340000 in their addend field. The data would consist of: |
|RELOCATION RECORDS FOR [.text]: |
|offset type value |
|00000002 HVRT16 _foo+0x12340000 |
|00000006 LVRT16 _foo+0x12340000 |
| |
|00000000 5da05678 ; or.u r13,r0,0x5678 |
|00000004 1c4d5678 ; ld.b r2,r13,0x5678 |
|00000008 f400c001 ; jmp r1 |
The relocation routine digs out the value from the data, adds |
it to the addend to get the original offset, and then adds the |
value of <<_foo>>. Note that all 32 bits have to be kept around |
somewhere, to cope with carry from bit 15 to bit 16. |
One further example is the sparc and the a.out format. The |
sparc has a similar problem to the 88k, in that some |
instructions don't have room for an entire offset, but on the |
sparc the parts are created in odd sized lumps. The designers of |
the a.out format chose to not use the data within the section |
for storing part of the offset; all the offset is kept within |
the reloc. Anything in the data should be ignored. |
| save %sp,-112,%sp |
| sethi %hi(_foo+0x12345678),%g2 |
| ldsb [%g2+%lo(_foo+0x12345678)],%i0 |
| ret |
| restore |
Both relocs contain a pointer to <<foo>>, and the offsets |
contain junk. |
|RELOCATION RECORDS FOR [.text]: |
|offset type value |
|00000004 HI22 _foo+0x12345678 |
|00000008 LO10 _foo+0x12345678 |
| |
|00000000 9de3bf90 ; save %sp,-112,%sp |
|00000004 05000000 ; sethi %hi(_foo+0),%g2 |
|00000008 f048a000 ; ldsb [%g2+%lo(_foo+0)],%i0 |
|0000000c 81c7e008 ; ret |
|00000010 81e80000 ; restore |
o <<howto>> |
The <<howto>> field can be imagined as a |
relocation instruction. It is a pointer to a structure which |
contains information on what to do with all of the other |
information in the reloc record and data section. A back end |
would normally have a relocation instruction set and turn |
relocations into pointers to the correct structure on input - |
but it would be possible to create each howto field on demand. |
*/ |
/* |
SUBSUBSECTION |
<<enum complain_overflow>> |
Indicates what sort of overflow checking should be done when |
performing a relocation. |
CODE_FRAGMENT |
. |
.enum complain_overflow |
.{ |
. {* Do not complain on overflow. *} |
. complain_overflow_dont, |
. |
. {* Complain if the value overflows when considered as a signed |
. number one bit larger than the field. ie. A bitfield of N bits |
. is allowed to represent -2**n to 2**n-1. *} |
. complain_overflow_bitfield, |
. |
. {* Complain if the value overflows when considered as a signed |
. number. *} |
. complain_overflow_signed, |
. |
. {* Complain if the value overflows when considered as an |
. unsigned number. *} |
. complain_overflow_unsigned |
.}; |
*/ |
/* |
SUBSUBSECTION |
<<reloc_howto_type>> |
The <<reloc_howto_type>> is a structure which contains all the |
information that libbfd needs to know to tie up a back end's data. |
CODE_FRAGMENT |
.struct bfd_symbol; {* Forward declaration. *} |
. |
.struct reloc_howto_struct |
.{ |
. {* The type field has mainly a documentary use - the back end can |
. do what it wants with it, though normally the back end's |
. external idea of what a reloc number is stored |
. in this field. For example, a PC relative word relocation |
. in a coff environment has the type 023 - because that's |
. what the outside world calls a R_PCRWORD reloc. *} |
. unsigned int type; |
. |
. {* The value the final relocation is shifted right by. This drops |
. unwanted data from the relocation. *} |
. unsigned int rightshift; |
. |
. {* The size of the item to be relocated. This is *not* a |
. power-of-two measure. To get the number of bytes operated |
. on by a type of relocation, use bfd_get_reloc_size. *} |
. int size; |
. |
. {* The number of bits in the item to be relocated. This is used |
. when doing overflow checking. *} |
. unsigned int bitsize; |
. |
. {* The relocation is relative to the field being relocated. *} |
. bfd_boolean pc_relative; |
. |
. {* The bit position of the reloc value in the destination. |
. The relocated value is left shifted by this amount. *} |
. unsigned int bitpos; |
. |
. {* What type of overflow error should be checked for when |
. relocating. *} |
. enum complain_overflow complain_on_overflow; |
. |
. {* If this field is non null, then the supplied function is |
. called rather than the normal function. This allows really |
. strange relocation methods to be accommodated (e.g., i960 callj |
. instructions). *} |
. bfd_reloc_status_type (*special_function) |
. (bfd *, arelent *, struct bfd_symbol *, void *, asection *, |
. bfd *, char **); |
. |
. {* The textual name of the relocation type. *} |
. char *name; |
. |
. {* Some formats record a relocation addend in the section contents |
. rather than with the relocation. For ELF formats this is the |
. distinction between USE_REL and USE_RELA (though the code checks |
. for USE_REL == 1/0). The value of this field is TRUE if the |
. addend is recorded with the section contents; when performing a |
. partial link (ld -r) the section contents (the data) will be |
. modified. The value of this field is FALSE if addends are |
. recorded with the relocation (in arelent.addend); when performing |
. a partial link the relocation will be modified. |
. All relocations for all ELF USE_RELA targets should set this field |
. to FALSE (values of TRUE should be looked on with suspicion). |
. However, the converse is not true: not all relocations of all ELF |
. USE_REL targets set this field to TRUE. Why this is so is peculiar |
. to each particular target. For relocs that aren't used in partial |
. links (e.g. GOT stuff) it doesn't matter what this is set to. *} |
. bfd_boolean partial_inplace; |
. |
. {* src_mask selects the part of the instruction (or data) to be used |
. in the relocation sum. If the target relocations don't have an |
. addend in the reloc, eg. ELF USE_REL, src_mask will normally equal |
. dst_mask to extract the addend from the section contents. If |
. relocations do have an addend in the reloc, eg. ELF USE_RELA, this |
. field should be zero. Non-zero values for ELF USE_RELA targets are |
. bogus as in those cases the value in the dst_mask part of the |
. section contents should be treated as garbage. *} |
. bfd_vma src_mask; |
. |
. {* dst_mask selects which parts of the instruction (or data) are |
. replaced with a relocated value. *} |
. bfd_vma dst_mask; |
. |
. {* When some formats create PC relative instructions, they leave |
. the value of the pc of the place being relocated in the offset |
. slot of the instruction, so that a PC relative relocation can |
. be made just by adding in an ordinary offset (e.g., sun3 a.out). |
. Some formats leave the displacement part of an instruction |
. empty (e.g., m88k bcs); this flag signals the fact. *} |
. bfd_boolean pcrel_offset; |
.}; |
. |
*/ |
/* |
FUNCTION |
The HOWTO Macro |
DESCRIPTION |
The HOWTO define is horrible and will go away. |
.#define HOWTO(C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC) \ |
. { (unsigned) C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC } |
DESCRIPTION |
And will be replaced with the totally magic way. But for the |
moment, we are compatible, so do it this way. |
.#define NEWHOWTO(FUNCTION, NAME, SIZE, REL, IN) \ |
. HOWTO (0, 0, SIZE, 0, REL, 0, complain_overflow_dont, FUNCTION, \ |
. NAME, FALSE, 0, 0, IN) |
. |
DESCRIPTION |
This is used to fill in an empty howto entry in an array. |
.#define EMPTY_HOWTO(C) \ |
. HOWTO ((C), 0, 0, 0, FALSE, 0, complain_overflow_dont, NULL, \ |
. NULL, FALSE, 0, 0, FALSE) |
. |
DESCRIPTION |
Helper routine to turn a symbol into a relocation value. |
.#define HOWTO_PREPARE(relocation, symbol) \ |
. { \ |
. if (symbol != NULL) \ |
. { \ |
. if (bfd_is_com_section (symbol->section)) \ |
. { \ |
. relocation = 0; \ |
. } \ |
. else \ |
. { \ |
. relocation = symbol->value; \ |
. } \ |
. } \ |
. } |
. |
*/ |
/* |
FUNCTION |
bfd_get_reloc_size |
SYNOPSIS |
unsigned int bfd_get_reloc_size (reloc_howto_type *); |
DESCRIPTION |
For a reloc_howto_type that operates on a fixed number of bytes, |
this returns the number of bytes operated on. |
*/ |
unsigned int |
bfd_get_reloc_size (reloc_howto_type *howto) |
{ |
switch (howto->size) |
{ |
case 0: return 1; |
case 1: return 2; |
case 2: return 4; |
case 3: return 0; |
case 4: return 8; |
case 8: return 16; |
case -2: return 4; |
default: abort (); |
} |
} |
/* |
TYPEDEF |
arelent_chain |
DESCRIPTION |
How relocs are tied together in an <<asection>>: |
.typedef struct relent_chain |
.{ |
. arelent relent; |
. struct relent_chain *next; |
.} |
.arelent_chain; |
. |
*/ |
/* N_ONES produces N one bits, without overflowing machine arithmetic. */ |
#define N_ONES(n) (((((bfd_vma) 1 << ((n) - 1)) - 1) << 1) | 1) |
/* |
FUNCTION |
bfd_check_overflow |
SYNOPSIS |
bfd_reloc_status_type bfd_check_overflow |
(enum complain_overflow how, |
unsigned int bitsize, |
unsigned int rightshift, |
unsigned int addrsize, |
bfd_vma relocation); |
DESCRIPTION |
Perform overflow checking on @var{relocation} which has |
@var{bitsize} significant bits and will be shifted right by |
@var{rightshift} bits, on a machine with addresses containing |
@var{addrsize} significant bits. The result is either of |
@code{bfd_reloc_ok} or @code{bfd_reloc_overflow}. |
*/ |
bfd_reloc_status_type |
bfd_check_overflow (enum complain_overflow how, |
unsigned int bitsize, |
unsigned int rightshift, |
unsigned int addrsize, |
bfd_vma relocation) |
{ |
bfd_vma fieldmask, addrmask, signmask, ss, a; |
bfd_reloc_status_type flag = bfd_reloc_ok; |
/* Note: BITSIZE should always be <= ADDRSIZE, but in case it's not, |
we'll be permissive: extra bits in the field mask will |
automatically extend the address mask for purposes of the |
overflow check. */ |
fieldmask = N_ONES (bitsize); |
signmask = ~fieldmask; |
addrmask = N_ONES (addrsize) | (fieldmask << rightshift); |
a = (relocation & addrmask) >> rightshift; |
switch (how) |
{ |
case complain_overflow_dont: |
break; |
case complain_overflow_signed: |
/* If any sign bits are set, all sign bits must be set. That |
is, A must be a valid negative address after shifting. */ |
signmask = ~ (fieldmask >> 1); |
/* Fall thru */ |
case complain_overflow_bitfield: |
/* Bitfields are sometimes signed, sometimes unsigned. We |
explicitly allow an address wrap too, which means a bitfield |
of n bits is allowed to store -2**n to 2**n-1. Thus overflow |
if the value has some, but not all, bits set outside the |
field. */ |
ss = a & signmask; |
if (ss != 0 && ss != ((addrmask >> rightshift) & signmask)) |
flag = bfd_reloc_overflow; |
break; |
case complain_overflow_unsigned: |
/* We have an overflow if the address does not fit in the field. */ |
if ((a & signmask) != 0) |
flag = bfd_reloc_overflow; |
break; |
default: |
abort (); |
} |
return flag; |
} |
/* |
FUNCTION |
bfd_perform_relocation |
SYNOPSIS |
bfd_reloc_status_type bfd_perform_relocation |
(bfd *abfd, |
arelent *reloc_entry, |
void *data, |
asection *input_section, |
bfd *output_bfd, |
char **error_message); |
DESCRIPTION |
If @var{output_bfd} is supplied to this function, the |
generated image will be relocatable; the relocations are |
copied to the output file after they have been changed to |
reflect the new state of the world. There are two ways of |
reflecting the results of partial linkage in an output file: |
by modifying the output data in place, and by modifying the |
relocation record. Some native formats (e.g., basic a.out and |
basic coff) have no way of specifying an addend in the |
relocation type, so the addend has to go in the output data. |
This is no big deal since in these formats the output data |
slot will always be big enough for the addend. Complex reloc |
types with addends were invented to solve just this problem. |
The @var{error_message} argument is set to an error message if |
this return @code{bfd_reloc_dangerous}. |
*/ |
bfd_reloc_status_type |
bfd_perform_relocation (bfd *abfd, |
arelent *reloc_entry, |
void *data, |
asection *input_section, |
bfd *output_bfd, |
char **error_message) |
{ |
bfd_vma relocation; |
bfd_reloc_status_type flag = bfd_reloc_ok; |
bfd_size_type octets = reloc_entry->address * bfd_octets_per_byte (abfd); |
bfd_vma output_base = 0; |
reloc_howto_type *howto = reloc_entry->howto; |
asection *reloc_target_output_section; |
asymbol *symbol; |
symbol = *(reloc_entry->sym_ptr_ptr); |
if (bfd_is_abs_section (symbol->section) |
&& output_bfd != NULL) |
{ |
reloc_entry->address += input_section->output_offset; |
return bfd_reloc_ok; |
} |
/* If we are not producing relocatable output, return an error if |
the symbol is not defined. An undefined weak symbol is |
considered to have a value of zero (SVR4 ABI, p. 4-27). */ |
if (bfd_is_und_section (symbol->section) |
&& (symbol->flags & BSF_WEAK) == 0 |
&& output_bfd == NULL) |
flag = bfd_reloc_undefined; |
/* If there is a function supplied to handle this relocation type, |
call it. It'll return `bfd_reloc_continue' if further processing |
can be done. */ |
if (howto->special_function) |
{ |
bfd_reloc_status_type cont; |
cont = howto->special_function (abfd, reloc_entry, symbol, data, |
input_section, output_bfd, |
error_message); |
if (cont != bfd_reloc_continue) |
return cont; |
} |
/* Is the address of the relocation really within the section? */ |
if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) |
return bfd_reloc_outofrange; |
/* Work out which section the relocation is targeted at and the |
initial relocation command value. */ |
/* Get symbol value. (Common symbols are special.) */ |
if (bfd_is_com_section (symbol->section)) |
relocation = 0; |
else |
relocation = symbol->value; |
reloc_target_output_section = symbol->section->output_section; |
/* Convert input-section-relative symbol value to absolute. */ |
if ((output_bfd && ! howto->partial_inplace) |
|| reloc_target_output_section == NULL) |
output_base = 0; |
else |
output_base = reloc_target_output_section->vma; |
relocation += output_base + symbol->section->output_offset; |
/* Add in supplied addend. */ |
relocation += reloc_entry->addend; |
/* Here the variable relocation holds the final address of the |
symbol we are relocating against, plus any addend. */ |
if (howto->pc_relative) |
{ |
/* This is a PC relative relocation. We want to set RELOCATION |
to the distance between the address of the symbol and the |
location. RELOCATION is already the address of the symbol. |
We start by subtracting the address of the section containing |
the location. |
If pcrel_offset is set, we must further subtract the position |
of the location within the section. Some targets arrange for |
the addend to be the negative of the position of the location |
within the section; for example, i386-aout does this. For |
i386-aout, pcrel_offset is FALSE. Some other targets do not |
include the position of the location; for example, m88kbcs, |
or ELF. For those targets, pcrel_offset is TRUE. |
If we are producing relocatable output, then we must ensure |
that this reloc will be correctly computed when the final |
relocation is done. If pcrel_offset is FALSE we want to wind |
up with the negative of the location within the section, |
which means we must adjust the existing addend by the change |
in the location within the section. If pcrel_offset is TRUE |
we do not want to adjust the existing addend at all. |
FIXME: This seems logical to me, but for the case of |
producing relocatable output it is not what the code |
actually does. I don't want to change it, because it seems |
far too likely that something will break. */ |
relocation -= |
input_section->output_section->vma + input_section->output_offset; |
if (howto->pcrel_offset) |
relocation -= reloc_entry->address; |
} |
if (output_bfd != NULL) |
{ |
if (! howto->partial_inplace) |
{ |
/* This is a partial relocation, and we want to apply the relocation |
to the reloc entry rather than the raw data. Modify the reloc |
inplace to reflect what we now know. */ |
reloc_entry->addend = relocation; |
reloc_entry->address += input_section->output_offset; |
return flag; |
} |
else |
{ |
/* This is a partial relocation, but inplace, so modify the |
reloc record a bit. |
If we've relocated with a symbol with a section, change |
into a ref to the section belonging to the symbol. */ |
reloc_entry->address += input_section->output_offset; |
/* WTF?? */ |
if (abfd->xvec->flavour == bfd_target_coff_flavour |
&& strcmp (abfd->xvec->name, "coff-Intel-little") != 0 |
&& strcmp (abfd->xvec->name, "coff-Intel-big") != 0) |
{ |
/* For m68k-coff, the addend was being subtracted twice during |
relocation with -r. Removing the line below this comment |
fixes that problem; see PR 2953. |
However, Ian wrote the following, regarding removing the line below, |
which explains why it is still enabled: --djm |
If you put a patch like that into BFD you need to check all the COFF |
linkers. I am fairly certain that patch will break coff-i386 (e.g., |
SCO); see coff_i386_reloc in coff-i386.c where I worked around the |
problem in a different way. There may very well be a reason that the |
code works as it does. |
Hmmm. The first obvious point is that bfd_perform_relocation should |
not have any tests that depend upon the flavour. It's seem like |
entirely the wrong place for such a thing. The second obvious point |
is that the current code ignores the reloc addend when producing |
relocatable output for COFF. That's peculiar. In fact, I really |
have no idea what the point of the line you want to remove is. |
A typical COFF reloc subtracts the old value of the symbol and adds in |
the new value to the location in the object file (if it's a pc |
relative reloc it adds the difference between the symbol value and the |
location). When relocating we need to preserve that property. |
BFD handles this by setting the addend to the negative of the old |
value of the symbol. Unfortunately it handles common symbols in a |
non-standard way (it doesn't subtract the old value) but that's a |
different story (we can't change it without losing backward |
compatibility with old object files) (coff-i386 does subtract the old |
value, to be compatible with existing coff-i386 targets, like SCO). |
So everything works fine when not producing relocatable output. When |
we are producing relocatable output, logically we should do exactly |
what we do when not producing relocatable output. Therefore, your |
patch is correct. In fact, it should probably always just set |
reloc_entry->addend to 0 for all cases, since it is, in fact, going to |
add the value into the object file. This won't hurt the COFF code, |
which doesn't use the addend; I'm not sure what it will do to other |
formats (the thing to check for would be whether any formats both use |
the addend and set partial_inplace). |
When I wanted to make coff-i386 produce relocatable output, I ran |
into the problem that you are running into: I wanted to remove that |
line. Rather than risk it, I made the coff-i386 relocs use a special |
function; it's coff_i386_reloc in coff-i386.c. The function |
specifically adds the addend field into the object file, knowing that |
bfd_perform_relocation is not going to. If you remove that line, then |
coff-i386.c will wind up adding the addend field in twice. It's |
trivial to fix; it just needs to be done. |
The problem with removing the line is just that it may break some |
working code. With BFD it's hard to be sure of anything. The right |
way to deal with this is simply to build and test at least all the |
supported COFF targets. It should be straightforward if time and disk |
space consuming. For each target: |
1) build the linker |
2) generate some executable, and link it using -r (I would |
probably use paranoia.o and link against newlib/libc.a, which |
for all the supported targets would be available in |
/usr/cygnus/progressive/H-host/target/lib/libc.a). |
3) make the change to reloc.c |
4) rebuild the linker |
5) repeat step 2 |
6) if the resulting object files are the same, you have at least |
made it no worse |
7) if they are different you have to figure out which version is |
right |
*/ |
relocation -= reloc_entry->addend; |
reloc_entry->addend = 0; |
} |
else |
{ |
reloc_entry->addend = relocation; |
} |
} |
} |
else |
{ |
reloc_entry->addend = 0; |
} |
/* FIXME: This overflow checking is incomplete, because the value |
might have overflowed before we get here. For a correct check we |
need to compute the value in a size larger than bitsize, but we |
can't reasonably do that for a reloc the same size as a host |
machine word. |
FIXME: We should also do overflow checking on the result after |
adding in the value contained in the object file. */ |
if (howto->complain_on_overflow != complain_overflow_dont |
&& flag == bfd_reloc_ok) |
flag = bfd_check_overflow (howto->complain_on_overflow, |
howto->bitsize, |
howto->rightshift, |
bfd_arch_bits_per_address (abfd), |
relocation); |
/* Either we are relocating all the way, or we don't want to apply |
the relocation to the reloc entry (probably because there isn't |
any room in the output format to describe addends to relocs). */ |
/* The cast to bfd_vma avoids a bug in the Alpha OSF/1 C compiler |
(OSF version 1.3, compiler version 3.11). It miscompiles the |
following program: |
struct str |
{ |
unsigned int i0; |
} s = { 0 }; |
int |
main () |
{ |
unsigned long x; |
x = 0x100000000; |
x <<= (unsigned long) s.i0; |
if (x == 0) |
printf ("failed\n"); |
else |
printf ("succeeded (%lx)\n", x); |
} |
*/ |
relocation >>= (bfd_vma) howto->rightshift; |
/* Shift everything up to where it's going to be used. */ |
relocation <<= (bfd_vma) howto->bitpos; |
/* Wait for the day when all have the mask in them. */ |
/* What we do: |
i instruction to be left alone |
o offset within instruction |
r relocation offset to apply |
S src mask |
D dst mask |
N ~dst mask |
A part 1 |
B part 2 |
R result |
Do this: |
(( i i i i i o o o o o from bfd_get<size> |
and S S S S S) to get the size offset we want |
+ r r r r r r r r r r) to get the final value to place |
and D D D D D to chop to right size |
----------------------- |
= A A A A A |
And this: |
( i i i i i o o o o o from bfd_get<size> |
and N N N N N ) get instruction |
----------------------- |
= B B B B B |
And then: |
( B B B B B |
or A A A A A) |
----------------------- |
= R R R R R R R R R R put into bfd_put<size> |
*/ |
#define DOIT(x) \ |
x = ( (x & ~howto->dst_mask) | (((x & howto->src_mask) + relocation) & howto->dst_mask)) |
switch (howto->size) |
{ |
case 0: |
{ |
char x = bfd_get_8 (abfd, (char *) data + octets); |
DOIT (x); |
bfd_put_8 (abfd, x, (unsigned char *) data + octets); |
} |
break; |
case 1: |
{ |
short x = bfd_get_16 (abfd, (bfd_byte *) data + octets); |
DOIT (x); |
bfd_put_16 (abfd, (bfd_vma) x, (unsigned char *) data + octets); |
} |
break; |
case 2: |
{ |
long x = bfd_get_32 (abfd, (bfd_byte *) data + octets); |
DOIT (x); |
bfd_put_32 (abfd, (bfd_vma) x, (bfd_byte *) data + octets); |
} |
break; |
case -2: |
{ |
long x = bfd_get_32 (abfd, (bfd_byte *) data + octets); |
relocation = -relocation; |
DOIT (x); |
bfd_put_32 (abfd, (bfd_vma) x, (bfd_byte *) data + octets); |
} |
break; |
case -1: |
{ |
long x = bfd_get_16 (abfd, (bfd_byte *) data + octets); |
relocation = -relocation; |
DOIT (x); |
bfd_put_16 (abfd, (bfd_vma) x, (bfd_byte *) data + octets); |
} |
break; |
case 3: |
/* Do nothing */ |
break; |
case 4: |
#ifdef BFD64 |
{ |
bfd_vma x = bfd_get_64 (abfd, (bfd_byte *) data + octets); |
DOIT (x); |
bfd_put_64 (abfd, x, (bfd_byte *) data + octets); |
} |
#else |
abort (); |
#endif |
break; |
default: |
return bfd_reloc_other; |
} |
return flag; |
} |
/* |
FUNCTION |
bfd_install_relocation |
SYNOPSIS |
bfd_reloc_status_type bfd_install_relocation |
(bfd *abfd, |
arelent *reloc_entry, |
void *data, bfd_vma data_start, |
asection *input_section, |
char **error_message); |
DESCRIPTION |
This looks remarkably like <<bfd_perform_relocation>>, except it |
does not expect that the section contents have been filled in. |
I.e., it's suitable for use when creating, rather than applying |
a relocation. |
For now, this function should be considered reserved for the |
assembler. |
*/ |
bfd_reloc_status_type |
bfd_install_relocation (bfd *abfd, |
arelent *reloc_entry, |
void *data_start, |
bfd_vma data_start_offset, |
asection *input_section, |
char **error_message) |
{ |
bfd_vma relocation; |
bfd_reloc_status_type flag = bfd_reloc_ok; |
bfd_size_type octets = reloc_entry->address * bfd_octets_per_byte (abfd); |
bfd_vma output_base = 0; |
reloc_howto_type *howto = reloc_entry->howto; |
asection *reloc_target_output_section; |
asymbol *symbol; |
bfd_byte *data; |
symbol = *(reloc_entry->sym_ptr_ptr); |
if (bfd_is_abs_section (symbol->section)) |
{ |
reloc_entry->address += input_section->output_offset; |
return bfd_reloc_ok; |
} |
/* If there is a function supplied to handle this relocation type, |
call it. It'll return `bfd_reloc_continue' if further processing |
can be done. */ |
if (howto->special_function) |
{ |
bfd_reloc_status_type cont; |
/* XXX - The special_function calls haven't been fixed up to deal |
with creating new relocations and section contents. */ |
cont = howto->special_function (abfd, reloc_entry, symbol, |
/* XXX - Non-portable! */ |
((bfd_byte *) data_start |
- data_start_offset), |
input_section, abfd, error_message); |
if (cont != bfd_reloc_continue) |
return cont; |
} |
/* Is the address of the relocation really within the section? */ |
if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) |
return bfd_reloc_outofrange; |
/* Work out which section the relocation is targeted at and the |
initial relocation command value. */ |
/* Get symbol value. (Common symbols are special.) */ |
if (bfd_is_com_section (symbol->section)) |
relocation = 0; |
else |
relocation = symbol->value; |
reloc_target_output_section = symbol->section->output_section; |
/* Convert input-section-relative symbol value to absolute. */ |
if (! howto->partial_inplace) |
output_base = 0; |
else |
output_base = reloc_target_output_section->vma; |
relocation += output_base + symbol->section->output_offset; |
/* Add in supplied addend. */ |
relocation += reloc_entry->addend; |
/* Here the variable relocation holds the final address of the |
symbol we are relocating against, plus any addend. */ |
if (howto->pc_relative) |
{ |
/* This is a PC relative relocation. We want to set RELOCATION |
to the distance between the address of the symbol and the |
location. RELOCATION is already the address of the symbol. |
We start by subtracting the address of the section containing |
the location. |
If pcrel_offset is set, we must further subtract the position |
of the location within the section. Some targets arrange for |
the addend to be the negative of the position of the location |
within the section; for example, i386-aout does this. For |
i386-aout, pcrel_offset is FALSE. Some other targets do not |
include the position of the location; for example, m88kbcs, |
or ELF. For those targets, pcrel_offset is TRUE. |
If we are producing relocatable output, then we must ensure |
that this reloc will be correctly computed when the final |
relocation is done. If pcrel_offset is FALSE we want to wind |
up with the negative of the location within the section, |
which means we must adjust the existing addend by the change |
in the location within the section. If pcrel_offset is TRUE |
we do not want to adjust the existing addend at all. |
FIXME: This seems logical to me, but for the case of |
producing relocatable output it is not what the code |
actually does. I don't want to change it, because it seems |
far too likely that something will break. */ |
relocation -= |
input_section->output_section->vma + input_section->output_offset; |
if (howto->pcrel_offset && howto->partial_inplace) |
relocation -= reloc_entry->address; |
} |
if (! howto->partial_inplace) |
{ |
/* This is a partial relocation, and we want to apply the relocation |
to the reloc entry rather than the raw data. Modify the reloc |
inplace to reflect what we now know. */ |
reloc_entry->addend = relocation; |
reloc_entry->address += input_section->output_offset; |
return flag; |
} |
else |
{ |
/* This is a partial relocation, but inplace, so modify the |
reloc record a bit. |
If we've relocated with a symbol with a section, change |
into a ref to the section belonging to the symbol. */ |
reloc_entry->address += input_section->output_offset; |
/* WTF?? */ |
if (abfd->xvec->flavour == bfd_target_coff_flavour |
&& strcmp (abfd->xvec->name, "coff-Intel-little") != 0 |
&& strcmp (abfd->xvec->name, "coff-Intel-big") != 0) |
{ |
/* For m68k-coff, the addend was being subtracted twice during |
relocation with -r. Removing the line below this comment |
fixes that problem; see PR 2953. |
However, Ian wrote the following, regarding removing the line below, |
which explains why it is still enabled: --djm |
If you put a patch like that into BFD you need to check all the COFF |
linkers. I am fairly certain that patch will break coff-i386 (e.g., |
SCO); see coff_i386_reloc in coff-i386.c where I worked around the |
problem in a different way. There may very well be a reason that the |
code works as it does. |
Hmmm. The first obvious point is that bfd_install_relocation should |
not have any tests that depend upon the flavour. It's seem like |
entirely the wrong place for such a thing. The second obvious point |
is that the current code ignores the reloc addend when producing |
relocatable output for COFF. That's peculiar. In fact, I really |
have no idea what the point of the line you want to remove is. |
A typical COFF reloc subtracts the old value of the symbol and adds in |
the new value to the location in the object file (if it's a pc |
relative reloc it adds the difference between the symbol value and the |
location). When relocating we need to preserve that property. |
BFD handles this by setting the addend to the negative of the old |
value of the symbol. Unfortunately it handles common symbols in a |
non-standard way (it doesn't subtract the old value) but that's a |
different story (we can't change it without losing backward |
compatibility with old object files) (coff-i386 does subtract the old |
value, to be compatible with existing coff-i386 targets, like SCO). |
So everything works fine when not producing relocatable output. When |
we are producing relocatable output, logically we should do exactly |
what we do when not producing relocatable output. Therefore, your |
patch is correct. In fact, it should probably always just set |
reloc_entry->addend to 0 for all cases, since it is, in fact, going to |
add the value into the object file. This won't hurt the COFF code, |
which doesn't use the addend; I'm not sure what it will do to other |
formats (the thing to check for would be whether any formats both use |
the addend and set partial_inplace). |
When I wanted to make coff-i386 produce relocatable output, I ran |
into the problem that you are running into: I wanted to remove that |
line. Rather than risk it, I made the coff-i386 relocs use a special |
function; it's coff_i386_reloc in coff-i386.c. The function |
specifically adds the addend field into the object file, knowing that |
bfd_install_relocation is not going to. If you remove that line, then |
coff-i386.c will wind up adding the addend field in twice. It's |
trivial to fix; it just needs to be done. |
The problem with removing the line is just that it may break some |
working code. With BFD it's hard to be sure of anything. The right |
way to deal with this is simply to build and test at least all the |
supported COFF targets. It should be straightforward if time and disk |
space consuming. For each target: |
1) build the linker |
2) generate some executable, and link it using -r (I would |
probably use paranoia.o and link against newlib/libc.a, which |
for all the supported targets would be available in |
/usr/cygnus/progressive/H-host/target/lib/libc.a). |
3) make the change to reloc.c |
4) rebuild the linker |
5) repeat step 2 |
6) if the resulting object files are the same, you have at least |
made it no worse |
7) if they are different you have to figure out which version is |
right. */ |
relocation -= reloc_entry->addend; |
/* FIXME: There should be no target specific code here... */ |
if (strcmp (abfd->xvec->name, "coff-z8k") != 0) |
reloc_entry->addend = 0; |
} |
else |
{ |
reloc_entry->addend = relocation; |
} |
} |
/* FIXME: This overflow checking is incomplete, because the value |
might have overflowed before we get here. For a correct check we |
need to compute the value in a size larger than bitsize, but we |
can't reasonably do that for a reloc the same size as a host |
machine word. |
FIXME: We should also do overflow checking on the result after |
adding in the value contained in the object file. */ |
if (howto->complain_on_overflow != complain_overflow_dont) |
flag = bfd_check_overflow (howto->complain_on_overflow, |
howto->bitsize, |
howto->rightshift, |
bfd_arch_bits_per_address (abfd), |
relocation); |
/* Either we are relocating all the way, or we don't want to apply |
the relocation to the reloc entry (probably because there isn't |
any room in the output format to describe addends to relocs). */ |
/* The cast to bfd_vma avoids a bug in the Alpha OSF/1 C compiler |
(OSF version 1.3, compiler version 3.11). It miscompiles the |
following program: |
struct str |
{ |
unsigned int i0; |
} s = { 0 }; |
int |
main () |
{ |
unsigned long x; |
x = 0x100000000; |
x <<= (unsigned long) s.i0; |
if (x == 0) |
printf ("failed\n"); |
else |
printf ("succeeded (%lx)\n", x); |
} |
*/ |
relocation >>= (bfd_vma) howto->rightshift; |
/* Shift everything up to where it's going to be used. */ |
relocation <<= (bfd_vma) howto->bitpos; |
/* Wait for the day when all have the mask in them. */ |
/* What we do: |
i instruction to be left alone |
o offset within instruction |
r relocation offset to apply |
S src mask |
D dst mask |
N ~dst mask |
A part 1 |
B part 2 |
R result |
Do this: |
(( i i i i i o o o o o from bfd_get<size> |
and S S S S S) to get the size offset we want |
+ r r r r r r r r r r) to get the final value to place |
and D D D D D to chop to right size |
----------------------- |
= A A A A A |
And this: |
( i i i i i o o o o o from bfd_get<size> |
and N N N N N ) get instruction |
----------------------- |
= B B B B B |
And then: |
( B B B B B |
or A A A A A) |
----------------------- |
= R R R R R R R R R R put into bfd_put<size> |
*/ |
#define DOIT(x) \ |
x = ( (x & ~howto->dst_mask) | (((x & howto->src_mask) + relocation) & howto->dst_mask)) |
data = (bfd_byte *) data_start + (octets - data_start_offset); |
switch (howto->size) |
{ |
case 0: |
{ |
char x = bfd_get_8 (abfd, data); |
DOIT (x); |
bfd_put_8 (abfd, x, data); |
} |
break; |
case 1: |
{ |
short x = bfd_get_16 (abfd, data); |
DOIT (x); |
bfd_put_16 (abfd, (bfd_vma) x, data); |
} |
break; |
case 2: |
{ |
long x = bfd_get_32 (abfd, data); |
DOIT (x); |
bfd_put_32 (abfd, (bfd_vma) x, data); |
} |
break; |
case -2: |
{ |
long x = bfd_get_32 (abfd, data); |
relocation = -relocation; |
DOIT (x); |
bfd_put_32 (abfd, (bfd_vma) x, data); |
} |
break; |
case 3: |
/* Do nothing */ |
break; |
case 4: |
{ |
bfd_vma x = bfd_get_64 (abfd, data); |
DOIT (x); |
bfd_put_64 (abfd, x, data); |
} |
break; |
default: |
return bfd_reloc_other; |
} |
return flag; |
} |
/* This relocation routine is used by some of the backend linkers. |
They do not construct asymbol or arelent structures, so there is no |
reason for them to use bfd_perform_relocation. Also, |
bfd_perform_relocation is so hacked up it is easier to write a new |
function than to try to deal with it. |
This routine does a final relocation. Whether it is useful for a |
relocatable link depends upon how the object format defines |
relocations. |
FIXME: This routine ignores any special_function in the HOWTO, |
since the existing special_function values have been written for |
bfd_perform_relocation. |
HOWTO is the reloc howto information. |
INPUT_BFD is the BFD which the reloc applies to. |
INPUT_SECTION is the section which the reloc applies to. |
CONTENTS is the contents of the section. |
ADDRESS is the address of the reloc within INPUT_SECTION. |
VALUE is the value of the symbol the reloc refers to. |
ADDEND is the addend of the reloc. */ |
bfd_reloc_status_type |
_bfd_final_link_relocate (reloc_howto_type *howto, |
bfd *input_bfd, |
asection *input_section, |
bfd_byte *contents, |
bfd_vma address, |
bfd_vma value, |
bfd_vma addend) |
{ |
bfd_vma relocation; |
/* Sanity check the address. */ |
if (address > bfd_get_section_limit (input_bfd, input_section)) |
return bfd_reloc_outofrange; |
/* This function assumes that we are dealing with a basic relocation |
against a symbol. We want to compute the value of the symbol to |
relocate to. This is just VALUE, the value of the symbol, plus |
ADDEND, any addend associated with the reloc. */ |
relocation = value + addend; |
/* If the relocation is PC relative, we want to set RELOCATION to |
the distance between the symbol (currently in RELOCATION) and the |
location we are relocating. Some targets (e.g., i386-aout) |
arrange for the contents of the section to be the negative of the |
offset of the location within the section; for such targets |
pcrel_offset is FALSE. Other targets (e.g., m88kbcs or ELF) |
simply leave the contents of the section as zero; for such |
targets pcrel_offset is TRUE. If pcrel_offset is FALSE we do not |
need to subtract out the offset of the location within the |
section (which is just ADDRESS). */ |
if (howto->pc_relative) |
{ |
relocation -= (input_section->output_section->vma |
+ input_section->output_offset); |
if (howto->pcrel_offset) |
relocation -= address; |
} |
return _bfd_relocate_contents (howto, input_bfd, relocation, |
contents + address); |
} |
/* Relocate a given location using a given value and howto. */ |
bfd_reloc_status_type |
_bfd_relocate_contents (reloc_howto_type *howto, |
bfd *input_bfd, |
bfd_vma relocation, |
bfd_byte *location) |
{ |
int size; |
bfd_vma x = 0; |
bfd_reloc_status_type flag; |
unsigned int rightshift = howto->rightshift; |
unsigned int bitpos = howto->bitpos; |
/* If the size is negative, negate RELOCATION. This isn't very |
general. */ |
if (howto->size < 0) |
relocation = -relocation; |
/* Get the value we are going to relocate. */ |
size = bfd_get_reloc_size (howto); |
switch (size) |
{ |
default: |
case 0: |
abort (); |
case 1: |
x = bfd_get_8 (input_bfd, location); |
break; |
case 2: |
x = bfd_get_16 (input_bfd, location); |
break; |
case 4: |
x = bfd_get_32 (input_bfd, location); |
break; |
case 8: |
#ifdef BFD64 |
x = bfd_get_64 (input_bfd, location); |
#else |
abort (); |
#endif |
break; |
} |
/* Check for overflow. FIXME: We may drop bits during the addition |
which we don't check for. We must either check at every single |
operation, which would be tedious, or we must do the computations |
in a type larger than bfd_vma, which would be inefficient. */ |
flag = bfd_reloc_ok; |
if (howto->complain_on_overflow != complain_overflow_dont) |
{ |
bfd_vma addrmask, fieldmask, signmask, ss; |
bfd_vma a, b, sum; |
/* Get the values to be added together. For signed and unsigned |
relocations, we assume that all values should be truncated to |
the size of an address. For bitfields, all the bits matter. |
See also bfd_check_overflow. */ |
fieldmask = N_ONES (howto->bitsize); |
signmask = ~fieldmask; |
addrmask = (N_ONES (bfd_arch_bits_per_address (input_bfd)) |
| (fieldmask << rightshift)); |
a = (relocation & addrmask) >> rightshift; |
b = (x & howto->src_mask & addrmask) >> bitpos; |
addrmask >>= rightshift; |
switch (howto->complain_on_overflow) |
{ |
case complain_overflow_signed: |
/* If any sign bits are set, all sign bits must be set. |
That is, A must be a valid negative address after |
shifting. */ |
signmask = ~(fieldmask >> 1); |
/* Fall thru */ |
case complain_overflow_bitfield: |
/* Much like the signed check, but for a field one bit |
wider. We allow a bitfield to represent numbers in the |
range -2**n to 2**n-1, where n is the number of bits in the |
field. Note that when bfd_vma is 32 bits, a 32-bit reloc |
can't overflow, which is exactly what we want. */ |
ss = a & signmask; |
if (ss != 0 && ss != (addrmask & signmask)) |
flag = bfd_reloc_overflow; |
/* We only need this next bit of code if the sign bit of B |
is below the sign bit of A. This would only happen if |
SRC_MASK had fewer bits than BITSIZE. Note that if |
SRC_MASK has more bits than BITSIZE, we can get into |
trouble; we would need to verify that B is in range, as |
we do for A above. */ |
ss = ((~howto->src_mask) >> 1) & howto->src_mask; |
ss >>= bitpos; |
/* Set all the bits above the sign bit. */ |
b = (b ^ ss) - ss; |
/* Now we can do the addition. */ |
sum = a + b; |
/* See if the result has the correct sign. Bits above the |
sign bit are junk now; ignore them. If the sum is |
positive, make sure we did not have all negative inputs; |
if the sum is negative, make sure we did not have all |
positive inputs. The test below looks only at the sign |
bits, and it really just |
SIGN (A) == SIGN (B) && SIGN (A) != SIGN (SUM) |
We mask with addrmask here to explicitly allow an address |
wrap-around. The Linux kernel relies on it, and it is |
the only way to write assembler code which can run when |
loaded at a location 0x80000000 away from the location at |
which it is linked. */ |
if (((~(a ^ b)) & (a ^ sum)) & signmask & addrmask) |
flag = bfd_reloc_overflow; |
break; |
case complain_overflow_unsigned: |
/* Checking for an unsigned overflow is relatively easy: |
trim the addresses and add, and trim the result as well. |
Overflow is normally indicated when the result does not |
fit in the field. However, we also need to consider the |
case when, e.g., fieldmask is 0x7fffffff or smaller, an |
input is 0x80000000, and bfd_vma is only 32 bits; then we |
will get sum == 0, but there is an overflow, since the |
inputs did not fit in the field. Instead of doing a |
separate test, we can check for this by or-ing in the |
operands when testing for the sum overflowing its final |
field. */ |
sum = (a + b) & addrmask; |
if ((a | b | sum) & signmask) |
flag = bfd_reloc_overflow; |
break; |
default: |
abort (); |
} |
} |
/* Put RELOCATION in the right bits. */ |
relocation >>= (bfd_vma) rightshift; |
relocation <<= (bfd_vma) bitpos; |
/* Add RELOCATION to the right bits of X. */ |
x = ((x & ~howto->dst_mask) |
| (((x & howto->src_mask) + relocation) & howto->dst_mask)); |
/* Put the relocated value back in the object file. */ |
switch (size) |
{ |
default: |
abort (); |
case 1: |
bfd_put_8 (input_bfd, x, location); |
break; |
case 2: |
bfd_put_16 (input_bfd, x, location); |
break; |
case 4: |
bfd_put_32 (input_bfd, x, location); |
break; |
case 8: |
#ifdef BFD64 |
bfd_put_64 (input_bfd, x, location); |
#else |
abort (); |
#endif |
break; |
} |
return flag; |
} |
/* Clear a given location using a given howto, by applying a fixed relocation |
value and discarding any in-place addend. This is used for fixed-up |
relocations against discarded symbols, to make ignorable debug or unwind |
information more obvious. */ |
void |
_bfd_clear_contents (reloc_howto_type *howto, |
bfd *input_bfd, |
asection *input_section, |
bfd_byte *location) |
{ |
int size; |
bfd_vma x = 0; |
/* Get the value we are going to relocate. */ |
size = bfd_get_reloc_size (howto); |
switch (size) |
{ |
default: |
case 0: |
abort (); |
case 1: |
x = bfd_get_8 (input_bfd, location); |
break; |
case 2: |
x = bfd_get_16 (input_bfd, location); |
break; |
case 4: |
x = bfd_get_32 (input_bfd, location); |
break; |
case 8: |
#ifdef BFD64 |
x = bfd_get_64 (input_bfd, location); |
#else |
abort (); |
#endif |
break; |
} |
/* Zero out the unwanted bits of X. */ |
x &= ~howto->dst_mask; |
/* For a range list, use 1 instead of 0 as placeholder. 0 |
would terminate the list, hiding any later entries. */ |
if (strcmp (bfd_get_section_name (input_bfd, input_section), |
".debug_ranges") == 0 |
&& (howto->dst_mask & 1) != 0) |
x |= 1; |
/* Put the relocated value back in the object file. */ |
switch (size) |
{ |
default: |
case 0: |
abort (); |
case 1: |
bfd_put_8 (input_bfd, x, location); |
break; |
case 2: |
bfd_put_16 (input_bfd, x, location); |
break; |
case 4: |
bfd_put_32 (input_bfd, x, location); |
break; |
case 8: |
#ifdef BFD64 |
bfd_put_64 (input_bfd, x, location); |
#else |
abort (); |
#endif |
break; |
} |
} |
/* |
DOCDD |
INODE |
howto manager, , typedef arelent, Relocations |
SUBSECTION |
The howto manager |
When an application wants to create a relocation, but doesn't |
know what the target machine might call it, it can find out by |
using this bit of code. |
*/ |
/* |
TYPEDEF |
bfd_reloc_code_type |
DESCRIPTION |
The insides of a reloc code. The idea is that, eventually, there |
will be one enumerator for every type of relocation we ever do. |
Pass one of these values to <<bfd_reloc_type_lookup>>, and it'll |
return a howto pointer. |
This does mean that the application must determine the correct |
enumerator value; you can't get a howto pointer from a random set |
of attributes. |
SENUM |
bfd_reloc_code_real |
ENUM |
BFD_RELOC_64 |
ENUMX |
BFD_RELOC_32 |
ENUMX |
BFD_RELOC_26 |
ENUMX |
BFD_RELOC_24 |
ENUMX |
BFD_RELOC_16 |
ENUMX |
BFD_RELOC_14 |
ENUMX |
BFD_RELOC_8 |
ENUMDOC |
Basic absolute relocations of N bits. |
ENUM |
BFD_RELOC_64_PCREL |
ENUMX |
BFD_RELOC_32_PCREL |
ENUMX |
BFD_RELOC_24_PCREL |
ENUMX |
BFD_RELOC_16_PCREL |
ENUMX |
BFD_RELOC_12_PCREL |
ENUMX |
BFD_RELOC_8_PCREL |
ENUMDOC |
PC-relative relocations. Sometimes these are relative to the address |
of the relocation itself; sometimes they are relative to the start of |
the section containing the relocation. It depends on the specific target. |
The 24-bit relocation is used in some Intel 960 configurations. |
ENUM |
BFD_RELOC_32_SECREL |
ENUMDOC |
Section relative relocations. Some targets need this for DWARF2. |
ENUM |
BFD_RELOC_32_GOT_PCREL |
ENUMX |
BFD_RELOC_16_GOT_PCREL |
ENUMX |
BFD_RELOC_8_GOT_PCREL |
ENUMX |
BFD_RELOC_32_GOTOFF |
ENUMX |
BFD_RELOC_16_GOTOFF |
ENUMX |
BFD_RELOC_LO16_GOTOFF |
ENUMX |
BFD_RELOC_HI16_GOTOFF |
ENUMX |
BFD_RELOC_HI16_S_GOTOFF |
ENUMX |
BFD_RELOC_8_GOTOFF |
ENUMX |
BFD_RELOC_64_PLT_PCREL |
ENUMX |
BFD_RELOC_32_PLT_PCREL |
ENUMX |
BFD_RELOC_24_PLT_PCREL |
ENUMX |
BFD_RELOC_16_PLT_PCREL |
ENUMX |
BFD_RELOC_8_PLT_PCREL |
ENUMX |
BFD_RELOC_64_PLTOFF |
ENUMX |
BFD_RELOC_32_PLTOFF |
ENUMX |
BFD_RELOC_16_PLTOFF |
ENUMX |
BFD_RELOC_LO16_PLTOFF |
ENUMX |
BFD_RELOC_HI16_PLTOFF |
ENUMX |
BFD_RELOC_HI16_S_PLTOFF |
ENUMX |
BFD_RELOC_8_PLTOFF |
ENUMDOC |
For ELF. |
ENUM |
BFD_RELOC_SIZE32 |
ENUMX |
BFD_RELOC_SIZE64 |
ENUMDOC |
Size relocations. |
ENUM |
BFD_RELOC_68K_GLOB_DAT |
ENUMX |
BFD_RELOC_68K_JMP_SLOT |
ENUMX |
BFD_RELOC_68K_RELATIVE |
ENUMX |
BFD_RELOC_68K_TLS_GD32 |
ENUMX |
BFD_RELOC_68K_TLS_GD16 |
ENUMX |
BFD_RELOC_68K_TLS_GD8 |
ENUMX |
BFD_RELOC_68K_TLS_LDM32 |
ENUMX |
BFD_RELOC_68K_TLS_LDM16 |
ENUMX |
BFD_RELOC_68K_TLS_LDM8 |
ENUMX |
BFD_RELOC_68K_TLS_LDO32 |
ENUMX |
BFD_RELOC_68K_TLS_LDO16 |
ENUMX |
BFD_RELOC_68K_TLS_LDO8 |
ENUMX |
BFD_RELOC_68K_TLS_IE32 |
ENUMX |
BFD_RELOC_68K_TLS_IE16 |
ENUMX |
BFD_RELOC_68K_TLS_IE8 |
ENUMX |
BFD_RELOC_68K_TLS_LE32 |
ENUMX |
BFD_RELOC_68K_TLS_LE16 |
ENUMX |
BFD_RELOC_68K_TLS_LE8 |
ENUMDOC |
Relocations used by 68K ELF. |
ENUM |
BFD_RELOC_32_BASEREL |
ENUMX |
BFD_RELOC_16_BASEREL |
ENUMX |
BFD_RELOC_LO16_BASEREL |
ENUMX |
BFD_RELOC_HI16_BASEREL |
ENUMX |
BFD_RELOC_HI16_S_BASEREL |
ENUMX |
BFD_RELOC_8_BASEREL |
ENUMX |
BFD_RELOC_RVA |
ENUMDOC |
Linkage-table relative. |
ENUM |
BFD_RELOC_8_FFnn |
ENUMDOC |
Absolute 8-bit relocation, but used to form an address like 0xFFnn. |
ENUM |
BFD_RELOC_32_PCREL_S2 |
ENUMX |
BFD_RELOC_16_PCREL_S2 |
ENUMX |
BFD_RELOC_23_PCREL_S2 |
ENUMDOC |
These PC-relative relocations are stored as word displacements -- |
i.e., byte displacements shifted right two bits. The 30-bit word |
displacement (<<32_PCREL_S2>> -- 32 bits, shifted 2) is used on the |
SPARC. (SPARC tools generally refer to this as <<WDISP30>>.) The |
signed 16-bit displacement is used on the MIPS, and the 23-bit |
displacement is used on the Alpha. |
ENUM |
BFD_RELOC_HI22 |
ENUMX |
BFD_RELOC_LO10 |
ENUMDOC |
High 22 bits and low 10 bits of 32-bit value, placed into lower bits of |
the target word. These are used on the SPARC. |
ENUM |
BFD_RELOC_GPREL16 |
ENUMX |
BFD_RELOC_GPREL32 |
ENUMDOC |
For systems that allocate a Global Pointer register, these are |
displacements off that register. These relocation types are |
handled specially, because the value the register will have is |
decided relatively late. |
ENUM |
BFD_RELOC_I960_CALLJ |
ENUMDOC |
Reloc types used for i960/b.out. |
ENUM |
BFD_RELOC_NONE |
ENUMX |
BFD_RELOC_SPARC_WDISP22 |
ENUMX |
BFD_RELOC_SPARC22 |
ENUMX |
BFD_RELOC_SPARC13 |
ENUMX |
BFD_RELOC_SPARC_GOT10 |
ENUMX |
BFD_RELOC_SPARC_GOT13 |
ENUMX |
BFD_RELOC_SPARC_GOT22 |
ENUMX |
BFD_RELOC_SPARC_PC10 |
ENUMX |
BFD_RELOC_SPARC_PC22 |
ENUMX |
BFD_RELOC_SPARC_WPLT30 |
ENUMX |
BFD_RELOC_SPARC_COPY |
ENUMX |
BFD_RELOC_SPARC_GLOB_DAT |
ENUMX |
BFD_RELOC_SPARC_JMP_SLOT |
ENUMX |
BFD_RELOC_SPARC_RELATIVE |
ENUMX |
BFD_RELOC_SPARC_UA16 |
ENUMX |
BFD_RELOC_SPARC_UA32 |
ENUMX |
BFD_RELOC_SPARC_UA64 |
ENUMX |
BFD_RELOC_SPARC_GOTDATA_HIX22 |
ENUMX |
BFD_RELOC_SPARC_GOTDATA_LOX10 |
ENUMX |
BFD_RELOC_SPARC_GOTDATA_OP_HIX22 |
ENUMX |
BFD_RELOC_SPARC_GOTDATA_OP_LOX10 |
ENUMX |
BFD_RELOC_SPARC_GOTDATA_OP |
ENUMX |
BFD_RELOC_SPARC_JMP_IREL |
ENUMX |
BFD_RELOC_SPARC_IRELATIVE |
ENUMDOC |
SPARC ELF relocations. There is probably some overlap with other |
relocation types already defined. |
ENUM |
BFD_RELOC_SPARC_BASE13 |
ENUMX |
BFD_RELOC_SPARC_BASE22 |
ENUMDOC |
I think these are specific to SPARC a.out (e.g., Sun 4). |
ENUMEQ |
BFD_RELOC_SPARC_64 |
BFD_RELOC_64 |
ENUMX |
BFD_RELOC_SPARC_10 |
ENUMX |
BFD_RELOC_SPARC_11 |
ENUMX |
BFD_RELOC_SPARC_OLO10 |
ENUMX |
BFD_RELOC_SPARC_HH22 |
ENUMX |
BFD_RELOC_SPARC_HM10 |
ENUMX |
BFD_RELOC_SPARC_LM22 |
ENUMX |
BFD_RELOC_SPARC_PC_HH22 |
ENUMX |
BFD_RELOC_SPARC_PC_HM10 |
ENUMX |
BFD_RELOC_SPARC_PC_LM22 |
ENUMX |
BFD_RELOC_SPARC_WDISP16 |
ENUMX |
BFD_RELOC_SPARC_WDISP19 |
ENUMX |
BFD_RELOC_SPARC_7 |
ENUMX |
BFD_RELOC_SPARC_6 |
ENUMX |
BFD_RELOC_SPARC_5 |
ENUMEQX |
BFD_RELOC_SPARC_DISP64 |
BFD_RELOC_64_PCREL |
ENUMX |
BFD_RELOC_SPARC_PLT32 |
ENUMX |
BFD_RELOC_SPARC_PLT64 |
ENUMX |
BFD_RELOC_SPARC_HIX22 |
ENUMX |
BFD_RELOC_SPARC_LOX10 |
ENUMX |
BFD_RELOC_SPARC_H44 |
ENUMX |
BFD_RELOC_SPARC_M44 |
ENUMX |
BFD_RELOC_SPARC_L44 |
ENUMX |
BFD_RELOC_SPARC_REGISTER |
ENUMX |
BFD_RELOC_SPARC_H34 |
ENUMX |
BFD_RELOC_SPARC_SIZE32 |
ENUMX |
BFD_RELOC_SPARC_SIZE64 |
ENUMX |
BFD_RELOC_SPARC_WDISP10 |
ENUMDOC |
SPARC64 relocations |
ENUM |
BFD_RELOC_SPARC_REV32 |
ENUMDOC |
SPARC little endian relocation |
ENUM |
BFD_RELOC_SPARC_TLS_GD_HI22 |
ENUMX |
BFD_RELOC_SPARC_TLS_GD_LO10 |
ENUMX |
BFD_RELOC_SPARC_TLS_GD_ADD |
ENUMX |
BFD_RELOC_SPARC_TLS_GD_CALL |
ENUMX |
BFD_RELOC_SPARC_TLS_LDM_HI22 |
ENUMX |
BFD_RELOC_SPARC_TLS_LDM_LO10 |
ENUMX |
BFD_RELOC_SPARC_TLS_LDM_ADD |
ENUMX |
BFD_RELOC_SPARC_TLS_LDM_CALL |
ENUMX |
BFD_RELOC_SPARC_TLS_LDO_HIX22 |
ENUMX |
BFD_RELOC_SPARC_TLS_LDO_LOX10 |
ENUMX |
BFD_RELOC_SPARC_TLS_LDO_ADD |
ENUMX |
BFD_RELOC_SPARC_TLS_IE_HI22 |
ENUMX |
BFD_RELOC_SPARC_TLS_IE_LO10 |
ENUMX |
BFD_RELOC_SPARC_TLS_IE_LD |
ENUMX |
BFD_RELOC_SPARC_TLS_IE_LDX |
ENUMX |
BFD_RELOC_SPARC_TLS_IE_ADD |
ENUMX |
BFD_RELOC_SPARC_TLS_LE_HIX22 |
ENUMX |
BFD_RELOC_SPARC_TLS_LE_LOX10 |
ENUMX |
BFD_RELOC_SPARC_TLS_DTPMOD32 |
ENUMX |
BFD_RELOC_SPARC_TLS_DTPMOD64 |
ENUMX |
BFD_RELOC_SPARC_TLS_DTPOFF32 |
ENUMX |
BFD_RELOC_SPARC_TLS_DTPOFF64 |
ENUMX |
BFD_RELOC_SPARC_TLS_TPOFF32 |
ENUMX |
BFD_RELOC_SPARC_TLS_TPOFF64 |
ENUMDOC |
SPARC TLS relocations |
ENUM |
BFD_RELOC_SPU_IMM7 |
ENUMX |
BFD_RELOC_SPU_IMM8 |
ENUMX |
BFD_RELOC_SPU_IMM10 |
ENUMX |
BFD_RELOC_SPU_IMM10W |
ENUMX |
BFD_RELOC_SPU_IMM16 |
ENUMX |
BFD_RELOC_SPU_IMM16W |
ENUMX |
BFD_RELOC_SPU_IMM18 |
ENUMX |
BFD_RELOC_SPU_PCREL9a |
ENUMX |
BFD_RELOC_SPU_PCREL9b |
ENUMX |
BFD_RELOC_SPU_PCREL16 |
ENUMX |
BFD_RELOC_SPU_LO16 |
ENUMX |
BFD_RELOC_SPU_HI16 |
ENUMX |
BFD_RELOC_SPU_PPU32 |
ENUMX |
BFD_RELOC_SPU_PPU64 |
ENUMX |
BFD_RELOC_SPU_ADD_PIC |
ENUMDOC |
SPU Relocations. |
ENUM |
BFD_RELOC_ALPHA_GPDISP_HI16 |
ENUMDOC |
Alpha ECOFF and ELF relocations. Some of these treat the symbol or |
"addend" in some special way. |
For GPDISP_HI16 ("gpdisp") relocations, the symbol is ignored when |
writing; when reading, it will be the absolute section symbol. The |
addend is the displacement in bytes of the "lda" instruction from |
the "ldah" instruction (which is at the address of this reloc). |
ENUM |
BFD_RELOC_ALPHA_GPDISP_LO16 |
ENUMDOC |
For GPDISP_LO16 ("ignore") relocations, the symbol is handled as |
with GPDISP_HI16 relocs. The addend is ignored when writing the |
relocations out, and is filled in with the file's GP value on |
reading, for convenience. |
ENUM |
BFD_RELOC_ALPHA_GPDISP |
ENUMDOC |
The ELF GPDISP relocation is exactly the same as the GPDISP_HI16 |
relocation except that there is no accompanying GPDISP_LO16 |
relocation. |
ENUM |
BFD_RELOC_ALPHA_LITERAL |
ENUMX |
BFD_RELOC_ALPHA_ELF_LITERAL |
ENUMX |
BFD_RELOC_ALPHA_LITUSE |
ENUMDOC |
The Alpha LITERAL/LITUSE relocs are produced by a symbol reference; |
the assembler turns it into a LDQ instruction to load the address of |
the symbol, and then fills in a register in the real instruction. |
The LITERAL reloc, at the LDQ instruction, refers to the .lita |
section symbol. The addend is ignored when writing, but is filled |
in with the file's GP value on reading, for convenience, as with the |
GPDISP_LO16 reloc. |
The ELF_LITERAL reloc is somewhere between 16_GOTOFF and GPDISP_LO16. |
It should refer to the symbol to be referenced, as with 16_GOTOFF, |
but it generates output not based on the position within the .got |
section, but relative to the GP value chosen for the file during the |
final link stage. |
The LITUSE reloc, on the instruction using the loaded address, gives |
information to the linker that it might be able to use to optimize |
away some literal section references. The symbol is ignored (read |
as the absolute section symbol), and the "addend" indicates the type |
of instruction using the register: |
1 - "memory" fmt insn |
2 - byte-manipulation (byte offset reg) |
3 - jsr (target of branch) |
ENUM |
BFD_RELOC_ALPHA_HINT |
ENUMDOC |
The HINT relocation indicates a value that should be filled into the |
"hint" field of a jmp/jsr/ret instruction, for possible branch- |
prediction logic which may be provided on some processors. |
ENUM |
BFD_RELOC_ALPHA_LINKAGE |
ENUMDOC |
The LINKAGE relocation outputs a linkage pair in the object file, |
which is filled by the linker. |
ENUM |
BFD_RELOC_ALPHA_CODEADDR |
ENUMDOC |
The CODEADDR relocation outputs a STO_CA in the object file, |
which is filled by the linker. |
ENUM |
BFD_RELOC_ALPHA_GPREL_HI16 |
ENUMX |
BFD_RELOC_ALPHA_GPREL_LO16 |
ENUMDOC |
The GPREL_HI/LO relocations together form a 32-bit offset from the |
GP register. |
ENUM |
BFD_RELOC_ALPHA_BRSGP |
ENUMDOC |
Like BFD_RELOC_23_PCREL_S2, except that the source and target must |
share a common GP, and the target address is adjusted for |
STO_ALPHA_STD_GPLOAD. |
ENUM |
BFD_RELOC_ALPHA_NOP |
ENUMDOC |
The NOP relocation outputs a NOP if the longword displacement |
between two procedure entry points is < 2^21. |
ENUM |
BFD_RELOC_ALPHA_BSR |
ENUMDOC |
The BSR relocation outputs a BSR if the longword displacement |
between two procedure entry points is < 2^21. |
ENUM |
BFD_RELOC_ALPHA_LDA |
ENUMDOC |
The LDA relocation outputs a LDA if the longword displacement |
between two procedure entry points is < 2^16. |
ENUM |
BFD_RELOC_ALPHA_BOH |
ENUMDOC |
The BOH relocation outputs a BSR if the longword displacement |
between two procedure entry points is < 2^21, or else a hint. |
ENUM |
BFD_RELOC_ALPHA_TLSGD |
ENUMX |
BFD_RELOC_ALPHA_TLSLDM |
ENUMX |
BFD_RELOC_ALPHA_DTPMOD64 |
ENUMX |
BFD_RELOC_ALPHA_GOTDTPREL16 |
ENUMX |
BFD_RELOC_ALPHA_DTPREL64 |
ENUMX |
BFD_RELOC_ALPHA_DTPREL_HI16 |
ENUMX |
BFD_RELOC_ALPHA_DTPREL_LO16 |
ENUMX |
BFD_RELOC_ALPHA_DTPREL16 |
ENUMX |
BFD_RELOC_ALPHA_GOTTPREL16 |
ENUMX |
BFD_RELOC_ALPHA_TPREL64 |
ENUMX |
BFD_RELOC_ALPHA_TPREL_HI16 |
ENUMX |
BFD_RELOC_ALPHA_TPREL_LO16 |
ENUMX |
BFD_RELOC_ALPHA_TPREL16 |
ENUMDOC |
Alpha thread-local storage relocations. |
ENUM |
BFD_RELOC_MIPS_JMP |
ENUMX |
BFD_RELOC_MICROMIPS_JMP |
ENUMDOC |
The MIPS jump instruction. |
ENUM |
BFD_RELOC_MIPS16_JMP |
ENUMDOC |
The MIPS16 jump instruction. |
ENUM |
BFD_RELOC_MIPS16_GPREL |
ENUMDOC |
MIPS16 GP relative reloc. |
ENUM |
BFD_RELOC_HI16 |
ENUMDOC |
High 16 bits of 32-bit value; simple reloc. |
ENUM |
BFD_RELOC_HI16_S |
ENUMDOC |
High 16 bits of 32-bit value but the low 16 bits will be sign |
extended and added to form the final result. If the low 16 |
bits form a negative number, we need to add one to the high value |
to compensate for the borrow when the low bits are added. |
ENUM |
BFD_RELOC_LO16 |
ENUMDOC |
Low 16 bits. |
ENUM |
BFD_RELOC_HI16_PCREL |
ENUMDOC |
High 16 bits of 32-bit pc-relative value |
ENUM |
BFD_RELOC_HI16_S_PCREL |
ENUMDOC |
High 16 bits of 32-bit pc-relative value, adjusted |
ENUM |
BFD_RELOC_LO16_PCREL |
ENUMDOC |
Low 16 bits of pc-relative value |
ENUM |
BFD_RELOC_MIPS16_GOT16 |
ENUMX |
BFD_RELOC_MIPS16_CALL16 |
ENUMDOC |
Equivalent of BFD_RELOC_MIPS_*, but with the MIPS16 layout of |
16-bit immediate fields |
ENUM |
BFD_RELOC_MIPS16_HI16 |
ENUMDOC |
MIPS16 high 16 bits of 32-bit value. |
ENUM |
BFD_RELOC_MIPS16_HI16_S |
ENUMDOC |
MIPS16 high 16 bits of 32-bit value but the low 16 bits will be sign |
extended and added to form the final result. If the low 16 |
bits form a negative number, we need to add one to the high value |
to compensate for the borrow when the low bits are added. |
ENUM |
BFD_RELOC_MIPS16_LO16 |
ENUMDOC |
MIPS16 low 16 bits. |
ENUM |
BFD_RELOC_MIPS16_TLS_GD |
ENUMX |
BFD_RELOC_MIPS16_TLS_LDM |
ENUMX |
BFD_RELOC_MIPS16_TLS_DTPREL_HI16 |
ENUMX |
BFD_RELOC_MIPS16_TLS_DTPREL_LO16 |
ENUMX |
BFD_RELOC_MIPS16_TLS_GOTTPREL |
ENUMX |
BFD_RELOC_MIPS16_TLS_TPREL_HI16 |
ENUMX |
BFD_RELOC_MIPS16_TLS_TPREL_LO16 |
ENUMDOC |
MIPS16 TLS relocations |
ENUM |
BFD_RELOC_MIPS_LITERAL |
ENUMX |
BFD_RELOC_MICROMIPS_LITERAL |
ENUMDOC |
Relocation against a MIPS literal section. |
ENUM |
BFD_RELOC_MICROMIPS_7_PCREL_S1 |
ENUMX |
BFD_RELOC_MICROMIPS_10_PCREL_S1 |
ENUMX |
BFD_RELOC_MICROMIPS_16_PCREL_S1 |
ENUMDOC |
microMIPS PC-relative relocations. |
ENUM |
BFD_RELOC_MICROMIPS_GPREL16 |
ENUMX |
BFD_RELOC_MICROMIPS_HI16 |
ENUMX |
BFD_RELOC_MICROMIPS_HI16_S |
ENUMX |
BFD_RELOC_MICROMIPS_LO16 |
ENUMDOC |
microMIPS versions of generic BFD relocs. |
ENUM |
BFD_RELOC_MIPS_GOT16 |
ENUMX |
BFD_RELOC_MICROMIPS_GOT16 |
ENUMX |
BFD_RELOC_MIPS_CALL16 |
ENUMX |
BFD_RELOC_MICROMIPS_CALL16 |
ENUMX |
BFD_RELOC_MIPS_GOT_HI16 |
ENUMX |
BFD_RELOC_MICROMIPS_GOT_HI16 |
ENUMX |
BFD_RELOC_MIPS_GOT_LO16 |
ENUMX |
BFD_RELOC_MICROMIPS_GOT_LO16 |
ENUMX |
BFD_RELOC_MIPS_CALL_HI16 |
ENUMX |
BFD_RELOC_MICROMIPS_CALL_HI16 |
ENUMX |
BFD_RELOC_MIPS_CALL_LO16 |
ENUMX |
BFD_RELOC_MICROMIPS_CALL_LO16 |
ENUMX |
BFD_RELOC_MIPS_SUB |
ENUMX |
BFD_RELOC_MICROMIPS_SUB |
ENUMX |
BFD_RELOC_MIPS_GOT_PAGE |
ENUMX |
BFD_RELOC_MICROMIPS_GOT_PAGE |
ENUMX |
BFD_RELOC_MIPS_GOT_OFST |
ENUMX |
BFD_RELOC_MICROMIPS_GOT_OFST |
ENUMX |
BFD_RELOC_MIPS_GOT_DISP |
ENUMX |
BFD_RELOC_MICROMIPS_GOT_DISP |
ENUMX |
BFD_RELOC_MIPS_SHIFT5 |
ENUMX |
BFD_RELOC_MIPS_SHIFT6 |
ENUMX |
BFD_RELOC_MIPS_INSERT_A |
ENUMX |
BFD_RELOC_MIPS_INSERT_B |
ENUMX |
BFD_RELOC_MIPS_DELETE |
ENUMX |
BFD_RELOC_MIPS_HIGHEST |
ENUMX |
BFD_RELOC_MICROMIPS_HIGHEST |
ENUMX |
BFD_RELOC_MIPS_HIGHER |
ENUMX |
BFD_RELOC_MICROMIPS_HIGHER |
ENUMX |
BFD_RELOC_MIPS_SCN_DISP |
ENUMX |
BFD_RELOC_MICROMIPS_SCN_DISP |
ENUMX |
BFD_RELOC_MIPS_REL16 |
ENUMX |
BFD_RELOC_MIPS_RELGOT |
ENUMX |
BFD_RELOC_MIPS_JALR |
ENUMX |
BFD_RELOC_MICROMIPS_JALR |
ENUMX |
BFD_RELOC_MIPS_TLS_DTPMOD32 |
ENUMX |
BFD_RELOC_MIPS_TLS_DTPREL32 |
ENUMX |
BFD_RELOC_MIPS_TLS_DTPMOD64 |
ENUMX |
BFD_RELOC_MIPS_TLS_DTPREL64 |
ENUMX |
BFD_RELOC_MIPS_TLS_GD |
ENUMX |
BFD_RELOC_MICROMIPS_TLS_GD |
ENUMX |
BFD_RELOC_MIPS_TLS_LDM |
ENUMX |
BFD_RELOC_MICROMIPS_TLS_LDM |
ENUMX |
BFD_RELOC_MIPS_TLS_DTPREL_HI16 |
ENUMX |
BFD_RELOC_MICROMIPS_TLS_DTPREL_HI16 |
ENUMX |
BFD_RELOC_MIPS_TLS_DTPREL_LO16 |
ENUMX |
BFD_RELOC_MICROMIPS_TLS_DTPREL_LO16 |
ENUMX |
BFD_RELOC_MIPS_TLS_GOTTPREL |
ENUMX |
BFD_RELOC_MICROMIPS_TLS_GOTTPREL |
ENUMX |
BFD_RELOC_MIPS_TLS_TPREL32 |
ENUMX |
BFD_RELOC_MIPS_TLS_TPREL64 |
ENUMX |
BFD_RELOC_MIPS_TLS_TPREL_HI16 |
ENUMX |
BFD_RELOC_MICROMIPS_TLS_TPREL_HI16 |
ENUMX |
BFD_RELOC_MIPS_TLS_TPREL_LO16 |
ENUMX |
BFD_RELOC_MICROMIPS_TLS_TPREL_LO16 |
ENUMX |
BFD_RELOC_MIPS_EH |
ENUMDOC |
MIPS ELF relocations. |
COMMENT |
ENUM |
BFD_RELOC_MIPS_COPY |
ENUMX |
BFD_RELOC_MIPS_JUMP_SLOT |
ENUMDOC |
MIPS ELF relocations (VxWorks and PLT extensions). |
COMMENT |
ENUM |
BFD_RELOC_MOXIE_10_PCREL |
ENUMDOC |
Moxie ELF relocations. |
COMMENT |
ENUM |
BFD_RELOC_FRV_LABEL16 |
ENUMX |
BFD_RELOC_FRV_LABEL24 |
ENUMX |
BFD_RELOC_FRV_LO16 |
ENUMX |
BFD_RELOC_FRV_HI16 |
ENUMX |
BFD_RELOC_FRV_GPREL12 |
ENUMX |
BFD_RELOC_FRV_GPRELU12 |
ENUMX |
BFD_RELOC_FRV_GPREL32 |
ENUMX |
BFD_RELOC_FRV_GPRELHI |
ENUMX |
BFD_RELOC_FRV_GPRELLO |
ENUMX |
BFD_RELOC_FRV_GOT12 |
ENUMX |
BFD_RELOC_FRV_GOTHI |
ENUMX |
BFD_RELOC_FRV_GOTLO |
ENUMX |
BFD_RELOC_FRV_FUNCDESC |
ENUMX |
BFD_RELOC_FRV_FUNCDESC_GOT12 |
ENUMX |
BFD_RELOC_FRV_FUNCDESC_GOTHI |
ENUMX |
BFD_RELOC_FRV_FUNCDESC_GOTLO |
ENUMX |
BFD_RELOC_FRV_FUNCDESC_VALUE |
ENUMX |
BFD_RELOC_FRV_FUNCDESC_GOTOFF12 |
ENUMX |
BFD_RELOC_FRV_FUNCDESC_GOTOFFHI |
ENUMX |
BFD_RELOC_FRV_FUNCDESC_GOTOFFLO |
ENUMX |
BFD_RELOC_FRV_GOTOFF12 |
ENUMX |
BFD_RELOC_FRV_GOTOFFHI |
ENUMX |
BFD_RELOC_FRV_GOTOFFLO |
ENUMX |
BFD_RELOC_FRV_GETTLSOFF |
ENUMX |
BFD_RELOC_FRV_TLSDESC_VALUE |
ENUMX |
BFD_RELOC_FRV_GOTTLSDESC12 |
ENUMX |
BFD_RELOC_FRV_GOTTLSDESCHI |
ENUMX |
BFD_RELOC_FRV_GOTTLSDESCLO |
ENUMX |
BFD_RELOC_FRV_TLSMOFF12 |
ENUMX |
BFD_RELOC_FRV_TLSMOFFHI |
ENUMX |
BFD_RELOC_FRV_TLSMOFFLO |
ENUMX |
BFD_RELOC_FRV_GOTTLSOFF12 |
ENUMX |
BFD_RELOC_FRV_GOTTLSOFFHI |
ENUMX |
BFD_RELOC_FRV_GOTTLSOFFLO |
ENUMX |
BFD_RELOC_FRV_TLSOFF |
ENUMX |
BFD_RELOC_FRV_TLSDESC_RELAX |
ENUMX |
BFD_RELOC_FRV_GETTLSOFF_RELAX |
ENUMX |
BFD_RELOC_FRV_TLSOFF_RELAX |
ENUMX |
BFD_RELOC_FRV_TLSMOFF |
ENUMDOC |
Fujitsu Frv Relocations. |
COMMENT |
ENUM |
BFD_RELOC_MN10300_GOTOFF24 |
ENUMDOC |
This is a 24bit GOT-relative reloc for the mn10300. |
ENUM |
BFD_RELOC_MN10300_GOT32 |
ENUMDOC |
This is a 32bit GOT-relative reloc for the mn10300, offset by two bytes |
in the instruction. |
ENUM |
BFD_RELOC_MN10300_GOT24 |
ENUMDOC |
This is a 24bit GOT-relative reloc for the mn10300, offset by two bytes |
in the instruction. |
ENUM |
BFD_RELOC_MN10300_GOT16 |
ENUMDOC |
This is a 16bit GOT-relative reloc for the mn10300, offset by two bytes |
in the instruction. |
ENUM |
BFD_RELOC_MN10300_COPY |
ENUMDOC |
Copy symbol at runtime. |
ENUM |
BFD_RELOC_MN10300_GLOB_DAT |
ENUMDOC |
Create GOT entry. |
ENUM |
BFD_RELOC_MN10300_JMP_SLOT |
ENUMDOC |
Create PLT entry. |
ENUM |
BFD_RELOC_MN10300_RELATIVE |
ENUMDOC |
Adjust by program base. |
ENUM |
BFD_RELOC_MN10300_SYM_DIFF |
ENUMDOC |
Together with another reloc targeted at the same location, |
allows for a value that is the difference of two symbols |
in the same section. |
ENUM |
BFD_RELOC_MN10300_ALIGN |
ENUMDOC |
The addend of this reloc is an alignment power that must |
be honoured at the offset's location, regardless of linker |
relaxation. |
ENUM |
BFD_RELOC_MN10300_TLS_GD |
ENUMX |
BFD_RELOC_MN10300_TLS_LD |
ENUMX |
BFD_RELOC_MN10300_TLS_LDO |
ENUMX |
BFD_RELOC_MN10300_TLS_GOTIE |
ENUMX |
BFD_RELOC_MN10300_TLS_IE |
ENUMX |
BFD_RELOC_MN10300_TLS_LE |
ENUMX |
BFD_RELOC_MN10300_TLS_DTPMOD |
ENUMX |
BFD_RELOC_MN10300_TLS_DTPOFF |
ENUMX |
BFD_RELOC_MN10300_TLS_TPOFF |
ENUMDOC |
Various TLS-related relocations. |
ENUM |
BFD_RELOC_MN10300_32_PCREL |
ENUMDOC |
This is a 32bit pcrel reloc for the mn10300, offset by two bytes in the |
instruction. |
ENUM |
BFD_RELOC_MN10300_16_PCREL |
ENUMDOC |
This is a 16bit pcrel reloc for the mn10300, offset by two bytes in the |
instruction. |
COMMENT |
ENUM |
BFD_RELOC_386_GOT32 |
ENUMX |
BFD_RELOC_386_PLT32 |
ENUMX |
BFD_RELOC_386_COPY |
ENUMX |
BFD_RELOC_386_GLOB_DAT |
ENUMX |
BFD_RELOC_386_JUMP_SLOT |
ENUMX |
BFD_RELOC_386_RELATIVE |
ENUMX |
BFD_RELOC_386_GOTOFF |
ENUMX |
BFD_RELOC_386_GOTPC |
ENUMX |
BFD_RELOC_386_TLS_TPOFF |
ENUMX |
BFD_RELOC_386_TLS_IE |
ENUMX |
BFD_RELOC_386_TLS_GOTIE |
ENUMX |
BFD_RELOC_386_TLS_LE |
ENUMX |
BFD_RELOC_386_TLS_GD |
ENUMX |
BFD_RELOC_386_TLS_LDM |
ENUMX |
BFD_RELOC_386_TLS_LDO_32 |
ENUMX |
BFD_RELOC_386_TLS_IE_32 |
ENUMX |
BFD_RELOC_386_TLS_LE_32 |
ENUMX |
BFD_RELOC_386_TLS_DTPMOD32 |
ENUMX |
BFD_RELOC_386_TLS_DTPOFF32 |
ENUMX |
BFD_RELOC_386_TLS_TPOFF32 |
ENUMX |
BFD_RELOC_386_TLS_GOTDESC |
ENUMX |
BFD_RELOC_386_TLS_DESC_CALL |
ENUMX |
BFD_RELOC_386_TLS_DESC |
ENUMX |
BFD_RELOC_386_IRELATIVE |
ENUMDOC |
i386/elf relocations |
ENUM |
BFD_RELOC_X86_64_GOT32 |
ENUMX |
BFD_RELOC_X86_64_PLT32 |
ENUMX |
BFD_RELOC_X86_64_COPY |
ENUMX |
BFD_RELOC_X86_64_GLOB_DAT |
ENUMX |
BFD_RELOC_X86_64_JUMP_SLOT |
ENUMX |
BFD_RELOC_X86_64_RELATIVE |
ENUMX |
BFD_RELOC_X86_64_GOTPCREL |
ENUMX |
BFD_RELOC_X86_64_32S |
ENUMX |
BFD_RELOC_X86_64_DTPMOD64 |
ENUMX |
BFD_RELOC_X86_64_DTPOFF64 |
ENUMX |
BFD_RELOC_X86_64_TPOFF64 |
ENUMX |
BFD_RELOC_X86_64_TLSGD |
ENUMX |
BFD_RELOC_X86_64_TLSLD |
ENUMX |
BFD_RELOC_X86_64_DTPOFF32 |
ENUMX |
BFD_RELOC_X86_64_GOTTPOFF |
ENUMX |
BFD_RELOC_X86_64_TPOFF32 |
ENUMX |
BFD_RELOC_X86_64_GOTOFF64 |
ENUMX |
BFD_RELOC_X86_64_GOTPC32 |
ENUMX |
BFD_RELOC_X86_64_GOT64 |
ENUMX |
BFD_RELOC_X86_64_GOTPCREL64 |
ENUMX |
BFD_RELOC_X86_64_GOTPC64 |
ENUMX |
BFD_RELOC_X86_64_GOTPLT64 |
ENUMX |
BFD_RELOC_X86_64_PLTOFF64 |
ENUMX |
BFD_RELOC_X86_64_GOTPC32_TLSDESC |
ENUMX |
BFD_RELOC_X86_64_TLSDESC_CALL |
ENUMX |
BFD_RELOC_X86_64_TLSDESC |
ENUMX |
BFD_RELOC_X86_64_IRELATIVE |
ENUMX |
BFD_RELOC_X86_64_PC32_BND |
ENUMX |
BFD_RELOC_X86_64_PLT32_BND |
ENUMDOC |
x86-64/elf relocations |
ENUM |
BFD_RELOC_NS32K_IMM_8 |
ENUMX |
BFD_RELOC_NS32K_IMM_16 |
ENUMX |
BFD_RELOC_NS32K_IMM_32 |
ENUMX |
BFD_RELOC_NS32K_IMM_8_PCREL |
ENUMX |
BFD_RELOC_NS32K_IMM_16_PCREL |
ENUMX |
BFD_RELOC_NS32K_IMM_32_PCREL |
ENUMX |
BFD_RELOC_NS32K_DISP_8 |
ENUMX |
BFD_RELOC_NS32K_DISP_16 |
ENUMX |
BFD_RELOC_NS32K_DISP_32 |
ENUMX |
BFD_RELOC_NS32K_DISP_8_PCREL |
ENUMX |
BFD_RELOC_NS32K_DISP_16_PCREL |
ENUMX |
BFD_RELOC_NS32K_DISP_32_PCREL |
ENUMDOC |
ns32k relocations |
ENUM |
BFD_RELOC_PDP11_DISP_8_PCREL |
ENUMX |
BFD_RELOC_PDP11_DISP_6_PCREL |
ENUMDOC |
PDP11 relocations |
ENUM |
BFD_RELOC_PJ_CODE_HI16 |
ENUMX |
BFD_RELOC_PJ_CODE_LO16 |
ENUMX |
BFD_RELOC_PJ_CODE_DIR16 |
ENUMX |
BFD_RELOC_PJ_CODE_DIR32 |
ENUMX |
BFD_RELOC_PJ_CODE_REL16 |
ENUMX |
BFD_RELOC_PJ_CODE_REL32 |
ENUMDOC |
Picojava relocs. Not all of these appear in object files. |
ENUM |
BFD_RELOC_PPC_B26 |
ENUMX |
BFD_RELOC_PPC_BA26 |
ENUMX |
BFD_RELOC_PPC_TOC16 |
ENUMX |
BFD_RELOC_PPC_B16 |
ENUMX |
BFD_RELOC_PPC_B16_BRTAKEN |
ENUMX |
BFD_RELOC_PPC_B16_BRNTAKEN |
ENUMX |
BFD_RELOC_PPC_BA16 |
ENUMX |
BFD_RELOC_PPC_BA16_BRTAKEN |
ENUMX |
BFD_RELOC_PPC_BA16_BRNTAKEN |
ENUMX |
BFD_RELOC_PPC_COPY |
ENUMX |
BFD_RELOC_PPC_GLOB_DAT |
ENUMX |
BFD_RELOC_PPC_JMP_SLOT |
ENUMX |
BFD_RELOC_PPC_RELATIVE |
ENUMX |
BFD_RELOC_PPC_LOCAL24PC |
ENUMX |
BFD_RELOC_PPC_EMB_NADDR32 |
ENUMX |
BFD_RELOC_PPC_EMB_NADDR16 |
ENUMX |
BFD_RELOC_PPC_EMB_NADDR16_LO |
ENUMX |
BFD_RELOC_PPC_EMB_NADDR16_HI |
ENUMX |
BFD_RELOC_PPC_EMB_NADDR16_HA |
ENUMX |
BFD_RELOC_PPC_EMB_SDAI16 |
ENUMX |
BFD_RELOC_PPC_EMB_SDA2I16 |
ENUMX |
BFD_RELOC_PPC_EMB_SDA2REL |
ENUMX |
BFD_RELOC_PPC_EMB_SDA21 |
ENUMX |
BFD_RELOC_PPC_EMB_MRKREF |
ENUMX |
BFD_RELOC_PPC_EMB_RELSEC16 |
ENUMX |
BFD_RELOC_PPC_EMB_RELST_LO |
ENUMX |
BFD_RELOC_PPC_EMB_RELST_HI |
ENUMX |
BFD_RELOC_PPC_EMB_RELST_HA |
ENUMX |
BFD_RELOC_PPC_EMB_BIT_FLD |
ENUMX |
BFD_RELOC_PPC_EMB_RELSDA |
ENUMX |
BFD_RELOC_PPC_VLE_REL8 |
ENUMX |
BFD_RELOC_PPC_VLE_REL15 |
ENUMX |
BFD_RELOC_PPC_VLE_REL24 |
ENUMX |
BFD_RELOC_PPC_VLE_LO16A |
ENUMX |
BFD_RELOC_PPC_VLE_LO16D |
ENUMX |
BFD_RELOC_PPC_VLE_HI16A |
ENUMX |
BFD_RELOC_PPC_VLE_HI16D |
ENUMX |
BFD_RELOC_PPC_VLE_HA16A |
ENUMX |
BFD_RELOC_PPC_VLE_HA16D |
ENUMX |
BFD_RELOC_PPC_VLE_SDA21 |
ENUMX |
BFD_RELOC_PPC_VLE_SDA21_LO |
ENUMX |
BFD_RELOC_PPC_VLE_SDAREL_LO16A |
ENUMX |
BFD_RELOC_PPC_VLE_SDAREL_LO16D |
ENUMX |
BFD_RELOC_PPC_VLE_SDAREL_HI16A |
ENUMX |
BFD_RELOC_PPC_VLE_SDAREL_HI16D |
ENUMX |
BFD_RELOC_PPC_VLE_SDAREL_HA16A |
ENUMX |
BFD_RELOC_PPC_VLE_SDAREL_HA16D |
ENUMX |
BFD_RELOC_PPC64_HIGHER |
ENUMX |
BFD_RELOC_PPC64_HIGHER_S |
ENUMX |
BFD_RELOC_PPC64_HIGHEST |
ENUMX |
BFD_RELOC_PPC64_HIGHEST_S |
ENUMX |
BFD_RELOC_PPC64_TOC16_LO |
ENUMX |
BFD_RELOC_PPC64_TOC16_HI |
ENUMX |
BFD_RELOC_PPC64_TOC16_HA |
ENUMX |
BFD_RELOC_PPC64_TOC |
ENUMX |
BFD_RELOC_PPC64_PLTGOT16 |
ENUMX |
BFD_RELOC_PPC64_PLTGOT16_LO |
ENUMX |
BFD_RELOC_PPC64_PLTGOT16_HI |
ENUMX |
BFD_RELOC_PPC64_PLTGOT16_HA |
ENUMX |
BFD_RELOC_PPC64_ADDR16_DS |
ENUMX |
BFD_RELOC_PPC64_ADDR16_LO_DS |
ENUMX |
BFD_RELOC_PPC64_GOT16_DS |
ENUMX |
BFD_RELOC_PPC64_GOT16_LO_DS |
ENUMX |
BFD_RELOC_PPC64_PLT16_LO_DS |
ENUMX |
BFD_RELOC_PPC64_SECTOFF_DS |
ENUMX |
BFD_RELOC_PPC64_SECTOFF_LO_DS |
ENUMX |
BFD_RELOC_PPC64_TOC16_DS |
ENUMX |
BFD_RELOC_PPC64_TOC16_LO_DS |
ENUMX |
BFD_RELOC_PPC64_PLTGOT16_DS |
ENUMX |
BFD_RELOC_PPC64_PLTGOT16_LO_DS |
ENUMX |
BFD_RELOC_PPC64_ADDR16_HIGH |
ENUMX |
BFD_RELOC_PPC64_ADDR16_HIGHA |
ENUMDOC |
Power(rs6000) and PowerPC relocations. |
ENUM |
BFD_RELOC_PPC_TLS |
ENUMX |
BFD_RELOC_PPC_TLSGD |
ENUMX |
BFD_RELOC_PPC_TLSLD |
ENUMX |
BFD_RELOC_PPC_DTPMOD |
ENUMX |
BFD_RELOC_PPC_TPREL16 |
ENUMX |
BFD_RELOC_PPC_TPREL16_LO |
ENUMX |
BFD_RELOC_PPC_TPREL16_HI |
ENUMX |
BFD_RELOC_PPC_TPREL16_HA |
ENUMX |
BFD_RELOC_PPC_TPREL |
ENUMX |
BFD_RELOC_PPC_DTPREL16 |
ENUMX |
BFD_RELOC_PPC_DTPREL16_LO |
ENUMX |
BFD_RELOC_PPC_DTPREL16_HI |
ENUMX |
BFD_RELOC_PPC_DTPREL16_HA |
ENUMX |
BFD_RELOC_PPC_DTPREL |
ENUMX |
BFD_RELOC_PPC_GOT_TLSGD16 |
ENUMX |
BFD_RELOC_PPC_GOT_TLSGD16_LO |
ENUMX |
BFD_RELOC_PPC_GOT_TLSGD16_HI |
ENUMX |
BFD_RELOC_PPC_GOT_TLSGD16_HA |
ENUMX |
BFD_RELOC_PPC_GOT_TLSLD16 |
ENUMX |
BFD_RELOC_PPC_GOT_TLSLD16_LO |
ENUMX |
BFD_RELOC_PPC_GOT_TLSLD16_HI |
ENUMX |
BFD_RELOC_PPC_GOT_TLSLD16_HA |
ENUMX |
BFD_RELOC_PPC_GOT_TPREL16 |
ENUMX |
BFD_RELOC_PPC_GOT_TPREL16_LO |
ENUMX |
BFD_RELOC_PPC_GOT_TPREL16_HI |
ENUMX |
BFD_RELOC_PPC_GOT_TPREL16_HA |
ENUMX |
BFD_RELOC_PPC_GOT_DTPREL16 |
ENUMX |
BFD_RELOC_PPC_GOT_DTPREL16_LO |
ENUMX |
BFD_RELOC_PPC_GOT_DTPREL16_HI |
ENUMX |
BFD_RELOC_PPC_GOT_DTPREL16_HA |
ENUMX |
BFD_RELOC_PPC64_TPREL16_DS |
ENUMX |
BFD_RELOC_PPC64_TPREL16_LO_DS |
ENUMX |
BFD_RELOC_PPC64_TPREL16_HIGHER |
ENUMX |
BFD_RELOC_PPC64_TPREL16_HIGHERA |
ENUMX |
BFD_RELOC_PPC64_TPREL16_HIGHEST |
ENUMX |
BFD_RELOC_PPC64_TPREL16_HIGHESTA |
ENUMX |
BFD_RELOC_PPC64_DTPREL16_DS |
ENUMX |
BFD_RELOC_PPC64_DTPREL16_LO_DS |
ENUMX |
BFD_RELOC_PPC64_DTPREL16_HIGHER |
ENUMX |
BFD_RELOC_PPC64_DTPREL16_HIGHERA |
ENUMX |
BFD_RELOC_PPC64_DTPREL16_HIGHEST |
ENUMX |
BFD_RELOC_PPC64_DTPREL16_HIGHESTA |
ENUMX |
BFD_RELOC_PPC64_TPREL16_HIGH |
ENUMX |
BFD_RELOC_PPC64_TPREL16_HIGHA |
ENUMX |
BFD_RELOC_PPC64_DTPREL16_HIGH |
ENUMX |
BFD_RELOC_PPC64_DTPREL16_HIGHA |
ENUMDOC |
PowerPC and PowerPC64 thread-local storage relocations. |
ENUM |
BFD_RELOC_I370_D12 |
ENUMDOC |
IBM 370/390 relocations |
ENUM |
BFD_RELOC_CTOR |
ENUMDOC |
The type of reloc used to build a constructor table - at the moment |
probably a 32 bit wide absolute relocation, but the target can choose. |
It generally does map to one of the other relocation types. |
ENUM |
BFD_RELOC_ARM_PCREL_BRANCH |
ENUMDOC |
ARM 26 bit pc-relative branch. The lowest two bits must be zero and are |
not stored in the instruction. |
ENUM |
BFD_RELOC_ARM_PCREL_BLX |
ENUMDOC |
ARM 26 bit pc-relative branch. The lowest bit must be zero and is |
not stored in the instruction. The 2nd lowest bit comes from a 1 bit |
field in the instruction. |
ENUM |
BFD_RELOC_THUMB_PCREL_BLX |
ENUMDOC |
Thumb 22 bit pc-relative branch. The lowest bit must be zero and is |
not stored in the instruction. The 2nd lowest bit comes from a 1 bit |
field in the instruction. |
ENUM |
BFD_RELOC_ARM_PCREL_CALL |
ENUMDOC |
ARM 26-bit pc-relative branch for an unconditional BL or BLX instruction. |
ENUM |
BFD_RELOC_ARM_PCREL_JUMP |
ENUMDOC |
ARM 26-bit pc-relative branch for B or conditional BL instruction. |
ENUM |
BFD_RELOC_THUMB_PCREL_BRANCH7 |
ENUMX |
BFD_RELOC_THUMB_PCREL_BRANCH9 |
ENUMX |
BFD_RELOC_THUMB_PCREL_BRANCH12 |
ENUMX |
BFD_RELOC_THUMB_PCREL_BRANCH20 |
ENUMX |
BFD_RELOC_THUMB_PCREL_BRANCH23 |
ENUMX |
BFD_RELOC_THUMB_PCREL_BRANCH25 |
ENUMDOC |
Thumb 7-, 9-, 12-, 20-, 23-, and 25-bit pc-relative branches. |
The lowest bit must be zero and is not stored in the instruction. |
Note that the corresponding ELF R_ARM_THM_JUMPnn constant has an |
"nn" one smaller in all cases. Note further that BRANCH23 |
corresponds to R_ARM_THM_CALL. |
ENUM |
BFD_RELOC_ARM_OFFSET_IMM |
ENUMDOC |
12-bit immediate offset, used in ARM-format ldr and str instructions. |
ENUM |
BFD_RELOC_ARM_THUMB_OFFSET |
ENUMDOC |
5-bit immediate offset, used in Thumb-format ldr and str instructions. |
ENUM |
BFD_RELOC_ARM_TARGET1 |
ENUMDOC |
Pc-relative or absolute relocation depending on target. Used for |
entries in .init_array sections. |
ENUM |
BFD_RELOC_ARM_ROSEGREL32 |
ENUMDOC |
Read-only segment base relative address. |
ENUM |
BFD_RELOC_ARM_SBREL32 |
ENUMDOC |
Data segment base relative address. |
ENUM |
BFD_RELOC_ARM_TARGET2 |
ENUMDOC |
This reloc is used for references to RTTI data from exception handling |
tables. The actual definition depends on the target. It may be a |
pc-relative or some form of GOT-indirect relocation. |
ENUM |
BFD_RELOC_ARM_PREL31 |
ENUMDOC |
31-bit PC relative address. |
ENUM |
BFD_RELOC_ARM_MOVW |
ENUMX |
BFD_RELOC_ARM_MOVT |
ENUMX |
BFD_RELOC_ARM_MOVW_PCREL |
ENUMX |
BFD_RELOC_ARM_MOVT_PCREL |
ENUMX |
BFD_RELOC_ARM_THUMB_MOVW |
ENUMX |
BFD_RELOC_ARM_THUMB_MOVT |
ENUMX |
BFD_RELOC_ARM_THUMB_MOVW_PCREL |
ENUMX |
BFD_RELOC_ARM_THUMB_MOVT_PCREL |
ENUMDOC |
Low and High halfword relocations for MOVW and MOVT instructions. |
ENUM |
BFD_RELOC_ARM_JUMP_SLOT |
ENUMX |
BFD_RELOC_ARM_GLOB_DAT |
ENUMX |
BFD_RELOC_ARM_GOT32 |
ENUMX |
BFD_RELOC_ARM_PLT32 |
ENUMX |
BFD_RELOC_ARM_RELATIVE |
ENUMX |
BFD_RELOC_ARM_GOTOFF |
ENUMX |
BFD_RELOC_ARM_GOTPC |
ENUMX |
BFD_RELOC_ARM_GOT_PREL |
ENUMDOC |
Relocations for setting up GOTs and PLTs for shared libraries. |
ENUM |
BFD_RELOC_ARM_TLS_GD32 |
ENUMX |
BFD_RELOC_ARM_TLS_LDO32 |
ENUMX |
BFD_RELOC_ARM_TLS_LDM32 |
ENUMX |
BFD_RELOC_ARM_TLS_DTPOFF32 |
ENUMX |
BFD_RELOC_ARM_TLS_DTPMOD32 |
ENUMX |
BFD_RELOC_ARM_TLS_TPOFF32 |
ENUMX |
BFD_RELOC_ARM_TLS_IE32 |
ENUMX |
BFD_RELOC_ARM_TLS_LE32 |
ENUMX |
BFD_RELOC_ARM_TLS_GOTDESC |
ENUMX |
BFD_RELOC_ARM_TLS_CALL |
ENUMX |
BFD_RELOC_ARM_THM_TLS_CALL |
ENUMX |
BFD_RELOC_ARM_TLS_DESCSEQ |
ENUMX |
BFD_RELOC_ARM_THM_TLS_DESCSEQ |
ENUMX |
BFD_RELOC_ARM_TLS_DESC |
ENUMDOC |
ARM thread-local storage relocations. |
ENUM |
BFD_RELOC_ARM_ALU_PC_G0_NC |
ENUMX |
BFD_RELOC_ARM_ALU_PC_G0 |
ENUMX |
BFD_RELOC_ARM_ALU_PC_G1_NC |
ENUMX |
BFD_RELOC_ARM_ALU_PC_G1 |
ENUMX |
BFD_RELOC_ARM_ALU_PC_G2 |
ENUMX |
BFD_RELOC_ARM_LDR_PC_G0 |
ENUMX |
BFD_RELOC_ARM_LDR_PC_G1 |
ENUMX |
BFD_RELOC_ARM_LDR_PC_G2 |
ENUMX |
BFD_RELOC_ARM_LDRS_PC_G0 |
ENUMX |
BFD_RELOC_ARM_LDRS_PC_G1 |
ENUMX |
BFD_RELOC_ARM_LDRS_PC_G2 |
ENUMX |
BFD_RELOC_ARM_LDC_PC_G0 |
ENUMX |
BFD_RELOC_ARM_LDC_PC_G1 |
ENUMX |
BFD_RELOC_ARM_LDC_PC_G2 |
ENUMX |
BFD_RELOC_ARM_ALU_SB_G0_NC |
ENUMX |
BFD_RELOC_ARM_ALU_SB_G0 |
ENUMX |
BFD_RELOC_ARM_ALU_SB_G1_NC |
ENUMX |
BFD_RELOC_ARM_ALU_SB_G1 |
ENUMX |
BFD_RELOC_ARM_ALU_SB_G2 |
ENUMX |
BFD_RELOC_ARM_LDR_SB_G0 |
ENUMX |
BFD_RELOC_ARM_LDR_SB_G1 |
ENUMX |
BFD_RELOC_ARM_LDR_SB_G2 |
ENUMX |
BFD_RELOC_ARM_LDRS_SB_G0 |
ENUMX |
BFD_RELOC_ARM_LDRS_SB_G1 |
ENUMX |
BFD_RELOC_ARM_LDRS_SB_G2 |
ENUMX |
BFD_RELOC_ARM_LDC_SB_G0 |
ENUMX |
BFD_RELOC_ARM_LDC_SB_G1 |
ENUMX |
BFD_RELOC_ARM_LDC_SB_G2 |
ENUMDOC |
ARM group relocations. |
ENUM |
BFD_RELOC_ARM_V4BX |
ENUMDOC |
Annotation of BX instructions. |
ENUM |
BFD_RELOC_ARM_IRELATIVE |
ENUMDOC |
ARM support for STT_GNU_IFUNC. |
ENUM |
BFD_RELOC_ARM_IMMEDIATE |
ENUMX |
BFD_RELOC_ARM_ADRL_IMMEDIATE |
ENUMX |
BFD_RELOC_ARM_T32_IMMEDIATE |
ENUMX |
BFD_RELOC_ARM_T32_ADD_IMM |
ENUMX |
BFD_RELOC_ARM_T32_IMM12 |
ENUMX |
BFD_RELOC_ARM_T32_ADD_PC12 |
ENUMX |
BFD_RELOC_ARM_SHIFT_IMM |
ENUMX |
BFD_RELOC_ARM_SMC |
ENUMX |
BFD_RELOC_ARM_HVC |
ENUMX |
BFD_RELOC_ARM_SWI |
ENUMX |
BFD_RELOC_ARM_MULTI |
ENUMX |
BFD_RELOC_ARM_CP_OFF_IMM |
ENUMX |
BFD_RELOC_ARM_CP_OFF_IMM_S2 |
ENUMX |
BFD_RELOC_ARM_T32_CP_OFF_IMM |
ENUMX |
BFD_RELOC_ARM_T32_CP_OFF_IMM_S2 |
ENUMX |
BFD_RELOC_ARM_ADR_IMM |
ENUMX |
BFD_RELOC_ARM_LDR_IMM |
ENUMX |
BFD_RELOC_ARM_LITERAL |
ENUMX |
BFD_RELOC_ARM_IN_POOL |
ENUMX |
BFD_RELOC_ARM_OFFSET_IMM8 |
ENUMX |
BFD_RELOC_ARM_T32_OFFSET_U8 |
ENUMX |
BFD_RELOC_ARM_T32_OFFSET_IMM |
ENUMX |
BFD_RELOC_ARM_HWLITERAL |
ENUMX |
BFD_RELOC_ARM_THUMB_ADD |
ENUMX |
BFD_RELOC_ARM_THUMB_IMM |
ENUMX |
BFD_RELOC_ARM_THUMB_SHIFT |
ENUMDOC |
These relocs are only used within the ARM assembler. They are not |
(at present) written to any object files. |
ENUM |
BFD_RELOC_SH_PCDISP8BY2 |
ENUMX |
BFD_RELOC_SH_PCDISP12BY2 |
ENUMX |
BFD_RELOC_SH_IMM3 |
ENUMX |
BFD_RELOC_SH_IMM3U |
ENUMX |
BFD_RELOC_SH_DISP12 |
ENUMX |
BFD_RELOC_SH_DISP12BY2 |
ENUMX |
BFD_RELOC_SH_DISP12BY4 |
ENUMX |
BFD_RELOC_SH_DISP12BY8 |
ENUMX |
BFD_RELOC_SH_DISP20 |
ENUMX |
BFD_RELOC_SH_DISP20BY8 |
ENUMX |
BFD_RELOC_SH_IMM4 |
ENUMX |
BFD_RELOC_SH_IMM4BY2 |
ENUMX |
BFD_RELOC_SH_IMM4BY4 |
ENUMX |
BFD_RELOC_SH_IMM8 |
ENUMX |
BFD_RELOC_SH_IMM8BY2 |
ENUMX |
BFD_RELOC_SH_IMM8BY4 |
ENUMX |
BFD_RELOC_SH_PCRELIMM8BY2 |
ENUMX |
BFD_RELOC_SH_PCRELIMM8BY4 |
ENUMX |
BFD_RELOC_SH_SWITCH16 |
ENUMX |
BFD_RELOC_SH_SWITCH32 |
ENUMX |
BFD_RELOC_SH_USES |
ENUMX |
BFD_RELOC_SH_COUNT |
ENUMX |
BFD_RELOC_SH_ALIGN |
ENUMX |
BFD_RELOC_SH_CODE |
ENUMX |
BFD_RELOC_SH_DATA |
ENUMX |
BFD_RELOC_SH_LABEL |
ENUMX |
BFD_RELOC_SH_LOOP_START |
ENUMX |
BFD_RELOC_SH_LOOP_END |
ENUMX |
BFD_RELOC_SH_COPY |
ENUMX |
BFD_RELOC_SH_GLOB_DAT |
ENUMX |
BFD_RELOC_SH_JMP_SLOT |
ENUMX |
BFD_RELOC_SH_RELATIVE |
ENUMX |
BFD_RELOC_SH_GOTPC |
ENUMX |
BFD_RELOC_SH_GOT_LOW16 |
ENUMX |
BFD_RELOC_SH_GOT_MEDLOW16 |
ENUMX |
BFD_RELOC_SH_GOT_MEDHI16 |
ENUMX |
BFD_RELOC_SH_GOT_HI16 |
ENUMX |
BFD_RELOC_SH_GOTPLT_LOW16 |
ENUMX |
BFD_RELOC_SH_GOTPLT_MEDLOW16 |
ENUMX |
BFD_RELOC_SH_GOTPLT_MEDHI16 |
ENUMX |
BFD_RELOC_SH_GOTPLT_HI16 |
ENUMX |
BFD_RELOC_SH_PLT_LOW16 |
ENUMX |
BFD_RELOC_SH_PLT_MEDLOW16 |
ENUMX |
BFD_RELOC_SH_PLT_MEDHI16 |
ENUMX |
BFD_RELOC_SH_PLT_HI16 |
ENUMX |
BFD_RELOC_SH_GOTOFF_LOW16 |
ENUMX |
BFD_RELOC_SH_GOTOFF_MEDLOW16 |
ENUMX |
BFD_RELOC_SH_GOTOFF_MEDHI16 |
ENUMX |
BFD_RELOC_SH_GOTOFF_HI16 |
ENUMX |
BFD_RELOC_SH_GOTPC_LOW16 |
ENUMX |
BFD_RELOC_SH_GOTPC_MEDLOW16 |
ENUMX |
BFD_RELOC_SH_GOTPC_MEDHI16 |
ENUMX |
BFD_RELOC_SH_GOTPC_HI16 |
ENUMX |
BFD_RELOC_SH_COPY64 |
ENUMX |
BFD_RELOC_SH_GLOB_DAT64 |
ENUMX |
BFD_RELOC_SH_JMP_SLOT64 |
ENUMX |
BFD_RELOC_SH_RELATIVE64 |
ENUMX |
BFD_RELOC_SH_GOT10BY4 |
ENUMX |
BFD_RELOC_SH_GOT10BY8 |
ENUMX |
BFD_RELOC_SH_GOTPLT10BY4 |
ENUMX |
BFD_RELOC_SH_GOTPLT10BY8 |
ENUMX |
BFD_RELOC_SH_GOTPLT32 |
ENUMX |
BFD_RELOC_SH_SHMEDIA_CODE |
ENUMX |
BFD_RELOC_SH_IMMU5 |
ENUMX |
BFD_RELOC_SH_IMMS6 |
ENUMX |
BFD_RELOC_SH_IMMS6BY32 |
ENUMX |
BFD_RELOC_SH_IMMU6 |
ENUMX |
BFD_RELOC_SH_IMMS10 |
ENUMX |
BFD_RELOC_SH_IMMS10BY2 |
ENUMX |
BFD_RELOC_SH_IMMS10BY4 |
ENUMX |
BFD_RELOC_SH_IMMS10BY8 |
ENUMX |
BFD_RELOC_SH_IMMS16 |
ENUMX |
BFD_RELOC_SH_IMMU16 |
ENUMX |
BFD_RELOC_SH_IMM_LOW16 |
ENUMX |
BFD_RELOC_SH_IMM_LOW16_PCREL |
ENUMX |
BFD_RELOC_SH_IMM_MEDLOW16 |
ENUMX |
BFD_RELOC_SH_IMM_MEDLOW16_PCREL |
ENUMX |
BFD_RELOC_SH_IMM_MEDHI16 |
ENUMX |
BFD_RELOC_SH_IMM_MEDHI16_PCREL |
ENUMX |
BFD_RELOC_SH_IMM_HI16 |
ENUMX |
BFD_RELOC_SH_IMM_HI16_PCREL |
ENUMX |
BFD_RELOC_SH_PT_16 |
ENUMX |
BFD_RELOC_SH_TLS_GD_32 |
ENUMX |
BFD_RELOC_SH_TLS_LD_32 |
ENUMX |
BFD_RELOC_SH_TLS_LDO_32 |
ENUMX |
BFD_RELOC_SH_TLS_IE_32 |
ENUMX |
BFD_RELOC_SH_TLS_LE_32 |
ENUMX |
BFD_RELOC_SH_TLS_DTPMOD32 |
ENUMX |
BFD_RELOC_SH_TLS_DTPOFF32 |
ENUMX |
BFD_RELOC_SH_TLS_TPOFF32 |
ENUMX |
BFD_RELOC_SH_GOT20 |
ENUMX |
BFD_RELOC_SH_GOTOFF20 |
ENUMX |
BFD_RELOC_SH_GOTFUNCDESC |
ENUMX |
BFD_RELOC_SH_GOTFUNCDESC20 |
ENUMX |
BFD_RELOC_SH_GOTOFFFUNCDESC |
ENUMX |
BFD_RELOC_SH_GOTOFFFUNCDESC20 |
ENUMX |
BFD_RELOC_SH_FUNCDESC |
ENUMDOC |
Renesas / SuperH SH relocs. Not all of these appear in object files. |
ENUM |
BFD_RELOC_ARC_B22_PCREL |
ENUMDOC |
ARC Cores relocs. |
ARC 22 bit pc-relative branch. The lowest two bits must be zero and are |
not stored in the instruction. The high 20 bits are installed in bits 26 |
through 7 of the instruction. |
ENUM |
BFD_RELOC_ARC_B26 |
ENUMDOC |
ARC 26 bit absolute branch. The lowest two bits must be zero and are not |
stored in the instruction. The high 24 bits are installed in bits 23 |
through 0. |
ENUM |
BFD_RELOC_BFIN_16_IMM |
ENUMDOC |
ADI Blackfin 16 bit immediate absolute reloc. |
ENUM |
BFD_RELOC_BFIN_16_HIGH |
ENUMDOC |
ADI Blackfin 16 bit immediate absolute reloc higher 16 bits. |
ENUM |
BFD_RELOC_BFIN_4_PCREL |
ENUMDOC |
ADI Blackfin 'a' part of LSETUP. |
ENUM |
BFD_RELOC_BFIN_5_PCREL |
ENUMDOC |
ADI Blackfin. |
ENUM |
BFD_RELOC_BFIN_16_LOW |
ENUMDOC |
ADI Blackfin 16 bit immediate absolute reloc lower 16 bits. |
ENUM |
BFD_RELOC_BFIN_10_PCREL |
ENUMDOC |
ADI Blackfin. |
ENUM |
BFD_RELOC_BFIN_11_PCREL |
ENUMDOC |
ADI Blackfin 'b' part of LSETUP. |
ENUM |
BFD_RELOC_BFIN_12_PCREL_JUMP |
ENUMDOC |
ADI Blackfin. |
ENUM |
BFD_RELOC_BFIN_12_PCREL_JUMP_S |
ENUMDOC |
ADI Blackfin Short jump, pcrel. |
ENUM |
BFD_RELOC_BFIN_24_PCREL_CALL_X |
ENUMDOC |
ADI Blackfin Call.x not implemented. |
ENUM |
BFD_RELOC_BFIN_24_PCREL_JUMP_L |
ENUMDOC |
ADI Blackfin Long Jump pcrel. |
ENUM |
BFD_RELOC_BFIN_GOT17M4 |
ENUMX |
BFD_RELOC_BFIN_GOTHI |
ENUMX |
BFD_RELOC_BFIN_GOTLO |
ENUMX |
BFD_RELOC_BFIN_FUNCDESC |
ENUMX |
BFD_RELOC_BFIN_FUNCDESC_GOT17M4 |
ENUMX |
BFD_RELOC_BFIN_FUNCDESC_GOTHI |
ENUMX |
BFD_RELOC_BFIN_FUNCDESC_GOTLO |
ENUMX |
BFD_RELOC_BFIN_FUNCDESC_VALUE |
ENUMX |
BFD_RELOC_BFIN_FUNCDESC_GOTOFF17M4 |
ENUMX |
BFD_RELOC_BFIN_FUNCDESC_GOTOFFHI |
ENUMX |
BFD_RELOC_BFIN_FUNCDESC_GOTOFFLO |
ENUMX |
BFD_RELOC_BFIN_GOTOFF17M4 |
ENUMX |
BFD_RELOC_BFIN_GOTOFFHI |
ENUMX |
BFD_RELOC_BFIN_GOTOFFLO |
ENUMDOC |
ADI Blackfin FD-PIC relocations. |
ENUM |
BFD_RELOC_BFIN_GOT |
ENUMDOC |
ADI Blackfin GOT relocation. |
ENUM |
BFD_RELOC_BFIN_PLTPC |
ENUMDOC |
ADI Blackfin PLTPC relocation. |
ENUM |
BFD_ARELOC_BFIN_PUSH |
ENUMDOC |
ADI Blackfin arithmetic relocation. |
ENUM |
BFD_ARELOC_BFIN_CONST |
ENUMDOC |
ADI Blackfin arithmetic relocation. |
ENUM |
BFD_ARELOC_BFIN_ADD |
ENUMDOC |
ADI Blackfin arithmetic relocation. |
ENUM |
BFD_ARELOC_BFIN_SUB |
ENUMDOC |
ADI Blackfin arithmetic relocation. |
ENUM |
BFD_ARELOC_BFIN_MULT |
ENUMDOC |
ADI Blackfin arithmetic relocation. |
ENUM |
BFD_ARELOC_BFIN_DIV |
ENUMDOC |
ADI Blackfin arithmetic relocation. |
ENUM |
BFD_ARELOC_BFIN_MOD |
ENUMDOC |
ADI Blackfin arithmetic relocation. |
ENUM |
BFD_ARELOC_BFIN_LSHIFT |
ENUMDOC |
ADI Blackfin arithmetic relocation. |
ENUM |
BFD_ARELOC_BFIN_RSHIFT |
ENUMDOC |
ADI Blackfin arithmetic relocation. |
ENUM |
BFD_ARELOC_BFIN_AND |
ENUMDOC |
ADI Blackfin arithmetic relocation. |
ENUM |
BFD_ARELOC_BFIN_OR |
ENUMDOC |
ADI Blackfin arithmetic relocation. |
ENUM |
BFD_ARELOC_BFIN_XOR |
ENUMDOC |
ADI Blackfin arithmetic relocation. |
ENUM |
BFD_ARELOC_BFIN_LAND |
ENUMDOC |
ADI Blackfin arithmetic relocation. |
ENUM |
BFD_ARELOC_BFIN_LOR |
ENUMDOC |
ADI Blackfin arithmetic relocation. |
ENUM |
BFD_ARELOC_BFIN_LEN |
ENUMDOC |
ADI Blackfin arithmetic relocation. |
ENUM |
BFD_ARELOC_BFIN_NEG |
ENUMDOC |
ADI Blackfin arithmetic relocation. |
ENUM |
BFD_ARELOC_BFIN_COMP |
ENUMDOC |
ADI Blackfin arithmetic relocation. |
ENUM |
BFD_ARELOC_BFIN_PAGE |
ENUMDOC |
ADI Blackfin arithmetic relocation. |
ENUM |
BFD_ARELOC_BFIN_HWPAGE |
ENUMDOC |
ADI Blackfin arithmetic relocation. |
ENUM |
BFD_ARELOC_BFIN_ADDR |
ENUMDOC |
ADI Blackfin arithmetic relocation. |
ENUM |
BFD_RELOC_D10V_10_PCREL_R |
ENUMDOC |
Mitsubishi D10V relocs. |
This is a 10-bit reloc with the right 2 bits |
assumed to be 0. |
ENUM |
BFD_RELOC_D10V_10_PCREL_L |
ENUMDOC |
Mitsubishi D10V relocs. |
This is a 10-bit reloc with the right 2 bits |
assumed to be 0. This is the same as the previous reloc |
except it is in the left container, i.e., |
shifted left 15 bits. |
ENUM |
BFD_RELOC_D10V_18 |
ENUMDOC |
This is an 18-bit reloc with the right 2 bits |
assumed to be 0. |
ENUM |
BFD_RELOC_D10V_18_PCREL |
ENUMDOC |
This is an 18-bit reloc with the right 2 bits |
assumed to be 0. |
ENUM |
BFD_RELOC_D30V_6 |
ENUMDOC |
Mitsubishi D30V relocs. |
This is a 6-bit absolute reloc. |
ENUM |
BFD_RELOC_D30V_9_PCREL |
ENUMDOC |
This is a 6-bit pc-relative reloc with |
the right 3 bits assumed to be 0. |
ENUM |
BFD_RELOC_D30V_9_PCREL_R |
ENUMDOC |
This is a 6-bit pc-relative reloc with |
the right 3 bits assumed to be 0. Same |
as the previous reloc but on the right side |
of the container. |
ENUM |
BFD_RELOC_D30V_15 |
ENUMDOC |
This is a 12-bit absolute reloc with the |
right 3 bitsassumed to be 0. |
ENUM |
BFD_RELOC_D30V_15_PCREL |
ENUMDOC |
This is a 12-bit pc-relative reloc with |
the right 3 bits assumed to be 0. |
ENUM |
BFD_RELOC_D30V_15_PCREL_R |
ENUMDOC |
This is a 12-bit pc-relative reloc with |
the right 3 bits assumed to be 0. Same |
as the previous reloc but on the right side |
of the container. |
ENUM |
BFD_RELOC_D30V_21 |
ENUMDOC |
This is an 18-bit absolute reloc with |
the right 3 bits assumed to be 0. |
ENUM |
BFD_RELOC_D30V_21_PCREL |
ENUMDOC |
This is an 18-bit pc-relative reloc with |
the right 3 bits assumed to be 0. |
ENUM |
BFD_RELOC_D30V_21_PCREL_R |
ENUMDOC |
This is an 18-bit pc-relative reloc with |
the right 3 bits assumed to be 0. Same |
as the previous reloc but on the right side |
of the container. |
ENUM |
BFD_RELOC_D30V_32 |
ENUMDOC |
This is a 32-bit absolute reloc. |
ENUM |
BFD_RELOC_D30V_32_PCREL |
ENUMDOC |
This is a 32-bit pc-relative reloc. |
ENUM |
BFD_RELOC_DLX_HI16_S |
ENUMDOC |
DLX relocs |
ENUM |
BFD_RELOC_DLX_LO16 |
ENUMDOC |
DLX relocs |
ENUM |
BFD_RELOC_DLX_JMP26 |
ENUMDOC |
DLX relocs |
ENUM |
BFD_RELOC_M32C_HI8 |
ENUMX |
BFD_RELOC_M32C_RL_JUMP |
ENUMX |
BFD_RELOC_M32C_RL_1ADDR |
ENUMX |
BFD_RELOC_M32C_RL_2ADDR |
ENUMDOC |
Renesas M16C/M32C Relocations. |
ENUM |
BFD_RELOC_M32R_24 |
ENUMDOC |
Renesas M32R (formerly Mitsubishi M32R) relocs. |
This is a 24 bit absolute address. |
ENUM |
BFD_RELOC_M32R_10_PCREL |
ENUMDOC |
This is a 10-bit pc-relative reloc with the right 2 bits assumed to be 0. |
ENUM |
BFD_RELOC_M32R_18_PCREL |
ENUMDOC |
This is an 18-bit reloc with the right 2 bits assumed to be 0. |
ENUM |
BFD_RELOC_M32R_26_PCREL |
ENUMDOC |
This is a 26-bit reloc with the right 2 bits assumed to be 0. |
ENUM |
BFD_RELOC_M32R_HI16_ULO |
ENUMDOC |
This is a 16-bit reloc containing the high 16 bits of an address |
used when the lower 16 bits are treated as unsigned. |
ENUM |
BFD_RELOC_M32R_HI16_SLO |
ENUMDOC |
This is a 16-bit reloc containing the high 16 bits of an address |
used when the lower 16 bits are treated as signed. |
ENUM |
BFD_RELOC_M32R_LO16 |
ENUMDOC |
This is a 16-bit reloc containing the lower 16 bits of an address. |
ENUM |
BFD_RELOC_M32R_SDA16 |
ENUMDOC |
This is a 16-bit reloc containing the small data area offset for use in |
add3, load, and store instructions. |
ENUM |
BFD_RELOC_M32R_GOT24 |
ENUMX |
BFD_RELOC_M32R_26_PLTREL |
ENUMX |
BFD_RELOC_M32R_COPY |
ENUMX |
BFD_RELOC_M32R_GLOB_DAT |
ENUMX |
BFD_RELOC_M32R_JMP_SLOT |
ENUMX |
BFD_RELOC_M32R_RELATIVE |
ENUMX |
BFD_RELOC_M32R_GOTOFF |
ENUMX |
BFD_RELOC_M32R_GOTOFF_HI_ULO |
ENUMX |
BFD_RELOC_M32R_GOTOFF_HI_SLO |
ENUMX |
BFD_RELOC_M32R_GOTOFF_LO |
ENUMX |
BFD_RELOC_M32R_GOTPC24 |
ENUMX |
BFD_RELOC_M32R_GOT16_HI_ULO |
ENUMX |
BFD_RELOC_M32R_GOT16_HI_SLO |
ENUMX |
BFD_RELOC_M32R_GOT16_LO |
ENUMX |
BFD_RELOC_M32R_GOTPC_HI_ULO |
ENUMX |
BFD_RELOC_M32R_GOTPC_HI_SLO |
ENUMX |
BFD_RELOC_M32R_GOTPC_LO |
ENUMDOC |
For PIC. |
ENUM |
BFD_RELOC_V850_9_PCREL |
ENUMDOC |
This is a 9-bit reloc |
ENUM |
BFD_RELOC_V850_22_PCREL |
ENUMDOC |
This is a 22-bit reloc |
ENUM |
BFD_RELOC_V850_SDA_16_16_OFFSET |
ENUMDOC |
This is a 16 bit offset from the short data area pointer. |
ENUM |
BFD_RELOC_V850_SDA_15_16_OFFSET |
ENUMDOC |
This is a 16 bit offset (of which only 15 bits are used) from the |
short data area pointer. |
ENUM |
BFD_RELOC_V850_ZDA_16_16_OFFSET |
ENUMDOC |
This is a 16 bit offset from the zero data area pointer. |
ENUM |
BFD_RELOC_V850_ZDA_15_16_OFFSET |
ENUMDOC |
This is a 16 bit offset (of which only 15 bits are used) from the |
zero data area pointer. |
ENUM |
BFD_RELOC_V850_TDA_6_8_OFFSET |
ENUMDOC |
This is an 8 bit offset (of which only 6 bits are used) from the |
tiny data area pointer. |
ENUM |
BFD_RELOC_V850_TDA_7_8_OFFSET |
ENUMDOC |
This is an 8bit offset (of which only 7 bits are used) from the tiny |
data area pointer. |
ENUM |
BFD_RELOC_V850_TDA_7_7_OFFSET |
ENUMDOC |
This is a 7 bit offset from the tiny data area pointer. |
ENUM |
BFD_RELOC_V850_TDA_16_16_OFFSET |
ENUMDOC |
This is a 16 bit offset from the tiny data area pointer. |
COMMENT |
ENUM |
BFD_RELOC_V850_TDA_4_5_OFFSET |
ENUMDOC |
This is a 5 bit offset (of which only 4 bits are used) from the tiny |
data area pointer. |
ENUM |
BFD_RELOC_V850_TDA_4_4_OFFSET |
ENUMDOC |
This is a 4 bit offset from the tiny data area pointer. |
ENUM |
BFD_RELOC_V850_SDA_16_16_SPLIT_OFFSET |
ENUMDOC |
This is a 16 bit offset from the short data area pointer, with the |
bits placed non-contiguously in the instruction. |
ENUM |
BFD_RELOC_V850_ZDA_16_16_SPLIT_OFFSET |
ENUMDOC |
This is a 16 bit offset from the zero data area pointer, with the |
bits placed non-contiguously in the instruction. |
ENUM |
BFD_RELOC_V850_CALLT_6_7_OFFSET |
ENUMDOC |
This is a 6 bit offset from the call table base pointer. |
ENUM |
BFD_RELOC_V850_CALLT_16_16_OFFSET |
ENUMDOC |
This is a 16 bit offset from the call table base pointer. |
ENUM |
BFD_RELOC_V850_LONGCALL |
ENUMDOC |
Used for relaxing indirect function calls. |
ENUM |
BFD_RELOC_V850_LONGJUMP |
ENUMDOC |
Used for relaxing indirect jumps. |
ENUM |
BFD_RELOC_V850_ALIGN |
ENUMDOC |
Used to maintain alignment whilst relaxing. |
ENUM |
BFD_RELOC_V850_LO16_SPLIT_OFFSET |
ENUMDOC |
This is a variation of BFD_RELOC_LO16 that can be used in v850e ld.bu |
instructions. |
ENUM |
BFD_RELOC_V850_16_PCREL |
ENUMDOC |
This is a 16-bit reloc. |
ENUM |
BFD_RELOC_V850_17_PCREL |
ENUMDOC |
This is a 17-bit reloc. |
ENUM |
BFD_RELOC_V850_23 |
ENUMDOC |
This is a 23-bit reloc. |
ENUM |
BFD_RELOC_V850_32_PCREL |
ENUMDOC |
This is a 32-bit reloc. |
ENUM |
BFD_RELOC_V850_32_ABS |
ENUMDOC |
This is a 32-bit reloc. |
ENUM |
BFD_RELOC_V850_16_SPLIT_OFFSET |
ENUMDOC |
This is a 16-bit reloc. |
ENUM |
BFD_RELOC_V850_16_S1 |
ENUMDOC |
This is a 16-bit reloc. |
ENUM |
BFD_RELOC_V850_LO16_S1 |
ENUMDOC |
Low 16 bits. 16 bit shifted by 1. |
ENUM |
BFD_RELOC_V850_CALLT_15_16_OFFSET |
ENUMDOC |
This is a 16 bit offset from the call table base pointer. |
ENUM |
BFD_RELOC_V850_32_GOTPCREL |
ENUMDOC |
DSO relocations. |
ENUM |
BFD_RELOC_V850_16_GOT |
ENUMDOC |
DSO relocations. |
ENUM |
BFD_RELOC_V850_32_GOT |
ENUMDOC |
DSO relocations. |
ENUM |
BFD_RELOC_V850_22_PLT_PCREL |
ENUMDOC |
DSO relocations. |
ENUM |
BFD_RELOC_V850_32_PLT_PCREL |
ENUMDOC |
DSO relocations. |
ENUM |
BFD_RELOC_V850_COPY |
ENUMDOC |
DSO relocations. |
ENUM |
BFD_RELOC_V850_GLOB_DAT |
ENUMDOC |
DSO relocations. |
ENUM |
BFD_RELOC_V850_JMP_SLOT |
ENUMDOC |
DSO relocations. |
ENUM |
BFD_RELOC_V850_RELATIVE |
ENUMDOC |
DSO relocations. |
ENUM |
BFD_RELOC_V850_16_GOTOFF |
ENUMDOC |
DSO relocations. |
ENUM |
BFD_RELOC_V850_32_GOTOFF |
ENUMDOC |
DSO relocations. |
ENUM |
BFD_RELOC_V850_CODE |
ENUMDOC |
start code. |
ENUM |
BFD_RELOC_V850_DATA |
ENUMDOC |
start data in text. |
ENUM |
BFD_RELOC_TIC30_LDP |
ENUMDOC |
This is a 8bit DP reloc for the tms320c30, where the most |
significant 8 bits of a 24 bit word are placed into the least |
significant 8 bits of the opcode. |
ENUM |
BFD_RELOC_TIC54X_PARTLS7 |
ENUMDOC |
This is a 7bit reloc for the tms320c54x, where the least |
significant 7 bits of a 16 bit word are placed into the least |
significant 7 bits of the opcode. |
ENUM |
BFD_RELOC_TIC54X_PARTMS9 |
ENUMDOC |
This is a 9bit DP reloc for the tms320c54x, where the most |
significant 9 bits of a 16 bit word are placed into the least |
significant 9 bits of the opcode. |
ENUM |
BFD_RELOC_TIC54X_23 |
ENUMDOC |
This is an extended address 23-bit reloc for the tms320c54x. |
ENUM |
BFD_RELOC_TIC54X_16_OF_23 |
ENUMDOC |
This is a 16-bit reloc for the tms320c54x, where the least |
significant 16 bits of a 23-bit extended address are placed into |
the opcode. |
ENUM |
BFD_RELOC_TIC54X_MS7_OF_23 |
ENUMDOC |
This is a reloc for the tms320c54x, where the most |
significant 7 bits of a 23-bit extended address are placed into |
the opcode. |
ENUM |
BFD_RELOC_C6000_PCR_S21 |
ENUMX |
BFD_RELOC_C6000_PCR_S12 |
ENUMX |
BFD_RELOC_C6000_PCR_S10 |
ENUMX |
BFD_RELOC_C6000_PCR_S7 |
ENUMX |
BFD_RELOC_C6000_ABS_S16 |
ENUMX |
BFD_RELOC_C6000_ABS_L16 |
ENUMX |
BFD_RELOC_C6000_ABS_H16 |
ENUMX |
BFD_RELOC_C6000_SBR_U15_B |
ENUMX |
BFD_RELOC_C6000_SBR_U15_H |
ENUMX |
BFD_RELOC_C6000_SBR_U15_W |
ENUMX |
BFD_RELOC_C6000_SBR_S16 |
ENUMX |
BFD_RELOC_C6000_SBR_L16_B |
ENUMX |
BFD_RELOC_C6000_SBR_L16_H |
ENUMX |
BFD_RELOC_C6000_SBR_L16_W |
ENUMX |
BFD_RELOC_C6000_SBR_H16_B |
ENUMX |
BFD_RELOC_C6000_SBR_H16_H |
ENUMX |
BFD_RELOC_C6000_SBR_H16_W |
ENUMX |
BFD_RELOC_C6000_SBR_GOT_U15_W |
ENUMX |
BFD_RELOC_C6000_SBR_GOT_L16_W |
ENUMX |
BFD_RELOC_C6000_SBR_GOT_H16_W |
ENUMX |
BFD_RELOC_C6000_DSBT_INDEX |
ENUMX |
BFD_RELOC_C6000_PREL31 |
ENUMX |
BFD_RELOC_C6000_COPY |
ENUMX |
BFD_RELOC_C6000_JUMP_SLOT |
ENUMX |
BFD_RELOC_C6000_EHTYPE |
ENUMX |
BFD_RELOC_C6000_PCR_H16 |
ENUMX |
BFD_RELOC_C6000_PCR_L16 |
ENUMX |
BFD_RELOC_C6000_ALIGN |
ENUMX |
BFD_RELOC_C6000_FPHEAD |
ENUMX |
BFD_RELOC_C6000_NOCMP |
ENUMDOC |
TMS320C6000 relocations. |
ENUM |
BFD_RELOC_FR30_48 |
ENUMDOC |
This is a 48 bit reloc for the FR30 that stores 32 bits. |
ENUM |
BFD_RELOC_FR30_20 |
ENUMDOC |
This is a 32 bit reloc for the FR30 that stores 20 bits split up into |
two sections. |
ENUM |
BFD_RELOC_FR30_6_IN_4 |
ENUMDOC |
This is a 16 bit reloc for the FR30 that stores a 6 bit word offset in |
4 bits. |
ENUM |
BFD_RELOC_FR30_8_IN_8 |
ENUMDOC |
This is a 16 bit reloc for the FR30 that stores an 8 bit byte offset |
into 8 bits. |
ENUM |
BFD_RELOC_FR30_9_IN_8 |
ENUMDOC |
This is a 16 bit reloc for the FR30 that stores a 9 bit short offset |
into 8 bits. |
ENUM |
BFD_RELOC_FR30_10_IN_8 |
ENUMDOC |
This is a 16 bit reloc for the FR30 that stores a 10 bit word offset |
into 8 bits. |
ENUM |
BFD_RELOC_FR30_9_PCREL |
ENUMDOC |
This is a 16 bit reloc for the FR30 that stores a 9 bit pc relative |
short offset into 8 bits. |
ENUM |
BFD_RELOC_FR30_12_PCREL |
ENUMDOC |
This is a 16 bit reloc for the FR30 that stores a 12 bit pc relative |
short offset into 11 bits. |
ENUM |
BFD_RELOC_MCORE_PCREL_IMM8BY4 |
ENUMX |
BFD_RELOC_MCORE_PCREL_IMM11BY2 |
ENUMX |
BFD_RELOC_MCORE_PCREL_IMM4BY2 |
ENUMX |
BFD_RELOC_MCORE_PCREL_32 |
ENUMX |
BFD_RELOC_MCORE_PCREL_JSR_IMM11BY2 |
ENUMX |
BFD_RELOC_MCORE_RVA |
ENUMDOC |
Motorola Mcore relocations. |
ENUM |
BFD_RELOC_MEP_8 |
ENUMX |
BFD_RELOC_MEP_16 |
ENUMX |
BFD_RELOC_MEP_32 |
ENUMX |
BFD_RELOC_MEP_PCREL8A2 |
ENUMX |
BFD_RELOC_MEP_PCREL12A2 |
ENUMX |
BFD_RELOC_MEP_PCREL17A2 |
ENUMX |
BFD_RELOC_MEP_PCREL24A2 |
ENUMX |
BFD_RELOC_MEP_PCABS24A2 |
ENUMX |
BFD_RELOC_MEP_LOW16 |
ENUMX |
BFD_RELOC_MEP_HI16U |
ENUMX |
BFD_RELOC_MEP_HI16S |
ENUMX |
BFD_RELOC_MEP_GPREL |
ENUMX |
BFD_RELOC_MEP_TPREL |
ENUMX |
BFD_RELOC_MEP_TPREL7 |
ENUMX |
BFD_RELOC_MEP_TPREL7A2 |
ENUMX |
BFD_RELOC_MEP_TPREL7A4 |
ENUMX |
BFD_RELOC_MEP_UIMM24 |
ENUMX |
BFD_RELOC_MEP_ADDR24A4 |
ENUMX |
BFD_RELOC_MEP_GNU_VTINHERIT |
ENUMX |
BFD_RELOC_MEP_GNU_VTENTRY |
ENUMDOC |
Toshiba Media Processor Relocations. |
COMMENT |
ENUM |
BFD_RELOC_METAG_HIADDR16 |
ENUMX |
BFD_RELOC_METAG_LOADDR16 |
ENUMX |
BFD_RELOC_METAG_RELBRANCH |
ENUMX |
BFD_RELOC_METAG_GETSETOFF |
ENUMX |
BFD_RELOC_METAG_HIOG |
ENUMX |
BFD_RELOC_METAG_LOOG |
ENUMX |
BFD_RELOC_METAG_REL8 |
ENUMX |
BFD_RELOC_METAG_REL16 |
ENUMX |
BFD_RELOC_METAG_HI16_GOTOFF |
ENUMX |
BFD_RELOC_METAG_LO16_GOTOFF |
ENUMX |
BFD_RELOC_METAG_GETSET_GOTOFF |
ENUMX |
BFD_RELOC_METAG_GETSET_GOT |
ENUMX |
BFD_RELOC_METAG_HI16_GOTPC |
ENUMX |
BFD_RELOC_METAG_LO16_GOTPC |
ENUMX |
BFD_RELOC_METAG_HI16_PLT |
ENUMX |
BFD_RELOC_METAG_LO16_PLT |
ENUMX |
BFD_RELOC_METAG_RELBRANCH_PLT |
ENUMX |
BFD_RELOC_METAG_GOTOFF |
ENUMX |
BFD_RELOC_METAG_PLT |
ENUMX |
BFD_RELOC_METAG_COPY |
ENUMX |
BFD_RELOC_METAG_JMP_SLOT |
ENUMX |
BFD_RELOC_METAG_RELATIVE |
ENUMX |
BFD_RELOC_METAG_GLOB_DAT |
ENUMX |
BFD_RELOC_METAG_TLS_GD |
ENUMX |
BFD_RELOC_METAG_TLS_LDM |
ENUMX |
BFD_RELOC_METAG_TLS_LDO_HI16 |
ENUMX |
BFD_RELOC_METAG_TLS_LDO_LO16 |
ENUMX |
BFD_RELOC_METAG_TLS_LDO |
ENUMX |
BFD_RELOC_METAG_TLS_IE |
ENUMX |
BFD_RELOC_METAG_TLS_IENONPIC |
ENUMX |
BFD_RELOC_METAG_TLS_IENONPIC_HI16 |
ENUMX |
BFD_RELOC_METAG_TLS_IENONPIC_LO16 |
ENUMX |
BFD_RELOC_METAG_TLS_TPOFF |
ENUMX |
BFD_RELOC_METAG_TLS_DTPMOD |
ENUMX |
BFD_RELOC_METAG_TLS_DTPOFF |
ENUMX |
BFD_RELOC_METAG_TLS_LE |
ENUMX |
BFD_RELOC_METAG_TLS_LE_HI16 |
ENUMX |
BFD_RELOC_METAG_TLS_LE_LO16 |
ENUMDOC |
Imagination Technologies Meta relocations. |
ENUM |
BFD_RELOC_MMIX_GETA |
ENUMX |
BFD_RELOC_MMIX_GETA_1 |
ENUMX |
BFD_RELOC_MMIX_GETA_2 |
ENUMX |
BFD_RELOC_MMIX_GETA_3 |
ENUMDOC |
These are relocations for the GETA instruction. |
ENUM |
BFD_RELOC_MMIX_CBRANCH |
ENUMX |
BFD_RELOC_MMIX_CBRANCH_J |
ENUMX |
BFD_RELOC_MMIX_CBRANCH_1 |
ENUMX |
BFD_RELOC_MMIX_CBRANCH_2 |
ENUMX |
BFD_RELOC_MMIX_CBRANCH_3 |
ENUMDOC |
These are relocations for a conditional branch instruction. |
ENUM |
BFD_RELOC_MMIX_PUSHJ |
ENUMX |
BFD_RELOC_MMIX_PUSHJ_1 |
ENUMX |
BFD_RELOC_MMIX_PUSHJ_2 |
ENUMX |
BFD_RELOC_MMIX_PUSHJ_3 |
ENUMX |
BFD_RELOC_MMIX_PUSHJ_STUBBABLE |
ENUMDOC |
These are relocations for the PUSHJ instruction. |
ENUM |
BFD_RELOC_MMIX_JMP |
ENUMX |
BFD_RELOC_MMIX_JMP_1 |
ENUMX |
BFD_RELOC_MMIX_JMP_2 |
ENUMX |
BFD_RELOC_MMIX_JMP_3 |
ENUMDOC |
These are relocations for the JMP instruction. |
ENUM |
BFD_RELOC_MMIX_ADDR19 |
ENUMDOC |
This is a relocation for a relative address as in a GETA instruction or |
a branch. |
ENUM |
BFD_RELOC_MMIX_ADDR27 |
ENUMDOC |
This is a relocation for a relative address as in a JMP instruction. |
ENUM |
BFD_RELOC_MMIX_REG_OR_BYTE |
ENUMDOC |
This is a relocation for an instruction field that may be a general |
register or a value 0..255. |
ENUM |
BFD_RELOC_MMIX_REG |
ENUMDOC |
This is a relocation for an instruction field that may be a general |
register. |
ENUM |
BFD_RELOC_MMIX_BASE_PLUS_OFFSET |
ENUMDOC |
This is a relocation for two instruction fields holding a register and |
an offset, the equivalent of the relocation. |
ENUM |
BFD_RELOC_MMIX_LOCAL |
ENUMDOC |
This relocation is an assertion that the expression is not allocated as |
a global register. It does not modify contents. |
ENUM |
BFD_RELOC_AVR_7_PCREL |
ENUMDOC |
This is a 16 bit reloc for the AVR that stores 8 bit pc relative |
short offset into 7 bits. |
ENUM |
BFD_RELOC_AVR_13_PCREL |
ENUMDOC |
This is a 16 bit reloc for the AVR that stores 13 bit pc relative |
short offset into 12 bits. |
ENUM |
BFD_RELOC_AVR_16_PM |
ENUMDOC |
This is a 16 bit reloc for the AVR that stores 17 bit value (usually |
program memory address) into 16 bits. |
ENUM |
BFD_RELOC_AVR_LO8_LDI |
ENUMDOC |
This is a 16 bit reloc for the AVR that stores 8 bit value (usually |
data memory address) into 8 bit immediate value of LDI insn. |
ENUM |
BFD_RELOC_AVR_HI8_LDI |
ENUMDOC |
This is a 16 bit reloc for the AVR that stores 8 bit value (high 8 bit |
of data memory address) into 8 bit immediate value of LDI insn. |
ENUM |
BFD_RELOC_AVR_HH8_LDI |
ENUMDOC |
This is a 16 bit reloc for the AVR that stores 8 bit value (most high 8 bit |
of program memory address) into 8 bit immediate value of LDI insn. |
ENUM |
BFD_RELOC_AVR_MS8_LDI |
ENUMDOC |
This is a 16 bit reloc for the AVR that stores 8 bit value (most high 8 bit |
of 32 bit value) into 8 bit immediate value of LDI insn. |
ENUM |
BFD_RELOC_AVR_LO8_LDI_NEG |
ENUMDOC |
This is a 16 bit reloc for the AVR that stores negated 8 bit value |
(usually data memory address) into 8 bit immediate value of SUBI insn. |
ENUM |
BFD_RELOC_AVR_HI8_LDI_NEG |
ENUMDOC |
This is a 16 bit reloc for the AVR that stores negated 8 bit value |
(high 8 bit of data memory address) into 8 bit immediate value of |
SUBI insn. |
ENUM |
BFD_RELOC_AVR_HH8_LDI_NEG |
ENUMDOC |
This is a 16 bit reloc for the AVR that stores negated 8 bit value |
(most high 8 bit of program memory address) into 8 bit immediate value |
of LDI or SUBI insn. |
ENUM |
BFD_RELOC_AVR_MS8_LDI_NEG |
ENUMDOC |
This is a 16 bit reloc for the AVR that stores negated 8 bit value (msb |
of 32 bit value) into 8 bit immediate value of LDI insn. |
ENUM |
BFD_RELOC_AVR_LO8_LDI_PM |
ENUMDOC |
This is a 16 bit reloc for the AVR that stores 8 bit value (usually |
command address) into 8 bit immediate value of LDI insn. |
ENUM |
BFD_RELOC_AVR_LO8_LDI_GS |
ENUMDOC |
This is a 16 bit reloc for the AVR that stores 8 bit value |
(command address) into 8 bit immediate value of LDI insn. If the address |
is beyond the 128k boundary, the linker inserts a jump stub for this reloc |
in the lower 128k. |
ENUM |
BFD_RELOC_AVR_HI8_LDI_PM |
ENUMDOC |
This is a 16 bit reloc for the AVR that stores 8 bit value (high 8 bit |
of command address) into 8 bit immediate value of LDI insn. |
ENUM |
BFD_RELOC_AVR_HI8_LDI_GS |
ENUMDOC |
This is a 16 bit reloc for the AVR that stores 8 bit value (high 8 bit |
of command address) into 8 bit immediate value of LDI insn. If the address |
is beyond the 128k boundary, the linker inserts a jump stub for this reloc |
below 128k. |
ENUM |
BFD_RELOC_AVR_HH8_LDI_PM |
ENUMDOC |
This is a 16 bit reloc for the AVR that stores 8 bit value (most high 8 bit |
of command address) into 8 bit immediate value of LDI insn. |
ENUM |
BFD_RELOC_AVR_LO8_LDI_PM_NEG |
ENUMDOC |
This is a 16 bit reloc for the AVR that stores negated 8 bit value |
(usually command address) into 8 bit immediate value of SUBI insn. |
ENUM |
BFD_RELOC_AVR_HI8_LDI_PM_NEG |
ENUMDOC |
This is a 16 bit reloc for the AVR that stores negated 8 bit value |
(high 8 bit of 16 bit command address) into 8 bit immediate value |
of SUBI insn. |
ENUM |
BFD_RELOC_AVR_HH8_LDI_PM_NEG |
ENUMDOC |
This is a 16 bit reloc for the AVR that stores negated 8 bit value |
(high 6 bit of 22 bit command address) into 8 bit immediate |
value of SUBI insn. |
ENUM |
BFD_RELOC_AVR_CALL |
ENUMDOC |
This is a 32 bit reloc for the AVR that stores 23 bit value |
into 22 bits. |
ENUM |
BFD_RELOC_AVR_LDI |
ENUMDOC |
This is a 16 bit reloc for the AVR that stores all needed bits |
for absolute addressing with ldi with overflow check to linktime |
ENUM |
BFD_RELOC_AVR_6 |
ENUMDOC |
This is a 6 bit reloc for the AVR that stores offset for ldd/std |
instructions |
ENUM |
BFD_RELOC_AVR_6_ADIW |
ENUMDOC |
This is a 6 bit reloc for the AVR that stores offset for adiw/sbiw |
instructions |
ENUM |
BFD_RELOC_AVR_8_LO |
ENUMDOC |
This is a 8 bit reloc for the AVR that stores bits 0..7 of a symbol |
in .byte lo8(symbol) |
ENUM |
BFD_RELOC_AVR_8_HI |
ENUMDOC |
This is a 8 bit reloc for the AVR that stores bits 8..15 of a symbol |
in .byte hi8(symbol) |
ENUM |
BFD_RELOC_AVR_8_HLO |
ENUMDOC |
This is a 8 bit reloc for the AVR that stores bits 16..23 of a symbol |
in .byte hlo8(symbol) |
ENUM |
BFD_RELOC_RL78_NEG8 |
ENUMX |
BFD_RELOC_RL78_NEG16 |
ENUMX |
BFD_RELOC_RL78_NEG24 |
ENUMX |
BFD_RELOC_RL78_NEG32 |
ENUMX |
BFD_RELOC_RL78_16_OP |
ENUMX |
BFD_RELOC_RL78_24_OP |
ENUMX |
BFD_RELOC_RL78_32_OP |
ENUMX |
BFD_RELOC_RL78_8U |
ENUMX |
BFD_RELOC_RL78_16U |
ENUMX |
BFD_RELOC_RL78_24U |
ENUMX |
BFD_RELOC_RL78_DIR3U_PCREL |
ENUMX |
BFD_RELOC_RL78_DIFF |
ENUMX |
BFD_RELOC_RL78_GPRELB |
ENUMX |
BFD_RELOC_RL78_GPRELW |
ENUMX |
BFD_RELOC_RL78_GPRELL |
ENUMX |
BFD_RELOC_RL78_SYM |
ENUMX |
BFD_RELOC_RL78_OP_SUBTRACT |
ENUMX |
BFD_RELOC_RL78_OP_NEG |
ENUMX |
BFD_RELOC_RL78_OP_AND |
ENUMX |
BFD_RELOC_RL78_OP_SHRA |
ENUMX |
BFD_RELOC_RL78_ABS8 |
ENUMX |
BFD_RELOC_RL78_ABS16 |
ENUMX |
BFD_RELOC_RL78_ABS16_REV |
ENUMX |
BFD_RELOC_RL78_ABS32 |
ENUMX |
BFD_RELOC_RL78_ABS32_REV |
ENUMX |
BFD_RELOC_RL78_ABS16U |
ENUMX |
BFD_RELOC_RL78_ABS16UW |
ENUMX |
BFD_RELOC_RL78_ABS16UL |
ENUMX |
BFD_RELOC_RL78_RELAX |
ENUMX |
BFD_RELOC_RL78_HI16 |
ENUMX |
BFD_RELOC_RL78_HI8 |
ENUMX |
BFD_RELOC_RL78_LO16 |
ENUMX |
BFD_RELOC_RL78_CODE |
ENUMDOC |
Renesas RL78 Relocations. |
ENUM |
BFD_RELOC_RX_NEG8 |
ENUMX |
BFD_RELOC_RX_NEG16 |
ENUMX |
BFD_RELOC_RX_NEG24 |
ENUMX |
BFD_RELOC_RX_NEG32 |
ENUMX |
BFD_RELOC_RX_16_OP |
ENUMX |
BFD_RELOC_RX_24_OP |
ENUMX |
BFD_RELOC_RX_32_OP |
ENUMX |
BFD_RELOC_RX_8U |
ENUMX |
BFD_RELOC_RX_16U |
ENUMX |
BFD_RELOC_RX_24U |
ENUMX |
BFD_RELOC_RX_DIR3U_PCREL |
ENUMX |
BFD_RELOC_RX_DIFF |
ENUMX |
BFD_RELOC_RX_GPRELB |
ENUMX |
BFD_RELOC_RX_GPRELW |
ENUMX |
BFD_RELOC_RX_GPRELL |
ENUMX |
BFD_RELOC_RX_SYM |
ENUMX |
BFD_RELOC_RX_OP_SUBTRACT |
ENUMX |
BFD_RELOC_RX_OP_NEG |
ENUMX |
BFD_RELOC_RX_ABS8 |
ENUMX |
BFD_RELOC_RX_ABS16 |
ENUMX |
BFD_RELOC_RX_ABS16_REV |
ENUMX |
BFD_RELOC_RX_ABS32 |
ENUMX |
BFD_RELOC_RX_ABS32_REV |
ENUMX |
BFD_RELOC_RX_ABS16U |
ENUMX |
BFD_RELOC_RX_ABS16UW |
ENUMX |
BFD_RELOC_RX_ABS16UL |
ENUMX |
BFD_RELOC_RX_RELAX |
ENUMDOC |
Renesas RX Relocations. |
ENUM |
BFD_RELOC_390_12 |
ENUMDOC |
Direct 12 bit. |
ENUM |
BFD_RELOC_390_GOT12 |
ENUMDOC |
12 bit GOT offset. |
ENUM |
BFD_RELOC_390_PLT32 |
ENUMDOC |
32 bit PC relative PLT address. |
ENUM |
BFD_RELOC_390_COPY |
ENUMDOC |
Copy symbol at runtime. |
ENUM |
BFD_RELOC_390_GLOB_DAT |
ENUMDOC |
Create GOT entry. |
ENUM |
BFD_RELOC_390_JMP_SLOT |
ENUMDOC |
Create PLT entry. |
ENUM |
BFD_RELOC_390_RELATIVE |
ENUMDOC |
Adjust by program base. |
ENUM |
BFD_RELOC_390_GOTPC |
ENUMDOC |
32 bit PC relative offset to GOT. |
ENUM |
BFD_RELOC_390_GOT16 |
ENUMDOC |
16 bit GOT offset. |
ENUM |
BFD_RELOC_390_PC12DBL |
ENUMDOC |
PC relative 12 bit shifted by 1. |
ENUM |
BFD_RELOC_390_PLT12DBL |
ENUMDOC |
12 bit PC rel. PLT shifted by 1. |
ENUM |
BFD_RELOC_390_PC16DBL |
ENUMDOC |
PC relative 16 bit shifted by 1. |
ENUM |
BFD_RELOC_390_PLT16DBL |
ENUMDOC |
16 bit PC rel. PLT shifted by 1. |
ENUM |
BFD_RELOC_390_PC24DBL |
ENUMDOC |
PC relative 24 bit shifted by 1. |
ENUM |
BFD_RELOC_390_PLT24DBL |
ENUMDOC |
24 bit PC rel. PLT shifted by 1. |
ENUM |
BFD_RELOC_390_PC32DBL |
ENUMDOC |
PC relative 32 bit shifted by 1. |
ENUM |
BFD_RELOC_390_PLT32DBL |
ENUMDOC |
32 bit PC rel. PLT shifted by 1. |
ENUM |
BFD_RELOC_390_GOTPCDBL |
ENUMDOC |
32 bit PC rel. GOT shifted by 1. |
ENUM |
BFD_RELOC_390_GOT64 |
ENUMDOC |
64 bit GOT offset. |
ENUM |
BFD_RELOC_390_PLT64 |
ENUMDOC |
64 bit PC relative PLT address. |
ENUM |
BFD_RELOC_390_GOTENT |
ENUMDOC |
32 bit rel. offset to GOT entry. |
ENUM |
BFD_RELOC_390_GOTOFF64 |
ENUMDOC |
64 bit offset to GOT. |
ENUM |
BFD_RELOC_390_GOTPLT12 |
ENUMDOC |
12-bit offset to symbol-entry within GOT, with PLT handling. |
ENUM |
BFD_RELOC_390_GOTPLT16 |
ENUMDOC |
16-bit offset to symbol-entry within GOT, with PLT handling. |
ENUM |
BFD_RELOC_390_GOTPLT32 |
ENUMDOC |
32-bit offset to symbol-entry within GOT, with PLT handling. |
ENUM |
BFD_RELOC_390_GOTPLT64 |
ENUMDOC |
64-bit offset to symbol-entry within GOT, with PLT handling. |
ENUM |
BFD_RELOC_390_GOTPLTENT |
ENUMDOC |
32-bit rel. offset to symbol-entry within GOT, with PLT handling. |
ENUM |
BFD_RELOC_390_PLTOFF16 |
ENUMDOC |
16-bit rel. offset from the GOT to a PLT entry. |
ENUM |
BFD_RELOC_390_PLTOFF32 |
ENUMDOC |
32-bit rel. offset from the GOT to a PLT entry. |
ENUM |
BFD_RELOC_390_PLTOFF64 |
ENUMDOC |
64-bit rel. offset from the GOT to a PLT entry. |
ENUM |
BFD_RELOC_390_TLS_LOAD |
ENUMX |
BFD_RELOC_390_TLS_GDCALL |
ENUMX |
BFD_RELOC_390_TLS_LDCALL |
ENUMX |
BFD_RELOC_390_TLS_GD32 |
ENUMX |
BFD_RELOC_390_TLS_GD64 |
ENUMX |
BFD_RELOC_390_TLS_GOTIE12 |
ENUMX |
BFD_RELOC_390_TLS_GOTIE32 |
ENUMX |
BFD_RELOC_390_TLS_GOTIE64 |
ENUMX |
BFD_RELOC_390_TLS_LDM32 |
ENUMX |
BFD_RELOC_390_TLS_LDM64 |
ENUMX |
BFD_RELOC_390_TLS_IE32 |
ENUMX |
BFD_RELOC_390_TLS_IE64 |
ENUMX |
BFD_RELOC_390_TLS_IEENT |
ENUMX |
BFD_RELOC_390_TLS_LE32 |
ENUMX |
BFD_RELOC_390_TLS_LE64 |
ENUMX |
BFD_RELOC_390_TLS_LDO32 |
ENUMX |
BFD_RELOC_390_TLS_LDO64 |
ENUMX |
BFD_RELOC_390_TLS_DTPMOD |
ENUMX |
BFD_RELOC_390_TLS_DTPOFF |
ENUMX |
BFD_RELOC_390_TLS_TPOFF |
ENUMDOC |
s390 tls relocations. |
ENUM |
BFD_RELOC_390_20 |
ENUMX |
BFD_RELOC_390_GOT20 |
ENUMX |
BFD_RELOC_390_GOTPLT20 |
ENUMX |
BFD_RELOC_390_TLS_GOTIE20 |
ENUMDOC |
Long displacement extension. |
ENUM |
BFD_RELOC_390_IRELATIVE |
ENUMDOC |
STT_GNU_IFUNC relocation. |
ENUM |
BFD_RELOC_SCORE_GPREL15 |
ENUMDOC |
Score relocations |
Low 16 bit for load/store |
ENUM |
BFD_RELOC_SCORE_DUMMY2 |
ENUMX |
BFD_RELOC_SCORE_JMP |
ENUMDOC |
This is a 24-bit reloc with the right 1 bit assumed to be 0 |
ENUM |
BFD_RELOC_SCORE_BRANCH |
ENUMDOC |
This is a 19-bit reloc with the right 1 bit assumed to be 0 |
ENUM |
BFD_RELOC_SCORE_IMM30 |
ENUMDOC |
This is a 32-bit reloc for 48-bit instructions. |
ENUM |
BFD_RELOC_SCORE_IMM32 |
ENUMDOC |
This is a 32-bit reloc for 48-bit instructions. |
ENUM |
BFD_RELOC_SCORE16_JMP |
ENUMDOC |
This is a 11-bit reloc with the right 1 bit assumed to be 0 |
ENUM |
BFD_RELOC_SCORE16_BRANCH |
ENUMDOC |
This is a 8-bit reloc with the right 1 bit assumed to be 0 |
ENUM |
BFD_RELOC_SCORE_BCMP |
ENUMDOC |
This is a 9-bit reloc with the right 1 bit assumed to be 0 |
ENUM |
BFD_RELOC_SCORE_GOT15 |
ENUMX |
BFD_RELOC_SCORE_GOT_LO16 |
ENUMX |
BFD_RELOC_SCORE_CALL15 |
ENUMX |
BFD_RELOC_SCORE_DUMMY_HI16 |
ENUMDOC |
Undocumented Score relocs |
ENUM |
BFD_RELOC_IP2K_FR9 |
ENUMDOC |
Scenix IP2K - 9-bit register number / data address |
ENUM |
BFD_RELOC_IP2K_BANK |
ENUMDOC |
Scenix IP2K - 4-bit register/data bank number |
ENUM |
BFD_RELOC_IP2K_ADDR16CJP |
ENUMDOC |
Scenix IP2K - low 13 bits of instruction word address |
ENUM |
BFD_RELOC_IP2K_PAGE3 |
ENUMDOC |
Scenix IP2K - high 3 bits of instruction word address |
ENUM |
BFD_RELOC_IP2K_LO8DATA |
ENUMX |
BFD_RELOC_IP2K_HI8DATA |
ENUMX |
BFD_RELOC_IP2K_EX8DATA |
ENUMDOC |
Scenix IP2K - ext/low/high 8 bits of data address |
ENUM |
BFD_RELOC_IP2K_LO8INSN |
ENUMX |
BFD_RELOC_IP2K_HI8INSN |
ENUMDOC |
Scenix IP2K - low/high 8 bits of instruction word address |
ENUM |
BFD_RELOC_IP2K_PC_SKIP |
ENUMDOC |
Scenix IP2K - even/odd PC modifier to modify snb pcl.0 |
ENUM |
BFD_RELOC_IP2K_TEXT |
ENUMDOC |
Scenix IP2K - 16 bit word address in text section. |
ENUM |
BFD_RELOC_IP2K_FR_OFFSET |
ENUMDOC |
Scenix IP2K - 7-bit sp or dp offset |
ENUM |
BFD_RELOC_VPE4KMATH_DATA |
ENUMX |
BFD_RELOC_VPE4KMATH_INSN |
ENUMDOC |
Scenix VPE4K coprocessor - data/insn-space addressing |
ENUM |
BFD_RELOC_VTABLE_INHERIT |
ENUMX |
BFD_RELOC_VTABLE_ENTRY |
ENUMDOC |
These two relocations are used by the linker to determine which of |
the entries in a C++ virtual function table are actually used. When |
the --gc-sections option is given, the linker will zero out the entries |
that are not used, so that the code for those functions need not be |
included in the output. |
VTABLE_INHERIT is a zero-space relocation used to describe to the |
linker the inheritance tree of a C++ virtual function table. The |
relocation's symbol should be the parent class' vtable, and the |
relocation should be located at the child vtable. |
VTABLE_ENTRY is a zero-space relocation that describes the use of a |
virtual function table entry. The reloc's symbol should refer to the |
table of the class mentioned in the code. Off of that base, an offset |
describes the entry that is being used. For Rela hosts, this offset |
is stored in the reloc's addend. For Rel hosts, we are forced to put |
this offset in the reloc's section offset. |
ENUM |
BFD_RELOC_IA64_IMM14 |
ENUMX |
BFD_RELOC_IA64_IMM22 |
ENUMX |
BFD_RELOC_IA64_IMM64 |
ENUMX |
BFD_RELOC_IA64_DIR32MSB |
ENUMX |
BFD_RELOC_IA64_DIR32LSB |
ENUMX |
BFD_RELOC_IA64_DIR64MSB |
ENUMX |
BFD_RELOC_IA64_DIR64LSB |
ENUMX |
BFD_RELOC_IA64_GPREL22 |
ENUMX |
BFD_RELOC_IA64_GPREL64I |
ENUMX |
BFD_RELOC_IA64_GPREL32MSB |
ENUMX |
BFD_RELOC_IA64_GPREL32LSB |
ENUMX |
BFD_RELOC_IA64_GPREL64MSB |
ENUMX |
BFD_RELOC_IA64_GPREL64LSB |
ENUMX |
BFD_RELOC_IA64_LTOFF22 |
ENUMX |
BFD_RELOC_IA64_LTOFF64I |
ENUMX |
BFD_RELOC_IA64_PLTOFF22 |
ENUMX |
BFD_RELOC_IA64_PLTOFF64I |
ENUMX |
BFD_RELOC_IA64_PLTOFF64MSB |
ENUMX |
BFD_RELOC_IA64_PLTOFF64LSB |
ENUMX |
BFD_RELOC_IA64_FPTR64I |
ENUMX |
BFD_RELOC_IA64_FPTR32MSB |
ENUMX |
BFD_RELOC_IA64_FPTR32LSB |
ENUMX |
BFD_RELOC_IA64_FPTR64MSB |
ENUMX |
BFD_RELOC_IA64_FPTR64LSB |
ENUMX |
BFD_RELOC_IA64_PCREL21B |
ENUMX |
BFD_RELOC_IA64_PCREL21BI |
ENUMX |
BFD_RELOC_IA64_PCREL21M |
ENUMX |
BFD_RELOC_IA64_PCREL21F |
ENUMX |
BFD_RELOC_IA64_PCREL22 |
ENUMX |
BFD_RELOC_IA64_PCREL60B |
ENUMX |
BFD_RELOC_IA64_PCREL64I |
ENUMX |
BFD_RELOC_IA64_PCREL32MSB |
ENUMX |
BFD_RELOC_IA64_PCREL32LSB |
ENUMX |
BFD_RELOC_IA64_PCREL64MSB |
ENUMX |
BFD_RELOC_IA64_PCREL64LSB |
ENUMX |
BFD_RELOC_IA64_LTOFF_FPTR22 |
ENUMX |
BFD_RELOC_IA64_LTOFF_FPTR64I |
ENUMX |
BFD_RELOC_IA64_LTOFF_FPTR32MSB |
ENUMX |
BFD_RELOC_IA64_LTOFF_FPTR32LSB |
ENUMX |
BFD_RELOC_IA64_LTOFF_FPTR64MSB |
ENUMX |
BFD_RELOC_IA64_LTOFF_FPTR64LSB |
ENUMX |
BFD_RELOC_IA64_SEGREL32MSB |
ENUMX |
BFD_RELOC_IA64_SEGREL32LSB |
ENUMX |
BFD_RELOC_IA64_SEGREL64MSB |
ENUMX |
BFD_RELOC_IA64_SEGREL64LSB |
ENUMX |
BFD_RELOC_IA64_SECREL32MSB |
ENUMX |
BFD_RELOC_IA64_SECREL32LSB |
ENUMX |
BFD_RELOC_IA64_SECREL64MSB |
ENUMX |
BFD_RELOC_IA64_SECREL64LSB |
ENUMX |
BFD_RELOC_IA64_REL32MSB |
ENUMX |
BFD_RELOC_IA64_REL32LSB |
ENUMX |
BFD_RELOC_IA64_REL64MSB |
ENUMX |
BFD_RELOC_IA64_REL64LSB |
ENUMX |
BFD_RELOC_IA64_LTV32MSB |
ENUMX |
BFD_RELOC_IA64_LTV32LSB |
ENUMX |
BFD_RELOC_IA64_LTV64MSB |
ENUMX |
BFD_RELOC_IA64_LTV64LSB |
ENUMX |
BFD_RELOC_IA64_IPLTMSB |
ENUMX |
BFD_RELOC_IA64_IPLTLSB |
ENUMX |
BFD_RELOC_IA64_COPY |
ENUMX |
BFD_RELOC_IA64_LTOFF22X |
ENUMX |
BFD_RELOC_IA64_LDXMOV |
ENUMX |
BFD_RELOC_IA64_TPREL14 |
ENUMX |
BFD_RELOC_IA64_TPREL22 |
ENUMX |
BFD_RELOC_IA64_TPREL64I |
ENUMX |
BFD_RELOC_IA64_TPREL64MSB |
ENUMX |
BFD_RELOC_IA64_TPREL64LSB |
ENUMX |
BFD_RELOC_IA64_LTOFF_TPREL22 |
ENUMX |
BFD_RELOC_IA64_DTPMOD64MSB |
ENUMX |
BFD_RELOC_IA64_DTPMOD64LSB |
ENUMX |
BFD_RELOC_IA64_LTOFF_DTPMOD22 |
ENUMX |
BFD_RELOC_IA64_DTPREL14 |
ENUMX |
BFD_RELOC_IA64_DTPREL22 |
ENUMX |
BFD_RELOC_IA64_DTPREL64I |
ENUMX |
BFD_RELOC_IA64_DTPREL32MSB |
ENUMX |
BFD_RELOC_IA64_DTPREL32LSB |
ENUMX |
BFD_RELOC_IA64_DTPREL64MSB |
ENUMX |
BFD_RELOC_IA64_DTPREL64LSB |
ENUMX |
BFD_RELOC_IA64_LTOFF_DTPREL22 |
ENUMDOC |
Intel IA64 Relocations. |
ENUM |
BFD_RELOC_M68HC11_HI8 |
ENUMDOC |
Motorola 68HC11 reloc. |
This is the 8 bit high part of an absolute address. |
ENUM |
BFD_RELOC_M68HC11_LO8 |
ENUMDOC |
Motorola 68HC11 reloc. |
This is the 8 bit low part of an absolute address. |
ENUM |
BFD_RELOC_M68HC11_3B |
ENUMDOC |
Motorola 68HC11 reloc. |
This is the 3 bit of a value. |
ENUM |
BFD_RELOC_M68HC11_RL_JUMP |
ENUMDOC |
Motorola 68HC11 reloc. |
This reloc marks the beginning of a jump/call instruction. |
It is used for linker relaxation to correctly identify beginning |
of instruction and change some branches to use PC-relative |
addressing mode. |
ENUM |
BFD_RELOC_M68HC11_RL_GROUP |
ENUMDOC |
Motorola 68HC11 reloc. |
This reloc marks a group of several instructions that gcc generates |
and for which the linker relaxation pass can modify and/or remove |
some of them. |
ENUM |
BFD_RELOC_M68HC11_LO16 |
ENUMDOC |
Motorola 68HC11 reloc. |
This is the 16-bit lower part of an address. It is used for 'call' |
instruction to specify the symbol address without any special |
transformation (due to memory bank window). |
ENUM |
BFD_RELOC_M68HC11_PAGE |
ENUMDOC |
Motorola 68HC11 reloc. |
This is a 8-bit reloc that specifies the page number of an address. |
It is used by 'call' instruction to specify the page number of |
the symbol. |
ENUM |
BFD_RELOC_M68HC11_24 |
ENUMDOC |
Motorola 68HC11 reloc. |
This is a 24-bit reloc that represents the address with a 16-bit |
value and a 8-bit page number. The symbol address is transformed |
to follow the 16K memory bank of 68HC12 (seen as mapped in the window). |
ENUM |
BFD_RELOC_M68HC12_5B |
ENUMDOC |
Motorola 68HC12 reloc. |
This is the 5 bits of a value. |
ENUM |
BFD_RELOC_XGATE_RL_JUMP |
ENUMDOC |
Freescale XGATE reloc. |
This reloc marks the beginning of a bra/jal instruction. |
ENUM |
BFD_RELOC_XGATE_RL_GROUP |
ENUMDOC |
Freescale XGATE reloc. |
This reloc marks a group of several instructions that gcc generates |
and for which the linker relaxation pass can modify and/or remove |
some of them. |
ENUM |
BFD_RELOC_XGATE_LO16 |
ENUMDOC |
Freescale XGATE reloc. |
This is the 16-bit lower part of an address. It is used for the '16-bit' |
instructions. |
ENUM |
BFD_RELOC_XGATE_GPAGE |
ENUMDOC |
Freescale XGATE reloc. |
ENUM |
BFD_RELOC_XGATE_24 |
ENUMDOC |
Freescale XGATE reloc. |
ENUM |
BFD_RELOC_XGATE_PCREL_9 |
ENUMDOC |
Freescale XGATE reloc. |
This is a 9-bit pc-relative reloc. |
ENUM |
BFD_RELOC_XGATE_PCREL_10 |
ENUMDOC |
Freescale XGATE reloc. |
This is a 10-bit pc-relative reloc. |
ENUM |
BFD_RELOC_XGATE_IMM8_LO |
ENUMDOC |
Freescale XGATE reloc. |
This is the 16-bit lower part of an address. It is used for the '16-bit' |
instructions. |
ENUM |
BFD_RELOC_XGATE_IMM8_HI |
ENUMDOC |
Freescale XGATE reloc. |
This is the 16-bit higher part of an address. It is used for the '16-bit' |
instructions. |
ENUM |
BFD_RELOC_XGATE_IMM3 |
ENUMDOC |
Freescale XGATE reloc. |
This is a 3-bit pc-relative reloc. |
ENUM |
BFD_RELOC_XGATE_IMM4 |
ENUMDOC |
Freescale XGATE reloc. |
This is a 4-bit pc-relative reloc. |
ENUM |
BFD_RELOC_XGATE_IMM5 |
ENUMDOC |
Freescale XGATE reloc. |
This is a 5-bit pc-relative reloc. |
ENUM |
BFD_RELOC_M68HC12_9B |
ENUMDOC |
Motorola 68HC12 reloc. |
This is the 9 bits of a value. |
ENUM |
BFD_RELOC_M68HC12_16B |
ENUMDOC |
Motorola 68HC12 reloc. |
This is the 16 bits of a value. |
ENUM |
BFD_RELOC_M68HC12_9_PCREL |
ENUMDOC |
Motorola 68HC12/XGATE reloc. |
This is a PCREL9 branch. |
ENUM |
BFD_RELOC_M68HC12_10_PCREL |
ENUMDOC |
Motorola 68HC12/XGATE reloc. |
This is a PCREL10 branch. |
ENUM |
BFD_RELOC_M68HC12_LO8XG |
ENUMDOC |
Motorola 68HC12/XGATE reloc. |
This is the 8 bit low part of an absolute address and immediately precedes |
a matching HI8XG part. |
ENUM |
BFD_RELOC_M68HC12_HI8XG |
ENUMDOC |
Motorola 68HC12/XGATE reloc. |
This is the 8 bit high part of an absolute address and immediately follows |
a matching LO8XG part. |
ENUM |
BFD_RELOC_16C_NUM08 |
ENUMX |
BFD_RELOC_16C_NUM08_C |
ENUMX |
BFD_RELOC_16C_NUM16 |
ENUMX |
BFD_RELOC_16C_NUM16_C |
ENUMX |
BFD_RELOC_16C_NUM32 |
ENUMX |
BFD_RELOC_16C_NUM32_C |
ENUMX |
BFD_RELOC_16C_DISP04 |
ENUMX |
BFD_RELOC_16C_DISP04_C |
ENUMX |
BFD_RELOC_16C_DISP08 |
ENUMX |
BFD_RELOC_16C_DISP08_C |
ENUMX |
BFD_RELOC_16C_DISP16 |
ENUMX |
BFD_RELOC_16C_DISP16_C |
ENUMX |
BFD_RELOC_16C_DISP24 |
ENUMX |
BFD_RELOC_16C_DISP24_C |
ENUMX |
BFD_RELOC_16C_DISP24a |
ENUMX |
BFD_RELOC_16C_DISP24a_C |
ENUMX |
BFD_RELOC_16C_REG04 |
ENUMX |
BFD_RELOC_16C_REG04_C |
ENUMX |
BFD_RELOC_16C_REG04a |
ENUMX |
BFD_RELOC_16C_REG04a_C |
ENUMX |
BFD_RELOC_16C_REG14 |
ENUMX |
BFD_RELOC_16C_REG14_C |
ENUMX |
BFD_RELOC_16C_REG16 |
ENUMX |
BFD_RELOC_16C_REG16_C |
ENUMX |
BFD_RELOC_16C_REG20 |
ENUMX |
BFD_RELOC_16C_REG20_C |
ENUMX |
BFD_RELOC_16C_ABS20 |
ENUMX |
BFD_RELOC_16C_ABS20_C |
ENUMX |
BFD_RELOC_16C_ABS24 |
ENUMX |
BFD_RELOC_16C_ABS24_C |
ENUMX |
BFD_RELOC_16C_IMM04 |
ENUMX |
BFD_RELOC_16C_IMM04_C |
ENUMX |
BFD_RELOC_16C_IMM16 |
ENUMX |
BFD_RELOC_16C_IMM16_C |
ENUMX |
BFD_RELOC_16C_IMM20 |
ENUMX |
BFD_RELOC_16C_IMM20_C |
ENUMX |
BFD_RELOC_16C_IMM24 |
ENUMX |
BFD_RELOC_16C_IMM24_C |
ENUMX |
BFD_RELOC_16C_IMM32 |
ENUMX |
BFD_RELOC_16C_IMM32_C |
ENUMDOC |
NS CR16C Relocations. |
ENUM |
BFD_RELOC_CR16_NUM8 |
ENUMX |
BFD_RELOC_CR16_NUM16 |
ENUMX |
BFD_RELOC_CR16_NUM32 |
ENUMX |
BFD_RELOC_CR16_NUM32a |
ENUMX |
BFD_RELOC_CR16_REGREL0 |
ENUMX |
BFD_RELOC_CR16_REGREL4 |
ENUMX |
BFD_RELOC_CR16_REGREL4a |
ENUMX |
BFD_RELOC_CR16_REGREL14 |
ENUMX |
BFD_RELOC_CR16_REGREL14a |
ENUMX |
BFD_RELOC_CR16_REGREL16 |
ENUMX |
BFD_RELOC_CR16_REGREL20 |
ENUMX |
BFD_RELOC_CR16_REGREL20a |
ENUMX |
BFD_RELOC_CR16_ABS20 |
ENUMX |
BFD_RELOC_CR16_ABS24 |
ENUMX |
BFD_RELOC_CR16_IMM4 |
ENUMX |
BFD_RELOC_CR16_IMM8 |
ENUMX |
BFD_RELOC_CR16_IMM16 |
ENUMX |
BFD_RELOC_CR16_IMM20 |
ENUMX |
BFD_RELOC_CR16_IMM24 |
ENUMX |
BFD_RELOC_CR16_IMM32 |
ENUMX |
BFD_RELOC_CR16_IMM32a |
ENUMX |
BFD_RELOC_CR16_DISP4 |
ENUMX |
BFD_RELOC_CR16_DISP8 |
ENUMX |
BFD_RELOC_CR16_DISP16 |
ENUMX |
BFD_RELOC_CR16_DISP20 |
ENUMX |
BFD_RELOC_CR16_DISP24 |
ENUMX |
BFD_RELOC_CR16_DISP24a |
ENUMX |
BFD_RELOC_CR16_SWITCH8 |
ENUMX |
BFD_RELOC_CR16_SWITCH16 |
ENUMX |
BFD_RELOC_CR16_SWITCH32 |
ENUMX |
BFD_RELOC_CR16_GOT_REGREL20 |
ENUMX |
BFD_RELOC_CR16_GOTC_REGREL20 |
ENUMX |
BFD_RELOC_CR16_GLOB_DAT |
ENUMDOC |
NS CR16 Relocations. |
ENUM |
BFD_RELOC_CRX_REL4 |
ENUMX |
BFD_RELOC_CRX_REL8 |
ENUMX |
BFD_RELOC_CRX_REL8_CMP |
ENUMX |
BFD_RELOC_CRX_REL16 |
ENUMX |
BFD_RELOC_CRX_REL24 |
ENUMX |
BFD_RELOC_CRX_REL32 |
ENUMX |
BFD_RELOC_CRX_REGREL12 |
ENUMX |
BFD_RELOC_CRX_REGREL22 |
ENUMX |
BFD_RELOC_CRX_REGREL28 |
ENUMX |
BFD_RELOC_CRX_REGREL32 |
ENUMX |
BFD_RELOC_CRX_ABS16 |
ENUMX |
BFD_RELOC_CRX_ABS32 |
ENUMX |
BFD_RELOC_CRX_NUM8 |
ENUMX |
BFD_RELOC_CRX_NUM16 |
ENUMX |
BFD_RELOC_CRX_NUM32 |
ENUMX |
BFD_RELOC_CRX_IMM16 |
ENUMX |
BFD_RELOC_CRX_IMM32 |
ENUMX |
BFD_RELOC_CRX_SWITCH8 |
ENUMX |
BFD_RELOC_CRX_SWITCH16 |
ENUMX |
BFD_RELOC_CRX_SWITCH32 |
ENUMDOC |
NS CRX Relocations. |
ENUM |
BFD_RELOC_CRIS_BDISP8 |
ENUMX |
BFD_RELOC_CRIS_UNSIGNED_5 |
ENUMX |
BFD_RELOC_CRIS_SIGNED_6 |
ENUMX |
BFD_RELOC_CRIS_UNSIGNED_6 |
ENUMX |
BFD_RELOC_CRIS_SIGNED_8 |
ENUMX |
BFD_RELOC_CRIS_UNSIGNED_8 |
ENUMX |
BFD_RELOC_CRIS_SIGNED_16 |
ENUMX |
BFD_RELOC_CRIS_UNSIGNED_16 |
ENUMX |
BFD_RELOC_CRIS_LAPCQ_OFFSET |
ENUMX |
BFD_RELOC_CRIS_UNSIGNED_4 |
ENUMDOC |
These relocs are only used within the CRIS assembler. They are not |
(at present) written to any object files. |
ENUM |
BFD_RELOC_CRIS_COPY |
ENUMX |
BFD_RELOC_CRIS_GLOB_DAT |
ENUMX |
BFD_RELOC_CRIS_JUMP_SLOT |
ENUMX |
BFD_RELOC_CRIS_RELATIVE |
ENUMDOC |
Relocs used in ELF shared libraries for CRIS. |
ENUM |
BFD_RELOC_CRIS_32_GOT |
ENUMDOC |
32-bit offset to symbol-entry within GOT. |
ENUM |
BFD_RELOC_CRIS_16_GOT |
ENUMDOC |
16-bit offset to symbol-entry within GOT. |
ENUM |
BFD_RELOC_CRIS_32_GOTPLT |
ENUMDOC |
32-bit offset to symbol-entry within GOT, with PLT handling. |
ENUM |
BFD_RELOC_CRIS_16_GOTPLT |
ENUMDOC |
16-bit offset to symbol-entry within GOT, with PLT handling. |
ENUM |
BFD_RELOC_CRIS_32_GOTREL |
ENUMDOC |
32-bit offset to symbol, relative to GOT. |
ENUM |
BFD_RELOC_CRIS_32_PLT_GOTREL |
ENUMDOC |
32-bit offset to symbol with PLT entry, relative to GOT. |
ENUM |
BFD_RELOC_CRIS_32_PLT_PCREL |
ENUMDOC |
32-bit offset to symbol with PLT entry, relative to this relocation. |
ENUM |
BFD_RELOC_CRIS_32_GOT_GD |
ENUMX |
BFD_RELOC_CRIS_16_GOT_GD |
ENUMX |
BFD_RELOC_CRIS_32_GD |
ENUMX |
BFD_RELOC_CRIS_DTP |
ENUMX |
BFD_RELOC_CRIS_32_DTPREL |
ENUMX |
BFD_RELOC_CRIS_16_DTPREL |
ENUMX |
BFD_RELOC_CRIS_32_GOT_TPREL |
ENUMX |
BFD_RELOC_CRIS_16_GOT_TPREL |
ENUMX |
BFD_RELOC_CRIS_32_TPREL |
ENUMX |
BFD_RELOC_CRIS_16_TPREL |
ENUMX |
BFD_RELOC_CRIS_DTPMOD |
ENUMX |
BFD_RELOC_CRIS_32_IE |
ENUMDOC |
Relocs used in TLS code for CRIS. |
ENUM |
BFD_RELOC_860_COPY |
ENUMX |
BFD_RELOC_860_GLOB_DAT |
ENUMX |
BFD_RELOC_860_JUMP_SLOT |
ENUMX |
BFD_RELOC_860_RELATIVE |
ENUMX |
BFD_RELOC_860_PC26 |
ENUMX |
BFD_RELOC_860_PLT26 |
ENUMX |
BFD_RELOC_860_PC16 |
ENUMX |
BFD_RELOC_860_LOW0 |
ENUMX |
BFD_RELOC_860_SPLIT0 |
ENUMX |
BFD_RELOC_860_LOW1 |
ENUMX |
BFD_RELOC_860_SPLIT1 |
ENUMX |
BFD_RELOC_860_LOW2 |
ENUMX |
BFD_RELOC_860_SPLIT2 |
ENUMX |
BFD_RELOC_860_LOW3 |
ENUMX |
BFD_RELOC_860_LOGOT0 |
ENUMX |
BFD_RELOC_860_SPGOT0 |
ENUMX |
BFD_RELOC_860_LOGOT1 |
ENUMX |
BFD_RELOC_860_SPGOT1 |
ENUMX |
BFD_RELOC_860_LOGOTOFF0 |
ENUMX |
BFD_RELOC_860_SPGOTOFF0 |
ENUMX |
BFD_RELOC_860_LOGOTOFF1 |
ENUMX |
BFD_RELOC_860_SPGOTOFF1 |
ENUMX |
BFD_RELOC_860_LOGOTOFF2 |
ENUMX |
BFD_RELOC_860_LOGOTOFF3 |
ENUMX |
BFD_RELOC_860_LOPC |
ENUMX |
BFD_RELOC_860_HIGHADJ |
ENUMX |
BFD_RELOC_860_HAGOT |
ENUMX |
BFD_RELOC_860_HAGOTOFF |
ENUMX |
BFD_RELOC_860_HAPC |
ENUMX |
BFD_RELOC_860_HIGH |
ENUMX |
BFD_RELOC_860_HIGOT |
ENUMX |
BFD_RELOC_860_HIGOTOFF |
ENUMDOC |
Intel i860 Relocations. |
ENUM |
BFD_RELOC_OPENRISC_ABS_26 |
ENUMX |
BFD_RELOC_OPENRISC_REL_26 |
ENUMDOC |
OpenRISC Relocations. |
ENUM |
BFD_RELOC_H8_DIR16A8 |
ENUMX |
BFD_RELOC_H8_DIR16R8 |
ENUMX |
BFD_RELOC_H8_DIR24A8 |
ENUMX |
BFD_RELOC_H8_DIR24R8 |
ENUMX |
BFD_RELOC_H8_DIR32A16 |
ENUMX |
BFD_RELOC_H8_DISP32A16 |
ENUMDOC |
H8 elf Relocations. |
ENUM |
BFD_RELOC_XSTORMY16_REL_12 |
ENUMX |
BFD_RELOC_XSTORMY16_12 |
ENUMX |
BFD_RELOC_XSTORMY16_24 |
ENUMX |
BFD_RELOC_XSTORMY16_FPTR16 |
ENUMDOC |
Sony Xstormy16 Relocations. |
ENUM |
BFD_RELOC_RELC |
ENUMDOC |
Self-describing complex relocations. |
COMMENT |
ENUM |
BFD_RELOC_XC16X_PAG |
ENUMX |
BFD_RELOC_XC16X_POF |
ENUMX |
BFD_RELOC_XC16X_SEG |
ENUMX |
BFD_RELOC_XC16X_SOF |
ENUMDOC |
Infineon Relocations. |
ENUM |
BFD_RELOC_VAX_GLOB_DAT |
ENUMX |
BFD_RELOC_VAX_JMP_SLOT |
ENUMX |
BFD_RELOC_VAX_RELATIVE |
ENUMDOC |
Relocations used by VAX ELF. |
ENUM |
BFD_RELOC_MT_PC16 |
ENUMDOC |
Morpho MT - 16 bit immediate relocation. |
ENUM |
BFD_RELOC_MT_HI16 |
ENUMDOC |
Morpho MT - Hi 16 bits of an address. |
ENUM |
BFD_RELOC_MT_LO16 |
ENUMDOC |
Morpho MT - Low 16 bits of an address. |
ENUM |
BFD_RELOC_MT_GNU_VTINHERIT |
ENUMDOC |
Morpho MT - Used to tell the linker which vtable entries are used. |
ENUM |
BFD_RELOC_MT_GNU_VTENTRY |
ENUMDOC |
Morpho MT - Used to tell the linker which vtable entries are used. |
ENUM |
BFD_RELOC_MT_PCINSN8 |
ENUMDOC |
Morpho MT - 8 bit immediate relocation. |
ENUM |
BFD_RELOC_MSP430_10_PCREL |
ENUMX |
BFD_RELOC_MSP430_16_PCREL |
ENUMX |
BFD_RELOC_MSP430_16 |
ENUMX |
BFD_RELOC_MSP430_16_PCREL_BYTE |
ENUMX |
BFD_RELOC_MSP430_16_BYTE |
ENUMX |
BFD_RELOC_MSP430_2X_PCREL |
ENUMX |
BFD_RELOC_MSP430_RL_PCREL |
ENUMX |
BFD_RELOC_MSP430_ABS8 |
ENUMX |
BFD_RELOC_MSP430X_PCR20_EXT_SRC |
ENUMX |
BFD_RELOC_MSP430X_PCR20_EXT_DST |
ENUMX |
BFD_RELOC_MSP430X_PCR20_EXT_ODST |
ENUMX |
BFD_RELOC_MSP430X_ABS20_EXT_SRC |
ENUMX |
BFD_RELOC_MSP430X_ABS20_EXT_DST |
ENUMX |
BFD_RELOC_MSP430X_ABS20_EXT_ODST |
ENUMX |
BFD_RELOC_MSP430X_ABS20_ADR_SRC |
ENUMX |
BFD_RELOC_MSP430X_ABS20_ADR_DST |
ENUMX |
BFD_RELOC_MSP430X_PCR16 |
ENUMX |
BFD_RELOC_MSP430X_PCR20_CALL |
ENUMX |
BFD_RELOC_MSP430X_ABS16 |
ENUMX |
BFD_RELOC_MSP430_ABS_HI16 |
ENUMX |
BFD_RELOC_MSP430_PREL31 |
ENUMX |
BFD_RELOC_MSP430_SYM_DIFF |
ENUMDOC |
msp430 specific relocation codes |
ENUM |
BFD_RELOC_NIOS2_S16 |
ENUMX |
BFD_RELOC_NIOS2_U16 |
ENUMX |
BFD_RELOC_NIOS2_CALL26 |
ENUMX |
BFD_RELOC_NIOS2_IMM5 |
ENUMX |
BFD_RELOC_NIOS2_CACHE_OPX |
ENUMX |
BFD_RELOC_NIOS2_IMM6 |
ENUMX |
BFD_RELOC_NIOS2_IMM8 |
ENUMX |
BFD_RELOC_NIOS2_HI16 |
ENUMX |
BFD_RELOC_NIOS2_LO16 |
ENUMX |
BFD_RELOC_NIOS2_HIADJ16 |
ENUMX |
BFD_RELOC_NIOS2_GPREL |
ENUMX |
BFD_RELOC_NIOS2_UJMP |
ENUMX |
BFD_RELOC_NIOS2_CJMP |
ENUMX |
BFD_RELOC_NIOS2_CALLR |
ENUMX |
BFD_RELOC_NIOS2_ALIGN |
ENUMX |
BFD_RELOC_NIOS2_GOT16 |
ENUMX |
BFD_RELOC_NIOS2_CALL16 |
ENUMX |
BFD_RELOC_NIOS2_GOTOFF_LO |
ENUMX |
BFD_RELOC_NIOS2_GOTOFF_HA |
ENUMX |
BFD_RELOC_NIOS2_PCREL_LO |
ENUMX |
BFD_RELOC_NIOS2_PCREL_HA |
ENUMX |
BFD_RELOC_NIOS2_TLS_GD16 |
ENUMX |
BFD_RELOC_NIOS2_TLS_LDM16 |
ENUMX |
BFD_RELOC_NIOS2_TLS_LDO16 |
ENUMX |
BFD_RELOC_NIOS2_TLS_IE16 |
ENUMX |
BFD_RELOC_NIOS2_TLS_LE16 |
ENUMX |
BFD_RELOC_NIOS2_TLS_DTPMOD |
ENUMX |
BFD_RELOC_NIOS2_TLS_DTPREL |
ENUMX |
BFD_RELOC_NIOS2_TLS_TPREL |
ENUMX |
BFD_RELOC_NIOS2_COPY |
ENUMX |
BFD_RELOC_NIOS2_GLOB_DAT |
ENUMX |
BFD_RELOC_NIOS2_JUMP_SLOT |
ENUMX |
BFD_RELOC_NIOS2_RELATIVE |
ENUMX |
BFD_RELOC_NIOS2_GOTOFF |
ENUMDOC |
Relocations used by the Altera Nios II core. |
ENUM |
BFD_RELOC_IQ2000_OFFSET_16 |
ENUMX |
BFD_RELOC_IQ2000_OFFSET_21 |
ENUMX |
BFD_RELOC_IQ2000_UHI16 |
ENUMDOC |
IQ2000 Relocations. |
ENUM |
BFD_RELOC_XTENSA_RTLD |
ENUMDOC |
Special Xtensa relocation used only by PLT entries in ELF shared |
objects to indicate that the runtime linker should set the value |
to one of its own internal functions or data structures. |
ENUM |
BFD_RELOC_XTENSA_GLOB_DAT |
ENUMX |
BFD_RELOC_XTENSA_JMP_SLOT |
ENUMX |
BFD_RELOC_XTENSA_RELATIVE |
ENUMDOC |
Xtensa relocations for ELF shared objects. |
ENUM |
BFD_RELOC_XTENSA_PLT |
ENUMDOC |
Xtensa relocation used in ELF object files for symbols that may require |
PLT entries. Otherwise, this is just a generic 32-bit relocation. |
ENUM |
BFD_RELOC_XTENSA_DIFF8 |
ENUMX |
BFD_RELOC_XTENSA_DIFF16 |
ENUMX |
BFD_RELOC_XTENSA_DIFF32 |
ENUMDOC |
Xtensa relocations to mark the difference of two local symbols. |
These are only needed to support linker relaxation and can be ignored |
when not relaxing. The field is set to the value of the difference |
assuming no relaxation. The relocation encodes the position of the |
first symbol so the linker can determine whether to adjust the field |
value. |
ENUM |
BFD_RELOC_XTENSA_SLOT0_OP |
ENUMX |
BFD_RELOC_XTENSA_SLOT1_OP |
ENUMX |
BFD_RELOC_XTENSA_SLOT2_OP |
ENUMX |
BFD_RELOC_XTENSA_SLOT3_OP |
ENUMX |
BFD_RELOC_XTENSA_SLOT4_OP |
ENUMX |
BFD_RELOC_XTENSA_SLOT5_OP |
ENUMX |
BFD_RELOC_XTENSA_SLOT6_OP |
ENUMX |
BFD_RELOC_XTENSA_SLOT7_OP |
ENUMX |
BFD_RELOC_XTENSA_SLOT8_OP |
ENUMX |
BFD_RELOC_XTENSA_SLOT9_OP |
ENUMX |
BFD_RELOC_XTENSA_SLOT10_OP |
ENUMX |
BFD_RELOC_XTENSA_SLOT11_OP |
ENUMX |
BFD_RELOC_XTENSA_SLOT12_OP |
ENUMX |
BFD_RELOC_XTENSA_SLOT13_OP |
ENUMX |
BFD_RELOC_XTENSA_SLOT14_OP |
ENUMDOC |
Generic Xtensa relocations for instruction operands. Only the slot |
number is encoded in the relocation. The relocation applies to the |
last PC-relative immediate operand, or if there are no PC-relative |
immediates, to the last immediate operand. |
ENUM |
BFD_RELOC_XTENSA_SLOT0_ALT |
ENUMX |
BFD_RELOC_XTENSA_SLOT1_ALT |
ENUMX |
BFD_RELOC_XTENSA_SLOT2_ALT |
ENUMX |
BFD_RELOC_XTENSA_SLOT3_ALT |
ENUMX |
BFD_RELOC_XTENSA_SLOT4_ALT |
ENUMX |
BFD_RELOC_XTENSA_SLOT5_ALT |
ENUMX |
BFD_RELOC_XTENSA_SLOT6_ALT |
ENUMX |
BFD_RELOC_XTENSA_SLOT7_ALT |
ENUMX |
BFD_RELOC_XTENSA_SLOT8_ALT |
ENUMX |
BFD_RELOC_XTENSA_SLOT9_ALT |
ENUMX |
BFD_RELOC_XTENSA_SLOT10_ALT |
ENUMX |
BFD_RELOC_XTENSA_SLOT11_ALT |
ENUMX |
BFD_RELOC_XTENSA_SLOT12_ALT |
ENUMX |
BFD_RELOC_XTENSA_SLOT13_ALT |
ENUMX |
BFD_RELOC_XTENSA_SLOT14_ALT |
ENUMDOC |
Alternate Xtensa relocations. Only the slot is encoded in the |
relocation. The meaning of these relocations is opcode-specific. |
ENUM |
BFD_RELOC_XTENSA_OP0 |
ENUMX |
BFD_RELOC_XTENSA_OP1 |
ENUMX |
BFD_RELOC_XTENSA_OP2 |
ENUMDOC |
Xtensa relocations for backward compatibility. These have all been |
replaced by BFD_RELOC_XTENSA_SLOT0_OP. |
ENUM |
BFD_RELOC_XTENSA_ASM_EXPAND |
ENUMDOC |
Xtensa relocation to mark that the assembler expanded the |
instructions from an original target. The expansion size is |
encoded in the reloc size. |
ENUM |
BFD_RELOC_XTENSA_ASM_SIMPLIFY |
ENUMDOC |
Xtensa relocation to mark that the linker should simplify |
assembler-expanded instructions. This is commonly used |
internally by the linker after analysis of a |
BFD_RELOC_XTENSA_ASM_EXPAND. |
ENUM |
BFD_RELOC_XTENSA_TLSDESC_FN |
ENUMX |
BFD_RELOC_XTENSA_TLSDESC_ARG |
ENUMX |
BFD_RELOC_XTENSA_TLS_DTPOFF |
ENUMX |
BFD_RELOC_XTENSA_TLS_TPOFF |
ENUMX |
BFD_RELOC_XTENSA_TLS_FUNC |
ENUMX |
BFD_RELOC_XTENSA_TLS_ARG |
ENUMX |
BFD_RELOC_XTENSA_TLS_CALL |
ENUMDOC |
Xtensa TLS relocations. |
ENUM |
BFD_RELOC_Z80_DISP8 |
ENUMDOC |
8 bit signed offset in (ix+d) or (iy+d). |
ENUM |
BFD_RELOC_Z8K_DISP7 |
ENUMDOC |
DJNZ offset. |
ENUM |
BFD_RELOC_Z8K_CALLR |
ENUMDOC |
CALR offset. |
ENUM |
BFD_RELOC_Z8K_IMM4L |
ENUMDOC |
4 bit value. |
ENUM |
BFD_RELOC_LM32_CALL |
ENUMX |
BFD_RELOC_LM32_BRANCH |
ENUMX |
BFD_RELOC_LM32_16_GOT |
ENUMX |
BFD_RELOC_LM32_GOTOFF_HI16 |
ENUMX |
BFD_RELOC_LM32_GOTOFF_LO16 |
ENUMX |
BFD_RELOC_LM32_COPY |
ENUMX |
BFD_RELOC_LM32_GLOB_DAT |
ENUMX |
BFD_RELOC_LM32_JMP_SLOT |
ENUMX |
BFD_RELOC_LM32_RELATIVE |
ENUMDOC |
Lattice Mico32 relocations. |
ENUM |
BFD_RELOC_MACH_O_SECTDIFF |
ENUMDOC |
Difference between two section addreses. Must be followed by a |
BFD_RELOC_MACH_O_PAIR. |
ENUM |
BFD_RELOC_MACH_O_LOCAL_SECTDIFF |
ENUMDOC |
Like BFD_RELOC_MACH_O_SECTDIFF but with a local symbol. |
ENUM |
BFD_RELOC_MACH_O_PAIR |
ENUMDOC |
Pair of relocation. Contains the first symbol. |
ENUM |
BFD_RELOC_MACH_O_X86_64_BRANCH32 |
ENUMX |
BFD_RELOC_MACH_O_X86_64_BRANCH8 |
ENUMDOC |
PCREL relocations. They are marked as branch to create PLT entry if |
required. |
ENUM |
BFD_RELOC_MACH_O_X86_64_GOT |
ENUMDOC |
Used when referencing a GOT entry. |
ENUM |
BFD_RELOC_MACH_O_X86_64_GOT_LOAD |
ENUMDOC |
Used when loading a GOT entry with movq. It is specially marked so that |
the linker could optimize the movq to a leaq if possible. |
ENUM |
BFD_RELOC_MACH_O_X86_64_SUBTRACTOR32 |
ENUMDOC |
Symbol will be substracted. Must be followed by a BFD_RELOC_64. |
ENUM |
BFD_RELOC_MACH_O_X86_64_SUBTRACTOR64 |
ENUMDOC |
Symbol will be substracted. Must be followed by a BFD_RELOC_64. |
ENUM |
BFD_RELOC_MACH_O_X86_64_PCREL32_1 |
ENUMDOC |
Same as BFD_RELOC_32_PCREL but with an implicit -1 addend. |
ENUM |
BFD_RELOC_MACH_O_X86_64_PCREL32_2 |
ENUMDOC |
Same as BFD_RELOC_32_PCREL but with an implicit -2 addend. |
ENUM |
BFD_RELOC_MACH_O_X86_64_PCREL32_4 |
ENUMDOC |
Same as BFD_RELOC_32_PCREL but with an implicit -4 addend. |
ENUM |
BFD_RELOC_MICROBLAZE_32_LO |
ENUMDOC |
This is a 32 bit reloc for the microblaze that stores the |
low 16 bits of a value |
ENUM |
BFD_RELOC_MICROBLAZE_32_LO_PCREL |
ENUMDOC |
This is a 32 bit pc-relative reloc for the microblaze that |
stores the low 16 bits of a value |
ENUM |
BFD_RELOC_MICROBLAZE_32_ROSDA |
ENUMDOC |
This is a 32 bit reloc for the microblaze that stores a |
value relative to the read-only small data area anchor |
ENUM |
BFD_RELOC_MICROBLAZE_32_RWSDA |
ENUMDOC |
This is a 32 bit reloc for the microblaze that stores a |
value relative to the read-write small data area anchor |
ENUM |
BFD_RELOC_MICROBLAZE_32_SYM_OP_SYM |
ENUMDOC |
This is a 32 bit reloc for the microblaze to handle |
expressions of the form "Symbol Op Symbol" |
ENUM |
BFD_RELOC_MICROBLAZE_64_NONE |
ENUMDOC |
This is a 64 bit reloc that stores the 32 bit pc relative |
value in two words (with an imm instruction). No relocation is |
done here - only used for relaxing |
ENUM |
BFD_RELOC_MICROBLAZE_64_GOTPC |
ENUMDOC |
This is a 64 bit reloc that stores the 32 bit pc relative |
value in two words (with an imm instruction). The relocation is |
PC-relative GOT offset |
ENUM |
BFD_RELOC_MICROBLAZE_64_GOT |
ENUMDOC |
This is a 64 bit reloc that stores the 32 bit pc relative |
value in two words (with an imm instruction). The relocation is |
GOT offset |
ENUM |
BFD_RELOC_MICROBLAZE_64_PLT |
ENUMDOC |
This is a 64 bit reloc that stores the 32 bit pc relative |
value in two words (with an imm instruction). The relocation is |
PC-relative offset into PLT |
ENUM |
BFD_RELOC_MICROBLAZE_64_GOTOFF |
ENUMDOC |
This is a 64 bit reloc that stores the 32 bit GOT relative |
value in two words (with an imm instruction). The relocation is |
relative offset from _GLOBAL_OFFSET_TABLE_ |
ENUM |
BFD_RELOC_MICROBLAZE_32_GOTOFF |
ENUMDOC |
This is a 32 bit reloc that stores the 32 bit GOT relative |
value in a word. The relocation is relative offset from |
_GLOBAL_OFFSET_TABLE_ |
ENUM |
BFD_RELOC_MICROBLAZE_COPY |
ENUMDOC |
This is used to tell the dynamic linker to copy the value out of |
the dynamic object into the runtime process image. |
ENUM |
BFD_RELOC_MICROBLAZE_64_TLS |
ENUMDOC |
Unused Reloc |
ENUM |
BFD_RELOC_MICROBLAZE_64_TLSGD |
ENUMDOC |
This is a 64 bit reloc that stores the 32 bit GOT relative value |
of the GOT TLS GD info entry in two words (with an imm instruction). The |
relocation is GOT offset. |
ENUM |
BFD_RELOC_MICROBLAZE_64_TLSLD |
ENUMDOC |
This is a 64 bit reloc that stores the 32 bit GOT relative value |
of the GOT TLS LD info entry in two words (with an imm instruction). The |
relocation is GOT offset. |
ENUM |
BFD_RELOC_MICROBLAZE_32_TLSDTPMOD |
ENUMDOC |
This is a 32 bit reloc that stores the Module ID to GOT(n). |
ENUM |
BFD_RELOC_MICROBLAZE_32_TLSDTPREL |
ENUMDOC |
This is a 32 bit reloc that stores TLS offset to GOT(n+1). |
ENUM |
BFD_RELOC_MICROBLAZE_64_TLSDTPREL |
ENUMDOC |
This is a 32 bit reloc for storing TLS offset to two words (uses imm |
instruction) |
ENUM |
BFD_RELOC_MICROBLAZE_64_TLSGOTTPREL |
ENUMDOC |
This is a 64 bit reloc that stores 32-bit thread pointer relative offset |
to two words (uses imm instruction). |
ENUM |
BFD_RELOC_MICROBLAZE_64_TLSTPREL |
ENUMDOC |
This is a 64 bit reloc that stores 32-bit thread pointer relative offset |
to two words (uses imm instruction). |
ENUM |
BFD_RELOC_AARCH64_RELOC_START |
ENUMDOC |
AArch64 pseudo relocation code to mark the start of the AArch64 |
relocation enumerators. N.B. the order of the enumerators is |
important as several tables in the AArch64 bfd backend are indexed |
by these enumerators; make sure they are all synced. |
ENUM |
BFD_RELOC_AARCH64_NONE |
ENUMDOC |
AArch64 null relocation code. |
ENUM |
BFD_RELOC_AARCH64_64 |
ENUMX |
BFD_RELOC_AARCH64_32 |
ENUMX |
BFD_RELOC_AARCH64_16 |
ENUMDOC |
Basic absolute relocations of N bits. These are equivalent to |
BFD_RELOC_N and they were added to assist the indexing of the howto |
table. |
ENUM |
BFD_RELOC_AARCH64_64_PCREL |
ENUMX |
BFD_RELOC_AARCH64_32_PCREL |
ENUMX |
BFD_RELOC_AARCH64_16_PCREL |
ENUMDOC |
PC-relative relocations. These are equivalent to BFD_RELOC_N_PCREL |
and they were added to assist the indexing of the howto table. |
ENUM |
BFD_RELOC_AARCH64_MOVW_G0 |
ENUMDOC |
AArch64 MOV[NZK] instruction with most significant bits 0 to 15 |
of an unsigned address/value. |
ENUM |
BFD_RELOC_AARCH64_MOVW_G0_NC |
ENUMDOC |
AArch64 MOV[NZK] instruction with less significant bits 0 to 15 of |
an address/value. No overflow checking. |
ENUM |
BFD_RELOC_AARCH64_MOVW_G1 |
ENUMDOC |
AArch64 MOV[NZK] instruction with most significant bits 16 to 31 |
of an unsigned address/value. |
ENUM |
BFD_RELOC_AARCH64_MOVW_G1_NC |
ENUMDOC |
AArch64 MOV[NZK] instruction with less significant bits 16 to 31 |
of an address/value. No overflow checking. |
ENUM |
BFD_RELOC_AARCH64_MOVW_G2 |
ENUMDOC |
AArch64 MOV[NZK] instruction with most significant bits 32 to 47 |
of an unsigned address/value. |
ENUM |
BFD_RELOC_AARCH64_MOVW_G2_NC |
ENUMDOC |
AArch64 MOV[NZK] instruction with less significant bits 32 to 47 |
of an address/value. No overflow checking. |
ENUM |
BFD_RELOC_AARCH64_MOVW_G3 |
ENUMDOC |
AArch64 MOV[NZK] instruction with most signficant bits 48 to 64 |
of a signed or unsigned address/value. |
ENUM |
BFD_RELOC_AARCH64_MOVW_G0_S |
ENUMDOC |
AArch64 MOV[NZ] instruction with most significant bits 0 to 15 |
of a signed value. Changes instruction to MOVZ or MOVN depending on the |
value's sign. |
ENUM |
BFD_RELOC_AARCH64_MOVW_G1_S |
ENUMDOC |
AArch64 MOV[NZ] instruction with most significant bits 16 to 31 |
of a signed value. Changes instruction to MOVZ or MOVN depending on the |
value's sign. |
ENUM |
BFD_RELOC_AARCH64_MOVW_G2_S |
ENUMDOC |
AArch64 MOV[NZ] instruction with most significant bits 32 to 47 |
of a signed value. Changes instruction to MOVZ or MOVN depending on the |
value's sign. |
ENUM |
BFD_RELOC_AARCH64_LD_LO19_PCREL |
ENUMDOC |
AArch64 Load Literal instruction, holding a 19 bit pc-relative word |
offset. The lowest two bits must be zero and are not stored in the |
instruction, giving a 21 bit signed byte offset. |
ENUM |
BFD_RELOC_AARCH64_ADR_LO21_PCREL |
ENUMDOC |
AArch64 ADR instruction, holding a simple 21 bit pc-relative byte offset. |
ENUM |
BFD_RELOC_AARCH64_ADR_HI21_PCREL |
ENUMDOC |
AArch64 ADRP instruction, with bits 12 to 32 of a pc-relative page |
offset, giving a 4KB aligned page base address. |
ENUM |
BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL |
ENUMDOC |
AArch64 ADRP instruction, with bits 12 to 32 of a pc-relative page |
offset, giving a 4KB aligned page base address, but with no overflow |
checking. |
ENUM |
BFD_RELOC_AARCH64_ADD_LO12 |
ENUMDOC |
AArch64 ADD immediate instruction, holding bits 0 to 11 of the address. |
Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. |
ENUM |
BFD_RELOC_AARCH64_LDST8_LO12 |
ENUMDOC |
AArch64 8-bit load/store instruction, holding bits 0 to 11 of the |
address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. |
ENUM |
BFD_RELOC_AARCH64_TSTBR14 |
ENUMDOC |
AArch64 14 bit pc-relative test bit and branch. |
The lowest two bits must be zero and are not stored in the instruction, |
giving a 16 bit signed byte offset. |
ENUM |
BFD_RELOC_AARCH64_BRANCH19 |
ENUMDOC |
AArch64 19 bit pc-relative conditional branch and compare & branch. |
The lowest two bits must be zero and are not stored in the instruction, |
giving a 21 bit signed byte offset. |
ENUM |
BFD_RELOC_AARCH64_JUMP26 |
ENUMDOC |
AArch64 26 bit pc-relative unconditional branch. |
The lowest two bits must be zero and are not stored in the instruction, |
giving a 28 bit signed byte offset. |
ENUM |
BFD_RELOC_AARCH64_CALL26 |
ENUMDOC |
AArch64 26 bit pc-relative unconditional branch and link. |
The lowest two bits must be zero and are not stored in the instruction, |
giving a 28 bit signed byte offset. |
ENUM |
BFD_RELOC_AARCH64_LDST16_LO12 |
ENUMDOC |
AArch64 16-bit load/store instruction, holding bits 0 to 11 of the |
address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. |
ENUM |
BFD_RELOC_AARCH64_LDST32_LO12 |
ENUMDOC |
AArch64 32-bit load/store instruction, holding bits 0 to 11 of the |
address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. |
ENUM |
BFD_RELOC_AARCH64_LDST64_LO12 |
ENUMDOC |
AArch64 64-bit load/store instruction, holding bits 0 to 11 of the |
address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. |
ENUM |
BFD_RELOC_AARCH64_LDST128_LO12 |
ENUMDOC |
AArch64 128-bit load/store instruction, holding bits 0 to 11 of the |
address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. |
ENUM |
BFD_RELOC_AARCH64_GOT_LD_PREL19 |
ENUMDOC |
AArch64 Load Literal instruction, holding a 19 bit PC relative word |
offset of the global offset table entry for a symbol. The lowest two |
bits must be zero and are not stored in the instruction, giving a 21 |
bit signed byte offset. This relocation type requires signed overflow |
checking. |
ENUM |
BFD_RELOC_AARCH64_ADR_GOT_PAGE |
ENUMDOC |
Get to the page base of the global offset table entry for a symbol as |
part of an ADRP instruction using a 21 bit PC relative value.Used in |
conjunction with BFD_RELOC_AARCH64_LD64_GOT_LO12_NC. |
ENUM |
BFD_RELOC_AARCH64_LD64_GOT_LO12_NC |
ENUMDOC |
Unsigned 12 bit byte offset for 64 bit load/store from the page of |
the GOT entry for this symbol. Used in conjunction with |
BFD_RELOC_AARCH64_ADR_GOTPAGE. Valid in LP64 ABI only. |
ENUM |
BFD_RELOC_AARCH64_LD32_GOT_LO12_NC |
ENUMDOC |
Unsigned 12 bit byte offset for 32 bit load/store from the page of |
the GOT entry for this symbol. Used in conjunction with |
BFD_RELOC_AARCH64_ADR_GOTPAGE. Valid in ILP32 ABI only. |
ENUM |
BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21 |
ENUMDOC |
Get to the page base of the global offset table entry for a symbols |
tls_index structure as part of an adrp instruction using a 21 bit PC |
relative value. Used in conjunction with |
BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC. |
ENUM |
BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC |
ENUMDOC |
Unsigned 12 bit byte offset to global offset table entry for a symbols |
tls_index structure. Used in conjunction with |
BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21. |
ENUM |
BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1 |
ENUMDOC |
AArch64 TLS INITIAL EXEC relocation. |
ENUM |
BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC |
ENUMDOC |
AArch64 TLS INITIAL EXEC relocation. |
ENUM |
BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 |
ENUMDOC |
AArch64 TLS INITIAL EXEC relocation. |
ENUM |
BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC |
ENUMDOC |
AArch64 TLS INITIAL EXEC relocation. |
ENUM |
BFD_RELOC_AARCH64_TLSIE_LD32_GOTTPREL_LO12_NC |
ENUMDOC |
AArch64 TLS INITIAL EXEC relocation. |
ENUM |
BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19 |
ENUMDOC |
AArch64 TLS INITIAL EXEC relocation. |
ENUM |
BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2 |
ENUMDOC |
AArch64 TLS LOCAL EXEC relocation. |
ENUM |
BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1 |
ENUMDOC |
AArch64 TLS LOCAL EXEC relocation. |
ENUM |
BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC |
ENUMDOC |
AArch64 TLS LOCAL EXEC relocation. |
ENUM |
BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0 |
ENUMDOC |
AArch64 TLS LOCAL EXEC relocation. |
ENUM |
BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC |
ENUMDOC |
AArch64 TLS LOCAL EXEC relocation. |
ENUM |
BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12 |
ENUMDOC |
AArch64 TLS LOCAL EXEC relocation. |
ENUM |
BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12 |
ENUMDOC |
AArch64 TLS LOCAL EXEC relocation. |
ENUM |
BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC |
ENUMDOC |
AArch64 TLS LOCAL EXEC relocation. |
ENUM |
BFD_RELOC_AARCH64_TLSDESC_LD_PREL19 |
ENUMDOC |
AArch64 TLS DESC relocation. |
ENUM |
BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21 |
ENUMDOC |
AArch64 TLS DESC relocation. |
ENUM |
BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21 |
ENUMDOC |
AArch64 TLS DESC relocation. |
ENUM |
BFD_RELOC_AARCH64_TLSDESC_LD64_LO12_NC |
ENUMDOC |
AArch64 TLS DESC relocation. |
ENUM |
BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC |
ENUMDOC |
AArch64 TLS DESC relocation. |
ENUM |
BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC |
ENUMDOC |
AArch64 TLS DESC relocation. |
ENUM |
BFD_RELOC_AARCH64_TLSDESC_OFF_G1 |
ENUMDOC |
AArch64 TLS DESC relocation. |
ENUM |
BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC |
ENUMDOC |
AArch64 TLS DESC relocation. |
ENUM |
BFD_RELOC_AARCH64_TLSDESC_LDR |
ENUMDOC |
AArch64 TLS DESC relocation. |
ENUM |
BFD_RELOC_AARCH64_TLSDESC_ADD |
ENUMDOC |
AArch64 TLS DESC relocation. |
ENUM |
BFD_RELOC_AARCH64_TLSDESC_CALL |
ENUMDOC |
AArch64 TLS DESC relocation. |
ENUM |
BFD_RELOC_AARCH64_COPY |
ENUMDOC |
AArch64 TLS relocation. |
ENUM |
BFD_RELOC_AARCH64_GLOB_DAT |
ENUMDOC |
AArch64 TLS relocation. |
ENUM |
BFD_RELOC_AARCH64_JUMP_SLOT |
ENUMDOC |
AArch64 TLS relocation. |
ENUM |
BFD_RELOC_AARCH64_RELATIVE |
ENUMDOC |
AArch64 TLS relocation. |
ENUM |
BFD_RELOC_AARCH64_TLS_DTPMOD |
ENUMDOC |
AArch64 TLS relocation. |
ENUM |
BFD_RELOC_AARCH64_TLS_DTPREL |
ENUMDOC |
AArch64 TLS relocation. |
ENUM |
BFD_RELOC_AARCH64_TLS_TPREL |
ENUMDOC |
AArch64 TLS relocation. |
ENUM |
BFD_RELOC_AARCH64_TLSDESC |
ENUMDOC |
AArch64 TLS relocation. |
ENUM |
BFD_RELOC_AARCH64_IRELATIVE |
ENUMDOC |
AArch64 support for STT_GNU_IFUNC. |
ENUM |
BFD_RELOC_AARCH64_RELOC_END |
ENUMDOC |
AArch64 pseudo relocation code to mark the end of the AArch64 |
relocation enumerators that have direct mapping to ELF reloc codes. |
There are a few more enumerators after this one; those are mainly |
used by the AArch64 assembler for the internal fixup or to select |
one of the above enumerators. |
ENUM |
BFD_RELOC_AARCH64_GAS_INTERNAL_FIXUP |
ENUMDOC |
AArch64 pseudo relocation code to be used internally by the AArch64 |
assembler and not (currently) written to any object files. |
ENUM |
BFD_RELOC_AARCH64_LDST_LO12 |
ENUMDOC |
AArch64 unspecified load/store instruction, holding bits 0 to 11 of the |
address. Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. |
ENUM |
BFD_RELOC_AARCH64_LD_GOT_LO12_NC |
ENUMDOC |
AArch64 pseudo relocation code to be used internally by the AArch64 |
assembler and not (currently) written to any object files. |
ENUM |
BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_LO12_NC |
ENUMDOC |
AArch64 pseudo relocation code to be used internally by the AArch64 |
assembler and not (currently) written to any object files. |
ENUM |
BFD_RELOC_AARCH64_TLSDESC_LD_LO12_NC |
ENUMDOC |
AArch64 pseudo relocation code to be used internally by the AArch64 |
assembler and not (currently) written to any object files. |
ENUM |
BFD_RELOC_TILEPRO_COPY |
ENUMX |
BFD_RELOC_TILEPRO_GLOB_DAT |
ENUMX |
BFD_RELOC_TILEPRO_JMP_SLOT |
ENUMX |
BFD_RELOC_TILEPRO_RELATIVE |
ENUMX |
BFD_RELOC_TILEPRO_BROFF_X1 |
ENUMX |
BFD_RELOC_TILEPRO_JOFFLONG_X1 |
ENUMX |
BFD_RELOC_TILEPRO_JOFFLONG_X1_PLT |
ENUMX |
BFD_RELOC_TILEPRO_IMM8_X0 |
ENUMX |
BFD_RELOC_TILEPRO_IMM8_Y0 |
ENUMX |
BFD_RELOC_TILEPRO_IMM8_X1 |
ENUMX |
BFD_RELOC_TILEPRO_IMM8_Y1 |
ENUMX |
BFD_RELOC_TILEPRO_DEST_IMM8_X1 |
ENUMX |
BFD_RELOC_TILEPRO_MT_IMM15_X1 |
ENUMX |
BFD_RELOC_TILEPRO_MF_IMM15_X1 |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X0 |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X1 |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X0_LO |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X1_LO |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X0_HI |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X1_HI |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X0_HA |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X1_HA |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X0_PCREL |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X1_PCREL |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X0_LO_PCREL |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X1_LO_PCREL |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X0_HI_PCREL |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X1_HI_PCREL |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X0_HA_PCREL |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X1_HA_PCREL |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X0_GOT |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X1_GOT |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X0_GOT_LO |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X1_GOT_LO |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X0_GOT_HI |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X1_GOT_HI |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X0_GOT_HA |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X1_GOT_HA |
ENUMX |
BFD_RELOC_TILEPRO_MMSTART_X0 |
ENUMX |
BFD_RELOC_TILEPRO_MMEND_X0 |
ENUMX |
BFD_RELOC_TILEPRO_MMSTART_X1 |
ENUMX |
BFD_RELOC_TILEPRO_MMEND_X1 |
ENUMX |
BFD_RELOC_TILEPRO_SHAMT_X0 |
ENUMX |
BFD_RELOC_TILEPRO_SHAMT_X1 |
ENUMX |
BFD_RELOC_TILEPRO_SHAMT_Y0 |
ENUMX |
BFD_RELOC_TILEPRO_SHAMT_Y1 |
ENUMX |
BFD_RELOC_TILEPRO_TLS_GD_CALL |
ENUMX |
BFD_RELOC_TILEPRO_IMM8_X0_TLS_GD_ADD |
ENUMX |
BFD_RELOC_TILEPRO_IMM8_X1_TLS_GD_ADD |
ENUMX |
BFD_RELOC_TILEPRO_IMM8_Y0_TLS_GD_ADD |
ENUMX |
BFD_RELOC_TILEPRO_IMM8_Y1_TLS_GD_ADD |
ENUMX |
BFD_RELOC_TILEPRO_TLS_IE_LOAD |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD_LO |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD_LO |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD_HI |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD_HI |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD_HA |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD_HA |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE_LO |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE_LO |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE_HI |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE_HI |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE_HA |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE_HA |
ENUMX |
BFD_RELOC_TILEPRO_TLS_DTPMOD32 |
ENUMX |
BFD_RELOC_TILEPRO_TLS_DTPOFF32 |
ENUMX |
BFD_RELOC_TILEPRO_TLS_TPOFF32 |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_LO |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_LO |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_HI |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_HI |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_HA |
ENUMX |
BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_HA |
ENUMDOC |
Tilera TILEPro Relocations. |
ENUM |
BFD_RELOC_TILEGX_HW0 |
ENUMX |
BFD_RELOC_TILEGX_HW1 |
ENUMX |
BFD_RELOC_TILEGX_HW2 |
ENUMX |
BFD_RELOC_TILEGX_HW3 |
ENUMX |
BFD_RELOC_TILEGX_HW0_LAST |
ENUMX |
BFD_RELOC_TILEGX_HW1_LAST |
ENUMX |
BFD_RELOC_TILEGX_HW2_LAST |
ENUMX |
BFD_RELOC_TILEGX_COPY |
ENUMX |
BFD_RELOC_TILEGX_GLOB_DAT |
ENUMX |
BFD_RELOC_TILEGX_JMP_SLOT |
ENUMX |
BFD_RELOC_TILEGX_RELATIVE |
ENUMX |
BFD_RELOC_TILEGX_BROFF_X1 |
ENUMX |
BFD_RELOC_TILEGX_JUMPOFF_X1 |
ENUMX |
BFD_RELOC_TILEGX_JUMPOFF_X1_PLT |
ENUMX |
BFD_RELOC_TILEGX_IMM8_X0 |
ENUMX |
BFD_RELOC_TILEGX_IMM8_Y0 |
ENUMX |
BFD_RELOC_TILEGX_IMM8_X1 |
ENUMX |
BFD_RELOC_TILEGX_IMM8_Y1 |
ENUMX |
BFD_RELOC_TILEGX_DEST_IMM8_X1 |
ENUMX |
BFD_RELOC_TILEGX_MT_IMM14_X1 |
ENUMX |
BFD_RELOC_TILEGX_MF_IMM14_X1 |
ENUMX |
BFD_RELOC_TILEGX_MMSTART_X0 |
ENUMX |
BFD_RELOC_TILEGX_MMEND_X0 |
ENUMX |
BFD_RELOC_TILEGX_SHAMT_X0 |
ENUMX |
BFD_RELOC_TILEGX_SHAMT_X1 |
ENUMX |
BFD_RELOC_TILEGX_SHAMT_Y0 |
ENUMX |
BFD_RELOC_TILEGX_SHAMT_Y1 |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW0 |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW0 |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW1 |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW1 |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW2 |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW2 |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW3 |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW3 |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW0_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW0_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW1_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW1_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW2_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW2_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW3_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW3_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW0_GOT |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW0_GOT |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW0_PLT_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW0_PLT_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW1_PLT_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW1_PLT_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW2_PLT_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW2_PLT_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_GOT |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_GOT |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_GOT |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_GOT |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW3_PLT_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW3_PLT_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_GD |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_GD |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_LE |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_LE |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_LE |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_TLS_LE |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_LE |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_LE |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_GD |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_TLS_GD |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_GD |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_GD |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_IE |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_IE |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_IE |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_TLS_IE |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_IE |
ENUMX |
BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_IE |
ENUMX |
BFD_RELOC_TILEGX_TLS_DTPMOD64 |
ENUMX |
BFD_RELOC_TILEGX_TLS_DTPOFF64 |
ENUMX |
BFD_RELOC_TILEGX_TLS_TPOFF64 |
ENUMX |
BFD_RELOC_TILEGX_TLS_DTPMOD32 |
ENUMX |
BFD_RELOC_TILEGX_TLS_DTPOFF32 |
ENUMX |
BFD_RELOC_TILEGX_TLS_TPOFF32 |
ENUMX |
BFD_RELOC_TILEGX_TLS_GD_CALL |
ENUMX |
BFD_RELOC_TILEGX_IMM8_X0_TLS_GD_ADD |
ENUMX |
BFD_RELOC_TILEGX_IMM8_X1_TLS_GD_ADD |
ENUMX |
BFD_RELOC_TILEGX_IMM8_Y0_TLS_GD_ADD |
ENUMX |
BFD_RELOC_TILEGX_IMM8_Y1_TLS_GD_ADD |
ENUMX |
BFD_RELOC_TILEGX_TLS_IE_LOAD |
ENUMX |
BFD_RELOC_TILEGX_IMM8_X0_TLS_ADD |
ENUMX |
BFD_RELOC_TILEGX_IMM8_X1_TLS_ADD |
ENUMX |
BFD_RELOC_TILEGX_IMM8_Y0_TLS_ADD |
ENUMX |
BFD_RELOC_TILEGX_IMM8_Y1_TLS_ADD |
ENUMDOC |
Tilera TILE-Gx Relocations. |
ENUM |
BFD_RELOC_EPIPHANY_SIMM8 |
ENUMDOC |
Adapteva EPIPHANY - 8 bit signed pc-relative displacement |
ENUM |
BFD_RELOC_EPIPHANY_SIMM24 |
ENUMDOC |
Adapteva EPIPHANY - 24 bit signed pc-relative displacement |
ENUM |
BFD_RELOC_EPIPHANY_HIGH |
ENUMDOC |
Adapteva EPIPHANY - 16 most-significant bits of absolute address |
ENUM |
BFD_RELOC_EPIPHANY_LOW |
ENUMDOC |
Adapteva EPIPHANY - 16 least-significant bits of absolute address |
ENUM |
BFD_RELOC_EPIPHANY_SIMM11 |
ENUMDOC |
Adapteva EPIPHANY - 11 bit signed number - add/sub immediate |
ENUM |
BFD_RELOC_EPIPHANY_IMM11 |
ENUMDOC |
Adapteva EPIPHANY - 11 bit sign-magnitude number (ld/st displacement) |
ENUM |
BFD_RELOC_EPIPHANY_IMM8 |
ENUMDOC |
Adapteva EPIPHANY - 8 bit immediate for 16 bit mov instruction. |
ENDSENUM |
BFD_RELOC_UNUSED |
CODE_FRAGMENT |
. |
.typedef enum bfd_reloc_code_real bfd_reloc_code_real_type; |
*/ |
/* |
FUNCTION |
bfd_reloc_type_lookup |
bfd_reloc_name_lookup |
SYNOPSIS |
reloc_howto_type *bfd_reloc_type_lookup |
(bfd *abfd, bfd_reloc_code_real_type code); |
reloc_howto_type *bfd_reloc_name_lookup |
(bfd *abfd, const char *reloc_name); |
DESCRIPTION |
Return a pointer to a howto structure which, when |
invoked, will perform the relocation @var{code} on data from the |
architecture noted. |
*/ |
reloc_howto_type * |
bfd_reloc_type_lookup (bfd *abfd, bfd_reloc_code_real_type code) |
{ |
return BFD_SEND (abfd, reloc_type_lookup, (abfd, code)); |
} |
reloc_howto_type * |
bfd_reloc_name_lookup (bfd *abfd, const char *reloc_name) |
{ |
return BFD_SEND (abfd, reloc_name_lookup, (abfd, reloc_name)); |
} |
static reloc_howto_type bfd_howto_32 = |
HOWTO (0, 00, 2, 32, FALSE, 0, complain_overflow_dont, 0, "VRT32", FALSE, 0xffffffff, 0xffffffff, TRUE); |
/* |
INTERNAL_FUNCTION |
bfd_default_reloc_type_lookup |
SYNOPSIS |
reloc_howto_type *bfd_default_reloc_type_lookup |
(bfd *abfd, bfd_reloc_code_real_type code); |
DESCRIPTION |
Provides a default relocation lookup routine for any architecture. |
*/ |
reloc_howto_type * |
bfd_default_reloc_type_lookup (bfd *abfd, bfd_reloc_code_real_type code) |
{ |
switch (code) |
{ |
case BFD_RELOC_CTOR: |
/* The type of reloc used in a ctor, which will be as wide as the |
address - so either a 64, 32, or 16 bitter. */ |
switch (bfd_arch_bits_per_address (abfd)) |
{ |
case 64: |
BFD_FAIL (); |
case 32: |
return &bfd_howto_32; |
case 16: |
BFD_FAIL (); |
default: |
BFD_FAIL (); |
} |
default: |
BFD_FAIL (); |
} |
return NULL; |
} |
/* |
FUNCTION |
bfd_get_reloc_code_name |
SYNOPSIS |
const char *bfd_get_reloc_code_name (bfd_reloc_code_real_type code); |
DESCRIPTION |
Provides a printable name for the supplied relocation code. |
Useful mainly for printing error messages. |
*/ |
const char * |
bfd_get_reloc_code_name (bfd_reloc_code_real_type code) |
{ |
if (code > BFD_RELOC_UNUSED) |
return 0; |
return bfd_reloc_code_real_names[code]; |
} |
/* |
INTERNAL_FUNCTION |
bfd_generic_relax_section |
SYNOPSIS |
bfd_boolean bfd_generic_relax_section |
(bfd *abfd, |
asection *section, |
struct bfd_link_info *, |
bfd_boolean *); |
DESCRIPTION |
Provides default handling for relaxing for back ends which |
don't do relaxing. |
*/ |
bfd_boolean |
bfd_generic_relax_section (bfd *abfd ATTRIBUTE_UNUSED, |
asection *section ATTRIBUTE_UNUSED, |
struct bfd_link_info *link_info ATTRIBUTE_UNUSED, |
bfd_boolean *again) |
{ |
if (link_info->relocatable) |
(*link_info->callbacks->einfo) |
(_("%P%F: --relax and -r may not be used together\n")); |
*again = FALSE; |
return TRUE; |
} |
/* |
INTERNAL_FUNCTION |
bfd_generic_gc_sections |
SYNOPSIS |
bfd_boolean bfd_generic_gc_sections |
(bfd *, struct bfd_link_info *); |
DESCRIPTION |
Provides default handling for relaxing for back ends which |
don't do section gc -- i.e., does nothing. |
*/ |
bfd_boolean |
bfd_generic_gc_sections (bfd *abfd ATTRIBUTE_UNUSED, |
struct bfd_link_info *info ATTRIBUTE_UNUSED) |
{ |
return TRUE; |
} |
/* |
INTERNAL_FUNCTION |
bfd_generic_lookup_section_flags |
SYNOPSIS |
bfd_boolean bfd_generic_lookup_section_flags |
(struct bfd_link_info *, struct flag_info *, asection *); |
DESCRIPTION |
Provides default handling for section flags lookup |
-- i.e., does nothing. |
Returns FALSE if the section should be omitted, otherwise TRUE. |
*/ |
bfd_boolean |
bfd_generic_lookup_section_flags (struct bfd_link_info *info ATTRIBUTE_UNUSED, |
struct flag_info *flaginfo, |
asection *section ATTRIBUTE_UNUSED) |
{ |
if (flaginfo != NULL) |
{ |
(*_bfd_error_handler) (_("INPUT_SECTION_FLAGS are not supported.\n")); |
return FALSE; |
} |
return TRUE; |
} |
/* |
INTERNAL_FUNCTION |
bfd_generic_merge_sections |
SYNOPSIS |
bfd_boolean bfd_generic_merge_sections |
(bfd *, struct bfd_link_info *); |
DESCRIPTION |
Provides default handling for SEC_MERGE section merging for back ends |
which don't have SEC_MERGE support -- i.e., does nothing. |
*/ |
bfd_boolean |
bfd_generic_merge_sections (bfd *abfd ATTRIBUTE_UNUSED, |
struct bfd_link_info *link_info ATTRIBUTE_UNUSED) |
{ |
return TRUE; |
} |
/* |
INTERNAL_FUNCTION |
bfd_generic_get_relocated_section_contents |
SYNOPSIS |
bfd_byte *bfd_generic_get_relocated_section_contents |
(bfd *abfd, |
struct bfd_link_info *link_info, |
struct bfd_link_order *link_order, |
bfd_byte *data, |
bfd_boolean relocatable, |
asymbol **symbols); |
DESCRIPTION |
Provides default handling of relocation effort for back ends |
which can't be bothered to do it efficiently. |
*/ |
bfd_byte * |
bfd_generic_get_relocated_section_contents (bfd *abfd, |
struct bfd_link_info *link_info, |
struct bfd_link_order *link_order, |
bfd_byte *data, |
bfd_boolean relocatable, |
asymbol **symbols) |
{ |
bfd *input_bfd = link_order->u.indirect.section->owner; |
asection *input_section = link_order->u.indirect.section; |
long reloc_size; |
arelent **reloc_vector; |
long reloc_count; |
reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section); |
if (reloc_size < 0) |
return NULL; |
/* Read in the section. */ |
if (!bfd_get_full_section_contents (input_bfd, input_section, &data)) |
return NULL; |
if (reloc_size == 0) |
return data; |
reloc_vector = (arelent **) bfd_malloc (reloc_size); |
if (reloc_vector == NULL) |
return NULL; |
reloc_count = bfd_canonicalize_reloc (input_bfd, |
input_section, |
reloc_vector, |
symbols); |
if (reloc_count < 0) |
goto error_return; |
if (reloc_count > 0) |
{ |
arelent **parent; |
for (parent = reloc_vector; *parent != NULL; parent++) |
{ |
char *error_message = NULL; |
asymbol *symbol; |
bfd_reloc_status_type r; |
symbol = *(*parent)->sym_ptr_ptr; |
if (symbol->section && discarded_section (symbol->section)) |
{ |
bfd_byte *p; |
static reloc_howto_type none_howto |
= HOWTO (0, 0, 0, 0, FALSE, 0, complain_overflow_dont, NULL, |
"unused", FALSE, 0, 0, FALSE); |
p = data + (*parent)->address * bfd_octets_per_byte (input_bfd); |
_bfd_clear_contents ((*parent)->howto, input_bfd, input_section, |
p); |
(*parent)->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; |
(*parent)->addend = 0; |
(*parent)->howto = &none_howto; |
r = bfd_reloc_ok; |
} |
else |
r = bfd_perform_relocation (input_bfd, |
*parent, |
data, |
input_section, |
relocatable ? abfd : NULL, |
&error_message); |
if (relocatable) |
{ |
asection *os = input_section->output_section; |
/* A partial link, so keep the relocs. */ |
os->orelocation[os->reloc_count] = *parent; |
os->reloc_count++; |
} |
if (r != bfd_reloc_ok) |
{ |
switch (r) |
{ |
case bfd_reloc_undefined: |
if (!((*link_info->callbacks->undefined_symbol) |
(link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr), |
input_bfd, input_section, (*parent)->address, |
TRUE))) |
goto error_return; |
break; |
case bfd_reloc_dangerous: |
BFD_ASSERT (error_message != NULL); |
if (!((*link_info->callbacks->reloc_dangerous) |
(link_info, error_message, input_bfd, input_section, |
(*parent)->address))) |
goto error_return; |
break; |
case bfd_reloc_overflow: |
if (!((*link_info->callbacks->reloc_overflow) |
(link_info, NULL, |
bfd_asymbol_name (*(*parent)->sym_ptr_ptr), |
(*parent)->howto->name, (*parent)->addend, |
input_bfd, input_section, (*parent)->address))) |
goto error_return; |
break; |
case bfd_reloc_outofrange: |
/* PR ld/13730: |
This error can result when processing some partially |
complete binaries. Do not abort, but issue an error |
message instead. */ |
link_info->callbacks->einfo |
(_("%X%P: %B(%A): relocation \"%R\" goes out of range\n"), |
abfd, input_section, * parent); |
goto error_return; |
default: |
abort (); |
break; |
} |
} |
} |
} |
free (reloc_vector); |
return data; |
error_return: |
free (reloc_vector); |
return NULL; |
} |
/contrib/toolchain/binutils/bfd/section.c |
---|
0,0 → 1,1633 |
/* Object file "section" support for the BFD library. |
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, |
2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, |
2012, 2013 |
Free Software Foundation, Inc. |
Written by Cygnus Support. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* |
SECTION |
Sections |
The raw data contained within a BFD is maintained through the |
section abstraction. A single BFD may have any number of |
sections. It keeps hold of them by pointing to the first; |
each one points to the next in the list. |
Sections are supported in BFD in <<section.c>>. |
@menu |
@* Section Input:: |
@* Section Output:: |
@* typedef asection:: |
@* section prototypes:: |
@end menu |
INODE |
Section Input, Section Output, Sections, Sections |
SUBSECTION |
Section input |
When a BFD is opened for reading, the section structures are |
created and attached to the BFD. |
Each section has a name which describes the section in the |
outside world---for example, <<a.out>> would contain at least |
three sections, called <<.text>>, <<.data>> and <<.bss>>. |
Names need not be unique; for example a COFF file may have several |
sections named <<.data>>. |
Sometimes a BFD will contain more than the ``natural'' number of |
sections. A back end may attach other sections containing |
constructor data, or an application may add a section (using |
<<bfd_make_section>>) to the sections attached to an already open |
BFD. For example, the linker creates an extra section |
<<COMMON>> for each input file's BFD to hold information about |
common storage. |
The raw data is not necessarily read in when |
the section descriptor is created. Some targets may leave the |
data in place until a <<bfd_get_section_contents>> call is |
made. Other back ends may read in all the data at once. For |
example, an S-record file has to be read once to determine the |
size of the data. An IEEE-695 file doesn't contain raw data in |
sections, but data and relocation expressions intermixed, so |
the data area has to be parsed to get out the data and |
relocations. |
INODE |
Section Output, typedef asection, Section Input, Sections |
SUBSECTION |
Section output |
To write a new object style BFD, the various sections to be |
written have to be created. They are attached to the BFD in |
the same way as input sections; data is written to the |
sections using <<bfd_set_section_contents>>. |
Any program that creates or combines sections (e.g., the assembler |
and linker) must use the <<asection>> fields <<output_section>> and |
<<output_offset>> to indicate the file sections to which each |
section must be written. (If the section is being created from |
scratch, <<output_section>> should probably point to the section |
itself and <<output_offset>> should probably be zero.) |
The data to be written comes from input sections attached |
(via <<output_section>> pointers) to |
the output sections. The output section structure can be |
considered a filter for the input section: the output section |
determines the vma of the output data and the name, but the |
input section determines the offset into the output section of |
the data to be written. |
E.g., to create a section "O", starting at 0x100, 0x123 long, |
containing two subsections, "A" at offset 0x0 (i.e., at vma |
0x100) and "B" at offset 0x20 (i.e., at vma 0x120) the <<asection>> |
structures would look like: |
| section name "A" |
| output_offset 0x00 |
| size 0x20 |
| output_section -----------> section name "O" |
| | vma 0x100 |
| section name "B" | size 0x123 |
| output_offset 0x20 | |
| size 0x103 | |
| output_section --------| |
SUBSECTION |
Link orders |
The data within a section is stored in a @dfn{link_order}. |
These are much like the fixups in <<gas>>. The link_order |
abstraction allows a section to grow and shrink within itself. |
A link_order knows how big it is, and which is the next |
link_order and where the raw data for it is; it also points to |
a list of relocations which apply to it. |
The link_order is used by the linker to perform relaxing on |
final code. The compiler creates code which is as big as |
necessary to make it work without relaxing, and the user can |
select whether to relax. Sometimes relaxing takes a lot of |
time. The linker runs around the relocations to see if any |
are attached to data which can be shrunk, if so it does it on |
a link_order by link_order basis. |
*/ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
#include "bfdlink.h" |
/* |
DOCDD |
INODE |
typedef asection, section prototypes, Section Output, Sections |
SUBSECTION |
typedef asection |
Here is the section structure: |
CODE_FRAGMENT |
. |
.typedef struct bfd_section |
.{ |
. {* The name of the section; the name isn't a copy, the pointer is |
. the same as that passed to bfd_make_section. *} |
. const char *name; |
. |
. {* A unique sequence number. *} |
. int id; |
. |
. {* Which section in the bfd; 0..n-1 as sections are created in a bfd. *} |
. int index; |
. |
. {* The next section in the list belonging to the BFD, or NULL. *} |
. struct bfd_section *next; |
. |
. {* The previous section in the list belonging to the BFD, or NULL. *} |
. struct bfd_section *prev; |
. |
. {* The field flags contains attributes of the section. Some |
. flags are read in from the object file, and some are |
. synthesized from other information. *} |
. flagword flags; |
. |
.#define SEC_NO_FLAGS 0x000 |
. |
. {* Tells the OS to allocate space for this section when loading. |
. This is clear for a section containing debug information only. *} |
.#define SEC_ALLOC 0x001 |
. |
. {* Tells the OS to load the section from the file when loading. |
. This is clear for a .bss section. *} |
.#define SEC_LOAD 0x002 |
. |
. {* The section contains data still to be relocated, so there is |
. some relocation information too. *} |
.#define SEC_RELOC 0x004 |
. |
. {* A signal to the OS that the section contains read only data. *} |
.#define SEC_READONLY 0x008 |
. |
. {* The section contains code only. *} |
.#define SEC_CODE 0x010 |
. |
. {* The section contains data only. *} |
.#define SEC_DATA 0x020 |
. |
. {* The section will reside in ROM. *} |
.#define SEC_ROM 0x040 |
. |
. {* The section contains constructor information. This section |
. type is used by the linker to create lists of constructors and |
. destructors used by <<g++>>. When a back end sees a symbol |
. which should be used in a constructor list, it creates a new |
. section for the type of name (e.g., <<__CTOR_LIST__>>), attaches |
. the symbol to it, and builds a relocation. To build the lists |
. of constructors, all the linker has to do is catenate all the |
. sections called <<__CTOR_LIST__>> and relocate the data |
. contained within - exactly the operations it would peform on |
. standard data. *} |
.#define SEC_CONSTRUCTOR 0x080 |
. |
. {* The section has contents - a data section could be |
. <<SEC_ALLOC>> | <<SEC_HAS_CONTENTS>>; a debug section could be |
. <<SEC_HAS_CONTENTS>> *} |
.#define SEC_HAS_CONTENTS 0x100 |
. |
. {* An instruction to the linker to not output the section |
. even if it has information which would normally be written. *} |
.#define SEC_NEVER_LOAD 0x200 |
. |
. {* The section contains thread local data. *} |
.#define SEC_THREAD_LOCAL 0x400 |
. |
. {* The section has GOT references. This flag is only for the |
. linker, and is currently only used by the elf32-hppa back end. |
. It will be set if global offset table references were detected |
. in this section, which indicate to the linker that the section |
. contains PIC code, and must be handled specially when doing a |
. static link. *} |
.#define SEC_HAS_GOT_REF 0x800 |
. |
. {* The section contains common symbols (symbols may be defined |
. multiple times, the value of a symbol is the amount of |
. space it requires, and the largest symbol value is the one |
. used). Most targets have exactly one of these (which we |
. translate to bfd_com_section_ptr), but ECOFF has two. *} |
.#define SEC_IS_COMMON 0x1000 |
. |
. {* The section contains only debugging information. For |
. example, this is set for ELF .debug and .stab sections. |
. strip tests this flag to see if a section can be |
. discarded. *} |
.#define SEC_DEBUGGING 0x2000 |
. |
. {* The contents of this section are held in memory pointed to |
. by the contents field. This is checked by bfd_get_section_contents, |
. and the data is retrieved from memory if appropriate. *} |
.#define SEC_IN_MEMORY 0x4000 |
. |
. {* The contents of this section are to be excluded by the |
. linker for executable and shared objects unless those |
. objects are to be further relocated. *} |
.#define SEC_EXCLUDE 0x8000 |
. |
. {* The contents of this section are to be sorted based on the sum of |
. the symbol and addend values specified by the associated relocation |
. entries. Entries without associated relocation entries will be |
. appended to the end of the section in an unspecified order. *} |
.#define SEC_SORT_ENTRIES 0x10000 |
. |
. {* When linking, duplicate sections of the same name should be |
. discarded, rather than being combined into a single section as |
. is usually done. This is similar to how common symbols are |
. handled. See SEC_LINK_DUPLICATES below. *} |
.#define SEC_LINK_ONCE 0x20000 |
. |
. {* If SEC_LINK_ONCE is set, this bitfield describes how the linker |
. should handle duplicate sections. *} |
.#define SEC_LINK_DUPLICATES 0xc0000 |
. |
. {* This value for SEC_LINK_DUPLICATES means that duplicate |
. sections with the same name should simply be discarded. *} |
.#define SEC_LINK_DUPLICATES_DISCARD 0x0 |
. |
. {* This value for SEC_LINK_DUPLICATES means that the linker |
. should warn if there are any duplicate sections, although |
. it should still only link one copy. *} |
.#define SEC_LINK_DUPLICATES_ONE_ONLY 0x40000 |
. |
. {* This value for SEC_LINK_DUPLICATES means that the linker |
. should warn if any duplicate sections are a different size. *} |
.#define SEC_LINK_DUPLICATES_SAME_SIZE 0x80000 |
. |
. {* This value for SEC_LINK_DUPLICATES means that the linker |
. should warn if any duplicate sections contain different |
. contents. *} |
.#define SEC_LINK_DUPLICATES_SAME_CONTENTS \ |
. (SEC_LINK_DUPLICATES_ONE_ONLY | SEC_LINK_DUPLICATES_SAME_SIZE) |
. |
. {* This section was created by the linker as part of dynamic |
. relocation or other arcane processing. It is skipped when |
. going through the first-pass output, trusting that someone |
. else up the line will take care of it later. *} |
.#define SEC_LINKER_CREATED 0x100000 |
. |
. {* This section should not be subject to garbage collection. |
. Also set to inform the linker that this section should not be |
. listed in the link map as discarded. *} |
.#define SEC_KEEP 0x200000 |
. |
. {* This section contains "short" data, and should be placed |
. "near" the GP. *} |
.#define SEC_SMALL_DATA 0x400000 |
. |
. {* Attempt to merge identical entities in the section. |
. Entity size is given in the entsize field. *} |
.#define SEC_MERGE 0x800000 |
. |
. {* If given with SEC_MERGE, entities to merge are zero terminated |
. strings where entsize specifies character size instead of fixed |
. size entries. *} |
.#define SEC_STRINGS 0x1000000 |
. |
. {* This section contains data about section groups. *} |
.#define SEC_GROUP 0x2000000 |
. |
. {* The section is a COFF shared library section. This flag is |
. only for the linker. If this type of section appears in |
. the input file, the linker must copy it to the output file |
. without changing the vma or size. FIXME: Although this |
. was originally intended to be general, it really is COFF |
. specific (and the flag was renamed to indicate this). It |
. might be cleaner to have some more general mechanism to |
. allow the back end to control what the linker does with |
. sections. *} |
.#define SEC_COFF_SHARED_LIBRARY 0x4000000 |
. |
. {* This input section should be copied to output in reverse order |
. as an array of pointers. This is for ELF linker internal use |
. only. *} |
.#define SEC_ELF_REVERSE_COPY 0x4000000 |
. |
. {* This section contains data which may be shared with other |
. executables or shared objects. This is for COFF only. *} |
.#define SEC_COFF_SHARED 0x8000000 |
. |
. {* When a section with this flag is being linked, then if the size of |
. the input section is less than a page, it should not cross a page |
. boundary. If the size of the input section is one page or more, |
. it should be aligned on a page boundary. This is for TI |
. TMS320C54X only. *} |
.#define SEC_TIC54X_BLOCK 0x10000000 |
. |
. {* Conditionally link this section; do not link if there are no |
. references found to any symbol in the section. This is for TI |
. TMS320C54X only. *} |
.#define SEC_TIC54X_CLINK 0x20000000 |
. |
. {* Indicate that section has the no read flag set. This happens |
. when memory read flag isn't set. *} |
.#define SEC_COFF_NOREAD 0x40000000 |
. |
. {* End of section flags. *} |
. |
. {* Some internal packed boolean fields. *} |
. |
. {* See the vma field. *} |
. unsigned int user_set_vma : 1; |
. |
. {* A mark flag used by some of the linker backends. *} |
. unsigned int linker_mark : 1; |
. |
. {* Another mark flag used by some of the linker backends. Set for |
. output sections that have an input section. *} |
. unsigned int linker_has_input : 1; |
. |
. {* Mark flag used by some linker backends for garbage collection. *} |
. unsigned int gc_mark : 1; |
. |
. {* Section compression status. *} |
. unsigned int compress_status : 2; |
.#define COMPRESS_SECTION_NONE 0 |
.#define COMPRESS_SECTION_DONE 1 |
.#define DECOMPRESS_SECTION_SIZED 2 |
. |
. {* The following flags are used by the ELF linker. *} |
. |
. {* Mark sections which have been allocated to segments. *} |
. unsigned int segment_mark : 1; |
. |
. {* Type of sec_info information. *} |
. unsigned int sec_info_type:3; |
.#define SEC_INFO_TYPE_NONE 0 |
.#define SEC_INFO_TYPE_STABS 1 |
.#define SEC_INFO_TYPE_MERGE 2 |
.#define SEC_INFO_TYPE_EH_FRAME 3 |
.#define SEC_INFO_TYPE_JUST_SYMS 4 |
. |
. {* Nonzero if this section uses RELA relocations, rather than REL. *} |
. unsigned int use_rela_p:1; |
. |
. {* Bits used by various backends. The generic code doesn't touch |
. these fields. *} |
. |
. unsigned int sec_flg0:1; |
. unsigned int sec_flg1:1; |
. unsigned int sec_flg2:1; |
. unsigned int sec_flg3:1; |
. unsigned int sec_flg4:1; |
. unsigned int sec_flg5:1; |
. |
. {* End of internal packed boolean fields. *} |
. |
. {* The virtual memory address of the section - where it will be |
. at run time. The symbols are relocated against this. The |
. user_set_vma flag is maintained by bfd; if it's not set, the |
. backend can assign addresses (for example, in <<a.out>>, where |
. the default address for <<.data>> is dependent on the specific |
. target and various flags). *} |
. bfd_vma vma; |
. |
. {* The load address of the section - where it would be in a |
. rom image; really only used for writing section header |
. information. *} |
. bfd_vma lma; |
. |
. {* The size of the section in octets, as it will be output. |
. Contains a value even if the section has no contents (e.g., the |
. size of <<.bss>>). *} |
. bfd_size_type size; |
. |
. {* For input sections, the original size on disk of the section, in |
. octets. This field should be set for any section whose size is |
. changed by linker relaxation. It is required for sections where |
. the linker relaxation scheme doesn't cache altered section and |
. reloc contents (stabs, eh_frame, SEC_MERGE, some coff relaxing |
. targets), and thus the original size needs to be kept to read the |
. section multiple times. For output sections, rawsize holds the |
. section size calculated on a previous linker relaxation pass. *} |
. bfd_size_type rawsize; |
. |
. {* The compressed size of the section in octets. *} |
. bfd_size_type compressed_size; |
. |
. {* Relaxation table. *} |
. struct relax_table *relax; |
. |
. {* Count of used relaxation table entries. *} |
. int relax_count; |
. |
. |
. {* If this section is going to be output, then this value is the |
. offset in *bytes* into the output section of the first byte in the |
. input section (byte ==> smallest addressable unit on the |
. target). In most cases, if this was going to start at the |
. 100th octet (8-bit quantity) in the output section, this value |
. would be 100. However, if the target byte size is 16 bits |
. (bfd_octets_per_byte is "2"), this value would be 50. *} |
. bfd_vma output_offset; |
. |
. {* The output section through which to map on output. *} |
. struct bfd_section *output_section; |
. |
. {* The alignment requirement of the section, as an exponent of 2 - |
. e.g., 3 aligns to 2^3 (or 8). *} |
. unsigned int alignment_power; |
. |
. {* If an input section, a pointer to a vector of relocation |
. records for the data in this section. *} |
. struct reloc_cache_entry *relocation; |
. |
. {* If an output section, a pointer to a vector of pointers to |
. relocation records for the data in this section. *} |
. struct reloc_cache_entry **orelocation; |
. |
. {* The number of relocation records in one of the above. *} |
. unsigned reloc_count; |
. |
. {* Information below is back end specific - and not always used |
. or updated. *} |
. |
. {* File position of section data. *} |
. file_ptr filepos; |
. |
. {* File position of relocation info. *} |
. file_ptr rel_filepos; |
. |
. {* File position of line data. *} |
. file_ptr line_filepos; |
. |
. {* Pointer to data for applications. *} |
. void *userdata; |
. |
. {* If the SEC_IN_MEMORY flag is set, this points to the actual |
. contents. *} |
. unsigned char *contents; |
. |
. {* Attached line number information. *} |
. alent *lineno; |
. |
. {* Number of line number records. *} |
. unsigned int lineno_count; |
. |
. {* Entity size for merging purposes. *} |
. unsigned int entsize; |
. |
. {* Points to the kept section if this section is a link-once section, |
. and is discarded. *} |
. struct bfd_section *kept_section; |
. |
. {* When a section is being output, this value changes as more |
. linenumbers are written out. *} |
. file_ptr moving_line_filepos; |
. |
. {* What the section number is in the target world. *} |
. int target_index; |
. |
. void *used_by_bfd; |
. |
. {* If this is a constructor section then here is a list of the |
. relocations created to relocate items within it. *} |
. struct relent_chain *constructor_chain; |
. |
. {* The BFD which owns the section. *} |
. bfd *owner; |
. |
. {* A symbol which points at this section only. *} |
. struct bfd_symbol *symbol; |
. struct bfd_symbol **symbol_ptr_ptr; |
. |
. {* Early in the link process, map_head and map_tail are used to build |
. a list of input sections attached to an output section. Later, |
. output sections use these fields for a list of bfd_link_order |
. structs. *} |
. union { |
. struct bfd_link_order *link_order; |
. struct bfd_section *s; |
. } map_head, map_tail; |
.} asection; |
. |
.{* Relax table contains information about instructions which can |
. be removed by relaxation -- replacing a long address with a |
. short address. *} |
.struct relax_table { |
. {* Address where bytes may be deleted. *} |
. bfd_vma addr; |
. |
. {* Number of bytes to be deleted. *} |
. int size; |
.}; |
. |
.{* These sections are global, and are managed by BFD. The application |
. and target back end are not permitted to change the values in |
. these sections. *} |
.extern asection _bfd_std_section[4]; |
. |
.#define BFD_ABS_SECTION_NAME "*ABS*" |
.#define BFD_UND_SECTION_NAME "*UND*" |
.#define BFD_COM_SECTION_NAME "*COM*" |
.#define BFD_IND_SECTION_NAME "*IND*" |
. |
.{* Pointer to the common section. *} |
.#define bfd_com_section_ptr (&_bfd_std_section[0]) |
.{* Pointer to the undefined section. *} |
.#define bfd_und_section_ptr (&_bfd_std_section[1]) |
.{* Pointer to the absolute section. *} |
.#define bfd_abs_section_ptr (&_bfd_std_section[2]) |
.{* Pointer to the indirect section. *} |
.#define bfd_ind_section_ptr (&_bfd_std_section[3]) |
. |
.#define bfd_is_und_section(sec) ((sec) == bfd_und_section_ptr) |
.#define bfd_is_abs_section(sec) ((sec) == bfd_abs_section_ptr) |
.#define bfd_is_ind_section(sec) ((sec) == bfd_ind_section_ptr) |
. |
.#define bfd_is_const_section(SEC) \ |
. ( ((SEC) == bfd_abs_section_ptr) \ |
. || ((SEC) == bfd_und_section_ptr) \ |
. || ((SEC) == bfd_com_section_ptr) \ |
. || ((SEC) == bfd_ind_section_ptr)) |
. |
.{* Macros to handle insertion and deletion of a bfd's sections. These |
. only handle the list pointers, ie. do not adjust section_count, |
. target_index etc. *} |
.#define bfd_section_list_remove(ABFD, S) \ |
. do \ |
. { \ |
. asection *_s = S; \ |
. asection *_next = _s->next; \ |
. asection *_prev = _s->prev; \ |
. if (_prev) \ |
. _prev->next = _next; \ |
. else \ |
. (ABFD)->sections = _next; \ |
. if (_next) \ |
. _next->prev = _prev; \ |
. else \ |
. (ABFD)->section_last = _prev; \ |
. } \ |
. while (0) |
.#define bfd_section_list_append(ABFD, S) \ |
. do \ |
. { \ |
. asection *_s = S; \ |
. bfd *_abfd = ABFD; \ |
. _s->next = NULL; \ |
. if (_abfd->section_last) \ |
. { \ |
. _s->prev = _abfd->section_last; \ |
. _abfd->section_last->next = _s; \ |
. } \ |
. else \ |
. { \ |
. _s->prev = NULL; \ |
. _abfd->sections = _s; \ |
. } \ |
. _abfd->section_last = _s; \ |
. } \ |
. while (0) |
.#define bfd_section_list_prepend(ABFD, S) \ |
. do \ |
. { \ |
. asection *_s = S; \ |
. bfd *_abfd = ABFD; \ |
. _s->prev = NULL; \ |
. if (_abfd->sections) \ |
. { \ |
. _s->next = _abfd->sections; \ |
. _abfd->sections->prev = _s; \ |
. } \ |
. else \ |
. { \ |
. _s->next = NULL; \ |
. _abfd->section_last = _s; \ |
. } \ |
. _abfd->sections = _s; \ |
. } \ |
. while (0) |
.#define bfd_section_list_insert_after(ABFD, A, S) \ |
. do \ |
. { \ |
. asection *_a = A; \ |
. asection *_s = S; \ |
. asection *_next = _a->next; \ |
. _s->next = _next; \ |
. _s->prev = _a; \ |
. _a->next = _s; \ |
. if (_next) \ |
. _next->prev = _s; \ |
. else \ |
. (ABFD)->section_last = _s; \ |
. } \ |
. while (0) |
.#define bfd_section_list_insert_before(ABFD, B, S) \ |
. do \ |
. { \ |
. asection *_b = B; \ |
. asection *_s = S; \ |
. asection *_prev = _b->prev; \ |
. _s->prev = _prev; \ |
. _s->next = _b; \ |
. _b->prev = _s; \ |
. if (_prev) \ |
. _prev->next = _s; \ |
. else \ |
. (ABFD)->sections = _s; \ |
. } \ |
. while (0) |
.#define bfd_section_removed_from_list(ABFD, S) \ |
. ((S)->next == NULL ? (ABFD)->section_last != (S) : (S)->next->prev != (S)) |
. |
.#define BFD_FAKE_SECTION(SEC, FLAGS, SYM, NAME, IDX) \ |
. {* name, id, index, next, prev, flags, user_set_vma, *} \ |
. { NAME, IDX, 0, NULL, NULL, FLAGS, 0, \ |
. \ |
. {* linker_mark, linker_has_input, gc_mark, decompress_status, *} \ |
. 0, 0, 1, 0, \ |
. \ |
. {* segment_mark, sec_info_type, use_rela_p, *} \ |
. 0, 0, 0, \ |
. \ |
. {* sec_flg0, sec_flg1, sec_flg2, sec_flg3, sec_flg4, sec_flg5, *} \ |
. 0, 0, 0, 0, 0, 0, \ |
. \ |
. {* vma, lma, size, rawsize, compressed_size, relax, relax_count, *} \ |
. 0, 0, 0, 0, 0, 0, 0, \ |
. \ |
. {* output_offset, output_section, alignment_power, *} \ |
. 0, &SEC, 0, \ |
. \ |
. {* relocation, orelocation, reloc_count, filepos, rel_filepos, *} \ |
. NULL, NULL, 0, 0, 0, \ |
. \ |
. {* line_filepos, userdata, contents, lineno, lineno_count, *} \ |
. 0, NULL, NULL, NULL, 0, \ |
. \ |
. {* entsize, kept_section, moving_line_filepos, *} \ |
. 0, NULL, 0, \ |
. \ |
. {* target_index, used_by_bfd, constructor_chain, owner, *} \ |
. 0, NULL, NULL, NULL, \ |
. \ |
. {* symbol, symbol_ptr_ptr, *} \ |
. (struct bfd_symbol *) SYM, &SEC.symbol, \ |
. \ |
. {* map_head, map_tail *} \ |
. { NULL }, { NULL } \ |
. } |
. |
*/ |
/* We use a macro to initialize the static asymbol structures because |
traditional C does not permit us to initialize a union member while |
gcc warns if we don't initialize it. */ |
/* the_bfd, name, value, attr, section [, udata] */ |
#ifdef __STDC__ |
#define GLOBAL_SYM_INIT(NAME, SECTION) \ |
{ 0, NAME, 0, BSF_SECTION_SYM, SECTION, { 0 }} |
#else |
#define GLOBAL_SYM_INIT(NAME, SECTION) \ |
{ 0, NAME, 0, BSF_SECTION_SYM, SECTION } |
#endif |
/* These symbols are global, not specific to any BFD. Therefore, anything |
that tries to change them is broken, and should be repaired. */ |
static const asymbol global_syms[] = |
{ |
GLOBAL_SYM_INIT (BFD_COM_SECTION_NAME, bfd_com_section_ptr), |
GLOBAL_SYM_INIT (BFD_UND_SECTION_NAME, bfd_und_section_ptr), |
GLOBAL_SYM_INIT (BFD_ABS_SECTION_NAME, bfd_abs_section_ptr), |
GLOBAL_SYM_INIT (BFD_IND_SECTION_NAME, bfd_ind_section_ptr) |
}; |
#define STD_SECTION(NAME, IDX, FLAGS) \ |
BFD_FAKE_SECTION(_bfd_std_section[IDX], FLAGS, &global_syms[IDX], NAME, IDX) |
asection _bfd_std_section[] = { |
STD_SECTION (BFD_COM_SECTION_NAME, 0, SEC_IS_COMMON), |
STD_SECTION (BFD_UND_SECTION_NAME, 1, 0), |
STD_SECTION (BFD_ABS_SECTION_NAME, 2, 0), |
STD_SECTION (BFD_IND_SECTION_NAME, 3, 0) |
}; |
#undef STD_SECTION |
/* Initialize an entry in the section hash table. */ |
struct bfd_hash_entry * |
bfd_section_hash_newfunc (struct bfd_hash_entry *entry, |
struct bfd_hash_table *table, |
const char *string) |
{ |
/* Allocate the structure if it has not already been allocated by a |
subclass. */ |
if (entry == NULL) |
{ |
entry = (struct bfd_hash_entry *) |
bfd_hash_allocate (table, sizeof (struct section_hash_entry)); |
if (entry == NULL) |
return entry; |
} |
/* Call the allocation method of the superclass. */ |
entry = bfd_hash_newfunc (entry, table, string); |
if (entry != NULL) |
memset (&((struct section_hash_entry *) entry)->section, 0, |
sizeof (asection)); |
return entry; |
} |
#define section_hash_lookup(table, string, create, copy) \ |
((struct section_hash_entry *) \ |
bfd_hash_lookup ((table), (string), (create), (copy))) |
/* Create a symbol whose only job is to point to this section. This |
is useful for things like relocs which are relative to the base |
of a section. */ |
bfd_boolean |
_bfd_generic_new_section_hook (bfd *abfd, asection *newsect) |
{ |
newsect->symbol = bfd_make_empty_symbol (abfd); |
if (newsect->symbol == NULL) |
return FALSE; |
newsect->symbol->name = newsect->name; |
newsect->symbol->value = 0; |
newsect->symbol->section = newsect; |
newsect->symbol->flags = BSF_SECTION_SYM; |
newsect->symbol_ptr_ptr = &newsect->symbol; |
return TRUE; |
} |
/* Initializes a new section. NEWSECT->NAME is already set. */ |
static asection * |
bfd_section_init (bfd *abfd, asection *newsect) |
{ |
static int section_id = 0x10; /* id 0 to 3 used by STD_SECTION. */ |
newsect->id = section_id; |
newsect->index = abfd->section_count; |
newsect->owner = abfd; |
if (! BFD_SEND (abfd, _new_section_hook, (abfd, newsect))) |
return NULL; |
section_id++; |
abfd->section_count++; |
bfd_section_list_append (abfd, newsect); |
return newsect; |
} |
/* |
DOCDD |
INODE |
section prototypes, , typedef asection, Sections |
SUBSECTION |
Section prototypes |
These are the functions exported by the section handling part of BFD. |
*/ |
/* |
FUNCTION |
bfd_section_list_clear |
SYNOPSIS |
void bfd_section_list_clear (bfd *); |
DESCRIPTION |
Clears the section list, and also resets the section count and |
hash table entries. |
*/ |
void |
bfd_section_list_clear (bfd *abfd) |
{ |
abfd->sections = NULL; |
abfd->section_last = NULL; |
abfd->section_count = 0; |
memset (abfd->section_htab.table, 0, |
abfd->section_htab.size * sizeof (struct bfd_hash_entry *)); |
abfd->section_htab.count = 0; |
} |
/* |
FUNCTION |
bfd_get_section_by_name |
SYNOPSIS |
asection *bfd_get_section_by_name (bfd *abfd, const char *name); |
DESCRIPTION |
Return the most recently created section attached to @var{abfd} |
named @var{name}. Return NULL if no such section exists. |
*/ |
asection * |
bfd_get_section_by_name (bfd *abfd, const char *name) |
{ |
struct section_hash_entry *sh; |
sh = section_hash_lookup (&abfd->section_htab, name, FALSE, FALSE); |
if (sh != NULL) |
return &sh->section; |
return NULL; |
} |
/* |
FUNCTION |
bfd_get_next_section_by_name |
SYNOPSIS |
asection *bfd_get_next_section_by_name (asection *sec); |
DESCRIPTION |
Given @var{sec} is a section returned by @code{bfd_get_section_by_name}, |
return the next most recently created section attached to the same |
BFD with the same name. Return NULL if no such section exists. |
*/ |
asection * |
bfd_get_next_section_by_name (asection *sec) |
{ |
struct section_hash_entry *sh; |
const char *name; |
unsigned long hash; |
sh = ((struct section_hash_entry *) |
((char *) sec - offsetof (struct section_hash_entry, section))); |
hash = sh->root.hash; |
name = sec->name; |
for (sh = (struct section_hash_entry *) sh->root.next; |
sh != NULL; |
sh = (struct section_hash_entry *) sh->root.next) |
if (sh->root.hash == hash |
&& strcmp (sh->root.string, name) == 0) |
return &sh->section; |
return NULL; |
} |
/* |
FUNCTION |
bfd_get_linker_section |
SYNOPSIS |
asection *bfd_get_linker_section (bfd *abfd, const char *name); |
DESCRIPTION |
Return the linker created section attached to @var{abfd} |
named @var{name}. Return NULL if no such section exists. |
*/ |
asection * |
bfd_get_linker_section (bfd *abfd, const char *name) |
{ |
asection *sec = bfd_get_section_by_name (abfd, name); |
while (sec != NULL && (sec->flags & SEC_LINKER_CREATED) == 0) |
sec = bfd_get_next_section_by_name (sec); |
return sec; |
} |
/* |
FUNCTION |
bfd_get_section_by_name_if |
SYNOPSIS |
asection *bfd_get_section_by_name_if |
(bfd *abfd, |
const char *name, |
bfd_boolean (*func) (bfd *abfd, asection *sect, void *obj), |
void *obj); |
DESCRIPTION |
Call the provided function @var{func} for each section |
attached to the BFD @var{abfd} whose name matches @var{name}, |
passing @var{obj} as an argument. The function will be called |
as if by |
| func (abfd, the_section, obj); |
It returns the first section for which @var{func} returns true, |
otherwise <<NULL>>. |
*/ |
asection * |
bfd_get_section_by_name_if (bfd *abfd, const char *name, |
bfd_boolean (*operation) (bfd *, |
asection *, |
void *), |
void *user_storage) |
{ |
struct section_hash_entry *sh; |
unsigned long hash; |
sh = section_hash_lookup (&abfd->section_htab, name, FALSE, FALSE); |
if (sh == NULL) |
return NULL; |
hash = sh->root.hash; |
do |
{ |
if ((*operation) (abfd, &sh->section, user_storage)) |
return &sh->section; |
sh = (struct section_hash_entry *) sh->root.next; |
} |
while (sh != NULL && sh->root.hash == hash |
&& strcmp (sh->root.string, name) == 0); |
return NULL; |
} |
/* |
FUNCTION |
bfd_get_unique_section_name |
SYNOPSIS |
char *bfd_get_unique_section_name |
(bfd *abfd, const char *templat, int *count); |
DESCRIPTION |
Invent a section name that is unique in @var{abfd} by tacking |
a dot and a digit suffix onto the original @var{templat}. If |
@var{count} is non-NULL, then it specifies the first number |
tried as a suffix to generate a unique name. The value |
pointed to by @var{count} will be incremented in this case. |
*/ |
char * |
bfd_get_unique_section_name (bfd *abfd, const char *templat, int *count) |
{ |
int num; |
unsigned int len; |
char *sname; |
len = strlen (templat); |
sname = (char *) bfd_malloc (len + 8); |
if (sname == NULL) |
return NULL; |
memcpy (sname, templat, len); |
num = 1; |
if (count != NULL) |
num = *count; |
do |
{ |
/* If we have a million sections, something is badly wrong. */ |
if (num > 999999) |
abort (); |
sprintf (sname + len, ".%d", num++); |
} |
while (section_hash_lookup (&abfd->section_htab, sname, FALSE, FALSE)); |
if (count != NULL) |
*count = num; |
return sname; |
} |
/* |
FUNCTION |
bfd_make_section_old_way |
SYNOPSIS |
asection *bfd_make_section_old_way (bfd *abfd, const char *name); |
DESCRIPTION |
Create a new empty section called @var{name} |
and attach it to the end of the chain of sections for the |
BFD @var{abfd}. An attempt to create a section with a name which |
is already in use returns its pointer without changing the |
section chain. |
It has the funny name since this is the way it used to be |
before it was rewritten.... |
Possible errors are: |
o <<bfd_error_invalid_operation>> - |
If output has already started for this BFD. |
o <<bfd_error_no_memory>> - |
If memory allocation fails. |
*/ |
asection * |
bfd_make_section_old_way (bfd *abfd, const char *name) |
{ |
asection *newsect; |
if (abfd->output_has_begun) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return NULL; |
} |
if (strcmp (name, BFD_ABS_SECTION_NAME) == 0) |
newsect = bfd_abs_section_ptr; |
else if (strcmp (name, BFD_COM_SECTION_NAME) == 0) |
newsect = bfd_com_section_ptr; |
else if (strcmp (name, BFD_UND_SECTION_NAME) == 0) |
newsect = bfd_und_section_ptr; |
else if (strcmp (name, BFD_IND_SECTION_NAME) == 0) |
newsect = bfd_ind_section_ptr; |
else |
{ |
struct section_hash_entry *sh; |
sh = section_hash_lookup (&abfd->section_htab, name, TRUE, FALSE); |
if (sh == NULL) |
return NULL; |
newsect = &sh->section; |
if (newsect->name != NULL) |
{ |
/* Section already exists. */ |
return newsect; |
} |
newsect->name = name; |
return bfd_section_init (abfd, newsect); |
} |
/* Call new_section_hook when "creating" the standard abs, com, und |
and ind sections to tack on format specific section data. |
Also, create a proper section symbol. */ |
if (! BFD_SEND (abfd, _new_section_hook, (abfd, newsect))) |
return NULL; |
return newsect; |
} |
/* |
FUNCTION |
bfd_make_section_anyway_with_flags |
SYNOPSIS |
asection *bfd_make_section_anyway_with_flags |
(bfd *abfd, const char *name, flagword flags); |
DESCRIPTION |
Create a new empty section called @var{name} and attach it to the end of |
the chain of sections for @var{abfd}. Create a new section even if there |
is already a section with that name. Also set the attributes of the |
new section to the value @var{flags}. |
Return <<NULL>> and set <<bfd_error>> on error; possible errors are: |
o <<bfd_error_invalid_operation>> - If output has already started for @var{abfd}. |
o <<bfd_error_no_memory>> - If memory allocation fails. |
*/ |
sec_ptr |
bfd_make_section_anyway_with_flags (bfd *abfd, const char *name, |
flagword flags) |
{ |
struct section_hash_entry *sh; |
asection *newsect; |
if (abfd->output_has_begun) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return NULL; |
} |
sh = section_hash_lookup (&abfd->section_htab, name, TRUE, FALSE); |
if (sh == NULL) |
return NULL; |
newsect = &sh->section; |
if (newsect->name != NULL) |
{ |
/* We are making a section of the same name. Put it in the |
section hash table. Even though we can't find it directly by a |
hash lookup, we'll be able to find the section by traversing |
sh->root.next quicker than looking at all the bfd sections. */ |
struct section_hash_entry *new_sh; |
new_sh = (struct section_hash_entry *) |
bfd_section_hash_newfunc (NULL, &abfd->section_htab, name); |
if (new_sh == NULL) |
return NULL; |
new_sh->root = sh->root; |
sh->root.next = &new_sh->root; |
newsect = &new_sh->section; |
} |
newsect->flags = flags; |
newsect->name = name; |
return bfd_section_init (abfd, newsect); |
} |
/* |
FUNCTION |
bfd_make_section_anyway |
SYNOPSIS |
asection *bfd_make_section_anyway (bfd *abfd, const char *name); |
DESCRIPTION |
Create a new empty section called @var{name} and attach it to the end of |
the chain of sections for @var{abfd}. Create a new section even if there |
is already a section with that name. |
Return <<NULL>> and set <<bfd_error>> on error; possible errors are: |
o <<bfd_error_invalid_operation>> - If output has already started for @var{abfd}. |
o <<bfd_error_no_memory>> - If memory allocation fails. |
*/ |
sec_ptr |
bfd_make_section_anyway (bfd *abfd, const char *name) |
{ |
return bfd_make_section_anyway_with_flags (abfd, name, 0); |
} |
/* |
FUNCTION |
bfd_make_section_with_flags |
SYNOPSIS |
asection *bfd_make_section_with_flags |
(bfd *, const char *name, flagword flags); |
DESCRIPTION |
Like <<bfd_make_section_anyway>>, but return <<NULL>> (without calling |
bfd_set_error ()) without changing the section chain if there is already a |
section named @var{name}. Also set the attributes of the new section to |
the value @var{flags}. If there is an error, return <<NULL>> and set |
<<bfd_error>>. |
*/ |
asection * |
bfd_make_section_with_flags (bfd *abfd, const char *name, |
flagword flags) |
{ |
struct section_hash_entry *sh; |
asection *newsect; |
if (abfd->output_has_begun) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return NULL; |
} |
if (strcmp (name, BFD_ABS_SECTION_NAME) == 0 |
|| strcmp (name, BFD_COM_SECTION_NAME) == 0 |
|| strcmp (name, BFD_UND_SECTION_NAME) == 0 |
|| strcmp (name, BFD_IND_SECTION_NAME) == 0) |
return NULL; |
sh = section_hash_lookup (&abfd->section_htab, name, TRUE, FALSE); |
if (sh == NULL) |
return NULL; |
newsect = &sh->section; |
if (newsect->name != NULL) |
{ |
/* Section already exists. */ |
return NULL; |
} |
newsect->name = name; |
newsect->flags = flags; |
return bfd_section_init (abfd, newsect); |
} |
/* |
FUNCTION |
bfd_make_section |
SYNOPSIS |
asection *bfd_make_section (bfd *, const char *name); |
DESCRIPTION |
Like <<bfd_make_section_anyway>>, but return <<NULL>> (without calling |
bfd_set_error ()) without changing the section chain if there is already a |
section named @var{name}. If there is an error, return <<NULL>> and set |
<<bfd_error>>. |
*/ |
asection * |
bfd_make_section (bfd *abfd, const char *name) |
{ |
return bfd_make_section_with_flags (abfd, name, 0); |
} |
/* |
FUNCTION |
bfd_set_section_flags |
SYNOPSIS |
bfd_boolean bfd_set_section_flags |
(bfd *abfd, asection *sec, flagword flags); |
DESCRIPTION |
Set the attributes of the section @var{sec} in the BFD |
@var{abfd} to the value @var{flags}. Return <<TRUE>> on success, |
<<FALSE>> on error. Possible error returns are: |
o <<bfd_error_invalid_operation>> - |
The section cannot have one or more of the attributes |
requested. For example, a .bss section in <<a.out>> may not |
have the <<SEC_HAS_CONTENTS>> field set. |
*/ |
bfd_boolean |
bfd_set_section_flags (bfd *abfd ATTRIBUTE_UNUSED, |
sec_ptr section, |
flagword flags) |
{ |
section->flags = flags; |
return TRUE; |
} |
/* |
FUNCTION |
bfd_rename_section |
SYNOPSIS |
void bfd_rename_section |
(bfd *abfd, asection *sec, const char *newname); |
DESCRIPTION |
Rename section @var{sec} in @var{abfd} to @var{newname}. |
*/ |
void |
bfd_rename_section (bfd *abfd, sec_ptr sec, const char *newname) |
{ |
struct section_hash_entry *sh; |
sh = (struct section_hash_entry *) |
((char *) sec - offsetof (struct section_hash_entry, section)); |
sh->section.name = newname; |
bfd_hash_rename (&abfd->section_htab, newname, &sh->root); |
} |
/* |
FUNCTION |
bfd_map_over_sections |
SYNOPSIS |
void bfd_map_over_sections |
(bfd *abfd, |
void (*func) (bfd *abfd, asection *sect, void *obj), |
void *obj); |
DESCRIPTION |
Call the provided function @var{func} for each section |
attached to the BFD @var{abfd}, passing @var{obj} as an |
argument. The function will be called as if by |
| func (abfd, the_section, obj); |
This is the preferred method for iterating over sections; an |
alternative would be to use a loop: |
| asection *p; |
| for (p = abfd->sections; p != NULL; p = p->next) |
| func (abfd, p, ...) |
*/ |
void |
bfd_map_over_sections (bfd *abfd, |
void (*operation) (bfd *, asection *, void *), |
void *user_storage) |
{ |
asection *sect; |
unsigned int i = 0; |
for (sect = abfd->sections; sect != NULL; i++, sect = sect->next) |
(*operation) (abfd, sect, user_storage); |
if (i != abfd->section_count) /* Debugging */ |
abort (); |
} |
/* |
FUNCTION |
bfd_sections_find_if |
SYNOPSIS |
asection *bfd_sections_find_if |
(bfd *abfd, |
bfd_boolean (*operation) (bfd *abfd, asection *sect, void *obj), |
void *obj); |
DESCRIPTION |
Call the provided function @var{operation} for each section |
attached to the BFD @var{abfd}, passing @var{obj} as an |
argument. The function will be called as if by |
| operation (abfd, the_section, obj); |
It returns the first section for which @var{operation} returns true. |
*/ |
asection * |
bfd_sections_find_if (bfd *abfd, |
bfd_boolean (*operation) (bfd *, asection *, void *), |
void *user_storage) |
{ |
asection *sect; |
for (sect = abfd->sections; sect != NULL; sect = sect->next) |
if ((*operation) (abfd, sect, user_storage)) |
break; |
return sect; |
} |
/* |
FUNCTION |
bfd_set_section_size |
SYNOPSIS |
bfd_boolean bfd_set_section_size |
(bfd *abfd, asection *sec, bfd_size_type val); |
DESCRIPTION |
Set @var{sec} to the size @var{val}. If the operation is |
ok, then <<TRUE>> is returned, else <<FALSE>>. |
Possible error returns: |
o <<bfd_error_invalid_operation>> - |
Writing has started to the BFD, so setting the size is invalid. |
*/ |
bfd_boolean |
bfd_set_section_size (bfd *abfd, sec_ptr ptr, bfd_size_type val) |
{ |
/* Once you've started writing to any section you cannot create or change |
the size of any others. */ |
if (abfd->output_has_begun) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
ptr->size = val; |
return TRUE; |
} |
/* |
FUNCTION |
bfd_set_section_contents |
SYNOPSIS |
bfd_boolean bfd_set_section_contents |
(bfd *abfd, asection *section, const void *data, |
file_ptr offset, bfd_size_type count); |
DESCRIPTION |
Sets the contents of the section @var{section} in BFD |
@var{abfd} to the data starting in memory at @var{data}. The |
data is written to the output section starting at offset |
@var{offset} for @var{count} octets. |
Normally <<TRUE>> is returned, else <<FALSE>>. Possible error |
returns are: |
o <<bfd_error_no_contents>> - |
The output section does not have the <<SEC_HAS_CONTENTS>> |
attribute, so nothing can be written to it. |
o and some more too |
This routine is front end to the back end function |
<<_bfd_set_section_contents>>. |
*/ |
bfd_boolean |
bfd_set_section_contents (bfd *abfd, |
sec_ptr section, |
const void *location, |
file_ptr offset, |
bfd_size_type count) |
{ |
bfd_size_type sz; |
if (!(bfd_get_section_flags (abfd, section) & SEC_HAS_CONTENTS)) |
{ |
bfd_set_error (bfd_error_no_contents); |
return FALSE; |
} |
sz = section->size; |
if ((bfd_size_type) offset > sz |
|| count > sz |
|| offset + count > sz |
|| count != (size_t) count) |
{ |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
if (!bfd_write_p (abfd)) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
/* Record a copy of the data in memory if desired. */ |
if (section->contents |
&& location != section->contents + offset) |
memcpy (section->contents + offset, location, (size_t) count); |
if (BFD_SEND (abfd, _bfd_set_section_contents, |
(abfd, section, location, offset, count))) |
{ |
abfd->output_has_begun = TRUE; |
return TRUE; |
} |
return FALSE; |
} |
/* |
FUNCTION |
bfd_get_section_contents |
SYNOPSIS |
bfd_boolean bfd_get_section_contents |
(bfd *abfd, asection *section, void *location, file_ptr offset, |
bfd_size_type count); |
DESCRIPTION |
Read data from @var{section} in BFD @var{abfd} |
into memory starting at @var{location}. The data is read at an |
offset of @var{offset} from the start of the input section, |
and is read for @var{count} bytes. |
If the contents of a constructor with the <<SEC_CONSTRUCTOR>> |
flag set are requested or if the section does not have the |
<<SEC_HAS_CONTENTS>> flag set, then the @var{location} is filled |
with zeroes. If no errors occur, <<TRUE>> is returned, else |
<<FALSE>>. |
*/ |
bfd_boolean |
bfd_get_section_contents (bfd *abfd, |
sec_ptr section, |
void *location, |
file_ptr offset, |
bfd_size_type count) |
{ |
bfd_size_type sz; |
if (section->flags & SEC_CONSTRUCTOR) |
{ |
memset (location, 0, (size_t) count); |
return TRUE; |
} |
if (abfd->direction != write_direction && section->rawsize != 0) |
sz = section->rawsize; |
else |
sz = section->size; |
if ((bfd_size_type) offset > sz |
|| count > sz |
|| offset + count > sz |
|| count != (size_t) count) |
{ |
bfd_set_error (bfd_error_bad_value); |
return FALSE; |
} |
if (count == 0) |
/* Don't bother. */ |
return TRUE; |
if ((section->flags & SEC_HAS_CONTENTS) == 0) |
{ |
memset (location, 0, (size_t) count); |
return TRUE; |
} |
if ((section->flags & SEC_IN_MEMORY) != 0) |
{ |
if (section->contents == NULL) |
{ |
/* This can happen because of errors earlier on in the linking process. |
We do not want to seg-fault here, so clear the flag and return an |
error code. */ |
section->flags &= ~ SEC_IN_MEMORY; |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
memmove (location, section->contents + offset, (size_t) count); |
return TRUE; |
} |
return BFD_SEND (abfd, _bfd_get_section_contents, |
(abfd, section, location, offset, count)); |
} |
/* |
FUNCTION |
bfd_malloc_and_get_section |
SYNOPSIS |
bfd_boolean bfd_malloc_and_get_section |
(bfd *abfd, asection *section, bfd_byte **buf); |
DESCRIPTION |
Read all data from @var{section} in BFD @var{abfd} |
into a buffer, *@var{buf}, malloc'd by this function. |
*/ |
bfd_boolean |
bfd_malloc_and_get_section (bfd *abfd, sec_ptr sec, bfd_byte **buf) |
{ |
*buf = NULL; |
return bfd_get_full_section_contents (abfd, sec, buf); |
} |
/* |
FUNCTION |
bfd_copy_private_section_data |
SYNOPSIS |
bfd_boolean bfd_copy_private_section_data |
(bfd *ibfd, asection *isec, bfd *obfd, asection *osec); |
DESCRIPTION |
Copy private section information from @var{isec} in the BFD |
@var{ibfd} to the section @var{osec} in the BFD @var{obfd}. |
Return <<TRUE>> on success, <<FALSE>> on error. Possible error |
returns are: |
o <<bfd_error_no_memory>> - |
Not enough memory exists to create private data for @var{osec}. |
.#define bfd_copy_private_section_data(ibfd, isection, obfd, osection) \ |
. BFD_SEND (obfd, _bfd_copy_private_section_data, \ |
. (ibfd, isection, obfd, osection)) |
*/ |
/* |
FUNCTION |
bfd_generic_is_group_section |
SYNOPSIS |
bfd_boolean bfd_generic_is_group_section (bfd *, const asection *sec); |
DESCRIPTION |
Returns TRUE if @var{sec} is a member of a group. |
*/ |
bfd_boolean |
bfd_generic_is_group_section (bfd *abfd ATTRIBUTE_UNUSED, |
const asection *sec ATTRIBUTE_UNUSED) |
{ |
return FALSE; |
} |
/* |
FUNCTION |
bfd_generic_discard_group |
SYNOPSIS |
bfd_boolean bfd_generic_discard_group (bfd *abfd, asection *group); |
DESCRIPTION |
Remove all members of @var{group} from the output. |
*/ |
bfd_boolean |
bfd_generic_discard_group (bfd *abfd ATTRIBUTE_UNUSED, |
asection *group ATTRIBUTE_UNUSED) |
{ |
return TRUE; |
} |
/contrib/toolchain/binutils/bfd/simple.c |
---|
0,0 → 1,253 |
/* simple.c -- BFD simple client routines |
Copyright 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011 |
Free Software Foundation, Inc. |
Contributed by MontaVista Software, Inc. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
#include "bfdlink.h" |
static bfd_boolean |
simple_dummy_warning (struct bfd_link_info *link_info ATTRIBUTE_UNUSED, |
const char *warning ATTRIBUTE_UNUSED, |
const char *symbol ATTRIBUTE_UNUSED, |
bfd *abfd ATTRIBUTE_UNUSED, |
asection *section ATTRIBUTE_UNUSED, |
bfd_vma address ATTRIBUTE_UNUSED) |
{ |
return TRUE; |
} |
static bfd_boolean |
simple_dummy_undefined_symbol (struct bfd_link_info *link_info ATTRIBUTE_UNUSED, |
const char *name ATTRIBUTE_UNUSED, |
bfd *abfd ATTRIBUTE_UNUSED, |
asection *section ATTRIBUTE_UNUSED, |
bfd_vma address ATTRIBUTE_UNUSED, |
bfd_boolean fatal ATTRIBUTE_UNUSED) |
{ |
return TRUE; |
} |
static bfd_boolean |
simple_dummy_reloc_overflow (struct bfd_link_info *link_info ATTRIBUTE_UNUSED, |
struct bfd_link_hash_entry *entry ATTRIBUTE_UNUSED, |
const char *name ATTRIBUTE_UNUSED, |
const char *reloc_name ATTRIBUTE_UNUSED, |
bfd_vma addend ATTRIBUTE_UNUSED, |
bfd *abfd ATTRIBUTE_UNUSED, |
asection *section ATTRIBUTE_UNUSED, |
bfd_vma address ATTRIBUTE_UNUSED) |
{ |
return TRUE; |
} |
static bfd_boolean |
simple_dummy_reloc_dangerous (struct bfd_link_info *link_info ATTRIBUTE_UNUSED, |
const char *message ATTRIBUTE_UNUSED, |
bfd *abfd ATTRIBUTE_UNUSED, |
asection *section ATTRIBUTE_UNUSED, |
bfd_vma address ATTRIBUTE_UNUSED) |
{ |
return TRUE; |
} |
static bfd_boolean |
simple_dummy_unattached_reloc (struct bfd_link_info *link_info ATTRIBUTE_UNUSED, |
const char *name ATTRIBUTE_UNUSED, |
bfd *abfd ATTRIBUTE_UNUSED, |
asection *section ATTRIBUTE_UNUSED, |
bfd_vma address ATTRIBUTE_UNUSED) |
{ |
return TRUE; |
} |
static bfd_boolean |
simple_dummy_multiple_definition (struct bfd_link_info *link_info ATTRIBUTE_UNUSED, |
struct bfd_link_hash_entry *h ATTRIBUTE_UNUSED, |
bfd *nbfd ATTRIBUTE_UNUSED, |
asection *nsec ATTRIBUTE_UNUSED, |
bfd_vma nval ATTRIBUTE_UNUSED) |
{ |
return TRUE; |
} |
static void |
simple_dummy_einfo (const char *fmt ATTRIBUTE_UNUSED, ...) |
{ |
} |
struct saved_output_info |
{ |
bfd_vma offset; |
asection *section; |
}; |
static void |
simple_save_output_info (bfd *abfd ATTRIBUTE_UNUSED, |
asection *section, |
void *ptr) |
{ |
struct saved_output_info *output_info = (struct saved_output_info *) ptr; |
output_info[section->index].offset = section->output_offset; |
output_info[section->index].section = section->output_section; |
if ((section->flags & SEC_DEBUGGING) != 0 |
|| section->output_section == NULL) |
{ |
section->output_offset = 0; |
section->output_section = section; |
} |
} |
static void |
simple_restore_output_info (bfd *abfd ATTRIBUTE_UNUSED, |
asection *section, |
void *ptr) |
{ |
struct saved_output_info *output_info = (struct saved_output_info *) ptr; |
section->output_offset = output_info[section->index].offset; |
section->output_section = output_info[section->index].section; |
} |
/* |
FUNCTION |
bfd_simple_relocate_secton |
SYNOPSIS |
bfd_byte *bfd_simple_get_relocated_section_contents |
(bfd *abfd, asection *sec, bfd_byte *outbuf, asymbol **symbol_table); |
DESCRIPTION |
Returns the relocated contents of section @var{sec}. The symbols in |
@var{symbol_table} will be used, or the symbols from @var{abfd} if |
@var{symbol_table} is NULL. The output offsets for debug sections will |
be temporarily reset to 0. The result will be stored at @var{outbuf} |
or allocated with @code{bfd_malloc} if @var{outbuf} is @code{NULL}. |
Returns @code{NULL} on a fatal error; ignores errors applying |
particular relocations. |
*/ |
bfd_byte * |
bfd_simple_get_relocated_section_contents (bfd *abfd, |
asection *sec, |
bfd_byte *outbuf, |
asymbol **symbol_table) |
{ |
struct bfd_link_info link_info; |
struct bfd_link_order link_order; |
struct bfd_link_callbacks callbacks; |
bfd_byte *contents, *data; |
int storage_needed; |
void *saved_offsets; |
/* Don't apply relocation on executable and shared library. See |
PR 4756. */ |
if ((abfd->flags & (HAS_RELOC | EXEC_P | DYNAMIC)) != HAS_RELOC |
|| ! (sec->flags & SEC_RELOC)) |
{ |
contents = outbuf; |
if (!bfd_get_full_section_contents (abfd, sec, &contents)) |
return NULL; |
return contents; |
} |
/* In order to use bfd_get_relocated_section_contents, we need |
to forge some data structures that it expects. */ |
/* Fill in the bare minimum number of fields for our purposes. */ |
memset (&link_info, 0, sizeof (link_info)); |
link_info.output_bfd = abfd; |
link_info.input_bfds = abfd; |
link_info.input_bfds_tail = &abfd->link_next; |
link_info.hash = _bfd_generic_link_hash_table_create (abfd); |
link_info.callbacks = &callbacks; |
callbacks.warning = simple_dummy_warning; |
callbacks.undefined_symbol = simple_dummy_undefined_symbol; |
callbacks.reloc_overflow = simple_dummy_reloc_overflow; |
callbacks.reloc_dangerous = simple_dummy_reloc_dangerous; |
callbacks.unattached_reloc = simple_dummy_unattached_reloc; |
callbacks.multiple_definition = simple_dummy_multiple_definition; |
callbacks.einfo = simple_dummy_einfo; |
memset (&link_order, 0, sizeof (link_order)); |
link_order.next = NULL; |
link_order.type = bfd_indirect_link_order; |
link_order.offset = 0; |
link_order.size = sec->size; |
link_order.u.indirect.section = sec; |
data = NULL; |
if (outbuf == NULL) |
{ |
bfd_size_type amt = sec->rawsize > sec->size ? sec->rawsize : sec->size; |
data = (bfd_byte *) bfd_malloc (amt); |
if (data == NULL) |
return NULL; |
outbuf = data; |
} |
/* The sections in ABFD may already have output sections and offsets set. |
Because this function is primarily for debug sections, and GCC uses the |
knowledge that debug sections will generally have VMA 0 when emitting |
relocations between DWARF-2 sections (which are supposed to be |
section-relative offsets anyway), we need to reset the output offsets |
to zero. We also need to arrange for section->output_section->vma plus |
section->output_offset to equal section->vma, which we do by setting |
section->output_section to point back to section. Save the original |
output offset and output section to restore later. */ |
saved_offsets = malloc (sizeof (struct saved_output_info) |
* abfd->section_count); |
if (saved_offsets == NULL) |
{ |
if (data) |
free (data); |
return NULL; |
} |
bfd_map_over_sections (abfd, simple_save_output_info, saved_offsets); |
if (symbol_table == NULL) |
{ |
_bfd_generic_link_add_symbols (abfd, &link_info); |
storage_needed = bfd_get_symtab_upper_bound (abfd); |
symbol_table = (asymbol **) bfd_malloc (storage_needed); |
bfd_canonicalize_symtab (abfd, symbol_table); |
} |
else |
storage_needed = 0; |
contents = bfd_get_relocated_section_contents (abfd, |
&link_info, |
&link_order, |
outbuf, |
0, |
symbol_table); |
if (contents == NULL && data != NULL) |
free (data); |
bfd_map_over_sections (abfd, simple_restore_output_info, saved_offsets); |
free (saved_offsets); |
_bfd_generic_link_hash_table_free (link_info.hash); |
return contents; |
} |
/contrib/toolchain/binutils/bfd/srec.c |
---|
0,0 → 1,1381 |
/* BFD back-end for s-record objects. |
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, |
2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011 |
Free Software Foundation, Inc. |
Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* SUBSECTION |
S-Record handling |
DESCRIPTION |
Ordinary S-Records cannot hold anything but addresses and |
data, so that's all that we implement. |
The only interesting thing is that S-Records may come out of |
order and there is no header, so an initial scan is required |
to discover the minimum and maximum addresses used to create |
the vma and size of the only section we create. We |
arbitrarily call this section ".text". |
When bfd_get_section_contents is called the file is read |
again, and this time the data is placed into a bfd_alloc'd |
area. |
Any number of sections may be created for output, we save them |
up and output them when it's time to close the bfd. |
An s record looks like: |
EXAMPLE |
S<type><length><address><data><checksum> |
DESCRIPTION |
Where |
o length |
is the number of bytes following upto the checksum. Note that |
this is not the number of chars following, since it takes two |
chars to represent a byte. |
o type |
is one of: |
0) header record |
1) two byte address data record |
2) three byte address data record |
3) four byte address data record |
7) four byte address termination record |
8) three byte address termination record |
9) two byte address termination record |
o address |
is the start address of the data following, or in the case of |
a termination record, the start address of the image |
o data |
is the data. |
o checksum |
is the sum of all the raw byte data in the record, from the length |
upwards, modulo 256 and subtracted from 255. |
SUBSECTION |
Symbol S-Record handling |
DESCRIPTION |
Some ICE equipment understands an addition to the standard |
S-Record format; symbols and their addresses can be sent |
before the data. |
The format of this is: |
($$ <modulename> |
(<space> <symbol> <address>)*) |
$$ |
so a short symbol table could look like: |
EXAMPLE |
$$ flash.x |
$$ flash.c |
_port6 $0 |
_delay $4 |
_start $14 |
_etext $8036 |
_edata $8036 |
_end $8036 |
$$ |
DESCRIPTION |
We allow symbols to be anywhere in the data stream - the module names |
are always ignored. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
#include "libiberty.h" |
#include "safe-ctype.h" |
/* Macros for converting between hex and binary. */ |
static const char digs[] = "0123456789ABCDEF"; |
#define NIBBLE(x) hex_value(x) |
#define HEX(buffer) ((NIBBLE ((buffer)[0])<<4) + NIBBLE ((buffer)[1])) |
#define TOHEX(d, x, ch) \ |
d[1] = digs[(x) & 0xf]; \ |
d[0] = digs[((x)>>4)&0xf]; \ |
ch += ((x) & 0xff); |
#define ISHEX(x) hex_p(x) |
/* The maximum number of address+data+crc bytes on a line is FF. */ |
#define MAXCHUNK 0xff |
/* Default size for a CHUNK. */ |
#define DEFAULT_CHUNK 16 |
/* The number of data bytes we actually fit onto a line on output. |
This variable can be modified by objcopy's --srec-len parameter. |
For a 0x75 byte record you should set --srec-len=0x70. */ |
unsigned int Chunk = DEFAULT_CHUNK; |
/* The type of srec output (free or forced to S3). |
This variable can be modified by objcopy's --srec-forceS3 |
parameter. */ |
bfd_boolean S3Forced = FALSE; |
/* When writing an S-record file, the S-records can not be output as |
they are seen. This structure is used to hold them in memory. */ |
struct srec_data_list_struct |
{ |
struct srec_data_list_struct *next; |
bfd_byte *data; |
bfd_vma where; |
bfd_size_type size; |
}; |
typedef struct srec_data_list_struct srec_data_list_type; |
/* When scanning the S-record file, a linked list of srec_symbol |
structures is built to represent the symbol table (if there is |
one). */ |
struct srec_symbol |
{ |
struct srec_symbol *next; |
const char *name; |
bfd_vma val; |
}; |
/* The S-record tdata information. */ |
typedef struct srec_data_struct |
{ |
srec_data_list_type *head; |
srec_data_list_type *tail; |
unsigned int type; |
struct srec_symbol *symbols; |
struct srec_symbol *symtail; |
asymbol *csymbols; |
} |
tdata_type; |
/* Initialize by filling in the hex conversion array. */ |
static void |
srec_init (void) |
{ |
static bfd_boolean inited = FALSE; |
if (! inited) |
{ |
inited = TRUE; |
hex_init (); |
} |
} |
/* Set up the S-record tdata information. */ |
static bfd_boolean |
srec_mkobject (bfd *abfd) |
{ |
tdata_type *tdata; |
srec_init (); |
tdata = (tdata_type *) bfd_alloc (abfd, sizeof (tdata_type)); |
if (tdata == NULL) |
return FALSE; |
abfd->tdata.srec_data = tdata; |
tdata->type = 1; |
tdata->head = NULL; |
tdata->tail = NULL; |
tdata->symbols = NULL; |
tdata->symtail = NULL; |
tdata->csymbols = NULL; |
return TRUE; |
} |
/* Read a byte from an S record file. Set *ERRORPTR if an error |
occurred. Return EOF on error or end of file. */ |
static int |
srec_get_byte (bfd *abfd, bfd_boolean *errorptr) |
{ |
bfd_byte c; |
if (bfd_bread (&c, (bfd_size_type) 1, abfd) != 1) |
{ |
if (bfd_get_error () != bfd_error_file_truncated) |
*errorptr = TRUE; |
return EOF; |
} |
return (int) (c & 0xff); |
} |
/* Report a problem in an S record file. FIXME: This probably should |
not call fprintf, but we really do need some mechanism for printing |
error messages. */ |
static void |
srec_bad_byte (bfd *abfd, |
unsigned int lineno, |
int c, |
bfd_boolean error) |
{ |
if (c == EOF) |
{ |
if (! error) |
bfd_set_error (bfd_error_file_truncated); |
} |
else |
{ |
char buf[10]; |
if (! ISPRINT (c)) |
sprintf (buf, "\\%03o", (unsigned int) c); |
else |
{ |
buf[0] = c; |
buf[1] = '\0'; |
} |
(*_bfd_error_handler) |
(_("%B:%d: Unexpected character `%s' in S-record file\n"), |
abfd, lineno, buf); |
bfd_set_error (bfd_error_bad_value); |
} |
} |
/* Add a new symbol found in an S-record file. */ |
static bfd_boolean |
srec_new_symbol (bfd *abfd, const char *name, bfd_vma val) |
{ |
struct srec_symbol *n; |
n = (struct srec_symbol *) bfd_alloc (abfd, sizeof (* n)); |
if (n == NULL) |
return FALSE; |
n->name = name; |
n->val = val; |
if (abfd->tdata.srec_data->symbols == NULL) |
abfd->tdata.srec_data->symbols = n; |
else |
abfd->tdata.srec_data->symtail->next = n; |
abfd->tdata.srec_data->symtail = n; |
n->next = NULL; |
++abfd->symcount; |
return TRUE; |
} |
/* Read the S record file and turn it into sections. We create a new |
section for each contiguous set of bytes. */ |
static bfd_boolean |
srec_scan (bfd *abfd) |
{ |
int c; |
unsigned int lineno = 1; |
bfd_boolean error = FALSE; |
bfd_byte *buf = NULL; |
size_t bufsize = 0; |
asection *sec = NULL; |
char *symbuf = NULL; |
if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) |
goto error_return; |
while ((c = srec_get_byte (abfd, &error)) != EOF) |
{ |
/* We only build sections from contiguous S-records, so if this |
is not an S-record, then stop building a section. */ |
if (c != 'S' && c != '\r' && c != '\n') |
sec = NULL; |
switch (c) |
{ |
default: |
srec_bad_byte (abfd, lineno, c, error); |
goto error_return; |
case '\n': |
++lineno; |
break; |
case '\r': |
break; |
case '$': |
/* Starting a module name, which we ignore. */ |
while ((c = srec_get_byte (abfd, &error)) != '\n' |
&& c != EOF) |
; |
if (c == EOF) |
{ |
srec_bad_byte (abfd, lineno, c, error); |
goto error_return; |
} |
++lineno; |
break; |
case ' ': |
do |
{ |
bfd_size_type alc; |
char *p, *symname; |
bfd_vma symval; |
/* Starting a symbol definition. */ |
while ((c = srec_get_byte (abfd, &error)) != EOF |
&& (c == ' ' || c == '\t')) |
; |
if (c == '\n' || c == '\r') |
break; |
if (c == EOF) |
{ |
srec_bad_byte (abfd, lineno, c, error); |
goto error_return; |
} |
alc = 10; |
symbuf = (char *) bfd_malloc (alc + 1); |
if (symbuf == NULL) |
goto error_return; |
p = symbuf; |
*p++ = c; |
while ((c = srec_get_byte (abfd, &error)) != EOF |
&& ! ISSPACE (c)) |
{ |
if ((bfd_size_type) (p - symbuf) >= alc) |
{ |
char *n; |
alc *= 2; |
n = (char *) bfd_realloc (symbuf, alc + 1); |
if (n == NULL) |
goto error_return; |
p = n + (p - symbuf); |
symbuf = n; |
} |
*p++ = c; |
} |
if (c == EOF) |
{ |
srec_bad_byte (abfd, lineno, c, error); |
goto error_return; |
} |
*p++ = '\0'; |
symname = (char *) bfd_alloc (abfd, (bfd_size_type) (p - symbuf)); |
if (symname == NULL) |
goto error_return; |
strcpy (symname, symbuf); |
free (symbuf); |
symbuf = NULL; |
while ((c = srec_get_byte (abfd, &error)) != EOF |
&& (c == ' ' || c == '\t')) |
; |
if (c == EOF) |
{ |
srec_bad_byte (abfd, lineno, c, error); |
goto error_return; |
} |
/* Skip a dollar sign before the hex value. */ |
if (c == '$') |
{ |
c = srec_get_byte (abfd, &error); |
if (c == EOF) |
{ |
srec_bad_byte (abfd, lineno, c, error); |
goto error_return; |
} |
} |
symval = 0; |
while (ISHEX (c)) |
{ |
symval <<= 4; |
symval += NIBBLE (c); |
c = srec_get_byte (abfd, &error); |
if (c == EOF) |
{ |
srec_bad_byte (abfd, lineno, c, error); |
goto error_return; |
} |
} |
if (! srec_new_symbol (abfd, symname, symval)) |
goto error_return; |
} |
while (c == ' ' || c == '\t') |
; |
if (c == '\n') |
++lineno; |
else if (c != '\r') |
{ |
srec_bad_byte (abfd, lineno, c, error); |
goto error_return; |
} |
break; |
case 'S': |
{ |
file_ptr pos; |
char hdr[3]; |
unsigned int bytes; |
bfd_vma address; |
bfd_byte *data; |
unsigned char check_sum; |
/* Starting an S-record. */ |
pos = bfd_tell (abfd) - 1; |
if (bfd_bread (hdr, (bfd_size_type) 3, abfd) != 3) |
goto error_return; |
if (! ISHEX (hdr[1]) || ! ISHEX (hdr[2])) |
{ |
if (! ISHEX (hdr[1])) |
c = hdr[1]; |
else |
c = hdr[2]; |
srec_bad_byte (abfd, lineno, c, error); |
goto error_return; |
} |
check_sum = bytes = HEX (hdr + 1); |
if (bytes * 2 > bufsize) |
{ |
if (buf != NULL) |
free (buf); |
buf = (bfd_byte *) bfd_malloc ((bfd_size_type) bytes * 2); |
if (buf == NULL) |
goto error_return; |
bufsize = bytes * 2; |
} |
if (bfd_bread (buf, (bfd_size_type) bytes * 2, abfd) != bytes * 2) |
goto error_return; |
/* Ignore the checksum byte. */ |
--bytes; |
address = 0; |
data = buf; |
switch (hdr[0]) |
{ |
case '0': |
case '5': |
/* Prologue--ignore the file name, but stop building a |
section at this point. */ |
sec = NULL; |
break; |
case '3': |
check_sum += HEX (data); |
address = HEX (data); |
data += 2; |
--bytes; |
/* Fall through. */ |
case '2': |
check_sum += HEX (data); |
address = (address << 8) | HEX (data); |
data += 2; |
--bytes; |
/* Fall through. */ |
case '1': |
check_sum += HEX (data); |
address = (address << 8) | HEX (data); |
data += 2; |
check_sum += HEX (data); |
address = (address << 8) | HEX (data); |
data += 2; |
bytes -= 2; |
if (sec != NULL |
&& sec->vma + sec->size == address) |
{ |
/* This data goes at the end of the section we are |
currently building. */ |
sec->size += bytes; |
} |
else |
{ |
char secbuf[20]; |
char *secname; |
bfd_size_type amt; |
flagword flags; |
sprintf (secbuf, ".sec%d", bfd_count_sections (abfd) + 1); |
amt = strlen (secbuf) + 1; |
secname = (char *) bfd_alloc (abfd, amt); |
strcpy (secname, secbuf); |
flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC; |
sec = bfd_make_section_with_flags (abfd, secname, flags); |
if (sec == NULL) |
goto error_return; |
sec->vma = address; |
sec->lma = address; |
sec->size = bytes; |
sec->filepos = pos; |
} |
while (bytes > 0) |
{ |
check_sum += HEX (data); |
data += 2; |
bytes--; |
} |
check_sum = 255 - (check_sum & 0xff); |
if (check_sum != HEX (data)) |
{ |
(*_bfd_error_handler) |
(_("%B:%d: Bad checksum in S-record file\n"), |
abfd, lineno); |
bfd_set_error (bfd_error_bad_value); |
goto error_return; |
} |
break; |
case '7': |
check_sum += HEX (data); |
address = HEX (data); |
data += 2; |
/* Fall through. */ |
case '8': |
check_sum += HEX (data); |
address = (address << 8) | HEX (data); |
data += 2; |
/* Fall through. */ |
case '9': |
check_sum += HEX (data); |
address = (address << 8) | HEX (data); |
data += 2; |
check_sum += HEX (data); |
address = (address << 8) | HEX (data); |
data += 2; |
/* This is a termination record. */ |
abfd->start_address = address; |
check_sum = 255 - (check_sum & 0xff); |
if (check_sum != HEX (data)) |
{ |
(*_bfd_error_handler) |
(_("%B:%d: Bad checksum in S-record file\n"), |
abfd, lineno); |
bfd_set_error (bfd_error_bad_value); |
goto error_return; |
} |
if (buf != NULL) |
free (buf); |
return TRUE; |
} |
} |
break; |
} |
} |
if (error) |
goto error_return; |
if (buf != NULL) |
free (buf); |
return TRUE; |
error_return: |
if (symbuf != NULL) |
free (symbuf); |
if (buf != NULL) |
free (buf); |
return FALSE; |
} |
/* Check whether an existing file is an S-record file. */ |
static const bfd_target * |
srec_object_p (bfd *abfd) |
{ |
void * tdata_save; |
bfd_byte b[4]; |
srec_init (); |
if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 |
|| bfd_bread (b, (bfd_size_type) 4, abfd) != 4) |
return NULL; |
if (b[0] != 'S' || !ISHEX (b[1]) || !ISHEX (b[2]) || !ISHEX (b[3])) |
{ |
bfd_set_error (bfd_error_wrong_format); |
return NULL; |
} |
tdata_save = abfd->tdata.any; |
if (! srec_mkobject (abfd) || ! srec_scan (abfd)) |
{ |
if (abfd->tdata.any != tdata_save && abfd->tdata.any != NULL) |
bfd_release (abfd, abfd->tdata.any); |
abfd->tdata.any = tdata_save; |
return NULL; |
} |
if (abfd->symcount > 0) |
abfd->flags |= HAS_SYMS; |
return abfd->xvec; |
} |
/* Check whether an existing file is an S-record file with symbols. */ |
static const bfd_target * |
symbolsrec_object_p (bfd *abfd) |
{ |
void * tdata_save; |
char b[2]; |
srec_init (); |
if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 |
|| bfd_bread (b, (bfd_size_type) 2, abfd) != 2) |
return NULL; |
if (b[0] != '$' || b[1] != '$') |
{ |
bfd_set_error (bfd_error_wrong_format); |
return NULL; |
} |
tdata_save = abfd->tdata.any; |
if (! srec_mkobject (abfd) || ! srec_scan (abfd)) |
{ |
if (abfd->tdata.any != tdata_save && abfd->tdata.any != NULL) |
bfd_release (abfd, abfd->tdata.any); |
abfd->tdata.any = tdata_save; |
return NULL; |
} |
if (abfd->symcount > 0) |
abfd->flags |= HAS_SYMS; |
return abfd->xvec; |
} |
/* Read in the contents of a section in an S-record file. */ |
static bfd_boolean |
srec_read_section (bfd *abfd, asection *section, bfd_byte *contents) |
{ |
int c; |
bfd_size_type sofar = 0; |
bfd_boolean error = FALSE; |
bfd_byte *buf = NULL; |
size_t bufsize = 0; |
if (bfd_seek (abfd, section->filepos, SEEK_SET) != 0) |
goto error_return; |
while ((c = srec_get_byte (abfd, &error)) != EOF) |
{ |
bfd_byte hdr[3]; |
unsigned int bytes; |
bfd_vma address; |
bfd_byte *data; |
if (c == '\r' || c == '\n') |
continue; |
/* This is called after srec_scan has already been called, so we |
ought to know the exact format. */ |
BFD_ASSERT (c == 'S'); |
if (bfd_bread (hdr, (bfd_size_type) 3, abfd) != 3) |
goto error_return; |
BFD_ASSERT (ISHEX (hdr[1]) && ISHEX (hdr[2])); |
bytes = HEX (hdr + 1); |
if (bytes * 2 > bufsize) |
{ |
if (buf != NULL) |
free (buf); |
buf = (bfd_byte *) bfd_malloc ((bfd_size_type) bytes * 2); |
if (buf == NULL) |
goto error_return; |
bufsize = bytes * 2; |
} |
if (bfd_bread (buf, (bfd_size_type) bytes * 2, abfd) != bytes * 2) |
goto error_return; |
address = 0; |
data = buf; |
switch (hdr[0]) |
{ |
default: |
BFD_ASSERT (sofar == section->size); |
if (buf != NULL) |
free (buf); |
return TRUE; |
case '3': |
address = HEX (data); |
data += 2; |
--bytes; |
/* Fall through. */ |
case '2': |
address = (address << 8) | HEX (data); |
data += 2; |
--bytes; |
/* Fall through. */ |
case '1': |
address = (address << 8) | HEX (data); |
data += 2; |
address = (address << 8) | HEX (data); |
data += 2; |
bytes -= 2; |
if (address != section->vma + sofar) |
{ |
/* We've come to the end of this section. */ |
BFD_ASSERT (sofar == section->size); |
if (buf != NULL) |
free (buf); |
return TRUE; |
} |
/* Don't consider checksum. */ |
--bytes; |
while (bytes-- != 0) |
{ |
contents[sofar] = HEX (data); |
data += 2; |
++sofar; |
} |
break; |
} |
} |
if (error) |
goto error_return; |
BFD_ASSERT (sofar == section->size); |
if (buf != NULL) |
free (buf); |
return TRUE; |
error_return: |
if (buf != NULL) |
free (buf); |
return FALSE; |
} |
/* Get the contents of a section in an S-record file. */ |
static bfd_boolean |
srec_get_section_contents (bfd *abfd, |
asection *section, |
void * location, |
file_ptr offset, |
bfd_size_type count) |
{ |
if (count == 0) |
return TRUE; |
if (offset + count < count |
|| offset + count > section->size) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
if (section->used_by_bfd == NULL) |
{ |
section->used_by_bfd = bfd_alloc (abfd, section->size); |
if (section->used_by_bfd == NULL) |
return FALSE; |
if (! srec_read_section (abfd, section, |
(bfd_byte *) section->used_by_bfd)) |
return FALSE; |
} |
memcpy (location, (bfd_byte *) section->used_by_bfd + offset, |
(size_t) count); |
return TRUE; |
} |
/* Set the architecture. We accept an unknown architecture here. */ |
static bfd_boolean |
srec_set_arch_mach (bfd *abfd, enum bfd_architecture arch, unsigned long mach) |
{ |
if (arch != bfd_arch_unknown) |
return bfd_default_set_arch_mach (abfd, arch, mach); |
abfd->arch_info = & bfd_default_arch_struct; |
return TRUE; |
} |
/* We have to save up all the Srecords for a splurge before output. */ |
static bfd_boolean |
srec_set_section_contents (bfd *abfd, |
sec_ptr section, |
const void * location, |
file_ptr offset, |
bfd_size_type bytes_to_do) |
{ |
int opb = bfd_octets_per_byte (abfd); |
tdata_type *tdata = abfd->tdata.srec_data; |
srec_data_list_type *entry; |
entry = (srec_data_list_type *) bfd_alloc (abfd, sizeof (* entry)); |
if (entry == NULL) |
return FALSE; |
if (bytes_to_do |
&& (section->flags & SEC_ALLOC) |
&& (section->flags & SEC_LOAD)) |
{ |
bfd_byte *data; |
data = (bfd_byte *) bfd_alloc (abfd, bytes_to_do); |
if (data == NULL) |
return FALSE; |
memcpy ((void *) data, location, (size_t) bytes_to_do); |
/* Ff S3Forced is TRUE then always select S3 records, |
regardless of the siez of the addresses. */ |
if (S3Forced) |
tdata->type = 3; |
else if ((section->lma + (offset + bytes_to_do) / opb - 1) <= 0xffff) |
; /* The default, S1, is OK. */ |
else if ((section->lma + (offset + bytes_to_do) / opb - 1) <= 0xffffff |
&& tdata->type <= 2) |
tdata->type = 2; |
else |
tdata->type = 3; |
entry->data = data; |
entry->where = section->lma + offset / opb; |
entry->size = bytes_to_do; |
/* Sort the records by address. Optimize for the common case of |
adding a record to the end of the list. */ |
if (tdata->tail != NULL |
&& entry->where >= tdata->tail->where) |
{ |
tdata->tail->next = entry; |
entry->next = NULL; |
tdata->tail = entry; |
} |
else |
{ |
srec_data_list_type **look; |
for (look = &tdata->head; |
*look != NULL && (*look)->where < entry->where; |
look = &(*look)->next) |
; |
entry->next = *look; |
*look = entry; |
if (entry->next == NULL) |
tdata->tail = entry; |
} |
} |
return TRUE; |
} |
/* Write a record of type, of the supplied number of bytes. The |
supplied bytes and length don't have a checksum. That's worked out |
here. */ |
static bfd_boolean |
srec_write_record (bfd *abfd, |
unsigned int type, |
bfd_vma address, |
const bfd_byte *data, |
const bfd_byte *end) |
{ |
char buffer[2 * MAXCHUNK + 6]; |
unsigned int check_sum = 0; |
const bfd_byte *src = data; |
char *dst = buffer; |
char *length; |
bfd_size_type wrlen; |
*dst++ = 'S'; |
*dst++ = '0' + type; |
length = dst; |
dst += 2; /* Leave room for dst. */ |
switch (type) |
{ |
case 3: |
case 7: |
TOHEX (dst, (address >> 24), check_sum); |
dst += 2; |
case 8: |
case 2: |
TOHEX (dst, (address >> 16), check_sum); |
dst += 2; |
case 9: |
case 1: |
case 0: |
TOHEX (dst, (address >> 8), check_sum); |
dst += 2; |
TOHEX (dst, (address), check_sum); |
dst += 2; |
break; |
} |
for (src = data; src < end; src++) |
{ |
TOHEX (dst, *src, check_sum); |
dst += 2; |
} |
/* Fill in the length. */ |
TOHEX (length, (dst - length) / 2, check_sum); |
check_sum &= 0xff; |
check_sum = 255 - check_sum; |
TOHEX (dst, check_sum, check_sum); |
dst += 2; |
*dst++ = '\r'; |
*dst++ = '\n'; |
wrlen = dst - buffer; |
return bfd_bwrite ((void *) buffer, wrlen, abfd) == wrlen; |
} |
static bfd_boolean |
srec_write_header (bfd *abfd) |
{ |
unsigned int len = strlen (abfd->filename); |
/* I'll put an arbitrary 40 char limit on header size. */ |
if (len > 40) |
len = 40; |
return srec_write_record (abfd, 0, (bfd_vma) 0, |
(bfd_byte *) abfd->filename, |
(bfd_byte *) abfd->filename + len); |
} |
static bfd_boolean |
srec_write_section (bfd *abfd, |
tdata_type *tdata, |
srec_data_list_type *list) |
{ |
unsigned int octets_written = 0; |
bfd_byte *location = list->data; |
/* Validate number of data bytes to write. The srec length byte |
counts the address, data and crc bytes. S1 (tdata->type == 1) |
records have two address bytes, S2 (tdata->type == 2) records |
have three, and S3 (tdata->type == 3) records have four. |
The total length can't exceed 255, and a zero data length will |
spin for a long time. */ |
if (Chunk == 0) |
Chunk = 1; |
else if (Chunk > MAXCHUNK - tdata->type - 2) |
Chunk = MAXCHUNK - tdata->type - 2; |
while (octets_written < list->size) |
{ |
bfd_vma address; |
unsigned int octets_this_chunk = list->size - octets_written; |
if (octets_this_chunk > Chunk) |
octets_this_chunk = Chunk; |
address = list->where + octets_written / bfd_octets_per_byte (abfd); |
if (! srec_write_record (abfd, |
tdata->type, |
address, |
location, |
location + octets_this_chunk)) |
return FALSE; |
octets_written += octets_this_chunk; |
location += octets_this_chunk; |
} |
return TRUE; |
} |
static bfd_boolean |
srec_write_terminator (bfd *abfd, tdata_type *tdata) |
{ |
return srec_write_record (abfd, 10 - tdata->type, |
abfd->start_address, NULL, NULL); |
} |
static bfd_boolean |
srec_write_symbols (bfd *abfd) |
{ |
/* Dump out the symbols of a bfd. */ |
int i; |
int count = bfd_get_symcount (abfd); |
if (count) |
{ |
bfd_size_type len; |
asymbol **table = bfd_get_outsymbols (abfd); |
len = strlen (abfd->filename); |
if (bfd_bwrite ("$$ ", (bfd_size_type) 3, abfd) != 3 |
|| bfd_bwrite (abfd->filename, len, abfd) != len |
|| bfd_bwrite ("\r\n", (bfd_size_type) 2, abfd) != 2) |
return FALSE; |
for (i = 0; i < count; i++) |
{ |
asymbol *s = table[i]; |
if (! bfd_is_local_label (abfd, s) |
&& (s->flags & BSF_DEBUGGING) == 0) |
{ |
/* Just dump out non debug symbols. */ |
char buf[43], *p; |
len = strlen (s->name); |
if (bfd_bwrite (" ", (bfd_size_type) 2, abfd) != 2 |
|| bfd_bwrite (s->name, len, abfd) != len) |
return FALSE; |
sprintf_vma (buf + 2, (s->value |
+ s->section->output_section->lma |
+ s->section->output_offset)); |
p = buf + 2; |
while (p[0] == '0' && p[1] != 0) |
p++; |
len = strlen (p); |
p[len] = '\r'; |
p[len + 1] = '\n'; |
*--p = '$'; |
*--p = ' '; |
len += 4; |
if (bfd_bwrite (p, len, abfd) != len) |
return FALSE; |
} |
} |
if (bfd_bwrite ("$$ \r\n", (bfd_size_type) 5, abfd) != 5) |
return FALSE; |
} |
return TRUE; |
} |
static bfd_boolean |
internal_srec_write_object_contents (bfd *abfd, int symbols) |
{ |
tdata_type *tdata = abfd->tdata.srec_data; |
srec_data_list_type *list; |
if (symbols) |
{ |
if (! srec_write_symbols (abfd)) |
return FALSE; |
} |
if (! srec_write_header (abfd)) |
return FALSE; |
/* Now wander though all the sections provided and output them. */ |
list = tdata->head; |
while (list != (srec_data_list_type *) NULL) |
{ |
if (! srec_write_section (abfd, tdata, list)) |
return FALSE; |
list = list->next; |
} |
return srec_write_terminator (abfd, tdata); |
} |
static bfd_boolean |
srec_write_object_contents (bfd *abfd) |
{ |
return internal_srec_write_object_contents (abfd, 0); |
} |
static bfd_boolean |
symbolsrec_write_object_contents (bfd *abfd) |
{ |
return internal_srec_write_object_contents (abfd, 1); |
} |
static int |
srec_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED, |
struct bfd_link_info *info ATTRIBUTE_UNUSED) |
{ |
return 0; |
} |
/* Return the amount of memory needed to read the symbol table. */ |
static long |
srec_get_symtab_upper_bound (bfd *abfd) |
{ |
return (bfd_get_symcount (abfd) + 1) * sizeof (asymbol *); |
} |
/* Return the symbol table. */ |
static long |
srec_canonicalize_symtab (bfd *abfd, asymbol **alocation) |
{ |
bfd_size_type symcount = bfd_get_symcount (abfd); |
asymbol *csymbols; |
unsigned int i; |
csymbols = abfd->tdata.srec_data->csymbols; |
if (csymbols == NULL && symcount != 0) |
{ |
asymbol *c; |
struct srec_symbol *s; |
csymbols = (asymbol *) bfd_alloc (abfd, symcount * sizeof (asymbol)); |
if (csymbols == NULL) |
return -1; |
abfd->tdata.srec_data->csymbols = csymbols; |
for (s = abfd->tdata.srec_data->symbols, c = csymbols; |
s != NULL; |
s = s->next, ++c) |
{ |
c->the_bfd = abfd; |
c->name = s->name; |
c->value = s->val; |
c->flags = BSF_GLOBAL; |
c->section = bfd_abs_section_ptr; |
c->udata.p = NULL; |
} |
} |
for (i = 0; i < symcount; i++) |
*alocation++ = csymbols++; |
*alocation = NULL; |
return symcount; |
} |
static void |
srec_get_symbol_info (bfd *ignore_abfd ATTRIBUTE_UNUSED, |
asymbol *symbol, |
symbol_info *ret) |
{ |
bfd_symbol_info (symbol, ret); |
} |
static void |
srec_print_symbol (bfd *abfd, |
void * afile, |
asymbol *symbol, |
bfd_print_symbol_type how) |
{ |
FILE *file = (FILE *) afile; |
switch (how) |
{ |
case bfd_print_symbol_name: |
fprintf (file, "%s", symbol->name); |
break; |
default: |
bfd_print_symbol_vandf (abfd, (void *) file, symbol); |
fprintf (file, " %-5s %s", |
symbol->section->name, |
symbol->name); |
} |
} |
#define srec_close_and_cleanup _bfd_generic_close_and_cleanup |
#define srec_bfd_free_cached_info _bfd_generic_bfd_free_cached_info |
#define srec_new_section_hook _bfd_generic_new_section_hook |
#define srec_bfd_is_target_special_symbol ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) |
#define srec_bfd_is_local_label_name bfd_generic_is_local_label_name |
#define srec_get_lineno _bfd_nosymbols_get_lineno |
#define srec_find_nearest_line _bfd_nosymbols_find_nearest_line |
#define srec_find_inliner_info _bfd_nosymbols_find_inliner_info |
#define srec_make_empty_symbol _bfd_generic_make_empty_symbol |
#define srec_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol |
#define srec_read_minisymbols _bfd_generic_read_minisymbols |
#define srec_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol |
#define srec_get_section_contents_in_window _bfd_generic_get_section_contents_in_window |
#define srec_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents |
#define srec_bfd_relax_section bfd_generic_relax_section |
#define srec_bfd_gc_sections bfd_generic_gc_sections |
#define srec_bfd_lookup_section_flags bfd_generic_lookup_section_flags |
#define srec_bfd_merge_sections bfd_generic_merge_sections |
#define srec_bfd_is_group_section bfd_generic_is_group_section |
#define srec_bfd_discard_group bfd_generic_discard_group |
#define srec_section_already_linked _bfd_generic_section_already_linked |
#define srec_bfd_define_common_symbol bfd_generic_define_common_symbol |
#define srec_bfd_link_hash_table_create _bfd_generic_link_hash_table_create |
#define srec_bfd_link_hash_table_free _bfd_generic_link_hash_table_free |
#define srec_bfd_link_add_symbols _bfd_generic_link_add_symbols |
#define srec_bfd_link_just_syms _bfd_generic_link_just_syms |
#define srec_bfd_copy_link_hash_symbol_type \ |
_bfd_generic_copy_link_hash_symbol_type |
#define srec_bfd_final_link _bfd_generic_final_link |
#define srec_bfd_link_split_section _bfd_generic_link_split_section |
const bfd_target srec_vec = |
{ |
"srec", /* Name. */ |
bfd_target_srec_flavour, |
BFD_ENDIAN_UNKNOWN, /* Target byte order. */ |
BFD_ENDIAN_UNKNOWN, /* Target headers byte order. */ |
(HAS_RELOC | EXEC_P | /* Object flags. */ |
HAS_LINENO | HAS_DEBUG | |
HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), |
(SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS |
| SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* Section flags. */ |
0, /* Leading underscore. */ |
' ', /* AR_pad_char. */ |
16, /* AR_max_namelen. */ |
0, /* match priority. */ |
bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Data. */ |
bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Hdrs. */ |
{ |
_bfd_dummy_target, |
srec_object_p, /* bfd_check_format. */ |
_bfd_dummy_target, |
_bfd_dummy_target, |
}, |
{ |
bfd_false, |
srec_mkobject, |
_bfd_generic_mkarchive, |
bfd_false, |
}, |
{ /* bfd_write_contents. */ |
bfd_false, |
srec_write_object_contents, |
_bfd_write_archive_contents, |
bfd_false, |
}, |
BFD_JUMP_TABLE_GENERIC (srec), |
BFD_JUMP_TABLE_COPY (_bfd_generic), |
BFD_JUMP_TABLE_CORE (_bfd_nocore), |
BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), |
BFD_JUMP_TABLE_SYMBOLS (srec), |
BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), |
BFD_JUMP_TABLE_WRITE (srec), |
BFD_JUMP_TABLE_LINK (srec), |
BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), |
NULL, |
NULL |
}; |
const bfd_target symbolsrec_vec = |
{ |
"symbolsrec", /* Name. */ |
bfd_target_srec_flavour, |
BFD_ENDIAN_UNKNOWN, /* Target byte order. */ |
BFD_ENDIAN_UNKNOWN, /* Target headers byte order. */ |
(HAS_RELOC | EXEC_P | /* Object flags. */ |
HAS_LINENO | HAS_DEBUG | |
HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), |
(SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS |
| SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* Section flags. */ |
0, /* Leading underscore. */ |
' ', /* AR_pad_char. */ |
16, /* AR_max_namelen. */ |
0, /* match priority. */ |
bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Data. */ |
bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Headers. */ |
{ |
_bfd_dummy_target, |
symbolsrec_object_p, /* bfd_check_format. */ |
_bfd_dummy_target, |
_bfd_dummy_target, |
}, |
{ |
bfd_false, |
srec_mkobject, |
_bfd_generic_mkarchive, |
bfd_false, |
}, |
{ /* bfd_write_contents. */ |
bfd_false, |
symbolsrec_write_object_contents, |
_bfd_write_archive_contents, |
bfd_false, |
}, |
BFD_JUMP_TABLE_GENERIC (srec), |
BFD_JUMP_TABLE_COPY (_bfd_generic), |
BFD_JUMP_TABLE_CORE (_bfd_nocore), |
BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), |
BFD_JUMP_TABLE_SYMBOLS (srec), |
BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), |
BFD_JUMP_TABLE_WRITE (srec), |
BFD_JUMP_TABLE_LINK (srec), |
BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), |
NULL, |
NULL |
}; |
/contrib/toolchain/binutils/bfd/stab-syms.c |
---|
0,0 → 1,60 |
/* Table of stab names for the BFD library. |
Copyright 1990, 1991, 1992, 1994, 1995, 1996, 2000, 2005, 2007, 2012 |
Free Software Foundation, Inc. |
Written by Cygnus Support. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#define ARCH_SIZE 32 /* Value doesn't matter. */ |
#include "libaout.h" |
#include "aout/aout64.h" |
/* Ignore duplicate stab codes; just return the string for the first |
one. */ |
#define __define_stab(NAME, CODE, STRING) __define_name(CODE, STRING) |
#define __define_stab_duplicate(NAME, CODE, STRING) |
/* These are not really stab symbols, but it is |
convenient to have them here for the sake of nm. |
For completeness, we could also add N_TEXT etc, but those |
are never needed, since nm treats those specially. */ |
#define EXTRA_SYMBOLS \ |
__define_name (N_SETA, "SETA")/* Absolute set element symbol */ \ |
__define_name (N_SETT, "SETT")/* Text set element symbol */ \ |
__define_name (N_SETD, "SETD")/* Data set element symbol */ \ |
__define_name (N_SETB, "SETB")/* Bss set element symbol */ \ |
__define_name (N_SETV, "SETV")/* Pointer to set vector in data area. */ \ |
__define_name (N_INDR, "INDR") \ |
__define_name (N_WARNING, "WARNING") |
const char * |
bfd_get_stab_name (code) |
int code; |
{ |
switch (code) |
{ |
#define __define_name(val, str) case val: return str; |
#include "aout/stab.def" |
EXTRA_SYMBOLS |
} |
return (const char *) 0; |
} |
/contrib/toolchain/binutils/bfd/stabs.c |
---|
0,0 → 1,789 |
/* Stabs in sections linking support. |
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, |
2006, 2007, 2008 Free Software Foundation, Inc. |
Written by Ian Lance Taylor, Cygnus Support. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* This file contains support for linking stabs in sections, as used |
on COFF and ELF. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
#include "aout/stab_gnu.h" |
#include "safe-ctype.h" |
/* Stabs entries use a 12 byte format: |
4 byte string table index |
1 byte stab type |
1 byte stab other field |
2 byte stab desc field |
4 byte stab value |
FIXME: This will have to change for a 64 bit object format. |
The stabs symbols are divided into compilation units. For the |
first entry in each unit, the type of 0, the value is the length of |
the string table for this unit, and the desc field is the number of |
stabs symbols for this unit. */ |
#define STRDXOFF 0 |
#define TYPEOFF 4 |
#define OTHEROFF 5 |
#define DESCOFF 6 |
#define VALOFF 8 |
#define STABSIZE 12 |
/* A linked list of totals that we have found for a particular header |
file. A total is a unique identifier for a particular BINCL...EINCL |
sequence of STABs that can be used to identify duplicate sequences. |
It consists of three fields, 'sum_chars' which is the sum of all the |
STABS characters; 'num_chars' which is the number of these charactes |
and 'symb' which is a buffer of all the symbols in the sequence. This |
buffer is only checked as a last resort. */ |
struct stab_link_includes_totals |
{ |
struct stab_link_includes_totals *next; |
bfd_vma sum_chars; /* Accumulated sum of STABS characters. */ |
bfd_vma num_chars; /* Number of STABS characters. */ |
const char* symb; /* The STABS characters themselves. */ |
}; |
/* An entry in the header file hash table. */ |
struct stab_link_includes_entry |
{ |
struct bfd_hash_entry root; |
/* List of totals we have found for this file. */ |
struct stab_link_includes_totals *totals; |
}; |
/* This structure is used to hold a list of N_BINCL symbols, some of |
which might be converted into N_EXCL symbols. */ |
struct stab_excl_list |
{ |
/* The next symbol to convert. */ |
struct stab_excl_list *next; |
/* The offset to this symbol in the section contents. */ |
bfd_size_type offset; |
/* The value to use for the symbol. */ |
bfd_vma val; |
/* The type of this symbol (N_BINCL or N_EXCL). */ |
int type; |
}; |
/* This structure is stored with each .stab section. */ |
struct stab_section_info |
{ |
/* This is a linked list of N_BINCL symbols which should be |
converted into N_EXCL symbols. */ |
struct stab_excl_list *excls; |
/* This is used to map input stab offsets within their sections |
to output stab offsets, to take into account stabs that have |
been deleted. If it is NULL, the output offsets are the same |
as the input offsets, because no stabs have been deleted from |
this section. Otherwise the i'th entry is the number of |
bytes of stabs that have been deleted prior to the i'th |
stab. */ |
bfd_size_type *cumulative_skips; |
/* This is an array of string indices. For each stab symbol, we |
store the string index here. If a stab symbol should not be |
included in the final output, the string index is -1. */ |
bfd_size_type stridxs[1]; |
}; |
/* The function to create a new entry in the header file hash table. */ |
static struct bfd_hash_entry * |
stab_link_includes_newfunc (struct bfd_hash_entry *entry, |
struct bfd_hash_table *table, |
const char *string) |
{ |
struct stab_link_includes_entry *ret = |
(struct stab_link_includes_entry *) entry; |
/* Allocate the structure if it has not already been allocated by a |
subclass. */ |
if (ret == NULL) |
ret = (struct stab_link_includes_entry *) |
bfd_hash_allocate (table, sizeof (struct stab_link_includes_entry)); |
if (ret == NULL) |
return NULL; |
/* Call the allocation method of the superclass. */ |
ret = ((struct stab_link_includes_entry *) |
bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); |
if (ret) |
/* Set local fields. */ |
ret->totals = NULL; |
return (struct bfd_hash_entry *) ret; |
} |
/* This function is called for each input file from the add_symbols |
pass of the linker. */ |
bfd_boolean |
_bfd_link_section_stabs (bfd *abfd, |
struct stab_info *sinfo, |
asection *stabsec, |
asection *stabstrsec, |
void * *psecinfo, |
bfd_size_type *pstring_offset) |
{ |
bfd_boolean first; |
bfd_size_type count, amt; |
struct stab_section_info *secinfo; |
bfd_byte *stabbuf = NULL; |
bfd_byte *stabstrbuf = NULL; |
bfd_byte *sym, *symend; |
bfd_size_type stroff, next_stroff, skip; |
bfd_size_type *pstridx; |
if (stabsec->size == 0 |
|| stabstrsec->size == 0) |
/* This file does not contain stabs debugging information. */ |
return TRUE; |
if (stabsec->size % STABSIZE != 0) |
/* Something is wrong with the format of these stab symbols. |
Don't try to optimize them. */ |
return TRUE; |
if ((stabstrsec->flags & SEC_RELOC) != 0) |
/* We shouldn't see relocations in the strings, and we aren't |
prepared to handle them. */ |
return TRUE; |
if (bfd_is_abs_section (stabsec->output_section) |
|| bfd_is_abs_section (stabstrsec->output_section)) |
/* At least one of the sections is being discarded from the |
link, so we should just ignore them. */ |
return TRUE; |
first = FALSE; |
if (sinfo->stabstr == NULL) |
{ |
flagword flags; |
/* Initialize the stabs information we need to keep track of. */ |
first = TRUE; |
sinfo->strings = _bfd_stringtab_init (); |
if (sinfo->strings == NULL) |
goto error_return; |
/* Make sure the first byte is zero. */ |
(void) _bfd_stringtab_add (sinfo->strings, "", TRUE, TRUE); |
if (! bfd_hash_table_init (&sinfo->includes, |
stab_link_includes_newfunc, |
sizeof (struct stab_link_includes_entry))) |
goto error_return; |
flags = (SEC_HAS_CONTENTS | SEC_READONLY | SEC_DEBUGGING |
| SEC_LINKER_CREATED); |
sinfo->stabstr = bfd_make_section_anyway_with_flags (abfd, ".stabstr", |
flags); |
if (sinfo->stabstr == NULL) |
goto error_return; |
} |
/* Initialize the information we are going to store for this .stab |
section. */ |
count = stabsec->size / STABSIZE; |
amt = sizeof (struct stab_section_info); |
amt += (count - 1) * sizeof (bfd_size_type); |
*psecinfo = bfd_alloc (abfd, amt); |
if (*psecinfo == NULL) |
goto error_return; |
secinfo = (struct stab_section_info *) *psecinfo; |
secinfo->excls = NULL; |
stabsec->rawsize = stabsec->size; |
secinfo->cumulative_skips = NULL; |
memset (secinfo->stridxs, 0, (size_t) count * sizeof (bfd_size_type)); |
/* Read the stabs information from abfd. */ |
if (!bfd_malloc_and_get_section (abfd, stabsec, &stabbuf) |
|| !bfd_malloc_and_get_section (abfd, stabstrsec, &stabstrbuf)) |
goto error_return; |
/* Look through the stabs symbols, work out the new string indices, |
and identify N_BINCL symbols which can be eliminated. */ |
stroff = 0; |
/* The stabs sections can be split when |
-split-by-reloc/-split-by-file is used. We must keep track of |
each stab section's place in the single concatenated string |
table. */ |
next_stroff = pstring_offset ? *pstring_offset : 0; |
skip = 0; |
symend = stabbuf + stabsec->size; |
for (sym = stabbuf, pstridx = secinfo->stridxs; |
sym < symend; |
sym += STABSIZE, ++pstridx) |
{ |
bfd_size_type symstroff; |
int type; |
const char *string; |
if (*pstridx != 0) |
/* This symbol has already been handled by an N_BINCL pass. */ |
continue; |
type = sym[TYPEOFF]; |
if (type == 0) |
{ |
/* Special type 0 stabs indicate the offset to the next |
string table. We only copy the very first one. */ |
stroff = next_stroff; |
next_stroff += bfd_get_32 (abfd, sym + 8); |
if (pstring_offset) |
*pstring_offset = next_stroff; |
if (! first) |
{ |
*pstridx = (bfd_size_type) -1; |
++skip; |
continue; |
} |
first = FALSE; |
} |
/* Store the string in the hash table, and record the index. */ |
symstroff = stroff + bfd_get_32 (abfd, sym + STRDXOFF); |
if (symstroff >= stabstrsec->size) |
{ |
(*_bfd_error_handler) |
(_("%B(%A+0x%lx): Stabs entry has invalid string index."), |
abfd, stabsec, (long) (sym - stabbuf)); |
bfd_set_error (bfd_error_bad_value); |
goto error_return; |
} |
string = (char *) stabstrbuf + symstroff; |
*pstridx = _bfd_stringtab_add (sinfo->strings, string, TRUE, TRUE); |
/* An N_BINCL symbol indicates the start of the stabs entries |
for a header file. We need to scan ahead to the next N_EINCL |
symbol, ignoring nesting, adding up all the characters in the |
symbol names, not including the file numbers in types (the |
first number after an open parenthesis). */ |
if (type == (int) N_BINCL) |
{ |
bfd_vma sum_chars; |
bfd_vma num_chars; |
bfd_vma buf_len = 0; |
char * symb; |
char * symb_rover; |
int nest; |
bfd_byte * incl_sym; |
struct stab_link_includes_entry * incl_entry; |
struct stab_link_includes_totals * t; |
struct stab_excl_list * ne; |
symb = symb_rover = NULL; |
sum_chars = num_chars = 0; |
nest = 0; |
for (incl_sym = sym + STABSIZE; |
incl_sym < symend; |
incl_sym += STABSIZE) |
{ |
int incl_type; |
incl_type = incl_sym[TYPEOFF]; |
if (incl_type == 0) |
break; |
else if (incl_type == (int) N_EXCL) |
continue; |
else if (incl_type == (int) N_EINCL) |
{ |
if (nest == 0) |
break; |
--nest; |
} |
else if (incl_type == (int) N_BINCL) |
++nest; |
else if (nest == 0) |
{ |
const char *str; |
str = ((char *) stabstrbuf |
+ stroff |
+ bfd_get_32 (abfd, incl_sym + STRDXOFF)); |
for (; *str != '\0'; str++) |
{ |
if (num_chars >= buf_len) |
{ |
buf_len += 32 * 1024; |
symb = (char *) bfd_realloc_or_free (symb, buf_len); |
if (symb == NULL) |
goto error_return; |
symb_rover = symb + num_chars; |
} |
* symb_rover ++ = * str; |
sum_chars += *str; |
num_chars ++; |
if (*str == '(') |
{ |
/* Skip the file number. */ |
++str; |
while (ISDIGIT (*str)) |
++str; |
--str; |
} |
} |
} |
} |
BFD_ASSERT (num_chars == (bfd_vma) (symb_rover - symb)); |
/* If we have already included a header file with the same |
value, then replaced this one with an N_EXCL symbol. */ |
incl_entry = (struct stab_link_includes_entry * ) |
bfd_hash_lookup (&sinfo->includes, string, TRUE, TRUE); |
if (incl_entry == NULL) |
goto error_return; |
for (t = incl_entry->totals; t != NULL; t = t->next) |
if (t->sum_chars == sum_chars |
&& t->num_chars == num_chars |
&& memcmp (t->symb, symb, num_chars) == 0) |
break; |
/* Record this symbol, so that we can set the value |
correctly. */ |
amt = sizeof *ne; |
ne = (struct stab_excl_list *) bfd_alloc (abfd, amt); |
if (ne == NULL) |
goto error_return; |
ne->offset = sym - stabbuf; |
ne->val = sum_chars; |
ne->type = (int) N_BINCL; |
ne->next = secinfo->excls; |
secinfo->excls = ne; |
if (t == NULL) |
{ |
/* This is the first time we have seen this header file |
with this set of stabs strings. */ |
t = (struct stab_link_includes_totals *) |
bfd_hash_allocate (&sinfo->includes, sizeof *t); |
if (t == NULL) |
goto error_return; |
t->sum_chars = sum_chars; |
t->num_chars = num_chars; |
/* Trim data down. */ |
t->symb = symb = (char *) bfd_realloc_or_free (symb, num_chars); |
t->next = incl_entry->totals; |
incl_entry->totals = t; |
} |
else |
{ |
bfd_size_type *incl_pstridx; |
/* We have seen this header file before. Tell the final |
pass to change the type to N_EXCL. */ |
ne->type = (int) N_EXCL; |
/* Free off superfluous symbols. */ |
free (symb); |
/* Mark the skipped symbols. */ |
nest = 0; |
for (incl_sym = sym + STABSIZE, incl_pstridx = pstridx + 1; |
incl_sym < symend; |
incl_sym += STABSIZE, ++incl_pstridx) |
{ |
int incl_type; |
incl_type = incl_sym[TYPEOFF]; |
if (incl_type == (int) N_EINCL) |
{ |
if (nest == 0) |
{ |
*incl_pstridx = (bfd_size_type) -1; |
++skip; |
break; |
} |
--nest; |
} |
else if (incl_type == (int) N_BINCL) |
++nest; |
else if (incl_type == (int) N_EXCL) |
/* Keep existing exclusion marks. */ |
continue; |
else if (nest == 0) |
{ |
*incl_pstridx = (bfd_size_type) -1; |
++skip; |
} |
} |
} |
} |
} |
free (stabbuf); |
stabbuf = NULL; |
free (stabstrbuf); |
stabstrbuf = NULL; |
/* We need to set the section sizes such that the linker will |
compute the output section sizes correctly. We set the .stab |
size to not include the entries we don't want. We set |
SEC_EXCLUDE for the .stabstr section, so that it will be dropped |
from the link. We record the size of the strtab in the first |
.stabstr section we saw, and make sure we don't set SEC_EXCLUDE |
for that section. */ |
stabsec->size = (count - skip) * STABSIZE; |
if (stabsec->size == 0) |
stabsec->flags |= SEC_EXCLUDE | SEC_KEEP; |
stabstrsec->flags |= SEC_EXCLUDE | SEC_KEEP; |
sinfo->stabstr->size = _bfd_stringtab_size (sinfo->strings); |
/* Calculate the `cumulative_skips' array now that stabs have been |
deleted for this section. */ |
if (skip != 0) |
{ |
bfd_size_type i, offset; |
bfd_size_type *pskips; |
amt = count * sizeof (bfd_size_type); |
secinfo->cumulative_skips = (bfd_size_type *) bfd_alloc (abfd, amt); |
if (secinfo->cumulative_skips == NULL) |
goto error_return; |
pskips = secinfo->cumulative_skips; |
pstridx = secinfo->stridxs; |
offset = 0; |
for (i = 0; i < count; i++, pskips++, pstridx++) |
{ |
*pskips = offset; |
if (*pstridx == (bfd_size_type) -1) |
offset += STABSIZE; |
} |
BFD_ASSERT (offset != 0); |
} |
return TRUE; |
error_return: |
if (stabbuf != NULL) |
free (stabbuf); |
if (stabstrbuf != NULL) |
free (stabstrbuf); |
return FALSE; |
} |
/* This function is called for each input file before the stab |
section is relocated. It discards stab entries for discarded |
functions and variables. The function returns TRUE iff |
any entries have been deleted. |
*/ |
bfd_boolean |
_bfd_discard_section_stabs (bfd *abfd, |
asection *stabsec, |
void * psecinfo, |
bfd_boolean (*reloc_symbol_deleted_p) (bfd_vma, void *), |
void * cookie) |
{ |
bfd_size_type count, amt; |
struct stab_section_info *secinfo; |
bfd_byte *stabbuf = NULL; |
bfd_byte *sym, *symend; |
bfd_size_type skip; |
bfd_size_type *pstridx; |
int deleting; |
if (stabsec->size == 0) |
/* This file does not contain stabs debugging information. */ |
return FALSE; |
if (stabsec->size % STABSIZE != 0) |
/* Something is wrong with the format of these stab symbols. |
Don't try to optimize them. */ |
return FALSE; |
if ((stabsec->output_section != NULL |
&& bfd_is_abs_section (stabsec->output_section))) |
/* At least one of the sections is being discarded from the |
link, so we should just ignore them. */ |
return FALSE; |
/* We should have initialized our data in _bfd_link_stab_sections. |
If there was some bizarre error reading the string sections, though, |
we might not have. Bail rather than asserting. */ |
if (psecinfo == NULL) |
return FALSE; |
count = stabsec->rawsize / STABSIZE; |
secinfo = (struct stab_section_info *) psecinfo; |
/* Read the stabs information from abfd. */ |
if (!bfd_malloc_and_get_section (abfd, stabsec, &stabbuf)) |
goto error_return; |
/* Look through the stabs symbols and discard any information for |
discarded functions. */ |
skip = 0; |
deleting = -1; |
symend = stabbuf + stabsec->rawsize; |
for (sym = stabbuf, pstridx = secinfo->stridxs; |
sym < symend; |
sym += STABSIZE, ++pstridx) |
{ |
int type; |
if (*pstridx == (bfd_size_type) -1) |
/* This stab was deleted in a previous pass. */ |
continue; |
type = sym[TYPEOFF]; |
if (type == (int) N_FUN) |
{ |
int strx = bfd_get_32 (abfd, sym + STRDXOFF); |
if (strx == 0) |
{ |
if (deleting) |
{ |
skip++; |
*pstridx = -1; |
} |
deleting = -1; |
continue; |
} |
deleting = 0; |
if ((*reloc_symbol_deleted_p) (sym + VALOFF - stabbuf, cookie)) |
deleting = 1; |
} |
if (deleting == 1) |
{ |
*pstridx = -1; |
skip++; |
} |
else if (deleting == -1) |
{ |
/* Outside of a function. Check for deleted variables. */ |
if (type == (int) N_STSYM || type == (int) N_LCSYM) |
if ((*reloc_symbol_deleted_p) (sym + VALOFF - stabbuf, cookie)) |
{ |
*pstridx = -1; |
skip ++; |
} |
/* We should also check for N_GSYM entries which reference a |
deleted global, but those are less harmful to debuggers |
and would require parsing the stab strings. */ |
} |
} |
free (stabbuf); |
stabbuf = NULL; |
/* Shrink the stabsec as needed. */ |
stabsec->size -= skip * STABSIZE; |
if (stabsec->size == 0) |
stabsec->flags |= SEC_EXCLUDE | SEC_KEEP; |
/* Recalculate the `cumulative_skips' array now that stabs have been |
deleted for this section. */ |
if (skip != 0) |
{ |
bfd_size_type i, offset; |
bfd_size_type *pskips; |
if (secinfo->cumulative_skips == NULL) |
{ |
amt = count * sizeof (bfd_size_type); |
secinfo->cumulative_skips = (bfd_size_type *) bfd_alloc (abfd, amt); |
if (secinfo->cumulative_skips == NULL) |
goto error_return; |
} |
pskips = secinfo->cumulative_skips; |
pstridx = secinfo->stridxs; |
offset = 0; |
for (i = 0; i < count; i++, pskips++, pstridx++) |
{ |
*pskips = offset; |
if (*pstridx == (bfd_size_type) -1) |
offset += STABSIZE; |
} |
BFD_ASSERT (offset != 0); |
} |
return skip > 0; |
error_return: |
if (stabbuf != NULL) |
free (stabbuf); |
return FALSE; |
} |
/* Write out the stab section. This is called with the relocated |
contents. */ |
bfd_boolean |
_bfd_write_section_stabs (bfd *output_bfd, |
struct stab_info *sinfo, |
asection *stabsec, |
void * *psecinfo, |
bfd_byte *contents) |
{ |
struct stab_section_info *secinfo; |
struct stab_excl_list *e; |
bfd_byte *sym, *tosym, *symend; |
bfd_size_type *pstridx; |
secinfo = (struct stab_section_info *) *psecinfo; |
if (secinfo == NULL) |
return bfd_set_section_contents (output_bfd, stabsec->output_section, |
contents, stabsec->output_offset, |
stabsec->size); |
/* Handle each N_BINCL entry. */ |
for (e = secinfo->excls; e != NULL; e = e->next) |
{ |
bfd_byte *excl_sym; |
BFD_ASSERT (e->offset < stabsec->rawsize); |
excl_sym = contents + e->offset; |
bfd_put_32 (output_bfd, e->val, excl_sym + VALOFF); |
excl_sym[TYPEOFF] = e->type; |
} |
/* Copy over all the stabs symbols, omitting the ones we don't want, |
and correcting the string indices for those we do want. */ |
tosym = contents; |
symend = contents + stabsec->rawsize; |
for (sym = contents, pstridx = secinfo->stridxs; |
sym < symend; |
sym += STABSIZE, ++pstridx) |
{ |
if (*pstridx != (bfd_size_type) -1) |
{ |
if (tosym != sym) |
memcpy (tosym, sym, STABSIZE); |
bfd_put_32 (output_bfd, *pstridx, tosym + STRDXOFF); |
if (sym[TYPEOFF] == 0) |
{ |
/* This is the header symbol for the stabs section. We |
don't really need one, since we have merged all the |
input stabs sections into one, but we generate one |
for the benefit of readers which expect to see one. */ |
BFD_ASSERT (sym == contents); |
bfd_put_32 (output_bfd, _bfd_stringtab_size (sinfo->strings), |
tosym + VALOFF); |
bfd_put_16 (output_bfd, |
stabsec->output_section->size / STABSIZE - 1, |
tosym + DESCOFF); |
} |
tosym += STABSIZE; |
} |
} |
BFD_ASSERT ((bfd_size_type) (tosym - contents) == stabsec->size); |
return bfd_set_section_contents (output_bfd, stabsec->output_section, |
contents, (file_ptr) stabsec->output_offset, |
stabsec->size); |
} |
/* Write out the .stabstr section. */ |
bfd_boolean |
_bfd_write_stab_strings (bfd *output_bfd, struct stab_info *sinfo) |
{ |
if (bfd_is_abs_section (sinfo->stabstr->output_section)) |
/* The section was discarded from the link. */ |
return TRUE; |
BFD_ASSERT ((sinfo->stabstr->output_offset |
+ _bfd_stringtab_size (sinfo->strings)) |
<= sinfo->stabstr->output_section->size); |
if (bfd_seek (output_bfd, |
(file_ptr) (sinfo->stabstr->output_section->filepos |
+ sinfo->stabstr->output_offset), |
SEEK_SET) != 0) |
return FALSE; |
if (! _bfd_stringtab_emit (output_bfd, sinfo->strings)) |
return FALSE; |
/* We no longer need the stabs information. */ |
_bfd_stringtab_free (sinfo->strings); |
bfd_hash_table_free (&sinfo->includes); |
return TRUE; |
} |
/* Adjust an address in the .stab section. Given OFFSET within |
STABSEC, this returns the new offset in the adjusted stab section, |
or -1 if the address refers to a stab which has been removed. */ |
bfd_vma |
_bfd_stab_section_offset (asection *stabsec, |
void * psecinfo, |
bfd_vma offset) |
{ |
struct stab_section_info *secinfo; |
secinfo = (struct stab_section_info *) psecinfo; |
if (secinfo == NULL) |
return offset; |
if (offset >= stabsec->rawsize) |
return offset - stabsec->rawsize + stabsec->size; |
if (secinfo->cumulative_skips) |
{ |
bfd_vma i; |
i = offset / STABSIZE; |
if (secinfo->stridxs [i] == (bfd_size_type) -1) |
return (bfd_vma) -1; |
return offset - secinfo->cumulative_skips [i]; |
} |
return offset; |
} |
/contrib/toolchain/binutils/bfd/syms.c |
---|
0,0 → 1,1426 |
/* Generic symbol-table support for the BFD library. |
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, |
2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2012 |
Free Software Foundation, Inc. |
Written by Cygnus Support. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* |
SECTION |
Symbols |
BFD tries to maintain as much symbol information as it can when |
it moves information from file to file. BFD passes information |
to applications though the <<asymbol>> structure. When the |
application requests the symbol table, BFD reads the table in |
the native form and translates parts of it into the internal |
format. To maintain more than the information passed to |
applications, some targets keep some information ``behind the |
scenes'' in a structure only the particular back end knows |
about. For example, the coff back end keeps the original |
symbol table structure as well as the canonical structure when |
a BFD is read in. On output, the coff back end can reconstruct |
the output symbol table so that no information is lost, even |
information unique to coff which BFD doesn't know or |
understand. If a coff symbol table were read, but were written |
through an a.out back end, all the coff specific information |
would be lost. The symbol table of a BFD |
is not necessarily read in until a canonicalize request is |
made. Then the BFD back end fills in a table provided by the |
application with pointers to the canonical information. To |
output symbols, the application provides BFD with a table of |
pointers to pointers to <<asymbol>>s. This allows applications |
like the linker to output a symbol as it was read, since the ``behind |
the scenes'' information will be still available. |
@menu |
@* Reading Symbols:: |
@* Writing Symbols:: |
@* Mini Symbols:: |
@* typedef asymbol:: |
@* symbol handling functions:: |
@end menu |
INODE |
Reading Symbols, Writing Symbols, Symbols, Symbols |
SUBSECTION |
Reading symbols |
There are two stages to reading a symbol table from a BFD: |
allocating storage, and the actual reading process. This is an |
excerpt from an application which reads the symbol table: |
| long storage_needed; |
| asymbol **symbol_table; |
| long number_of_symbols; |
| long i; |
| |
| storage_needed = bfd_get_symtab_upper_bound (abfd); |
| |
| if (storage_needed < 0) |
| FAIL |
| |
| if (storage_needed == 0) |
| return; |
| |
| symbol_table = xmalloc (storage_needed); |
| ... |
| number_of_symbols = |
| bfd_canonicalize_symtab (abfd, symbol_table); |
| |
| if (number_of_symbols < 0) |
| FAIL |
| |
| for (i = 0; i < number_of_symbols; i++) |
| process_symbol (symbol_table[i]); |
All storage for the symbols themselves is in an objalloc |
connected to the BFD; it is freed when the BFD is closed. |
INODE |
Writing Symbols, Mini Symbols, Reading Symbols, Symbols |
SUBSECTION |
Writing symbols |
Writing of a symbol table is automatic when a BFD open for |
writing is closed. The application attaches a vector of |
pointers to pointers to symbols to the BFD being written, and |
fills in the symbol count. The close and cleanup code reads |
through the table provided and performs all the necessary |
operations. The BFD output code must always be provided with an |
``owned'' symbol: one which has come from another BFD, or one |
which has been created using <<bfd_make_empty_symbol>>. Here is an |
example showing the creation of a symbol table with only one element: |
| #include "sysdep.h" |
| #include "bfd.h" |
| int main (void) |
| { |
| bfd *abfd; |
| asymbol *ptrs[2]; |
| asymbol *new; |
| |
| abfd = bfd_openw ("foo","a.out-sunos-big"); |
| bfd_set_format (abfd, bfd_object); |
| new = bfd_make_empty_symbol (abfd); |
| new->name = "dummy_symbol"; |
| new->section = bfd_make_section_old_way (abfd, ".text"); |
| new->flags = BSF_GLOBAL; |
| new->value = 0x12345; |
| |
| ptrs[0] = new; |
| ptrs[1] = 0; |
| |
| bfd_set_symtab (abfd, ptrs, 1); |
| bfd_close (abfd); |
| return 0; |
| } |
| |
| ./makesym |
| nm foo |
| 00012345 A dummy_symbol |
Many formats cannot represent arbitrary symbol information; for |
instance, the <<a.out>> object format does not allow an |
arbitrary number of sections. A symbol pointing to a section |
which is not one of <<.text>>, <<.data>> or <<.bss>> cannot |
be described. |
INODE |
Mini Symbols, typedef asymbol, Writing Symbols, Symbols |
SUBSECTION |
Mini Symbols |
Mini symbols provide read-only access to the symbol table. |
They use less memory space, but require more time to access. |
They can be useful for tools like nm or objdump, which may |
have to handle symbol tables of extremely large executables. |
The <<bfd_read_minisymbols>> function will read the symbols |
into memory in an internal form. It will return a <<void *>> |
pointer to a block of memory, a symbol count, and the size of |
each symbol. The pointer is allocated using <<malloc>>, and |
should be freed by the caller when it is no longer needed. |
The function <<bfd_minisymbol_to_symbol>> will take a pointer |
to a minisymbol, and a pointer to a structure returned by |
<<bfd_make_empty_symbol>>, and return a <<asymbol>> structure. |
The return value may or may not be the same as the value from |
<<bfd_make_empty_symbol>> which was passed in. |
*/ |
/* |
DOCDD |
INODE |
typedef asymbol, symbol handling functions, Mini Symbols, Symbols |
*/ |
/* |
SUBSECTION |
typedef asymbol |
An <<asymbol>> has the form: |
*/ |
/* |
CODE_FRAGMENT |
. |
.typedef struct bfd_symbol |
.{ |
. {* A pointer to the BFD which owns the symbol. This information |
. is necessary so that a back end can work out what additional |
. information (invisible to the application writer) is carried |
. with the symbol. |
. |
. This field is *almost* redundant, since you can use section->owner |
. instead, except that some symbols point to the global sections |
. bfd_{abs,com,und}_section. This could be fixed by making |
. these globals be per-bfd (or per-target-flavor). FIXME. *} |
. struct bfd *the_bfd; {* Use bfd_asymbol_bfd(sym) to access this field. *} |
. |
. {* The text of the symbol. The name is left alone, and not copied; the |
. application may not alter it. *} |
. const char *name; |
. |
. {* The value of the symbol. This really should be a union of a |
. numeric value with a pointer, since some flags indicate that |
. a pointer to another symbol is stored here. *} |
. symvalue value; |
. |
. {* Attributes of a symbol. *} |
.#define BSF_NO_FLAGS 0x00 |
. |
. {* The symbol has local scope; <<static>> in <<C>>. The value |
. is the offset into the section of the data. *} |
.#define BSF_LOCAL (1 << 0) |
. |
. {* The symbol has global scope; initialized data in <<C>>. The |
. value is the offset into the section of the data. *} |
.#define BSF_GLOBAL (1 << 1) |
. |
. {* The symbol has global scope and is exported. The value is |
. the offset into the section of the data. *} |
.#define BSF_EXPORT BSF_GLOBAL {* No real difference. *} |
. |
. {* A normal C symbol would be one of: |
. <<BSF_LOCAL>>, <<BSF_COMMON>>, <<BSF_UNDEFINED>> or |
. <<BSF_GLOBAL>>. *} |
. |
. {* The symbol is a debugging record. The value has an arbitrary |
. meaning, unless BSF_DEBUGGING_RELOC is also set. *} |
.#define BSF_DEBUGGING (1 << 2) |
. |
. {* The symbol denotes a function entry point. Used in ELF, |
. perhaps others someday. *} |
.#define BSF_FUNCTION (1 << 3) |
. |
. {* Used by the linker. *} |
.#define BSF_KEEP (1 << 5) |
.#define BSF_KEEP_G (1 << 6) |
. |
. {* A weak global symbol, overridable without warnings by |
. a regular global symbol of the same name. *} |
.#define BSF_WEAK (1 << 7) |
. |
. {* This symbol was created to point to a section, e.g. ELF's |
. STT_SECTION symbols. *} |
.#define BSF_SECTION_SYM (1 << 8) |
. |
. {* The symbol used to be a common symbol, but now it is |
. allocated. *} |
.#define BSF_OLD_COMMON (1 << 9) |
. |
. {* In some files the type of a symbol sometimes alters its |
. location in an output file - ie in coff a <<ISFCN>> symbol |
. which is also <<C_EXT>> symbol appears where it was |
. declared and not at the end of a section. This bit is set |
. by the target BFD part to convey this information. *} |
.#define BSF_NOT_AT_END (1 << 10) |
. |
. {* Signal that the symbol is the label of constructor section. *} |
.#define BSF_CONSTRUCTOR (1 << 11) |
. |
. {* Signal that the symbol is a warning symbol. The name is a |
. warning. The name of the next symbol is the one to warn about; |
. if a reference is made to a symbol with the same name as the next |
. symbol, a warning is issued by the linker. *} |
.#define BSF_WARNING (1 << 12) |
. |
. {* Signal that the symbol is indirect. This symbol is an indirect |
. pointer to the symbol with the same name as the next symbol. *} |
.#define BSF_INDIRECT (1 << 13) |
. |
. {* BSF_FILE marks symbols that contain a file name. This is used |
. for ELF STT_FILE symbols. *} |
.#define BSF_FILE (1 << 14) |
. |
. {* Symbol is from dynamic linking information. *} |
.#define BSF_DYNAMIC (1 << 15) |
. |
. {* The symbol denotes a data object. Used in ELF, and perhaps |
. others someday. *} |
.#define BSF_OBJECT (1 << 16) |
. |
. {* This symbol is a debugging symbol. The value is the offset |
. into the section of the data. BSF_DEBUGGING should be set |
. as well. *} |
.#define BSF_DEBUGGING_RELOC (1 << 17) |
. |
. {* This symbol is thread local. Used in ELF. *} |
.#define BSF_THREAD_LOCAL (1 << 18) |
. |
. {* This symbol represents a complex relocation expression, |
. with the expression tree serialized in the symbol name. *} |
.#define BSF_RELC (1 << 19) |
. |
. {* This symbol represents a signed complex relocation expression, |
. with the expression tree serialized in the symbol name. *} |
.#define BSF_SRELC (1 << 20) |
. |
. {* This symbol was created by bfd_get_synthetic_symtab. *} |
.#define BSF_SYNTHETIC (1 << 21) |
. |
. {* This symbol is an indirect code object. Unrelated to BSF_INDIRECT. |
. The dynamic linker will compute the value of this symbol by |
. calling the function that it points to. BSF_FUNCTION must |
. also be also set. *} |
.#define BSF_GNU_INDIRECT_FUNCTION (1 << 22) |
. {* This symbol is a globally unique data object. The dynamic linker |
. will make sure that in the entire process there is just one symbol |
. with this name and type in use. BSF_OBJECT must also be set. *} |
.#define BSF_GNU_UNIQUE (1 << 23) |
. |
. flagword flags; |
. |
. {* A pointer to the section to which this symbol is |
. relative. This will always be non NULL, there are special |
. sections for undefined and absolute symbols. *} |
. struct bfd_section *section; |
. |
. {* Back end special data. *} |
. union |
. { |
. void *p; |
. bfd_vma i; |
. } |
. udata; |
.} |
.asymbol; |
. |
*/ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
#include "safe-ctype.h" |
#include "bfdlink.h" |
#include "aout/stab_gnu.h" |
/* |
DOCDD |
INODE |
symbol handling functions, , typedef asymbol, Symbols |
SUBSECTION |
Symbol handling functions |
*/ |
/* |
FUNCTION |
bfd_get_symtab_upper_bound |
DESCRIPTION |
Return the number of bytes required to store a vector of pointers |
to <<asymbols>> for all the symbols in the BFD @var{abfd}, |
including a terminal NULL pointer. If there are no symbols in |
the BFD, then return 0. If an error occurs, return -1. |
.#define bfd_get_symtab_upper_bound(abfd) \ |
. BFD_SEND (abfd, _bfd_get_symtab_upper_bound, (abfd)) |
. |
*/ |
/* |
FUNCTION |
bfd_is_local_label |
SYNOPSIS |
bfd_boolean bfd_is_local_label (bfd *abfd, asymbol *sym); |
DESCRIPTION |
Return TRUE if the given symbol @var{sym} in the BFD @var{abfd} is |
a compiler generated local label, else return FALSE. |
*/ |
bfd_boolean |
bfd_is_local_label (bfd *abfd, asymbol *sym) |
{ |
/* The BSF_SECTION_SYM check is needed for IA-64, where every label that |
starts with '.' is local. This would accidentally catch section names |
if we didn't reject them here. */ |
if ((sym->flags & (BSF_GLOBAL | BSF_WEAK | BSF_FILE | BSF_SECTION_SYM)) != 0) |
return FALSE; |
if (sym->name == NULL) |
return FALSE; |
return bfd_is_local_label_name (abfd, sym->name); |
} |
/* |
FUNCTION |
bfd_is_local_label_name |
SYNOPSIS |
bfd_boolean bfd_is_local_label_name (bfd *abfd, const char *name); |
DESCRIPTION |
Return TRUE if a symbol with the name @var{name} in the BFD |
@var{abfd} is a compiler generated local label, else return |
FALSE. This just checks whether the name has the form of a |
local label. |
.#define bfd_is_local_label_name(abfd, name) \ |
. BFD_SEND (abfd, _bfd_is_local_label_name, (abfd, name)) |
. |
*/ |
/* |
FUNCTION |
bfd_is_target_special_symbol |
SYNOPSIS |
bfd_boolean bfd_is_target_special_symbol (bfd *abfd, asymbol *sym); |
DESCRIPTION |
Return TRUE iff a symbol @var{sym} in the BFD @var{abfd} is something |
special to the particular target represented by the BFD. Such symbols |
should normally not be mentioned to the user. |
.#define bfd_is_target_special_symbol(abfd, sym) \ |
. BFD_SEND (abfd, _bfd_is_target_special_symbol, (abfd, sym)) |
. |
*/ |
/* |
FUNCTION |
bfd_canonicalize_symtab |
DESCRIPTION |
Read the symbols from the BFD @var{abfd}, and fills in |
the vector @var{location} with pointers to the symbols and |
a trailing NULL. |
Return the actual number of symbol pointers, not |
including the NULL. |
.#define bfd_canonicalize_symtab(abfd, location) \ |
. BFD_SEND (abfd, _bfd_canonicalize_symtab, (abfd, location)) |
. |
*/ |
/* |
FUNCTION |
bfd_set_symtab |
SYNOPSIS |
bfd_boolean bfd_set_symtab |
(bfd *abfd, asymbol **location, unsigned int count); |
DESCRIPTION |
Arrange that when the output BFD @var{abfd} is closed, |
the table @var{location} of @var{count} pointers to symbols |
will be written. |
*/ |
bfd_boolean |
bfd_set_symtab (bfd *abfd, asymbol **location, unsigned int symcount) |
{ |
if (abfd->format != bfd_object || bfd_read_p (abfd)) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
bfd_get_outsymbols (abfd) = location; |
bfd_get_symcount (abfd) = symcount; |
return TRUE; |
} |
/* |
FUNCTION |
bfd_print_symbol_vandf |
SYNOPSIS |
void bfd_print_symbol_vandf (bfd *abfd, void *file, asymbol *symbol); |
DESCRIPTION |
Print the value and flags of the @var{symbol} supplied to the |
stream @var{file}. |
*/ |
void |
bfd_print_symbol_vandf (bfd *abfd, void *arg, asymbol *symbol) |
{ |
FILE *file = (FILE *) arg; |
flagword type = symbol->flags; |
if (symbol->section != NULL) |
bfd_fprintf_vma (abfd, file, symbol->value + symbol->section->vma); |
else |
bfd_fprintf_vma (abfd, file, symbol->value); |
/* This presumes that a symbol can not be both BSF_DEBUGGING and |
BSF_DYNAMIC, nor more than one of BSF_FUNCTION, BSF_FILE, and |
BSF_OBJECT. */ |
fprintf (file, " %c%c%c%c%c%c%c", |
((type & BSF_LOCAL) |
? (type & BSF_GLOBAL) ? '!' : 'l' |
: (type & BSF_GLOBAL) ? 'g' |
: (type & BSF_GNU_UNIQUE) ? 'u' : ' '), |
(type & BSF_WEAK) ? 'w' : ' ', |
(type & BSF_CONSTRUCTOR) ? 'C' : ' ', |
(type & BSF_WARNING) ? 'W' : ' ', |
(type & BSF_INDIRECT) ? 'I' : (type & BSF_GNU_INDIRECT_FUNCTION) ? 'i' : ' ', |
(type & BSF_DEBUGGING) ? 'd' : (type & BSF_DYNAMIC) ? 'D' : ' ', |
((type & BSF_FUNCTION) |
? 'F' |
: ((type & BSF_FILE) |
? 'f' |
: ((type & BSF_OBJECT) ? 'O' : ' ')))); |
} |
/* |
FUNCTION |
bfd_make_empty_symbol |
DESCRIPTION |
Create a new <<asymbol>> structure for the BFD @var{abfd} |
and return a pointer to it. |
This routine is necessary because each back end has private |
information surrounding the <<asymbol>>. Building your own |
<<asymbol>> and pointing to it will not create the private |
information, and will cause problems later on. |
.#define bfd_make_empty_symbol(abfd) \ |
. BFD_SEND (abfd, _bfd_make_empty_symbol, (abfd)) |
. |
*/ |
/* |
FUNCTION |
_bfd_generic_make_empty_symbol |
SYNOPSIS |
asymbol *_bfd_generic_make_empty_symbol (bfd *); |
DESCRIPTION |
Create a new <<asymbol>> structure for the BFD @var{abfd} |
and return a pointer to it. Used by core file routines, |
binary back-end and anywhere else where no private info |
is needed. |
*/ |
asymbol * |
_bfd_generic_make_empty_symbol (bfd *abfd) |
{ |
bfd_size_type amt = sizeof (asymbol); |
asymbol *new_symbol = (asymbol *) bfd_zalloc (abfd, amt); |
if (new_symbol) |
new_symbol->the_bfd = abfd; |
return new_symbol; |
} |
/* |
FUNCTION |
bfd_make_debug_symbol |
DESCRIPTION |
Create a new <<asymbol>> structure for the BFD @var{abfd}, |
to be used as a debugging symbol. Further details of its use have |
yet to be worked out. |
.#define bfd_make_debug_symbol(abfd,ptr,size) \ |
. BFD_SEND (abfd, _bfd_make_debug_symbol, (abfd, ptr, size)) |
. |
*/ |
struct section_to_type |
{ |
const char *section; |
char type; |
}; |
/* Map section names to POSIX/BSD single-character symbol types. |
This table is probably incomplete. It is sorted for convenience of |
adding entries. Since it is so short, a linear search is used. */ |
static const struct section_to_type stt[] = |
{ |
{".bss", 'b'}, |
{"code", 't'}, /* MRI .text */ |
{".data", 'd'}, |
{"*DEBUG*", 'N'}, |
{".debug", 'N'}, /* MSVC's .debug (non-standard debug syms) */ |
{".drectve", 'i'}, /* MSVC's .drective section */ |
{".edata", 'e'}, /* MSVC's .edata (export) section */ |
{".fini", 't'}, /* ELF fini section */ |
{".idata", 'i'}, /* MSVC's .idata (import) section */ |
{".init", 't'}, /* ELF init section */ |
{".pdata", 'p'}, /* MSVC's .pdata (stack unwind) section */ |
{".rdata", 'r'}, /* Read only data. */ |
{".rodata", 'r'}, /* Read only data. */ |
{".sbss", 's'}, /* Small BSS (uninitialized data). */ |
{".scommon", 'c'}, /* Small common. */ |
{".sdata", 'g'}, /* Small initialized data. */ |
{".text", 't'}, |
{"vars", 'd'}, /* MRI .data */ |
{"zerovars", 'b'}, /* MRI .bss */ |
{0, 0} |
}; |
/* Return the single-character symbol type corresponding to |
section S, or '?' for an unknown COFF section. |
Check for any leading string which matches, so .text5 returns |
't' as well as .text */ |
static char |
coff_section_type (const char *s) |
{ |
const struct section_to_type *t; |
for (t = &stt[0]; t->section; t++) |
if (!strncmp (s, t->section, strlen (t->section))) |
return t->type; |
return '?'; |
} |
/* Return the single-character symbol type corresponding to section |
SECTION, or '?' for an unknown section. This uses section flags to |
identify sections. |
FIXME These types are unhandled: c, i, e, p. If we handled these also, |
we could perhaps obsolete coff_section_type. */ |
static char |
decode_section_type (const struct bfd_section *section) |
{ |
if (section->flags & SEC_CODE) |
return 't'; |
if (section->flags & SEC_DATA) |
{ |
if (section->flags & SEC_READONLY) |
return 'r'; |
else if (section->flags & SEC_SMALL_DATA) |
return 'g'; |
else |
return 'd'; |
} |
if ((section->flags & SEC_HAS_CONTENTS) == 0) |
{ |
if (section->flags & SEC_SMALL_DATA) |
return 's'; |
else |
return 'b'; |
} |
if (section->flags & SEC_DEBUGGING) |
return 'N'; |
if ((section->flags & SEC_HAS_CONTENTS) && (section->flags & SEC_READONLY)) |
return 'n'; |
return '?'; |
} |
/* |
FUNCTION |
bfd_decode_symclass |
DESCRIPTION |
Return a character corresponding to the symbol |
class of @var{symbol}, or '?' for an unknown class. |
SYNOPSIS |
int bfd_decode_symclass (asymbol *symbol); |
*/ |
int |
bfd_decode_symclass (asymbol *symbol) |
{ |
char c; |
if (symbol->section && bfd_is_com_section (symbol->section)) |
return 'C'; |
if (bfd_is_und_section (symbol->section)) |
{ |
if (symbol->flags & BSF_WEAK) |
{ |
/* If weak, determine if it's specifically an object |
or non-object weak. */ |
if (symbol->flags & BSF_OBJECT) |
return 'v'; |
else |
return 'w'; |
} |
else |
return 'U'; |
} |
if (bfd_is_ind_section (symbol->section)) |
return 'I'; |
if (symbol->flags & BSF_GNU_INDIRECT_FUNCTION) |
return 'i'; |
if (symbol->flags & BSF_WEAK) |
{ |
/* If weak, determine if it's specifically an object |
or non-object weak. */ |
if (symbol->flags & BSF_OBJECT) |
return 'V'; |
else |
return 'W'; |
} |
if (symbol->flags & BSF_GNU_UNIQUE) |
return 'u'; |
if (!(symbol->flags & (BSF_GLOBAL | BSF_LOCAL))) |
return '?'; |
if (bfd_is_abs_section (symbol->section)) |
c = 'a'; |
else if (symbol->section) |
{ |
c = coff_section_type (symbol->section->name); |
if (c == '?') |
c = decode_section_type (symbol->section); |
} |
else |
return '?'; |
if (symbol->flags & BSF_GLOBAL) |
c = TOUPPER (c); |
return c; |
/* We don't have to handle these cases just yet, but we will soon: |
N_SETV: 'v'; |
N_SETA: 'l'; |
N_SETT: 'x'; |
N_SETD: 'z'; |
N_SETB: 's'; |
N_INDR: 'i'; |
*/ |
} |
/* |
FUNCTION |
bfd_is_undefined_symclass |
DESCRIPTION |
Returns non-zero if the class symbol returned by |
bfd_decode_symclass represents an undefined symbol. |
Returns zero otherwise. |
SYNOPSIS |
bfd_boolean bfd_is_undefined_symclass (int symclass); |
*/ |
bfd_boolean |
bfd_is_undefined_symclass (int symclass) |
{ |
return symclass == 'U' || symclass == 'w' || symclass == 'v'; |
} |
/* |
FUNCTION |
bfd_symbol_info |
DESCRIPTION |
Fill in the basic info about symbol that nm needs. |
Additional info may be added by the back-ends after |
calling this function. |
SYNOPSIS |
void bfd_symbol_info (asymbol *symbol, symbol_info *ret); |
*/ |
void |
bfd_symbol_info (asymbol *symbol, symbol_info *ret) |
{ |
ret->type = bfd_decode_symclass (symbol); |
if (bfd_is_undefined_symclass (ret->type)) |
ret->value = 0; |
else |
ret->value = symbol->value + symbol->section->vma; |
ret->name = symbol->name; |
} |
/* |
FUNCTION |
bfd_copy_private_symbol_data |
SYNOPSIS |
bfd_boolean bfd_copy_private_symbol_data |
(bfd *ibfd, asymbol *isym, bfd *obfd, asymbol *osym); |
DESCRIPTION |
Copy private symbol information from @var{isym} in the BFD |
@var{ibfd} to the symbol @var{osym} in the BFD @var{obfd}. |
Return <<TRUE>> on success, <<FALSE>> on error. Possible error |
returns are: |
o <<bfd_error_no_memory>> - |
Not enough memory exists to create private data for @var{osec}. |
.#define bfd_copy_private_symbol_data(ibfd, isymbol, obfd, osymbol) \ |
. BFD_SEND (obfd, _bfd_copy_private_symbol_data, \ |
. (ibfd, isymbol, obfd, osymbol)) |
. |
*/ |
/* The generic version of the function which returns mini symbols. |
This is used when the backend does not provide a more efficient |
version. It just uses BFD asymbol structures as mini symbols. */ |
long |
_bfd_generic_read_minisymbols (bfd *abfd, |
bfd_boolean dynamic, |
void **minisymsp, |
unsigned int *sizep) |
{ |
long storage; |
asymbol **syms = NULL; |
long symcount; |
if (dynamic) |
storage = bfd_get_dynamic_symtab_upper_bound (abfd); |
else |
storage = bfd_get_symtab_upper_bound (abfd); |
if (storage < 0) |
goto error_return; |
if (storage == 0) |
return 0; |
syms = (asymbol **) bfd_malloc (storage); |
if (syms == NULL) |
goto error_return; |
if (dynamic) |
symcount = bfd_canonicalize_dynamic_symtab (abfd, syms); |
else |
symcount = bfd_canonicalize_symtab (abfd, syms); |
if (symcount < 0) |
goto error_return; |
*minisymsp = syms; |
*sizep = sizeof (asymbol *); |
return symcount; |
error_return: |
bfd_set_error (bfd_error_no_symbols); |
if (syms != NULL) |
free (syms); |
return -1; |
} |
/* The generic version of the function which converts a minisymbol to |
an asymbol. We don't worry about the sym argument we are passed; |
we just return the asymbol the minisymbol points to. */ |
asymbol * |
_bfd_generic_minisymbol_to_symbol (bfd *abfd ATTRIBUTE_UNUSED, |
bfd_boolean dynamic ATTRIBUTE_UNUSED, |
const void *minisym, |
asymbol *sym ATTRIBUTE_UNUSED) |
{ |
return *(asymbol **) minisym; |
} |
/* Look through stabs debugging information in .stab and .stabstr |
sections to find the source file and line closest to a desired |
location. This is used by COFF and ELF targets. It sets *pfound |
to TRUE if it finds some information. The *pinfo field is used to |
pass cached information in and out of this routine; this first time |
the routine is called for a BFD, *pinfo should be NULL. The value |
placed in *pinfo should be saved with the BFD, and passed back each |
time this function is called. */ |
/* We use a cache by default. */ |
#define ENABLE_CACHING |
/* We keep an array of indexentry structures to record where in the |
stabs section we should look to find line number information for a |
particular address. */ |
struct indexentry |
{ |
bfd_vma val; |
bfd_byte *stab; |
bfd_byte *str; |
char *directory_name; |
char *file_name; |
char *function_name; |
}; |
/* Compare two indexentry structures. This is called via qsort. */ |
static int |
cmpindexentry (const void *a, const void *b) |
{ |
const struct indexentry *contestantA = (const struct indexentry *) a; |
const struct indexentry *contestantB = (const struct indexentry *) b; |
if (contestantA->val < contestantB->val) |
return -1; |
else if (contestantA->val > contestantB->val) |
return 1; |
else |
return 0; |
} |
/* A pointer to this structure is stored in *pinfo. */ |
struct stab_find_info |
{ |
/* The .stab section. */ |
asection *stabsec; |
/* The .stabstr section. */ |
asection *strsec; |
/* The contents of the .stab section. */ |
bfd_byte *stabs; |
/* The contents of the .stabstr section. */ |
bfd_byte *strs; |
/* A table that indexes stabs by memory address. */ |
struct indexentry *indextable; |
/* The number of entries in indextable. */ |
int indextablesize; |
#ifdef ENABLE_CACHING |
/* Cached values to restart quickly. */ |
struct indexentry *cached_indexentry; |
bfd_vma cached_offset; |
bfd_byte *cached_stab; |
char *cached_file_name; |
#endif |
/* Saved ptr to malloc'ed filename. */ |
char *filename; |
}; |
bfd_boolean |
_bfd_stab_section_find_nearest_line (bfd *abfd, |
asymbol **symbols, |
asection *section, |
bfd_vma offset, |
bfd_boolean *pfound, |
const char **pfilename, |
const char **pfnname, |
unsigned int *pline, |
void **pinfo) |
{ |
struct stab_find_info *info; |
bfd_size_type stabsize, strsize; |
bfd_byte *stab, *str; |
bfd_byte *last_stab, *last_str; |
bfd_size_type stroff; |
struct indexentry *indexentry; |
char *file_name; |
char *directory_name; |
int saw_fun; |
bfd_boolean saw_line, saw_func; |
*pfound = FALSE; |
*pfilename = bfd_get_filename (abfd); |
*pfnname = NULL; |
*pline = 0; |
/* Stabs entries use a 12 byte format: |
4 byte string table index |
1 byte stab type |
1 byte stab other field |
2 byte stab desc field |
4 byte stab value |
FIXME: This will have to change for a 64 bit object format. |
The stabs symbols are divided into compilation units. For the |
first entry in each unit, the type of 0, the value is the length |
of the string table for this unit, and the desc field is the |
number of stabs symbols for this unit. */ |
#define STRDXOFF (0) |
#define TYPEOFF (4) |
#define OTHEROFF (5) |
#define DESCOFF (6) |
#define VALOFF (8) |
#define STABSIZE (12) |
info = (struct stab_find_info *) *pinfo; |
if (info != NULL) |
{ |
if (info->stabsec == NULL || info->strsec == NULL) |
{ |
/* No stabs debugging information. */ |
return TRUE; |
} |
stabsize = (info->stabsec->rawsize |
? info->stabsec->rawsize |
: info->stabsec->size); |
strsize = (info->strsec->rawsize |
? info->strsec->rawsize |
: info->strsec->size); |
} |
else |
{ |
long reloc_size, reloc_count; |
arelent **reloc_vector; |
int i; |
char *name; |
char *function_name; |
bfd_size_type amt = sizeof *info; |
info = (struct stab_find_info *) bfd_zalloc (abfd, amt); |
if (info == NULL) |
return FALSE; |
/* FIXME: When using the linker --split-by-file or |
--split-by-reloc options, it is possible for the .stab and |
.stabstr sections to be split. We should handle that. */ |
info->stabsec = bfd_get_section_by_name (abfd, ".stab"); |
info->strsec = bfd_get_section_by_name (abfd, ".stabstr"); |
if (info->stabsec == NULL || info->strsec == NULL) |
{ |
/* Try SOM section names. */ |
info->stabsec = bfd_get_section_by_name (abfd, "$GDB_SYMBOLS$"); |
info->strsec = bfd_get_section_by_name (abfd, "$GDB_STRINGS$"); |
if (info->stabsec == NULL || info->strsec == NULL) |
{ |
/* No stabs debugging information. Set *pinfo so that we |
can return quickly in the info != NULL case above. */ |
*pinfo = info; |
return TRUE; |
} |
} |
stabsize = (info->stabsec->rawsize |
? info->stabsec->rawsize |
: info->stabsec->size); |
strsize = (info->strsec->rawsize |
? info->strsec->rawsize |
: info->strsec->size); |
info->stabs = (bfd_byte *) bfd_alloc (abfd, stabsize); |
info->strs = (bfd_byte *) bfd_alloc (abfd, strsize); |
if (info->stabs == NULL || info->strs == NULL) |
return FALSE; |
if (! bfd_get_section_contents (abfd, info->stabsec, info->stabs, |
0, stabsize) |
|| ! bfd_get_section_contents (abfd, info->strsec, info->strs, |
0, strsize)) |
return FALSE; |
/* If this is a relocatable object file, we have to relocate |
the entries in .stab. This should always be simple 32 bit |
relocations against symbols defined in this object file, so |
this should be no big deal. */ |
reloc_size = bfd_get_reloc_upper_bound (abfd, info->stabsec); |
if (reloc_size < 0) |
return FALSE; |
reloc_vector = (arelent **) bfd_malloc (reloc_size); |
if (reloc_vector == NULL && reloc_size != 0) |
return FALSE; |
reloc_count = bfd_canonicalize_reloc (abfd, info->stabsec, reloc_vector, |
symbols); |
if (reloc_count < 0) |
{ |
if (reloc_vector != NULL) |
free (reloc_vector); |
return FALSE; |
} |
if (reloc_count > 0) |
{ |
arelent **pr; |
for (pr = reloc_vector; *pr != NULL; pr++) |
{ |
arelent *r; |
unsigned long val; |
asymbol *sym; |
r = *pr; |
/* Ignore R_*_NONE relocs. */ |
if (r->howto->dst_mask == 0) |
continue; |
if (r->howto->rightshift != 0 |
|| r->howto->size != 2 |
|| r->howto->bitsize != 32 |
|| r->howto->pc_relative |
|| r->howto->bitpos != 0 |
|| r->howto->dst_mask != 0xffffffff) |
{ |
(*_bfd_error_handler) |
(_("Unsupported .stab relocation")); |
bfd_set_error (bfd_error_invalid_operation); |
if (reloc_vector != NULL) |
free (reloc_vector); |
return FALSE; |
} |
val = bfd_get_32 (abfd, info->stabs + r->address); |
val &= r->howto->src_mask; |
sym = *r->sym_ptr_ptr; |
val += sym->value + sym->section->vma + r->addend; |
bfd_put_32 (abfd, (bfd_vma) val, info->stabs + r->address); |
} |
} |
if (reloc_vector != NULL) |
free (reloc_vector); |
/* First time through this function, build a table matching |
function VM addresses to stabs, then sort based on starting |
VM address. Do this in two passes: once to count how many |
table entries we'll need, and a second to actually build the |
table. */ |
info->indextablesize = 0; |
saw_fun = 1; |
for (stab = info->stabs; stab < info->stabs + stabsize; stab += STABSIZE) |
{ |
if (stab[TYPEOFF] == (bfd_byte) N_SO) |
{ |
/* N_SO with null name indicates EOF */ |
if (bfd_get_32 (abfd, stab + STRDXOFF) == 0) |
continue; |
/* if we did not see a function def, leave space for one. */ |
if (saw_fun == 0) |
++info->indextablesize; |
saw_fun = 0; |
/* two N_SO's in a row is a filename and directory. Skip */ |
if (stab + STABSIZE < info->stabs + stabsize |
&& *(stab + STABSIZE + TYPEOFF) == (bfd_byte) N_SO) |
{ |
stab += STABSIZE; |
} |
} |
else if (stab[TYPEOFF] == (bfd_byte) N_FUN) |
{ |
saw_fun = 1; |
++info->indextablesize; |
} |
} |
if (saw_fun == 0) |
++info->indextablesize; |
if (info->indextablesize == 0) |
return TRUE; |
++info->indextablesize; |
amt = info->indextablesize; |
amt *= sizeof (struct indexentry); |
info->indextable = (struct indexentry *) bfd_alloc (abfd, amt); |
if (info->indextable == NULL) |
return FALSE; |
file_name = NULL; |
directory_name = NULL; |
saw_fun = 1; |
stroff = 0; |
for (i = 0, last_stab = stab = info->stabs, last_str = str = info->strs; |
i < info->indextablesize && stab < info->stabs + stabsize; |
stab += STABSIZE) |
{ |
switch (stab[TYPEOFF]) |
{ |
case 0: |
/* This is the first entry in a compilation unit. */ |
if ((bfd_size_type) ((info->strs + strsize) - str) < stroff) |
break; |
str += stroff; |
stroff = bfd_get_32 (abfd, stab + VALOFF); |
break; |
case N_SO: |
/* The main file name. */ |
/* The following code creates a new indextable entry with |
a NULL function name if there were no N_FUNs in a file. |
Note that a N_SO without a file name is an EOF and |
there could be 2 N_SO following it with the new filename |
and directory. */ |
if (saw_fun == 0) |
{ |
info->indextable[i].val = bfd_get_32 (abfd, last_stab + VALOFF); |
info->indextable[i].stab = last_stab; |
info->indextable[i].str = last_str; |
info->indextable[i].directory_name = directory_name; |
info->indextable[i].file_name = file_name; |
info->indextable[i].function_name = NULL; |
++i; |
} |
saw_fun = 0; |
file_name = (char *) str + bfd_get_32 (abfd, stab + STRDXOFF); |
if (*file_name == '\0') |
{ |
directory_name = NULL; |
file_name = NULL; |
saw_fun = 1; |
} |
else |
{ |
last_stab = stab; |
last_str = str; |
if (stab + STABSIZE >= info->stabs + stabsize |
|| *(stab + STABSIZE + TYPEOFF) != (bfd_byte) N_SO) |
{ |
directory_name = NULL; |
} |
else |
{ |
/* Two consecutive N_SOs are a directory and a |
file name. */ |
stab += STABSIZE; |
directory_name = file_name; |
file_name = ((char *) str |
+ bfd_get_32 (abfd, stab + STRDXOFF)); |
} |
} |
break; |
case N_SOL: |
/* The name of an include file. */ |
file_name = (char *) str + bfd_get_32 (abfd, stab + STRDXOFF); |
break; |
case N_FUN: |
/* A function name. */ |
saw_fun = 1; |
name = (char *) str + bfd_get_32 (abfd, stab + STRDXOFF); |
if (*name == '\0') |
name = NULL; |
function_name = name; |
if (name == NULL) |
continue; |
info->indextable[i].val = bfd_get_32 (abfd, stab + VALOFF); |
info->indextable[i].stab = stab; |
info->indextable[i].str = str; |
info->indextable[i].directory_name = directory_name; |
info->indextable[i].file_name = file_name; |
info->indextable[i].function_name = function_name; |
++i; |
break; |
} |
} |
if (saw_fun == 0) |
{ |
info->indextable[i].val = bfd_get_32 (abfd, last_stab + VALOFF); |
info->indextable[i].stab = last_stab; |
info->indextable[i].str = last_str; |
info->indextable[i].directory_name = directory_name; |
info->indextable[i].file_name = file_name; |
info->indextable[i].function_name = NULL; |
++i; |
} |
info->indextable[i].val = (bfd_vma) -1; |
info->indextable[i].stab = info->stabs + stabsize; |
info->indextable[i].str = str; |
info->indextable[i].directory_name = NULL; |
info->indextable[i].file_name = NULL; |
info->indextable[i].function_name = NULL; |
++i; |
info->indextablesize = i; |
qsort (info->indextable, (size_t) i, sizeof (struct indexentry), |
cmpindexentry); |
*pinfo = info; |
} |
/* We are passed a section relative offset. The offsets in the |
stabs information are absolute. */ |
offset += bfd_get_section_vma (abfd, section); |
#ifdef ENABLE_CACHING |
if (info->cached_indexentry != NULL |
&& offset >= info->cached_offset |
&& offset < (info->cached_indexentry + 1)->val) |
{ |
stab = info->cached_stab; |
indexentry = info->cached_indexentry; |
file_name = info->cached_file_name; |
} |
else |
#endif |
{ |
long low, high; |
long mid = -1; |
/* Cache non-existent or invalid. Do binary search on |
indextable. */ |
indexentry = NULL; |
low = 0; |
high = info->indextablesize - 1; |
while (low != high) |
{ |
mid = (high + low) / 2; |
if (offset >= info->indextable[mid].val |
&& offset < info->indextable[mid + 1].val) |
{ |
indexentry = &info->indextable[mid]; |
break; |
} |
if (info->indextable[mid].val > offset) |
high = mid; |
else |
low = mid + 1; |
} |
if (indexentry == NULL) |
return TRUE; |
stab = indexentry->stab + STABSIZE; |
file_name = indexentry->file_name; |
} |
directory_name = indexentry->directory_name; |
str = indexentry->str; |
saw_line = FALSE; |
saw_func = FALSE; |
for (; stab < (indexentry+1)->stab; stab += STABSIZE) |
{ |
bfd_boolean done; |
bfd_vma val; |
done = FALSE; |
switch (stab[TYPEOFF]) |
{ |
case N_SOL: |
/* The name of an include file. */ |
val = bfd_get_32 (abfd, stab + VALOFF); |
if (val <= offset) |
{ |
file_name = (char *) str + bfd_get_32 (abfd, stab + STRDXOFF); |
*pline = 0; |
} |
break; |
case N_SLINE: |
case N_DSLINE: |
case N_BSLINE: |
/* A line number. If the function was specified, then the value |
is relative to the start of the function. Otherwise, the |
value is an absolute address. */ |
val = ((indexentry->function_name ? indexentry->val : 0) |
+ bfd_get_32 (abfd, stab + VALOFF)); |
/* If this line starts before our desired offset, or if it's |
the first line we've been able to find, use it. The |
!saw_line check works around a bug in GCC 2.95.3, which emits |
the first N_SLINE late. */ |
if (!saw_line || val <= offset) |
{ |
*pline = bfd_get_16 (abfd, stab + DESCOFF); |
#ifdef ENABLE_CACHING |
info->cached_stab = stab; |
info->cached_offset = val; |
info->cached_file_name = file_name; |
info->cached_indexentry = indexentry; |
#endif |
} |
if (val > offset) |
done = TRUE; |
saw_line = TRUE; |
break; |
case N_FUN: |
case N_SO: |
if (saw_func || saw_line) |
done = TRUE; |
saw_func = TRUE; |
break; |
} |
if (done) |
break; |
} |
*pfound = TRUE; |
if (file_name == NULL || IS_ABSOLUTE_PATH (file_name) |
|| directory_name == NULL) |
*pfilename = file_name; |
else |
{ |
size_t dirlen; |
dirlen = strlen (directory_name); |
if (info->filename == NULL |
|| filename_ncmp (info->filename, directory_name, dirlen) != 0 |
|| filename_cmp (info->filename + dirlen, file_name) != 0) |
{ |
size_t len; |
/* Don't free info->filename here. objdump and other |
apps keep a copy of a previously returned file name |
pointer. */ |
len = strlen (file_name) + 1; |
info->filename = (char *) bfd_alloc (abfd, dirlen + len); |
if (info->filename == NULL) |
return FALSE; |
memcpy (info->filename, directory_name, dirlen); |
memcpy (info->filename + dirlen, file_name, len); |
} |
*pfilename = info->filename; |
} |
if (indexentry->function_name != NULL) |
{ |
char *s; |
/* This will typically be something like main:F(0,1), so we want |
to clobber the colon. It's OK to change the name, since the |
string is in our own local storage anyhow. */ |
s = strchr (indexentry->function_name, ':'); |
if (s != NULL) |
*s = '\0'; |
*pfnname = indexentry->function_name; |
} |
return TRUE; |
} |
/contrib/toolchain/binutils/bfd/sysdep.h |
---|
0,0 → 1,210 |
/* sysdep.h -- handle host dependencies for the BFD library |
Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2005, 2007, 2009 |
Free Software Foundation, Inc. |
Written by Cygnus Support. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#ifndef BFD_SYSDEP_H |
#define BFD_SYSDEP_H |
#ifdef PACKAGE |
#error sysdep.h must be included in lieu of config.h |
#endif |
#include "config.h" |
#include "ansidecl.h" |
#ifdef HAVE_STDDEF_H |
#include <stddef.h> |
#endif |
#include <stdio.h> |
#include <sys/types.h> |
#include <sys/stat.h> |
#include <errno.h> |
#if !(defined(errno) || defined(_MSC_VER) && defined(_INC_ERRNO)) |
extern int errno; |
#endif |
#ifdef STRING_WITH_STRINGS |
#include <string.h> |
#include <strings.h> |
#else |
#ifdef HAVE_STRING_H |
#include <string.h> |
#else |
#ifdef HAVE_STRINGS_H |
#include <strings.h> |
#else |
extern char *strchr (); |
extern char *strrchr (); |
#endif |
#endif |
#endif |
#ifdef HAVE_STDLIB_H |
#include <stdlib.h> |
#endif |
#ifdef TIME_WITH_SYS_TIME |
#include <sys/time.h> |
#include <time.h> |
#else |
#ifdef HAVE_SYS_TIME_H |
#include <sys/time.h> |
#else |
#include <time.h> |
#endif |
#endif |
#ifdef HAVE_UNISTD_H |
#include <unistd.h> |
#endif |
#ifdef HAVE_SYS_RESOURCE_H |
#include <sys/resource.h> |
#endif /* HAVE_SYS_RESOURCE_H */ |
#ifdef USE_BINARY_FOPEN |
#include "fopen-bin.h" |
#else |
#include "fopen-same.h" |
#endif |
#ifdef HAVE_FCNTL_H |
#include <fcntl.h> |
#else |
#ifdef HAVE_SYS_FILE_H |
#include <sys/file.h> |
#endif |
#endif |
#ifndef O_RDONLY |
#define O_RDONLY 0 |
#endif |
#ifndef O_WRONLY |
#define O_WRONLY 1 |
#endif |
#ifndef O_RDWR |
#define O_RDWR 2 |
#endif |
#ifndef O_ACCMODE |
#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR) |
#endif |
#ifndef SEEK_SET |
#define SEEK_SET 0 |
#endif |
#ifndef SEEK_CUR |
#define SEEK_CUR 1 |
#endif |
#include "filenames.h" |
#if !HAVE_DECL_FFS |
extern int ffs (int); |
#endif |
#if !HAVE_DECL_FREE |
extern void free (); |
#endif |
#if !HAVE_DECL_GETENV |
extern char *getenv (); |
#endif |
#if !HAVE_DECL_MALLOC |
extern PTR malloc (); |
#endif |
#if !HAVE_DECL_REALLOC |
extern PTR realloc (); |
#endif |
#if !HAVE_DECL_STPCPY |
extern char *stpcpy (char *__dest, const char *__src); |
#endif |
#if !HAVE_DECL_STRSTR |
extern char *strstr (); |
#endif |
#ifdef HAVE_FTELLO |
#if !HAVE_DECL_FTELLO |
extern off_t ftello (FILE *stream); |
#endif |
#endif |
#ifdef HAVE_FTELLO64 |
#if !HAVE_DECL_FTELLO64 |
extern off64_t ftello64 (FILE *stream); |
#endif |
#endif |
#ifdef HAVE_FSEEKO |
#if !HAVE_DECL_FSEEKO |
extern int fseeko (FILE *stream, off_t offset, int whence); |
#endif |
#endif |
#ifdef HAVE_FSEEKO64 |
#if !HAVE_DECL_FSEEKO64 |
extern int fseeko64 (FILE *stream, off64_t offset, int whence); |
#endif |
#endif |
/* Define offsetof for those systems which lack it */ |
#ifndef offsetof |
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) |
#endif |
#ifdef ENABLE_NLS |
#include <libintl.h> |
/* Note the use of dgetext() and PACKAGE here, rather than gettext(). |
This is because the code in this directory is used to build a library which |
will be linked with code in other directories to form programs. We want to |
maintain a seperate translation file for this directory however, rather |
than being forced to merge it with that of any program linked to libbfd. |
This is a library, so it cannot depend on the catalog currently loaded. |
In order to do this, we have to make sure that when we extract messages we |
use the OPCODES domain rather than the domain of the program that included |
the bfd library, (eg OBJDUMP). Hence we use dgettext (PACKAGE, String) |
and define PACKAGE to be 'bfd'. (See the code in configure). */ |
#define _(String) dgettext (PACKAGE, String) |
#ifdef gettext_noop |
#define N_(String) gettext_noop (String) |
#else |
#define N_(String) (String) |
#endif |
#else |
# define gettext(Msgid) (Msgid) |
# define dgettext(Domainname, Msgid) (Msgid) |
# define dcgettext(Domainname, Msgid, Category) (Msgid) |
# define textdomain(Domainname) while (0) /* nothing */ |
# define bindtextdomain(Domainname, Dirname) while (0) /* nothing */ |
# define _(String) (String) |
# define N_(String) (String) |
#endif |
#endif /* ! defined (BFD_SYSDEP_H) */ |
/contrib/toolchain/binutils/bfd/targets.c |
---|
0,0 → 1,1736 |
/* Generic target-file-type support for the BFD library. |
Copyright 1990-2013 Free Software Foundation, Inc. |
Written by Cygnus Support. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
#include "fnmatch.h" |
/* |
It's okay to see some: |
#if 0 |
directives in this source file, as targets.c uses them to exclude |
certain BFD vectors. This comment is specially formatted to catch |
users who grep for ^#if 0, so please keep it this way! |
*/ |
/* |
SECTION |
Targets |
DESCRIPTION |
Each port of BFD to a different machine requires the creation |
of a target back end. All the back end provides to the root |
part of BFD is a structure containing pointers to functions |
which perform certain low level operations on files. BFD |
translates the applications's requests through a pointer into |
calls to the back end routines. |
When a file is opened with <<bfd_openr>>, its format and |
target are unknown. BFD uses various mechanisms to determine |
how to interpret the file. The operations performed are: |
o Create a BFD by calling the internal routine |
<<_bfd_new_bfd>>, then call <<bfd_find_target>> with the |
target string supplied to <<bfd_openr>> and the new BFD pointer. |
o If a null target string was provided to <<bfd_find_target>>, |
look up the environment variable <<GNUTARGET>> and use |
that as the target string. |
o If the target string is still <<NULL>>, or the target string is |
<<default>>, then use the first item in the target vector |
as the target type, and set <<target_defaulted>> in the BFD to |
cause <<bfd_check_format>> to loop through all the targets. |
@xref{bfd_target}. @xref{Formats}. |
o Otherwise, inspect the elements in the target vector |
one by one, until a match on target name is found. When found, |
use it. |
o Otherwise return the error <<bfd_error_invalid_target>> to |
<<bfd_openr>>. |
o <<bfd_openr>> attempts to open the file using |
<<bfd_open_file>>, and returns the BFD. |
Once the BFD has been opened and the target selected, the file |
format may be determined. This is done by calling |
<<bfd_check_format>> on the BFD with a suggested format. |
If <<target_defaulted>> has been set, each possible target |
type is tried to see if it recognizes the specified format. |
<<bfd_check_format>> returns <<TRUE>> when the caller guesses right. |
@menu |
@* bfd_target:: |
@end menu |
*/ |
/* |
INODE |
bfd_target, , Targets, Targets |
DOCDD |
SUBSECTION |
bfd_target |
DESCRIPTION |
This structure contains everything that BFD knows about a |
target. It includes things like its byte order, name, and which |
routines to call to do various operations. |
Every BFD points to a target structure with its <<xvec>> |
member. |
The macros below are used to dispatch to functions through the |
<<bfd_target>> vector. They are used in a number of macros further |
down in @file{bfd.h}, and are also used when calling various |
routines by hand inside the BFD implementation. The @var{arglist} |
argument must be parenthesized; it contains all the arguments |
to the called function. |
They make the documentation (more) unpleasant to read, so if |
someone wants to fix this and not break the above, please do. |
.#define BFD_SEND(bfd, message, arglist) \ |
. ((*((bfd)->xvec->message)) arglist) |
. |
.#ifdef DEBUG_BFD_SEND |
.#undef BFD_SEND |
.#define BFD_SEND(bfd, message, arglist) \ |
. (((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \ |
. ((*((bfd)->xvec->message)) arglist) : \ |
. (bfd_assert (__FILE__,__LINE__), NULL)) |
.#endif |
For operations which index on the BFD format: |
.#define BFD_SEND_FMT(bfd, message, arglist) \ |
. (((bfd)->xvec->message[(int) ((bfd)->format)]) arglist) |
. |
.#ifdef DEBUG_BFD_SEND |
.#undef BFD_SEND_FMT |
.#define BFD_SEND_FMT(bfd, message, arglist) \ |
. (((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \ |
. (((bfd)->xvec->message[(int) ((bfd)->format)]) arglist) : \ |
. (bfd_assert (__FILE__,__LINE__), NULL)) |
.#endif |
. |
This is the structure which defines the type of BFD this is. The |
<<xvec>> member of the struct <<bfd>> itself points here. Each |
module that implements access to a different target under BFD, |
defines one of these. |
FIXME, these names should be rationalised with the names of |
the entry points which call them. Too bad we can't have one |
macro to define them both! |
.enum bfd_flavour |
.{ |
. bfd_target_unknown_flavour, |
. bfd_target_aout_flavour, |
. bfd_target_coff_flavour, |
. bfd_target_ecoff_flavour, |
. bfd_target_xcoff_flavour, |
. bfd_target_elf_flavour, |
. bfd_target_ieee_flavour, |
. bfd_target_nlm_flavour, |
. bfd_target_oasys_flavour, |
. bfd_target_tekhex_flavour, |
. bfd_target_srec_flavour, |
. bfd_target_verilog_flavour, |
. bfd_target_ihex_flavour, |
. bfd_target_som_flavour, |
. bfd_target_os9k_flavour, |
. bfd_target_versados_flavour, |
. bfd_target_msdos_flavour, |
. bfd_target_ovax_flavour, |
. bfd_target_evax_flavour, |
. bfd_target_mmo_flavour, |
. bfd_target_mach_o_flavour, |
. bfd_target_pef_flavour, |
. bfd_target_pef_xlib_flavour, |
. bfd_target_sym_flavour |
.}; |
. |
.enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN }; |
. |
.{* Forward declaration. *} |
.typedef struct bfd_link_info _bfd_link_info; |
. |
.{* Forward declaration. *} |
.typedef struct flag_info flag_info; |
. |
.typedef struct bfd_target |
.{ |
. {* Identifies the kind of target, e.g., SunOS4, Ultrix, etc. *} |
. char *name; |
. |
. {* The "flavour" of a back end is a general indication about |
. the contents of a file. *} |
. enum bfd_flavour flavour; |
. |
. {* The order of bytes within the data area of a file. *} |
. enum bfd_endian byteorder; |
. |
. {* The order of bytes within the header parts of a file. *} |
. enum bfd_endian header_byteorder; |
. |
. {* A mask of all the flags which an executable may have set - |
. from the set <<BFD_NO_FLAGS>>, <<HAS_RELOC>>, ...<<D_PAGED>>. *} |
. flagword object_flags; |
. |
. {* A mask of all the flags which a section may have set - from |
. the set <<SEC_NO_FLAGS>>, <<SEC_ALLOC>>, ...<<SET_NEVER_LOAD>>. *} |
. flagword section_flags; |
. |
. {* The character normally found at the front of a symbol. |
. (if any), perhaps `_'. *} |
. char symbol_leading_char; |
. |
. {* The pad character for file names within an archive header. *} |
. char ar_pad_char; |
. |
. {* The maximum number of characters in an archive header. *} |
. unsigned char ar_max_namelen; |
. |
. {* How well this target matches, used to select between various |
. possible targets when more than one target matches. *} |
. unsigned char match_priority; |
. |
. {* Entries for byte swapping for data. These are different from the |
. other entry points, since they don't take a BFD as the first argument. |
. Certain other handlers could do the same. *} |
. bfd_uint64_t (*bfd_getx64) (const void *); |
. bfd_int64_t (*bfd_getx_signed_64) (const void *); |
. void (*bfd_putx64) (bfd_uint64_t, void *); |
. bfd_vma (*bfd_getx32) (const void *); |
. bfd_signed_vma (*bfd_getx_signed_32) (const void *); |
. void (*bfd_putx32) (bfd_vma, void *); |
. bfd_vma (*bfd_getx16) (const void *); |
. bfd_signed_vma (*bfd_getx_signed_16) (const void *); |
. void (*bfd_putx16) (bfd_vma, void *); |
. |
. {* Byte swapping for the headers. *} |
. bfd_uint64_t (*bfd_h_getx64) (const void *); |
. bfd_int64_t (*bfd_h_getx_signed_64) (const void *); |
. void (*bfd_h_putx64) (bfd_uint64_t, void *); |
. bfd_vma (*bfd_h_getx32) (const void *); |
. bfd_signed_vma (*bfd_h_getx_signed_32) (const void *); |
. void (*bfd_h_putx32) (bfd_vma, void *); |
. bfd_vma (*bfd_h_getx16) (const void *); |
. bfd_signed_vma (*bfd_h_getx_signed_16) (const void *); |
. void (*bfd_h_putx16) (bfd_vma, void *); |
. |
. {* Format dependent routines: these are vectors of entry points |
. within the target vector structure, one for each format to check. *} |
. |
. {* Check the format of a file being read. Return a <<bfd_target *>> or zero. *} |
. const struct bfd_target *(*_bfd_check_format[bfd_type_end]) (bfd *); |
. |
. {* Set the format of a file being written. *} |
. bfd_boolean (*_bfd_set_format[bfd_type_end]) (bfd *); |
. |
. {* Write cached information into a file being written, at <<bfd_close>>. *} |
. bfd_boolean (*_bfd_write_contents[bfd_type_end]) (bfd *); |
. |
The general target vector. These vectors are initialized using the |
BFD_JUMP_TABLE macros. |
. |
. {* Generic entry points. *} |
.#define BFD_JUMP_TABLE_GENERIC(NAME) \ |
. NAME##_close_and_cleanup, \ |
. NAME##_bfd_free_cached_info, \ |
. NAME##_new_section_hook, \ |
. NAME##_get_section_contents, \ |
. NAME##_get_section_contents_in_window |
. |
. {* Called when the BFD is being closed to do any necessary cleanup. *} |
. bfd_boolean (*_close_and_cleanup) (bfd *); |
. {* Ask the BFD to free all cached information. *} |
. bfd_boolean (*_bfd_free_cached_info) (bfd *); |
. {* Called when a new section is created. *} |
. bfd_boolean (*_new_section_hook) (bfd *, sec_ptr); |
. {* Read the contents of a section. *} |
. bfd_boolean (*_bfd_get_section_contents) |
. (bfd *, sec_ptr, void *, file_ptr, bfd_size_type); |
. bfd_boolean (*_bfd_get_section_contents_in_window) |
. (bfd *, sec_ptr, bfd_window *, file_ptr, bfd_size_type); |
. |
. {* Entry points to copy private data. *} |
.#define BFD_JUMP_TABLE_COPY(NAME) \ |
. NAME##_bfd_copy_private_bfd_data, \ |
. NAME##_bfd_merge_private_bfd_data, \ |
. _bfd_generic_init_private_section_data, \ |
. NAME##_bfd_copy_private_section_data, \ |
. NAME##_bfd_copy_private_symbol_data, \ |
. NAME##_bfd_copy_private_header_data, \ |
. NAME##_bfd_set_private_flags, \ |
. NAME##_bfd_print_private_bfd_data |
. |
. {* Called to copy BFD general private data from one object file |
. to another. *} |
. bfd_boolean (*_bfd_copy_private_bfd_data) (bfd *, bfd *); |
. {* Called to merge BFD general private data from one object file |
. to a common output file when linking. *} |
. bfd_boolean (*_bfd_merge_private_bfd_data) (bfd *, bfd *); |
. {* Called to initialize BFD private section data from one object file |
. to another. *} |
.#define bfd_init_private_section_data(ibfd, isec, obfd, osec, link_info) \ |
. BFD_SEND (obfd, _bfd_init_private_section_data, (ibfd, isec, obfd, osec, link_info)) |
. bfd_boolean (*_bfd_init_private_section_data) |
. (bfd *, sec_ptr, bfd *, sec_ptr, struct bfd_link_info *); |
. {* Called to copy BFD private section data from one object file |
. to another. *} |
. bfd_boolean (*_bfd_copy_private_section_data) |
. (bfd *, sec_ptr, bfd *, sec_ptr); |
. {* Called to copy BFD private symbol data from one symbol |
. to another. *} |
. bfd_boolean (*_bfd_copy_private_symbol_data) |
. (bfd *, asymbol *, bfd *, asymbol *); |
. {* Called to copy BFD private header data from one object file |
. to another. *} |
. bfd_boolean (*_bfd_copy_private_header_data) |
. (bfd *, bfd *); |
. {* Called to set private backend flags. *} |
. bfd_boolean (*_bfd_set_private_flags) (bfd *, flagword); |
. |
. {* Called to print private BFD data. *} |
. bfd_boolean (*_bfd_print_private_bfd_data) (bfd *, void *); |
. |
. {* Core file entry points. *} |
.#define BFD_JUMP_TABLE_CORE(NAME) \ |
. NAME##_core_file_failing_command, \ |
. NAME##_core_file_failing_signal, \ |
. NAME##_core_file_matches_executable_p, \ |
. NAME##_core_file_pid |
. |
. char * (*_core_file_failing_command) (bfd *); |
. int (*_core_file_failing_signal) (bfd *); |
. bfd_boolean (*_core_file_matches_executable_p) (bfd *, bfd *); |
. int (*_core_file_pid) (bfd *); |
. |
. {* Archive entry points. *} |
.#define BFD_JUMP_TABLE_ARCHIVE(NAME) \ |
. NAME##_slurp_armap, \ |
. NAME##_slurp_extended_name_table, \ |
. NAME##_construct_extended_name_table, \ |
. NAME##_truncate_arname, \ |
. NAME##_write_armap, \ |
. NAME##_read_ar_hdr, \ |
. NAME##_write_ar_hdr, \ |
. NAME##_openr_next_archived_file, \ |
. NAME##_get_elt_at_index, \ |
. NAME##_generic_stat_arch_elt, \ |
. NAME##_update_armap_timestamp |
. |
. bfd_boolean (*_bfd_slurp_armap) (bfd *); |
. bfd_boolean (*_bfd_slurp_extended_name_table) (bfd *); |
. bfd_boolean (*_bfd_construct_extended_name_table) |
. (bfd *, char **, bfd_size_type *, const char **); |
. void (*_bfd_truncate_arname) (bfd *, const char *, char *); |
. bfd_boolean (*write_armap) |
. (bfd *, unsigned int, struct orl *, unsigned int, int); |
. void * (*_bfd_read_ar_hdr_fn) (bfd *); |
. bfd_boolean (*_bfd_write_ar_hdr_fn) (bfd *, bfd *); |
. bfd * (*openr_next_archived_file) (bfd *, bfd *); |
.#define bfd_get_elt_at_index(b,i) BFD_SEND (b, _bfd_get_elt_at_index, (b,i)) |
. bfd * (*_bfd_get_elt_at_index) (bfd *, symindex); |
. int (*_bfd_stat_arch_elt) (bfd *, struct stat *); |
. bfd_boolean (*_bfd_update_armap_timestamp) (bfd *); |
. |
. {* Entry points used for symbols. *} |
.#define BFD_JUMP_TABLE_SYMBOLS(NAME) \ |
. NAME##_get_symtab_upper_bound, \ |
. NAME##_canonicalize_symtab, \ |
. NAME##_make_empty_symbol, \ |
. NAME##_print_symbol, \ |
. NAME##_get_symbol_info, \ |
. NAME##_bfd_is_local_label_name, \ |
. NAME##_bfd_is_target_special_symbol, \ |
. NAME##_get_lineno, \ |
. NAME##_find_nearest_line, \ |
. _bfd_generic_find_nearest_line_discriminator, \ |
. _bfd_generic_find_line, \ |
. NAME##_find_inliner_info, \ |
. NAME##_bfd_make_debug_symbol, \ |
. NAME##_read_minisymbols, \ |
. NAME##_minisymbol_to_symbol |
. |
. long (*_bfd_get_symtab_upper_bound) (bfd *); |
. long (*_bfd_canonicalize_symtab) |
. (bfd *, struct bfd_symbol **); |
. struct bfd_symbol * |
. (*_bfd_make_empty_symbol) (bfd *); |
. void (*_bfd_print_symbol) |
. (bfd *, void *, struct bfd_symbol *, bfd_print_symbol_type); |
.#define bfd_print_symbol(b,p,s,e) BFD_SEND (b, _bfd_print_symbol, (b,p,s,e)) |
. void (*_bfd_get_symbol_info) |
. (bfd *, struct bfd_symbol *, symbol_info *); |
.#define bfd_get_symbol_info(b,p,e) BFD_SEND (b, _bfd_get_symbol_info, (b,p,e)) |
. bfd_boolean (*_bfd_is_local_label_name) (bfd *, const char *); |
. bfd_boolean (*_bfd_is_target_special_symbol) (bfd *, asymbol *); |
. alent * (*_get_lineno) (bfd *, struct bfd_symbol *); |
. bfd_boolean (*_bfd_find_nearest_line) |
. (bfd *, struct bfd_section *, struct bfd_symbol **, bfd_vma, |
. const char **, const char **, unsigned int *); |
. bfd_boolean (*_bfd_find_nearest_line_discriminator) |
. (bfd *, struct bfd_section *, struct bfd_symbol **, bfd_vma, |
. const char **, const char **, unsigned int *, unsigned int *); |
. bfd_boolean (*_bfd_find_line) |
. (bfd *, struct bfd_symbol **, struct bfd_symbol *, |
. const char **, unsigned int *); |
. bfd_boolean (*_bfd_find_inliner_info) |
. (bfd *, const char **, const char **, unsigned int *); |
. {* Back-door to allow format-aware applications to create debug symbols |
. while using BFD for everything else. Currently used by the assembler |
. when creating COFF files. *} |
. asymbol * (*_bfd_make_debug_symbol) |
. (bfd *, void *, unsigned long size); |
.#define bfd_read_minisymbols(b, d, m, s) \ |
. BFD_SEND (b, _read_minisymbols, (b, d, m, s)) |
. long (*_read_minisymbols) |
. (bfd *, bfd_boolean, void **, unsigned int *); |
.#define bfd_minisymbol_to_symbol(b, d, m, f) \ |
. BFD_SEND (b, _minisymbol_to_symbol, (b, d, m, f)) |
. asymbol * (*_minisymbol_to_symbol) |
. (bfd *, bfd_boolean, const void *, asymbol *); |
. |
. {* Routines for relocs. *} |
.#define BFD_JUMP_TABLE_RELOCS(NAME) \ |
. NAME##_get_reloc_upper_bound, \ |
. NAME##_canonicalize_reloc, \ |
. NAME##_bfd_reloc_type_lookup, \ |
. NAME##_bfd_reloc_name_lookup |
. |
. long (*_get_reloc_upper_bound) (bfd *, sec_ptr); |
. long (*_bfd_canonicalize_reloc) |
. (bfd *, sec_ptr, arelent **, struct bfd_symbol **); |
. {* See documentation on reloc types. *} |
. reloc_howto_type * |
. (*reloc_type_lookup) (bfd *, bfd_reloc_code_real_type); |
. reloc_howto_type * |
. (*reloc_name_lookup) (bfd *, const char *); |
. |
. |
. {* Routines used when writing an object file. *} |
.#define BFD_JUMP_TABLE_WRITE(NAME) \ |
. NAME##_set_arch_mach, \ |
. NAME##_set_section_contents |
. |
. bfd_boolean (*_bfd_set_arch_mach) |
. (bfd *, enum bfd_architecture, unsigned long); |
. bfd_boolean (*_bfd_set_section_contents) |
. (bfd *, sec_ptr, const void *, file_ptr, bfd_size_type); |
. |
. {* Routines used by the linker. *} |
.#define BFD_JUMP_TABLE_LINK(NAME) \ |
. NAME##_sizeof_headers, \ |
. NAME##_bfd_get_relocated_section_contents, \ |
. NAME##_bfd_relax_section, \ |
. NAME##_bfd_link_hash_table_create, \ |
. NAME##_bfd_link_hash_table_free, \ |
. NAME##_bfd_link_add_symbols, \ |
. NAME##_bfd_link_just_syms, \ |
. NAME##_bfd_copy_link_hash_symbol_type, \ |
. NAME##_bfd_final_link, \ |
. NAME##_bfd_link_split_section, \ |
. NAME##_bfd_gc_sections, \ |
. NAME##_bfd_lookup_section_flags, \ |
. NAME##_bfd_merge_sections, \ |
. NAME##_bfd_is_group_section, \ |
. NAME##_bfd_discard_group, \ |
. NAME##_section_already_linked, \ |
. NAME##_bfd_define_common_symbol |
. |
. int (*_bfd_sizeof_headers) (bfd *, struct bfd_link_info *); |
. bfd_byte * (*_bfd_get_relocated_section_contents) |
. (bfd *, struct bfd_link_info *, struct bfd_link_order *, |
. bfd_byte *, bfd_boolean, struct bfd_symbol **); |
. |
. bfd_boolean (*_bfd_relax_section) |
. (bfd *, struct bfd_section *, struct bfd_link_info *, bfd_boolean *); |
. |
. {* Create a hash table for the linker. Different backends store |
. different information in this table. *} |
. struct bfd_link_hash_table * |
. (*_bfd_link_hash_table_create) (bfd *); |
. |
. {* Release the memory associated with the linker hash table. *} |
. void (*_bfd_link_hash_table_free) (struct bfd_link_hash_table *); |
. |
. {* Add symbols from this object file into the hash table. *} |
. bfd_boolean (*_bfd_link_add_symbols) (bfd *, struct bfd_link_info *); |
. |
. {* Indicate that we are only retrieving symbol values from this section. *} |
. void (*_bfd_link_just_syms) (asection *, struct bfd_link_info *); |
. |
. {* Copy the symbol type of a linker hash table entry. *} |
.#define bfd_copy_link_hash_symbol_type(b, t, f) \ |
. BFD_SEND (b, _bfd_copy_link_hash_symbol_type, (b, t, f)) |
. void (*_bfd_copy_link_hash_symbol_type) |
. (bfd *, struct bfd_link_hash_entry *, struct bfd_link_hash_entry *); |
. |
. {* Do a link based on the link_order structures attached to each |
. section of the BFD. *} |
. bfd_boolean (*_bfd_final_link) (bfd *, struct bfd_link_info *); |
. |
. {* Should this section be split up into smaller pieces during linking. *} |
. bfd_boolean (*_bfd_link_split_section) (bfd *, struct bfd_section *); |
. |
. {* Remove sections that are not referenced from the output. *} |
. bfd_boolean (*_bfd_gc_sections) (bfd *, struct bfd_link_info *); |
. |
. {* Sets the bitmask of allowed and disallowed section flags. *} |
. bfd_boolean (*_bfd_lookup_section_flags) (struct bfd_link_info *, |
. struct flag_info *, |
. asection *); |
. |
. {* Attempt to merge SEC_MERGE sections. *} |
. bfd_boolean (*_bfd_merge_sections) (bfd *, struct bfd_link_info *); |
. |
. {* Is this section a member of a group? *} |
. bfd_boolean (*_bfd_is_group_section) (bfd *, const struct bfd_section *); |
. |
. {* Discard members of a group. *} |
. bfd_boolean (*_bfd_discard_group) (bfd *, struct bfd_section *); |
. |
. {* Check if SEC has been already linked during a reloceatable or |
. final link. *} |
. bfd_boolean (*_section_already_linked) (bfd *, asection *, |
. struct bfd_link_info *); |
. |
. {* Define a common symbol. *} |
. bfd_boolean (*_bfd_define_common_symbol) (bfd *, struct bfd_link_info *, |
. struct bfd_link_hash_entry *); |
. |
. {* Routines to handle dynamic symbols and relocs. *} |
.#define BFD_JUMP_TABLE_DYNAMIC(NAME) \ |
. NAME##_get_dynamic_symtab_upper_bound, \ |
. NAME##_canonicalize_dynamic_symtab, \ |
. NAME##_get_synthetic_symtab, \ |
. NAME##_get_dynamic_reloc_upper_bound, \ |
. NAME##_canonicalize_dynamic_reloc |
. |
. {* Get the amount of memory required to hold the dynamic symbols. *} |
. long (*_bfd_get_dynamic_symtab_upper_bound) (bfd *); |
. {* Read in the dynamic symbols. *} |
. long (*_bfd_canonicalize_dynamic_symtab) |
. (bfd *, struct bfd_symbol **); |
. {* Create synthetized symbols. *} |
. long (*_bfd_get_synthetic_symtab) |
. (bfd *, long, struct bfd_symbol **, long, struct bfd_symbol **, |
. struct bfd_symbol **); |
. {* Get the amount of memory required to hold the dynamic relocs. *} |
. long (*_bfd_get_dynamic_reloc_upper_bound) (bfd *); |
. {* Read in the dynamic relocs. *} |
. long (*_bfd_canonicalize_dynamic_reloc) |
. (bfd *, arelent **, struct bfd_symbol **); |
. |
A pointer to an alternative bfd_target in case the current one is not |
satisfactory. This can happen when the target cpu supports both big |
and little endian code, and target chosen by the linker has the wrong |
endianness. The function open_output() in ld/ldlang.c uses this field |
to find an alternative output format that is suitable. |
. {* Opposite endian version of this target. *} |
. const struct bfd_target * alternative_target; |
. |
. {* Data for use by back-end routines, which isn't |
. generic enough to belong in this structure. *} |
. const void *backend_data; |
. |
.} bfd_target; |
. |
*/ |
/* All known xvecs (even those that don't compile on all systems). |
Alphabetized for easy reference. |
They are listed a second time below, since |
we can't intermix extern's and initializers. */ |
extern const bfd_target a_out_adobe_vec; |
extern const bfd_target aix5coff64_vec; |
extern const bfd_target aout0_big_vec; |
extern const bfd_target aout_arm_big_vec; |
extern const bfd_target aout_arm_little_vec; |
extern const bfd_target aout_mips_big_vec; |
extern const bfd_target aout_mips_little_vec; |
extern const bfd_target apollocoff_vec; |
extern const bfd_target arm_epoc_pe_big_vec; |
extern const bfd_target arm_epoc_pe_little_vec; |
extern const bfd_target arm_epoc_pei_big_vec; |
extern const bfd_target arm_epoc_pei_little_vec; |
extern const bfd_target arm_wince_pe_big_vec; |
extern const bfd_target arm_wince_pe_little_vec; |
extern const bfd_target arm_wince_pei_big_vec; |
extern const bfd_target arm_wince_pei_little_vec; |
extern const bfd_target armcoff_big_vec; |
extern const bfd_target armcoff_little_vec; |
extern const bfd_target armnetbsd_vec; |
extern const bfd_target armpe_big_vec; |
extern const bfd_target armpe_little_vec; |
extern const bfd_target armpei_big_vec; |
extern const bfd_target armpei_little_vec; |
extern const bfd_target b_out_vec_big_host; |
extern const bfd_target b_out_vec_little_host; |
extern const bfd_target bfd_pei_ia64_vec; |
extern const bfd_target bfd_elf32_avr_vec; |
extern const bfd_target bfd_elf32_bfin_vec; |
extern const bfd_target bfd_elf32_bfinfdpic_vec; |
extern const bfd_target bfd_elf32_big_generic_vec; |
extern const bfd_target bfd_elf32_bigarc_vec; |
extern const bfd_target bfd_elf32_bigarm_vec; |
extern const bfd_target bfd_elf32_bigarm_nacl_vec; |
extern const bfd_target bfd_elf32_bigarm_symbian_vec; |
extern const bfd_target bfd_elf32_bigarm_vxworks_vec; |
extern const bfd_target bfd_elf32_bigmips_vec; |
extern const bfd_target bfd_elf32_bigmips_vxworks_vec; |
extern const bfd_target bfd_elf32_bigmoxie_vec; |
extern const bfd_target bfd_elf32_bignios2_vec; |
extern const bfd_target bfd_elf32_cr16_vec; |
extern const bfd_target bfd_elf32_cr16c_vec; |
extern const bfd_target bfd_elf32_cris_vec; |
extern const bfd_target bfd_elf32_crx_vec; |
extern const bfd_target bfd_elf32_d10v_vec; |
extern const bfd_target bfd_elf32_d30v_vec; |
extern const bfd_target bfd_elf32_dlx_big_vec; |
extern const bfd_target bfd_elf32_epiphany_vec; |
extern const bfd_target bfd_elf32_fr30_vec; |
extern const bfd_target bfd_elf32_frv_vec; |
extern const bfd_target bfd_elf32_frvfdpic_vec; |
extern const bfd_target bfd_elf32_h8300_vec; |
extern const bfd_target bfd_elf32_hppa_linux_vec; |
extern const bfd_target bfd_elf32_hppa_nbsd_vec; |
extern const bfd_target bfd_elf32_hppa_vec; |
extern const bfd_target bfd_elf32_i370_vec; |
extern const bfd_target bfd_elf32_i386_freebsd_vec; |
extern const bfd_target bfd_elf32_i386_nacl_vec; |
extern const bfd_target bfd_elf32_i386_sol2_vec; |
extern const bfd_target bfd_elf32_i386_vxworks_vec; |
extern const bfd_target bfd_elf32_i386_vec; |
extern const bfd_target bfd_elf32_i860_little_vec; |
extern const bfd_target bfd_elf32_i860_vec; |
extern const bfd_target bfd_elf32_i960_vec; |
extern const bfd_target bfd_elf32_ia64_big_vec; |
extern const bfd_target bfd_elf32_ia64_hpux_big_vec; |
extern const bfd_target bfd_elf32_ip2k_vec; |
extern const bfd_target bfd_elf32_iq2000_vec; |
extern const bfd_target bfd_elf32_lm32_vec; |
extern const bfd_target bfd_elf32_lm32fdpic_vec; |
extern const bfd_target bfd_elf32_little_generic_vec; |
extern const bfd_target bfd_elf32_littlearc_vec; |
extern const bfd_target bfd_elf32_littlearm_vec; |
extern const bfd_target bfd_elf32_littlearm_nacl_vec; |
extern const bfd_target bfd_elf32_littlearm_symbian_vec; |
extern const bfd_target bfd_elf32_littlearm_vxworks_vec; |
extern const bfd_target bfd_elf32_littlemips_vec; |
extern const bfd_target bfd_elf32_littlemips_vxworks_vec; |
extern const bfd_target bfd_elf32_littlemoxie_vec; |
extern const bfd_target bfd_elf32_littlenios2_vec; |
extern const bfd_target bfd_elf32_m32c_vec; |
extern const bfd_target bfd_elf32_m32r_vec; |
extern const bfd_target bfd_elf32_m32rle_vec; |
extern const bfd_target bfd_elf32_m32rlin_vec; |
extern const bfd_target bfd_elf32_m32rlelin_vec; |
extern const bfd_target bfd_elf32_m68hc11_vec; |
extern const bfd_target bfd_elf32_m68hc12_vec; |
extern const bfd_target bfd_elf32_m68k_vec; |
extern const bfd_target bfd_elf32_m88k_vec; |
extern const bfd_target bfd_elf32_mcore_big_vec; |
extern const bfd_target bfd_elf32_mcore_little_vec; |
extern const bfd_target bfd_elf32_mep_vec; |
extern const bfd_target bfd_elf32_mep_little_vec; |
extern const bfd_target bfd_elf32_metag_vec; |
extern const bfd_target bfd_elf32_microblazeel_vec; |
extern const bfd_target bfd_elf32_microblaze_vec; |
extern const bfd_target bfd_elf32_mn10200_vec; |
extern const bfd_target bfd_elf32_mn10300_vec; |
extern const bfd_target bfd_elf32_mt_vec; |
extern const bfd_target bfd_elf32_msp430_vec; |
extern const bfd_target bfd_elf32_msp430_ti_vec; |
extern const bfd_target bfd_elf32_nbigmips_vec; |
extern const bfd_target bfd_elf32_nlittlemips_vec; |
extern const bfd_target bfd_elf32_ntradbigmips_vec; |
extern const bfd_target bfd_elf32_ntradlittlemips_vec; |
extern const bfd_target bfd_elf32_ntradbigmips_freebsd_vec; |
extern const bfd_target bfd_elf32_ntradlittlemips_freebsd_vec; |
extern const bfd_target bfd_elf32_openrisc_vec; |
extern const bfd_target bfd_elf32_or32_big_vec; |
extern const bfd_target bfd_elf32_pj_vec; |
extern const bfd_target bfd_elf32_pjl_vec; |
extern const bfd_target bfd_elf32_powerpc_vec; |
extern const bfd_target bfd_elf32_powerpcle_vec; |
extern const bfd_target bfd_elf32_powerpc_freebsd_vec; |
extern const bfd_target bfd_elf32_powerpc_vxworks_vec; |
extern const bfd_target bfd_elf32_rl78_vec; |
extern const bfd_target bfd_elf32_rx_le_vec; |
extern const bfd_target bfd_elf32_rx_be_vec; |
extern const bfd_target bfd_elf32_rx_be_ns_vec; |
extern const bfd_target bfd_elf32_s390_vec; |
extern const bfd_target bfd_elf32_bigscore_vec; |
extern const bfd_target bfd_elf32_littlescore_vec; |
extern const bfd_target bfd_elf32_sh64_vec; |
extern const bfd_target bfd_elf32_sh64l_vec; |
extern const bfd_target bfd_elf32_sh64lin_vec; |
extern const bfd_target bfd_elf32_sh64blin_vec; |
extern const bfd_target bfd_elf32_sh64lnbsd_vec; |
extern const bfd_target bfd_elf32_sh64nbsd_vec; |
extern const bfd_target bfd_elf32_sh_vec; |
extern const bfd_target bfd_elf32_shbfd_vec; |
extern const bfd_target bfd_elf32_shblin_vec; |
extern const bfd_target bfd_elf32_shfd_vec; |
extern const bfd_target bfd_elf32_shl_vec; |
extern const bfd_target bfd_elf32_shl_symbian_vec; |
extern const bfd_target bfd_elf32_shlin_vec; |
extern const bfd_target bfd_elf32_shlnbsd_vec; |
extern const bfd_target bfd_elf32_shlvxworks_vec; |
extern const bfd_target bfd_elf32_shnbsd_vec; |
extern const bfd_target bfd_elf32_shvxworks_vec; |
extern const bfd_target bfd_elf32_sparc_vec; |
extern const bfd_target bfd_elf32_sparc_sol2_vec; |
extern const bfd_target bfd_elf32_sparc_vxworks_vec; |
extern const bfd_target bfd_elf32_spu_vec; |
extern const bfd_target bfd_elf32_tic6x_be_vec; |
extern const bfd_target bfd_elf32_tic6x_le_vec; |
extern const bfd_target bfd_elf32_tic6x_elf_be_vec; |
extern const bfd_target bfd_elf32_tic6x_elf_le_vec; |
extern const bfd_target bfd_elf32_tic6x_linux_be_vec; |
extern const bfd_target bfd_elf32_tic6x_linux_le_vec; |
extern const bfd_target bfd_elf32_tilegx_be_vec; |
extern const bfd_target bfd_elf32_tilegx_le_vec; |
extern const bfd_target bfd_elf32_tilepro_vec; |
extern const bfd_target bfd_elf32_tradbigmips_vec; |
extern const bfd_target bfd_elf32_tradlittlemips_vec; |
extern const bfd_target bfd_elf32_tradbigmips_freebsd_vec; |
extern const bfd_target bfd_elf32_tradlittlemips_freebsd_vec; |
extern const bfd_target bfd_elf32_us_cris_vec; |
extern const bfd_target bfd_elf32_v850_vec; |
extern const bfd_target bfd_elf32_v850_rh850_vec; |
extern const bfd_target bfd_elf32_vax_vec; |
extern const bfd_target bfd_elf32_xc16x_vec; |
extern const bfd_target bfd_elf32_xgate_vec; |
extern const bfd_target bfd_elf32_xstormy16_vec; |
extern const bfd_target bfd_elf32_xtensa_be_vec; |
extern const bfd_target bfd_elf32_xtensa_le_vec; |
extern const bfd_target bfd_elf64_alpha_freebsd_vec; |
extern const bfd_target bfd_elf64_alpha_vec; |
extern const bfd_target bfd_elf64_big_generic_vec; |
extern const bfd_target bfd_elf64_bigmips_vec; |
extern const bfd_target bfd_elf64_bigaarch64_vec; |
extern const bfd_target bfd_elf32_bigaarch64_vec; |
extern const bfd_target bfd_elf64_hppa_linux_vec; |
extern const bfd_target bfd_elf64_hppa_vec; |
extern const bfd_target bfd_elf64_ia64_big_vec; |
extern const bfd_target bfd_elf64_ia64_hpux_big_vec; |
extern const bfd_target bfd_elf64_ia64_little_vec; |
extern const bfd_target bfd_elf64_ia64_vms_vec; |
extern const bfd_target bfd_elf64_little_generic_vec; |
extern const bfd_target bfd_elf64_littlemips_vec; |
extern const bfd_target bfd_elf64_littleaarch64_vec; |
extern const bfd_target bfd_elf32_littleaarch64_vec; |
extern const bfd_target bfd_elf64_mmix_vec; |
extern const bfd_target bfd_elf64_powerpc_vec; |
extern const bfd_target bfd_elf64_powerpcle_vec; |
extern const bfd_target bfd_elf64_powerpc_freebsd_vec; |
extern const bfd_target bfd_elf64_s390_vec; |
extern const bfd_target bfd_elf64_sh64_vec; |
extern const bfd_target bfd_elf64_sh64l_vec; |
extern const bfd_target bfd_elf64_sh64lin_vec; |
extern const bfd_target bfd_elf64_sh64blin_vec; |
extern const bfd_target bfd_elf64_sh64lnbsd_vec; |
extern const bfd_target bfd_elf64_sh64nbsd_vec; |
extern const bfd_target bfd_elf64_sparc_vec; |
extern const bfd_target bfd_elf64_sparc_freebsd_vec; |
extern const bfd_target bfd_elf64_sparc_sol2_vec; |
extern const bfd_target bfd_elf64_tilegx_be_vec; |
extern const bfd_target bfd_elf64_tilegx_le_vec; |
extern const bfd_target bfd_elf64_tradbigmips_vec; |
extern const bfd_target bfd_elf64_tradlittlemips_vec; |
extern const bfd_target bfd_elf64_tradbigmips_freebsd_vec; |
extern const bfd_target bfd_elf64_tradlittlemips_freebsd_vec; |
extern const bfd_target bfd_elf64_x86_64_freebsd_vec; |
extern const bfd_target bfd_elf64_x86_64_nacl_vec; |
extern const bfd_target bfd_elf64_x86_64_sol2_vec; |
extern const bfd_target bfd_elf64_x86_64_vec; |
extern const bfd_target bfd_elf32_x86_64_nacl_vec; |
extern const bfd_target bfd_elf32_x86_64_vec; |
extern const bfd_target bfd_elf64_l1om_freebsd_vec; |
extern const bfd_target bfd_elf64_l1om_vec; |
extern const bfd_target bfd_elf64_k1om_freebsd_vec; |
extern const bfd_target bfd_elf64_k1om_vec; |
extern const bfd_target bfd_mmo_vec; |
extern const bfd_target bfd_powerpc_pe_vec; |
extern const bfd_target bfd_powerpc_pei_vec; |
extern const bfd_target bfd_powerpcle_pe_vec; |
extern const bfd_target bfd_powerpcle_pei_vec; |
extern const bfd_target cris_aout_vec; |
extern const bfd_target demo_64_vec; |
extern const bfd_target ecoff_big_vec; |
extern const bfd_target ecoff_biglittle_vec; |
extern const bfd_target ecoff_little_vec; |
extern const bfd_target ecoffalpha_little_vec; |
extern const bfd_target go32coff_vec; |
extern const bfd_target go32stubbedcoff_vec; |
extern const bfd_target h8300coff_vec; |
extern const bfd_target h8500coff_vec; |
extern const bfd_target host_aout_vec; |
extern const bfd_target hp300bsd_vec; |
extern const bfd_target hp300hpux_vec; |
extern const bfd_target i386aout_vec; |
extern const bfd_target i386bsd_vec; |
extern const bfd_target i386coff_vec; |
extern const bfd_target i386dynix_vec; |
extern const bfd_target i386freebsd_vec; |
extern const bfd_target i386linux_vec; |
extern const bfd_target i386lynx_aout_vec; |
extern const bfd_target i386lynx_coff_vec; |
extern const bfd_target i386mach3_vec; |
extern const bfd_target i386msdos_vec; |
extern const bfd_target i386netbsd_vec; |
extern const bfd_target i386os9k_vec; |
extern const bfd_target i386pe_vec; |
extern const bfd_target i386pei_vec; |
extern const bfd_target i860coff_vec; |
extern const bfd_target icoff_big_vec; |
extern const bfd_target icoff_little_vec; |
extern const bfd_target ieee_vec; |
extern const bfd_target m68k4knetbsd_vec; |
extern const bfd_target m68kaux_coff_vec; |
extern const bfd_target m68kcoff_vec; |
extern const bfd_target m68kcoffun_vec; |
extern const bfd_target m68klinux_vec; |
extern const bfd_target m68knetbsd_vec; |
extern const bfd_target m68ksysvcoff_vec; |
extern const bfd_target m88kbcs_vec; |
extern const bfd_target m88kmach3_vec; |
extern const bfd_target m88kopenbsd_vec; |
extern const bfd_target mach_o_be_vec; |
extern const bfd_target mach_o_le_vec; |
extern const bfd_target mach_o_fat_vec; |
extern const bfd_target mach_o_i386_vec; |
extern const bfd_target mach_o_x86_64_vec; |
extern const bfd_target mcore_pe_big_vec; |
extern const bfd_target mcore_pe_little_vec; |
extern const bfd_target mcore_pei_big_vec; |
extern const bfd_target mcore_pei_little_vec; |
extern const bfd_target mipslpe_vec; |
extern const bfd_target mipslpei_vec; |
extern const bfd_target newsos3_vec; |
extern const bfd_target nlm32_alpha_vec; |
extern const bfd_target nlm32_i386_vec; |
extern const bfd_target nlm32_powerpc_vec; |
extern const bfd_target nlm32_sparc_vec; |
extern const bfd_target oasys_vec; |
extern const bfd_target or32coff_big_vec; |
extern const bfd_target pc532machaout_vec; |
extern const bfd_target pc532netbsd_vec; |
extern const bfd_target pdp11_aout_vec; |
extern const bfd_target pef_vec; |
extern const bfd_target pef_xlib_vec; |
extern const bfd_target plugin_vec; |
extern const bfd_target pmac_xcoff_vec; |
extern const bfd_target ppcboot_vec; |
extern const bfd_target riscix_vec; |
extern const bfd_target rs6000coff64_vec; |
extern const bfd_target rs6000coff_vec; |
extern const bfd_target shcoff_small_vec; |
extern const bfd_target shcoff_vec; |
extern const bfd_target shlcoff_small_vec; |
extern const bfd_target shlcoff_vec; |
extern const bfd_target shlpe_vec; |
extern const bfd_target shlpei_vec; |
extern const bfd_target som_vec; |
extern const bfd_target sparccoff_vec; |
extern const bfd_target sparcle_aout_vec; |
extern const bfd_target sparclinux_vec; |
extern const bfd_target sparclynx_aout_vec; |
extern const bfd_target sparclynx_coff_vec; |
extern const bfd_target sparcnetbsd_vec; |
extern const bfd_target sunos_big_vec; |
extern const bfd_target sym_vec; |
extern const bfd_target tic30_aout_vec; |
extern const bfd_target tic30_coff_vec; |
extern const bfd_target tic4x_coff0_beh_vec; |
extern const bfd_target tic4x_coff0_vec; |
extern const bfd_target tic4x_coff1_beh_vec; |
extern const bfd_target tic4x_coff1_vec; |
extern const bfd_target tic4x_coff2_beh_vec; |
extern const bfd_target tic4x_coff2_vec; |
extern const bfd_target tic54x_coff0_beh_vec; |
extern const bfd_target tic54x_coff0_vec; |
extern const bfd_target tic54x_coff1_beh_vec; |
extern const bfd_target tic54x_coff1_vec; |
extern const bfd_target tic54x_coff2_beh_vec; |
extern const bfd_target tic54x_coff2_vec; |
extern const bfd_target tic80coff_vec; |
extern const bfd_target vaxbsd_vec; |
extern const bfd_target vaxnetbsd_vec; |
extern const bfd_target vax1knetbsd_vec; |
extern const bfd_target versados_vec; |
extern const bfd_target vms_alpha_vec; |
extern const bfd_target vms_lib_txt_vec; |
extern const bfd_target w65_vec; |
extern const bfd_target we32kcoff_vec; |
extern const bfd_target x86_64pe_vec; |
extern const bfd_target x86_64pei_vec; |
extern const bfd_target x86_64coff_vec; |
extern const bfd_target z80coff_vec; |
extern const bfd_target z8kcoff_vec; |
/* These are always included. */ |
extern const bfd_target srec_vec; |
extern const bfd_target verilog_vec; |
extern const bfd_target symbolsrec_vec; |
extern const bfd_target tekhex_vec; |
extern const bfd_target binary_vec; |
extern const bfd_target ihex_vec; |
/* All of the xvecs for core files. */ |
extern const bfd_target aix386_core_vec; |
extern const bfd_target cisco_core_big_vec; |
extern const bfd_target cisco_core_little_vec; |
extern const bfd_target hppabsd_core_vec; |
extern const bfd_target hpux_core_vec; |
extern const bfd_target irix_core_vec; |
extern const bfd_target netbsd_core_vec; |
extern const bfd_target osf_core_vec; |
extern const bfd_target ptrace_core_vec; |
extern const bfd_target sco5_core_vec; |
extern const bfd_target trad_core_vec; |
extern const bfd_target bfd_elf32_am33lin_vec; |
static const bfd_target * const _bfd_target_vector[] = |
{ |
#ifdef SELECT_VECS |
SELECT_VECS, |
#else /* not SELECT_VECS */ |
#ifdef DEFAULT_VECTOR |
&DEFAULT_VECTOR, |
#endif |
/* This list is alphabetized to make it easy to compare |
with other vector lists -- the decls above and |
the case statement in configure.in. |
Vectors that don't compile on all systems, or aren't finished, |
should have an entry here with #if 0 around it, to show that |
it wasn't omitted by mistake. */ |
&a_out_adobe_vec, |
#ifdef BFD64 |
&aix5coff64_vec, |
#endif |
&aout0_big_vec, |
#if 0 |
/* We have no way of distinguishing these from other a.out variants. */ |
&aout_arm_big_vec, |
&aout_arm_little_vec, |
/* No one seems to use this. */ |
&aout_mips_big_vec, |
#endif |
&aout_mips_little_vec, |
#if 0 |
&apollocoff_vec, |
#endif |
&arm_epoc_pe_big_vec, |
&arm_epoc_pe_little_vec, |
&arm_epoc_pei_big_vec, |
&arm_epoc_pei_little_vec, |
&arm_wince_pe_big_vec, |
&arm_wince_pe_little_vec, |
&arm_wince_pei_big_vec, |
&arm_wince_pei_little_vec, |
&armcoff_big_vec, |
&armcoff_little_vec, |
&armnetbsd_vec, |
&armpe_big_vec, |
&armpe_little_vec, |
&armpei_big_vec, |
&armpei_little_vec, |
&b_out_vec_big_host, |
&b_out_vec_little_host, |
#ifdef BFD64 |
&bfd_pei_ia64_vec, |
#endif |
&bfd_elf32_avr_vec, |
&bfd_elf32_bfin_vec, |
&bfd_elf32_bfinfdpic_vec, |
/* This, and other vectors, may not be used in any *.mt configuration. |
But that does not mean they are unnecessary. If configured with |
--enable-targets=all, objdump or gdb should be able to examine |
the file even if we don't recognize the machine type. */ |
&bfd_elf32_big_generic_vec, |
&bfd_elf32_bigarc_vec, |
&bfd_elf32_bigarm_vec, |
&bfd_elf32_bigarm_symbian_vec, |
&bfd_elf32_bigarm_vxworks_vec, |
#ifdef BFD64 |
&bfd_elf32_bigmips_vec, |
&bfd_elf32_bigmips_vxworks_vec, |
#endif |
&bfd_elf32_bigmoxie_vec, |
&bfd_elf32_bignios2_vec, |
&bfd_elf32_cr16_vec, |
&bfd_elf32_cr16c_vec, |
&bfd_elf32_cris_vec, |
&bfd_elf32_crx_vec, |
&bfd_elf32_d10v_vec, |
&bfd_elf32_d30v_vec, |
&bfd_elf32_dlx_big_vec, |
&bfd_elf32_epiphany_vec, |
&bfd_elf32_fr30_vec, |
&bfd_elf32_frv_vec, |
&bfd_elf32_frvfdpic_vec, |
&bfd_elf32_h8300_vec, |
&bfd_elf32_hppa_linux_vec, |
&bfd_elf32_hppa_nbsd_vec, |
&bfd_elf32_hppa_vec, |
&bfd_elf32_i370_vec, |
&bfd_elf32_i386_freebsd_vec, |
&bfd_elf32_i386_nacl_vec, |
&bfd_elf32_i386_sol2_vec, |
&bfd_elf32_i386_vxworks_vec, |
&bfd_elf32_i386_vec, |
&bfd_elf32_i860_little_vec, |
&bfd_elf32_i860_vec, |
&bfd_elf32_i960_vec, |
#if 0 |
&bfd_elf32_ia64_big_vec, |
#endif |
#ifdef BFD64 |
&bfd_elf32_ia64_hpux_big_vec, |
#endif |
&bfd_elf32_ip2k_vec, |
&bfd_elf32_iq2000_vec, |
&bfd_elf32_lm32_vec, |
&bfd_elf32_little_generic_vec, |
&bfd_elf32_littlearc_vec, |
&bfd_elf32_littlearm_vec, |
&bfd_elf32_littlearm_symbian_vec, |
&bfd_elf32_littlearm_vxworks_vec, |
#ifdef BFD64 |
&bfd_elf32_littlemips_vec, |
&bfd_elf32_littlemips_vxworks_vec, |
#endif |
&bfd_elf32_littlemoxie_vec, |
&bfd_elf32_littlenios2_vec, |
&bfd_elf32_m32c_vec, |
&bfd_elf32_m32r_vec, |
&bfd_elf32_m32rle_vec, |
&bfd_elf32_m32rlin_vec, |
&bfd_elf32_m32rlelin_vec, |
&bfd_elf32_m68hc11_vec, |
&bfd_elf32_m68hc12_vec, |
&bfd_elf32_m68k_vec, |
&bfd_elf32_m88k_vec, |
&bfd_elf32_mcore_big_vec, |
&bfd_elf32_mcore_little_vec, |
&bfd_elf32_mep_vec, |
&bfd_elf32_metag_vec, |
&bfd_elf32_microblaze_vec, |
&bfd_elf32_mn10200_vec, |
&bfd_elf32_mn10300_vec, |
&bfd_elf32_mt_vec, |
&bfd_elf32_msp430_vec, |
&bfd_elf32_msp430_ti_vec, |
#ifdef BFD64 |
&bfd_elf32_nbigmips_vec, |
&bfd_elf32_nlittlemips_vec, |
&bfd_elf32_ntradbigmips_vec, |
&bfd_elf32_ntradlittlemips_vec, |
&bfd_elf32_ntradbigmips_freebsd_vec, |
&bfd_elf32_ntradlittlemips_freebsd_vec, |
#endif |
&bfd_elf32_openrisc_vec, |
&bfd_elf32_or32_big_vec, |
&bfd_elf32_pj_vec, |
&bfd_elf32_pjl_vec, |
&bfd_elf32_powerpc_vec, |
&bfd_elf32_powerpc_vxworks_vec, |
&bfd_elf32_powerpcle_vec, |
&bfd_elf32_powerpc_freebsd_vec, |
&bfd_elf32_rl78_vec, |
&bfd_elf32_rx_be_vec, |
&bfd_elf32_rx_be_ns_vec, |
&bfd_elf32_rx_le_vec, |
&bfd_elf32_s390_vec, |
#ifdef BFD64 |
&bfd_elf32_bigscore_vec, |
&bfd_elf32_littlescore_vec, |
#endif |
&bfd_elf32_sh_vec, |
&bfd_elf32_shbfd_vec, |
&bfd_elf32_shblin_vec, |
&bfd_elf32_shfd_vec, |
&bfd_elf32_shl_vec, |
&bfd_elf32_shl_symbian_vec, |
&bfd_elf32_shlin_vec, |
&bfd_elf32_shlnbsd_vec, |
&bfd_elf32_shlvxworks_vec, |
&bfd_elf32_shnbsd_vec, |
&bfd_elf32_shvxworks_vec, |
#ifdef BFD64 |
&bfd_elf32_sh64_vec, |
&bfd_elf32_sh64l_vec, |
&bfd_elf32_sh64lnbsd_vec, |
&bfd_elf32_sh64nbsd_vec, |
&bfd_elf32_sh64lin_vec, |
&bfd_elf32_sh64blin_vec, |
#endif |
&bfd_elf32_sparc_vec, |
&bfd_elf32_sparc_sol2_vec, |
&bfd_elf32_sparc_vxworks_vec, |
&bfd_elf32_spu_vec, |
&bfd_elf32_tic6x_be_vec, |
&bfd_elf32_tic6x_le_vec, |
&bfd_elf32_tilegx_be_vec, |
&bfd_elf32_tilegx_le_vec, |
&bfd_elf32_tilepro_vec, |
#ifdef BFD64 |
&bfd_elf32_tradbigmips_vec, |
&bfd_elf32_tradlittlemips_vec, |
&bfd_elf32_tradbigmips_freebsd_vec, |
&bfd_elf32_tradlittlemips_freebsd_vec, |
#endif |
&bfd_elf32_us_cris_vec, |
&bfd_elf32_v850_vec, |
&bfd_elf32_v850_rh850_vec, |
&bfd_elf32_vax_vec, |
&bfd_elf32_xc16x_vec, |
&bfd_elf32_xgate_vec, |
&bfd_elf32_xstormy16_vec, |
&bfd_elf32_xtensa_be_vec, |
&bfd_elf32_xtensa_le_vec, |
#ifdef BFD64 |
&bfd_elf64_alpha_freebsd_vec, |
&bfd_elf64_alpha_vec, |
&bfd_elf64_big_generic_vec, |
&bfd_elf64_bigmips_vec, |
&bfd_elf64_bigaarch64_vec, |
&bfd_elf32_bigaarch64_vec, |
&bfd_elf64_hppa_linux_vec, |
&bfd_elf64_hppa_vec, |
&bfd_elf64_ia64_big_vec, |
&bfd_elf64_ia64_hpux_big_vec, |
&bfd_elf64_ia64_little_vec, |
&bfd_elf64_ia64_vms_vec, |
&bfd_elf64_little_generic_vec, |
&bfd_elf64_littlemips_vec, |
&bfd_elf64_littleaarch64_vec, |
&bfd_elf32_littleaarch64_vec, |
&bfd_elf64_mmix_vec, |
&bfd_elf64_powerpc_vec, |
&bfd_elf64_powerpcle_vec, |
&bfd_elf64_powerpc_freebsd_vec, |
&bfd_elf64_s390_vec, |
&bfd_elf64_sh64_vec, |
&bfd_elf64_sh64l_vec, |
&bfd_elf64_sh64lnbsd_vec, |
&bfd_elf64_sh64nbsd_vec, |
&bfd_elf64_sh64lin_vec, |
&bfd_elf64_sh64blin_vec, |
&bfd_elf64_sparc_vec, |
&bfd_elf64_sparc_freebsd_vec, |
&bfd_elf64_sparc_sol2_vec, |
&bfd_elf64_tilegx_be_vec, |
&bfd_elf64_tilegx_le_vec, |
&bfd_elf64_tradbigmips_vec, |
&bfd_elf64_tradlittlemips_vec, |
&bfd_elf64_tradbigmips_freebsd_vec, |
&bfd_elf64_tradlittlemips_freebsd_vec, |
&bfd_elf64_x86_64_freebsd_vec, |
&bfd_elf64_x86_64_nacl_vec, |
&bfd_elf64_x86_64_sol2_vec, |
&bfd_elf64_x86_64_vec, |
&bfd_elf32_x86_64_nacl_vec, |
&bfd_elf32_x86_64_vec, |
&bfd_elf64_l1om_freebsd_vec, |
&bfd_elf64_l1om_vec, |
&bfd_elf64_k1om_freebsd_vec, |
&bfd_elf64_k1om_vec, |
&bfd_mmo_vec, |
#endif |
&bfd_powerpc_pe_vec, |
&bfd_powerpc_pei_vec, |
&bfd_powerpcle_pe_vec, |
&bfd_powerpcle_pei_vec, |
&cris_aout_vec, |
#ifdef BFD64 |
&demo_64_vec, /* Only compiled if host has long-long support. */ |
#endif |
&ecoff_big_vec, |
&ecoff_biglittle_vec, |
&ecoff_little_vec, |
#ifdef BFD64 |
&ecoffalpha_little_vec, |
#endif |
&go32coff_vec, |
&go32stubbedcoff_vec, |
&h8300coff_vec, |
&h8500coff_vec, |
#if 0 |
/* Since a.out files lack decent magic numbers, no way to recognize |
which kind of a.out file it is. */ |
&host_aout_vec, |
/* Clashes with sunos_big_vec magic no. */ |
&hp300bsd_vec, |
#endif |
&hp300hpux_vec, |
&i386aout_vec, |
&i386bsd_vec, |
&i386coff_vec, |
#if 0 |
&i386dynix_vec, |
#endif |
&i386freebsd_vec, |
#if 0 |
/* Since a.out files lack decent magic numbers, no way to recognize |
which kind of a.out file it is. */ |
&i386linux_vec, |
#endif |
&i386lynx_aout_vec, |
&i386lynx_coff_vec, |
#if 0 |
/* No distinguishing features for Mach 3 executables. */ |
&i386mach3_vec, |
#endif |
&i386msdos_vec, |
&i386netbsd_vec, |
&i386os9k_vec, |
&i386pe_vec, |
&i386pei_vec, |
#ifdef BFD64 |
&x86_64coff_vec, |
&x86_64pe_vec, |
&x86_64pei_vec, |
#endif |
&i860coff_vec, |
&icoff_big_vec, |
&icoff_little_vec, |
&ieee_vec, |
#if 0 |
&m68k4knetbsd_vec, |
&m68kaux_coff_vec, |
#endif |
&m68kcoff_vec, |
&m68kcoffun_vec, |
#if 0 |
/* Since a.out files lack decent magic numbers, no way to recognize |
which kind of a.out file it is. */ |
&m68klinux_vec, |
#endif |
&m68knetbsd_vec, |
&m68ksysvcoff_vec, |
&m88kbcs_vec, |
&m88kmach3_vec, |
&m88kopenbsd_vec, |
&mach_o_be_vec, |
&mach_o_le_vec, |
&mach_o_fat_vec, |
&mach_o_i386_vec, |
#ifdef BFD64 |
&mach_o_x86_64_vec, |
#endif |
&mcore_pe_big_vec, |
&mcore_pe_little_vec, |
&mcore_pei_big_vec, |
&mcore_pei_little_vec, |
&mipslpe_vec, |
&mipslpei_vec, |
&newsos3_vec, |
#ifdef BFD64 |
&nlm32_alpha_vec, |
#endif |
&nlm32_i386_vec, |
&nlm32_powerpc_vec, |
&nlm32_sparc_vec, |
#if 0 |
/* We have no oasys tools anymore, so we can't test any of this |
anymore. If you want to test the stuff yourself, go ahead... |
steve@cygnus.com |
Worse, since there is no magic number for archives, there |
can be annoying target mis-matches. */ |
&oasys_vec, |
#endif |
/* Entry for the OpenRISC family. */ |
&or32coff_big_vec, |
&pc532machaout_vec, |
&pc532netbsd_vec, |
&pdp11_aout_vec, |
&pef_vec, |
&pef_xlib_vec, |
#if BFD_SUPPORTS_PLUGINS |
&plugin_vec, |
#endif |
#if 0 |
/* This has the same magic number as RS/6000. */ |
&pmac_xcoff_vec, |
#endif |
&ppcboot_vec, |
#if 0 |
/* We have no way of distinguishing these from other a.out variants. */ |
&riscix_vec, |
#endif |
#ifdef BFD64 |
&rs6000coff64_vec, |
#endif |
&rs6000coff_vec, |
&shcoff_small_vec, |
&shcoff_vec, |
&shlcoff_small_vec, |
&shlcoff_vec, |
&shlpe_vec, |
&shlpei_vec, |
&som_vec, |
&sparccoff_vec, |
&sparcle_aout_vec, |
&sparclinux_vec, |
&sparclynx_aout_vec, |
&sparclynx_coff_vec, |
&sparcnetbsd_vec, |
&sunos_big_vec, |
&sym_vec, |
&tic30_aout_vec, |
&tic30_coff_vec, |
&tic54x_coff0_beh_vec, |
&tic54x_coff0_vec, |
&tic54x_coff1_beh_vec, |
&tic54x_coff1_vec, |
&tic54x_coff2_beh_vec, |
&tic54x_coff2_vec, |
&tic80coff_vec, |
&vaxbsd_vec, |
&vaxnetbsd_vec, |
&vax1knetbsd_vec, |
&versados_vec, |
#ifdef BFD64 |
&vms_alpha_vec, |
#endif |
&vms_lib_txt_vec, |
&w65_vec, |
&we32kcoff_vec, |
&z80coff_vec, |
&z8kcoff_vec, |
&bfd_elf32_am33lin_vec, |
#endif /* not SELECT_VECS */ |
/* Always support S-records, for convenience. */ |
&srec_vec, |
&symbolsrec_vec, |
/* And verilog. */ |
&verilog_vec, |
/* And tekhex */ |
&tekhex_vec, |
/* Likewise for binary output. */ |
&binary_vec, |
/* Likewise for ihex. */ |
&ihex_vec, |
/* Add any required traditional-core-file-handler. */ |
#ifdef AIX386_CORE |
&aix386_core_vec, |
#endif |
#if 0 |
/* We don't include cisco_core_*_vec. Although it has a magic number, |
the magic number isn't at the beginning of the file, and thus |
might spuriously match other kinds of files. */ |
&cisco_core_big_vec, |
&cisco_core_little_vec, |
#endif |
#ifdef HPPABSD_CORE |
&hppabsd_core_vec, |
#endif |
#ifdef HPUX_CORE |
&hpux_core_vec, |
#endif |
#ifdef IRIX_CORE |
&irix_core_vec, |
#endif |
#ifdef NETBSD_CORE |
&netbsd_core_vec, |
#endif |
#ifdef OSF_CORE |
&osf_core_vec, |
#endif |
#ifdef PTRACE_CORE |
&ptrace_core_vec, |
#endif |
#ifdef SCO5_CORE |
&sco5_core_vec, |
#endif |
#ifdef TRAD_CORE |
&trad_core_vec, |
#endif |
NULL /* end of list marker */ |
}; |
const bfd_target * const *bfd_target_vector = _bfd_target_vector; |
/* bfd_default_vector[0] contains either the address of the default vector, |
if there is one, or zero if there isn't. */ |
const bfd_target *bfd_default_vector[] = { |
#ifdef DEFAULT_VECTOR |
&DEFAULT_VECTOR, |
#endif |
NULL |
}; |
/* bfd_associated_vector[] contains the associated target vectors used |
to reduce the ambiguity in bfd_check_format_matches. */ |
static const bfd_target *_bfd_associated_vector[] = { |
#ifdef ASSOCIATED_VECS |
ASSOCIATED_VECS, |
#endif |
NULL |
}; |
const bfd_target * const *bfd_associated_vector = _bfd_associated_vector; |
/* When there is an ambiguous match, bfd_check_format_matches puts the |
names of the matching targets in an array. This variable is the maximum |
number of entries that the array could possibly need. */ |
const size_t _bfd_target_vector_entries = sizeof (_bfd_target_vector)/sizeof (*_bfd_target_vector); |
/* This array maps configuration triplets onto BFD vectors. */ |
struct targmatch |
{ |
/* The configuration triplet. */ |
const char *triplet; |
/* The BFD vector. If this is NULL, then the vector is found by |
searching forward for the next structure with a non NULL vector |
field. */ |
const bfd_target *vector; |
}; |
/* targmatch.h is built by Makefile out of config.bfd. */ |
static const struct targmatch bfd_target_match[] = { |
#include "targmatch.h" |
{ NULL, NULL } |
}; |
/* Find a target vector, given a name or configuration triplet. */ |
static const bfd_target * |
find_target (const char *name) |
{ |
const bfd_target * const *target; |
const struct targmatch *match; |
for (target = &bfd_target_vector[0]; *target != NULL; target++) |
if (strcmp (name, (*target)->name) == 0) |
return *target; |
/* If we couldn't match on the exact name, try matching on the |
configuration triplet. FIXME: We should run the triplet through |
config.sub first, but that is hard. */ |
for (match = &bfd_target_match[0]; match->triplet != NULL; match++) |
{ |
if (fnmatch (match->triplet, name, 0) == 0) |
{ |
while (match->vector == NULL) |
++match; |
return match->vector; |
} |
} |
bfd_set_error (bfd_error_invalid_target); |
return NULL; |
} |
/* |
FUNCTION |
bfd_set_default_target |
SYNOPSIS |
bfd_boolean bfd_set_default_target (const char *name); |
DESCRIPTION |
Set the default target vector to use when recognizing a BFD. |
This takes the name of the target, which may be a BFD target |
name or a configuration triplet. |
*/ |
bfd_boolean |
bfd_set_default_target (const char *name) |
{ |
const bfd_target *target; |
if (bfd_default_vector[0] != NULL |
&& strcmp (name, bfd_default_vector[0]->name) == 0) |
return TRUE; |
target = find_target (name); |
if (target == NULL) |
return FALSE; |
bfd_default_vector[0] = target; |
return TRUE; |
} |
/* |
FUNCTION |
bfd_find_target |
SYNOPSIS |
const bfd_target *bfd_find_target (const char *target_name, bfd *abfd); |
DESCRIPTION |
Return a pointer to the transfer vector for the object target |
named @var{target_name}. If @var{target_name} is <<NULL>>, |
choose the one in the environment variable <<GNUTARGET>>; if |
that is null or not defined, then choose the first entry in the |
target list. Passing in the string "default" or setting the |
environment variable to "default" will cause the first entry in |
the target list to be returned, and "target_defaulted" will be |
set in the BFD if @var{abfd} isn't <<NULL>>. This causes |
<<bfd_check_format>> to loop over all the targets to find the |
one that matches the file being read. |
*/ |
const bfd_target * |
bfd_find_target (const char *target_name, bfd *abfd) |
{ |
const char *targname; |
const bfd_target *target; |
if (target_name != NULL) |
targname = target_name; |
else |
targname = getenv ("GNUTARGET"); |
/* This is safe; the vector cannot be null. */ |
if (targname == NULL || strcmp (targname, "default") == 0) |
{ |
if (bfd_default_vector[0] != NULL) |
target = bfd_default_vector[0]; |
else |
target = bfd_target_vector[0]; |
if (abfd) |
{ |
abfd->xvec = target; |
abfd->target_defaulted = TRUE; |
} |
return target; |
} |
if (abfd) |
abfd->target_defaulted = FALSE; |
target = find_target (targname); |
if (target == NULL) |
return NULL; |
if (abfd) |
abfd->xvec = target; |
return target; |
} |
/* Helper function for bfd_get_target_info to determine the target's |
architecture. This method handles bfd internal target names as |
tuples and triplets. */ |
static bfd_boolean |
_bfd_find_arch_match (const char *tname, const char **arch, |
const char **def_target_arch) |
{ |
if (!arch) |
return FALSE; |
while (*arch != NULL) |
{ |
const char *in_a = strstr (*arch, tname); |
char end_ch = (in_a ? in_a[strlen (tname)] : 0); |
if (in_a && (in_a == *arch || in_a[-1] == ':') |
&& end_ch == 0) |
{ |
*def_target_arch = *arch; |
return TRUE; |
} |
arch++; |
} |
return FALSE; |
} |
/* |
FUNCTION |
bfd_get_target_info |
SYNOPSIS |
const bfd_target *bfd_get_target_info (const char *target_name, |
bfd *abfd, |
bfd_boolean *is_bigendian, |
int *underscoring, |
const char **def_target_arch); |
DESCRIPTION |
Return a pointer to the transfer vector for the object target |
named @var{target_name}. If @var{target_name} is <<NULL>>, |
choose the one in the environment variable <<GNUTARGET>>; if |
that is null or not defined, then choose the first entry in the |
target list. Passing in the string "default" or setting the |
environment variable to "default" will cause the first entry in |
the target list to be returned, and "target_defaulted" will be |
set in the BFD if @var{abfd} isn't <<NULL>>. This causes |
<<bfd_check_format>> to loop over all the targets to find the |
one that matches the file being read. |
If @var{is_bigendian} is not <<NULL>>, then set this value to target's |
endian mode. True for big-endian, FALSE for little-endian or for |
invalid target. |
If @var{underscoring} is not <<NULL>>, then set this value to target's |
underscoring mode. Zero for none-underscoring, -1 for invalid target, |
else the value of target vector's symbol underscoring. |
If @var{def_target_arch} is not <<NULL>>, then set it to the architecture |
string specified by the target_name. |
*/ |
const bfd_target * |
bfd_get_target_info (const char *target_name, bfd *abfd, |
bfd_boolean *is_bigendian, |
int *underscoring, const char **def_target_arch) |
{ |
const bfd_target *target_vec; |
if (is_bigendian) |
*is_bigendian = FALSE; |
if (underscoring) |
*underscoring = -1; |
if (def_target_arch) |
*def_target_arch = NULL; |
target_vec = bfd_find_target (target_name, abfd); |
if (! target_vec) |
return NULL; |
if (is_bigendian) |
*is_bigendian = ((target_vec->byteorder == BFD_ENDIAN_BIG) ? TRUE |
: FALSE); |
if (underscoring) |
*underscoring = ((int) target_vec->symbol_leading_char) & 0xff; |
if (def_target_arch) |
{ |
const char *tname = target_vec->name; |
const char **arches = bfd_arch_list (); |
if (arches && tname) |
{ |
char *hyp = strchr (tname, '-'); |
if (hyp != NULL) |
{ |
tname = ++hyp; |
/* Make sure we detect architecture names |
for triplets like "pe-arm-wince-little". */ |
if (!_bfd_find_arch_match (tname, arches, def_target_arch)) |
{ |
char new_tname[50]; |
strcpy (new_tname, hyp); |
while ((hyp = strrchr (new_tname, '-')) != NULL) |
{ |
*hyp = 0; |
if (_bfd_find_arch_match (new_tname, arches, |
def_target_arch)) |
break; |
} |
} |
} |
else |
_bfd_find_arch_match (tname, arches, def_target_arch); |
} |
if (arches) |
free (arches); |
} |
return target_vec; |
} |
/* |
FUNCTION |
bfd_target_list |
SYNOPSIS |
const char ** bfd_target_list (void); |
DESCRIPTION |
Return a freshly malloced NULL-terminated |
vector of the names of all the valid BFD targets. Do not |
modify the names. |
*/ |
const char ** |
bfd_target_list (void) |
{ |
int vec_length = 0; |
bfd_size_type amt; |
const bfd_target * const *target; |
const char **name_list, **name_ptr; |
for (target = &bfd_target_vector[0]; *target != NULL; target++) |
vec_length++; |
amt = (vec_length + 1) * sizeof (char **); |
name_ptr = name_list = (const char **) bfd_malloc (amt); |
if (name_list == NULL) |
return NULL; |
for (target = &bfd_target_vector[0]; *target != NULL; target++) |
if (target == &bfd_target_vector[0] |
|| *target != bfd_target_vector[0]) |
*name_ptr++ = (*target)->name; |
*name_ptr = NULL; |
return name_list; |
} |
/* |
FUNCTION |
bfd_seach_for_target |
SYNOPSIS |
const bfd_target *bfd_search_for_target |
(int (*search_func) (const bfd_target *, void *), |
void *); |
DESCRIPTION |
Return a pointer to the first transfer vector in the list of |
transfer vectors maintained by BFD that produces a non-zero |
result when passed to the function @var{search_func}. The |
parameter @var{data} is passed, unexamined, to the search |
function. |
*/ |
const bfd_target * |
bfd_search_for_target (int (*search_func) (const bfd_target *, void *), |
void *data) |
{ |
const bfd_target * const *target; |
for (target = bfd_target_vector; *target != NULL; target ++) |
if (search_func (*target, data)) |
return *target; |
return NULL; |
} |
/contrib/toolchain/binutils/bfd/targmatch.h |
---|
0,0 → 1,2763 |
#ifdef BFD64 |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_littleaarch64_vec) |
{ "aarch64-*-elf", |
&bfd_elf64_littleaarch64_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_bigaarch64_vec) |
{ "aarch64_be-*-elf", |
&bfd_elf64_bigaarch64_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_littleaarch64_vec) |
{ "aarch64-*-linux*", |
&bfd_elf64_littleaarch64_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_bigaarch64_vec) |
{ "aarch64_be-*-linux*", |
&bfd_elf64_bigaarch64_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_alpha_freebsd_vec) |
{ "alpha*-*-freebsd*", NULL },{ "alpha*-*-kfreebsd*-gnu", |
&bfd_elf64_alpha_freebsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_alpha_vec) |
{ "alpha*-*-netbsd*", NULL },{ "alpha*-*-openbsd*", |
&bfd_elf64_alpha_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_ecoffalpha_little_vec) |
{ "alpha*-*-netware*", |
&ecoffalpha_little_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_ecoffalpha_little_vec) |
{ "alpha*-*-linux*ecoff*", |
&ecoffalpha_little_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_alpha_vec) |
{ "alpha*-*-linux-*", NULL },{ "alpha*-*-elf*", |
&bfd_elf64_alpha_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_vms_alpha_vec) |
{ "alpha*-*-*vms*", |
&vms_alpha_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_ecoffalpha_little_vec) |
{ "alpha*-*-*", |
&ecoffalpha_little_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_ia64_little_vec) |
{ "ia64*-*-freebsd*", NULL },{ "ia64*-*-netbsd*", NULL },{ "ia64*-*-linux-*", NULL },{ "ia64*-*-elf*", NULL },{ "ia64*-*-kfreebsd*-gnu", |
&bfd_elf64_ia64_little_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_ia64_hpux_big_vec) |
{ "ia64*-*-hpux*", |
&bfd_elf32_ia64_hpux_big_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_ia64_vms_vec) |
{ "ia64*-*-*vms*", |
&bfd_elf64_ia64_vms_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_sparc_freebsd_vec) |
{ "sparc64-*-freebsd*", NULL },{ "sparc64-*-kfreebsd*-gnu", |
&bfd_elf64_sparc_freebsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_sparc_vec) |
{ "sparc64-*-netbsd*", NULL },{ "sparc64-*-openbsd*", |
&bfd_elf64_sparc_vec }, |
#endif |
#endif /* BFD64 */ |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_am33lin_vec) |
{ "am34-*-linux*", NULL },{ "am33_2.0-*-linux*", |
&bfd_elf32_am33lin_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_littlearc_vec) |
{ "arc-*-elf*", |
&bfd_elf32_littlearc_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_littlearm_nacl_vec) |
{ "arm-*-nacl*", |
&bfd_elf32_littlearm_nacl_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_bigarm_nacl_vec) |
{ "armeb-*-nacl*", |
&bfd_elf32_bigarm_nacl_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_bigarm_vec) |
{ "armeb-*-netbsdelf*", |
&bfd_elf32_bigarm_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_littlearm_vec) |
{ "arm-*-netbsdelf*", |
&bfd_elf32_littlearm_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_armnetbsd_vec) |
{ "arm-*-netbsd*", NULL },{ "arm-*-openbsd*", |
&armnetbsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_littlearm_vec) |
{ "arm-*-nto*", NULL },{ "nto*arm*", |
&bfd_elf32_littlearm_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_riscix_vec) |
{ "arm-*-riscix*", |
&riscix_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_arm_epoc_pe_little_vec) |
{ "arm-epoc-pe*", |
&arm_epoc_pe_little_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_arm_wince_pe_little_vec) |
{ "arm-wince-pe", NULL },{ "arm-*-wince", NULL },{ "arm*-*-mingw32ce*", NULL },{ "arm*-*-cegcc*", |
&arm_wince_pe_little_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_armpe_little_vec) |
{ "arm-*-pe*", |
&armpe_little_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_aout_arm_little_vec) |
{ "arm-*-aout", NULL },{ "armel-*-aout", |
&aout_arm_little_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_aout_arm_big_vec) |
{ "armeb-*-aout", |
&aout_arm_big_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_armcoff_little_vec) |
{ "arm-*-coff", |
&armcoff_little_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_littlearm_vec) |
{ "arm-*-rtems*", |
&bfd_elf32_littlearm_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_bigarm_vec) |
{ "armeb-*-elf", NULL },{ "arm*b-*-linux-*", |
&bfd_elf32_bigarm_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_littlearm_vec) |
{ "arm-*-kaos*", |
&bfd_elf32_littlearm_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_littlearm_vec) |
{ "arm-*-elf", NULL },{ "arm-*-freebsd*", NULL },{ "arm*-*-linux-*", NULL },{ "arm*-*-conix*", NULL }, |
{ "arm*-*-uclinux*", NULL },{ "arm-*-kfreebsd*-gnu", NULL }, |
{ "arm*-*-eabi*", |
&bfd_elf32_littlearm_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_littlearm_vxworks_vec) |
{ "arm*-*-vxworks", NULL },{ "arm*-*-windiss", |
&bfd_elf32_littlearm_vxworks_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_littlearm_symbian_vec) |
{ "arm*-*-symbianelf*", |
&bfd_elf32_littlearm_symbian_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_littlearm_vec) |
{ "arm9e-*-elf", |
&bfd_elf32_littlearm_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_avr_vec) |
{ "avr-*-*", |
&bfd_elf32_avr_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_bfin_vec) |
{ "bfin-*-*", |
&bfd_elf32_bfin_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_tic30_aout_vec) |
{ "c30-*-*aout*", NULL },{ "tic30-*-*aout*", |
&tic30_aout_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_tic30_coff_vec) |
{ "c30-*-*coff*", NULL },{ "tic30-*-*coff*", |
&tic30_coff_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_tic4x_coff1_vec) |
{ "c4x-*-*coff*", NULL },{ "tic4x-*-*coff*", NULL },{ "tic4x-*-rtems*", |
&tic4x_coff1_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_tic54x_coff1_vec) |
{ "c54x*-*-*coff*", NULL },{ "tic54x-*-*coff*", |
&tic54x_coff1_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_cr16_vec) |
{ "cr16-*-elf*", NULL },{ "cr16*-*-uclinux*", |
&bfd_elf32_cr16_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_cr16c_vec) |
{ "cr16c-*-elf*", |
&bfd_elf32_cr16c_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_cris_aout_vec) |
{ "cris-*-*", NULL },{ "crisv32-*-*", |
&cris_aout_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_crx_vec) |
{ "crx-*-elf*", |
&bfd_elf32_crx_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_d10v_vec) |
{ "d10v-*-*", |
&bfd_elf32_d10v_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_dlx_big_vec) |
{ "dlx-*-elf*", |
&bfd_elf32_dlx_big_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_d30v_vec) |
{ "d30v-*-*", |
&bfd_elf32_d30v_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_epiphany_vec) |
{ "epiphany-*-elf", |
&bfd_elf32_epiphany_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_m68k_vec) |
{ "fido-*-elf*", |
&bfd_elf32_m68k_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_fr30_vec) |
{ "fr30-*-elf", |
&bfd_elf32_fr30_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_frv_vec) |
{ "frv-*-elf", |
&bfd_elf32_frv_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_frvfdpic_vec) |
{ "frv-*-*linux*", |
&bfd_elf32_frvfdpic_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_bigmoxie_vec) |
{ "moxie-*-elf", NULL },{ "moxie-*-rtems*", NULL },{ "moxie-*-uclinux", |
&bfd_elf32_bigmoxie_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_h8300coff_vec) |
{ "h8300*-*-rtemscoff*", |
&h8300coff_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_h8300_vec) |
{ "h8300*-*-elf", NULL },{ "h8300*-*-rtems*", |
&bfd_elf32_h8300_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_h8300coff_vec) |
{ "h8300*-*-*", |
&h8300coff_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_h8500coff_vec) |
{ "h8500-*-*", |
&h8500coff_vec }, |
#endif |
#ifdef BFD64 |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_hppa_linux_vec) |
{ "hppa*64*-*-linux-*", |
&bfd_elf64_hppa_linux_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_hppa_vec) |
{ "hppa*64*-*-hpux11*", |
&bfd_elf64_hppa_vec }, |
#endif |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_hppa_linux_vec) |
{ "hppa*-*-linux-*", |
&bfd_elf32_hppa_linux_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_hppa_nbsd_vec) |
{ "hppa*-*-netbsd*", |
&bfd_elf32_hppa_nbsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_hppa_vec) |
{ "hppa*-*-*elf*", NULL },{ "hppa*-*-lites*", NULL },{ "hppa*-*-sysv4*", NULL },{ "hppa*-*-openbsd*", |
&bfd_elf32_hppa_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_som_vec) |
{ "hppa*-*-bsd*", |
&som_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_som_vec) |
{ "hppa*-*-hpux*", NULL },{ "hppa*-*-hiux*", NULL },{ "hppa*-*-mpeix*", |
&som_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_som_vec) |
{ "hppa*-*-osf*", |
&som_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_i370_vec) |
{ "i370-*-*", |
&bfd_elf32_i370_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_i386coff_vec) |
{ "i[3-7]86-*-sco3.2v5*coff", |
&i386coff_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_i386_vec) |
{ "i[3-7]86-*-sysv4*", NULL },{ "i[3-7]86-*-unixware*", NULL }, |
{ "i[3-7]86-*-elf", NULL },{ "i[3-7]86-*-sco3.2v5*", NULL }, |
{ "i[3-7]86-*-dgux*", NULL },{ "i[3-7]86-*-sysv5*", |
&bfd_elf32_i386_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_i386_sol2_vec) |
{ "i[3-7]86-*-solaris2*", |
&bfd_elf32_i386_sol2_vec }, |
#endif |
#ifdef BFD64 |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_i386_sol2_vec) |
{ "x86_64-*-solaris2*", |
&bfd_elf32_i386_sol2_vec }, |
#endif |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_i386_vec) |
{ "i[3-7]86-*-kaos*", |
&bfd_elf32_i386_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_i386_vec) |
{ "i[3-7]86-*-nto*", |
&bfd_elf32_i386_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_i386_vec) |
{ "i[3-7]86-*-aros*", |
&bfd_elf32_i386_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_i386_vec) |
{ "i[3-7]86-*-chorus*", |
&bfd_elf32_i386_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_i386_vec) |
{ "i[3-7]86-*-dicos*", |
&bfd_elf32_i386_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_go32coff_vec) |
{ "*-*-msdosdjgpp*", NULL },{ "*-*-go32*", |
&go32coff_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_i386coff_vec) |
{ "i[3-7]86-*-sysv*", NULL },{ "i[3-7]86-*-isc*", NULL },{ "i[3-7]86-*-sco*", NULL },{ "i[3-7]86-*-coff", NULL }, |
{ "i[3-7]86-*-aix*", |
&i386coff_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_i386_vec) |
{ "i[3-7]86-*-rtems*", |
&bfd_elf32_i386_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_mach_o_i386_vec) |
{ "i[3-7]86-*-darwin*", NULL },{ "i[3-7]86-*-macos10*", NULL },{ "i[3-7]86-*-rhapsody*", |
&mach_o_i386_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_i386dynix_vec) |
{ "i[3-7]86-sequent-bsd*", |
&i386dynix_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_i386bsd_vec) |
{ "i[3-7]86-*-bsd*", |
&i386bsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_i386_vec) |
{ "i[3-7]86-*-dragonfly*", |
&bfd_elf32_i386_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_i386freebsd_vec) |
{ "i[3-7]86-*-freebsdaout*", NULL },{ "i[3-7]86-*-freebsd[12].*", NULL }, |
{ "i[3-7]86-*-freebsd[12]", |
&i386freebsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_i386_freebsd_vec) |
{ "i[3-7]86-*-freebsd*", NULL },{ "i[3-7]86-*-kfreebsd*-gnu", |
&bfd_elf32_i386_freebsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_i386_vec) |
{ "i[3-7]86-*-netbsdelf*", NULL },{ "i[3-7]86-*-netbsd*-gnu*", NULL },{ "i[3-7]86-*-knetbsd*-gnu", |
&bfd_elf32_i386_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_i386pe_vec) |
{ "i[3-7]86-*-netbsdpe*", |
&i386pe_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_i386netbsd_vec) |
{ "i[3-7]86-*-netbsdaout*", NULL },{ "i[3-7]86-*-netbsd*", NULL }, |
{ "i[3-7]86-*-openbsd[0-2].*", NULL },{ "i[3-7]86-*-openbsd3.[0-3]", |
&i386netbsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_i386_vec) |
{ "i[3-7]86-*-openbsd*", |
&bfd_elf32_i386_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_i386_vec) |
{ "i[3-7]86-*-netware*", |
&bfd_elf32_i386_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_i386linux_vec) |
{ "i[3-7]86-*-linux*aout*", |
&i386linux_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_i386_vec) |
{ "i[3-7]86-*-linux-*", |
&bfd_elf32_i386_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_i386_nacl_vec) |
{ "i[3-7]86-*-nacl*", |
&bfd_elf32_i386_nacl_vec }, |
#endif |
#ifdef BFD64 |
#if !defined (SELECT_VECS) || defined (HAVE_mach_o_x86_64_vec) |
{ "x86_64-*-darwin*", |
&mach_o_x86_64_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_x86_64_vec) |
{ "x86_64-*-dicos*", |
&bfd_elf64_x86_64_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_x86_64_vec) |
{ "x86_64-*-elf*", |
&bfd_elf64_x86_64_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_x86_64_vec) |
{ "x86_64-*-dragonfly*", |
&bfd_elf64_x86_64_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_x86_64_freebsd_vec) |
{ "x86_64-*-freebsd*", NULL },{ "x86_64-*-kfreebsd*-gnu", |
&bfd_elf64_x86_64_freebsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_x86_64_vec) |
{ "x86_64-*-netbsd*", NULL },{ "x86_64-*-openbsd*", |
&bfd_elf64_x86_64_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_x86_64_vec) |
{ "x86_64-*-linux-*", |
&bfd_elf64_x86_64_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_x86_64_nacl_vec) |
{ "x86_64-*-nacl*", |
&bfd_elf32_x86_64_nacl_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_x86_64pe_vec) |
{ "x86_64-*-mingw*", NULL },{ "x86_64-*-pe", NULL },{ "x86_64-*-pep", NULL },{ "x86_64-*-cygwin", |
&x86_64pe_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_x86_64_vec) |
{ "x86_64-*-rdos*", |
&bfd_elf64_x86_64_vec }, |
#endif |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_i386_vec) |
{ "i[3-7]86-*-lynxos*", |
&bfd_elf32_i386_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_i386_vec) |
{ "i[3-7]86-*-gnu*", |
&bfd_elf32_i386_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_i386mach3_vec) |
{ "i[3-7]86-*-mach*", NULL },{ "i[3-7]86-*-osf1mk*", |
&i386mach3_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_i386os9k_vec) |
{ "i[3-7]86-*-os9k", |
&i386os9k_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_i386aout_vec) |
{ "i[3-7]86-*-msdos*", |
&i386aout_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_i386_vec) |
{ "i[3-7]86-*-moss*", |
&bfd_elf32_i386_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_i386pe_vec) |
{ "i[3-7]86-*-beospe*", |
&i386pe_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_i386_vec) |
{ "i[3-7]86-*-beoself*", NULL },{ "i[3-7]86-*-beos*", |
&bfd_elf32_i386_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_i386pei_vec) |
{ "i[3-7]86-*-interix*", |
&i386pei_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_i386_vec) |
{ "i[3-7]86-*-rdos*", |
&bfd_elf32_i386_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_i386pe_vec) |
{ "i[3-7]86-*-mingw32*", NULL },{ "i[3-7]86-*-cygwin*", NULL },{ "i[3-7]86-*-winnt", NULL },{ "i[3-7]86-*-pe", |
&i386pe_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_i386coff_vec) |
{ "i[3-7]86-none-*", |
&i386coff_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_i386aout_vec) |
{ "i[3-7]86-*-aout*", NULL },{ "i[3-7]86*-*-vsta*", |
&i386aout_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_i386_vxworks_vec) |
{ "i[3-7]86-*-vxworks*", |
&bfd_elf32_i386_vxworks_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_i386_vec) |
{ "i[3-7]86-*-chaos", |
&bfd_elf32_i386_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_i860coff_vec) |
{ "i860-*-mach3*", NULL },{ "i860-*-osf1*", NULL },{ "i860-*-coff*", |
&i860coff_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_i860_little_vec) |
{ "i860-stardent-sysv4*", NULL },{ "i860-stardent-elf*", |
&bfd_elf32_i860_little_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_i860_vec) |
{ "i860-*-sysv4*", NULL },{ "i860-*-elf*", |
&bfd_elf32_i860_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_b_out_vec_little_host) |
{ "i960-*-vxworks4*", NULL },{ "i960-*-vxworks5.0", |
&b_out_vec_little_host }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_icoff_little_vec) |
{ "i960-*-vxworks5.*", NULL },{ "i960-*-coff*", NULL },{ "i960-*-sysv*", |
&icoff_little_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_b_out_vec_little_host) |
{ "i960-*-vxworks*", NULL },{ "i960-*-aout*", NULL },{ "i960-*-bout*", NULL },{ "i960-*-nindy*", |
&b_out_vec_little_host }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_i960_vec) |
{ "i960-*-elf*", |
&bfd_elf32_i960_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_ip2k_vec) |
{ "ip2k-*-elf", |
&bfd_elf32_ip2k_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_iq2000_vec) |
{ "iq2000-*-elf", |
&bfd_elf32_iq2000_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_lm32_vec) |
{ "lm32-*-elf", NULL },{ "lm32-*-rtems*", |
&bfd_elf32_lm32_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_lm32fdpic_vec) |
{ "lm32-*-*linux*", |
&bfd_elf32_lm32fdpic_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_m32c_vec) |
{ "m32c-*-elf", NULL },{ "m32c-*-rtems*", |
&bfd_elf32_m32c_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_m32rlelin_vec) |
{ "m32r*le-*-linux*", |
&bfd_elf32_m32rlelin_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_m32rlin_vec) |
{ "m32r*-*-linux*", |
&bfd_elf32_m32rlin_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_m32rle_vec) |
{ "m32r*le-*-*", |
&bfd_elf32_m32rle_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_m32r_vec) |
{ "m32r-*-*", |
&bfd_elf32_m32r_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_m68hc11_vec) |
{ "m68hc11-*-*", NULL },{ "m6811-*-*", |
&bfd_elf32_m68hc11_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_m68hc12_vec) |
{ "m68hc12-*-*", NULL },{ "m6812-*-*", |
&bfd_elf32_m68hc12_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_m68ksysvcoff_vec) |
{ "m68*-motorola-sysv*", |
&m68ksysvcoff_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_hp300bsd_vec) |
{ "m68*-hp-bsd*", |
&hp300bsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_aout0_big_vec) |
{ "m68*-*-aout*", |
&aout0_big_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_m68k_vec) |
{ "m68*-*-elf*", NULL },{ "m68*-*-sysv4*", NULL },{ "m68*-*-uclinux*", |
&bfd_elf32_m68k_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_m68k_vec) |
{ "m68*-*-rtems*", |
&bfd_elf32_m68k_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_m68kcoff_vec) |
{ "m68*-*-coff*", NULL },{ "m68*-*-sysv*", |
&m68kcoff_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_hp300hpux_vec) |
{ "m68*-*-hpux*", |
&hp300hpux_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_m68klinux_vec) |
{ "m68*-*-linux*aout*", |
&m68klinux_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_m68k_vec) |
{ "m68*-*-linux-*", |
&bfd_elf32_m68k_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_m68k_vec) |
{ "m68*-*-gnu*", |
&bfd_elf32_m68k_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_m68k4knetbsd_vec) |
{ "m68*-hp*-netbsd*", |
&m68k4knetbsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_m68k_vec) |
{ "m68*-*-netbsdelf*", |
&bfd_elf32_m68k_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_m68knetbsd_vec) |
{ "m68*-*-netbsdaout*", NULL },{ "m68*-*-netbsd*", |
&m68knetbsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_m68knetbsd_vec) |
{ "m68*-*-openbsd*", |
&m68knetbsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_sunos_big_vec) |
{ "m68*-*-sunos*", NULL },{ "m68*-*-os68k*", NULL },{ "m68*-*-vxworks*", NULL },{ "m68*-netx-*", NULL }, |
{ "m68*-*-bsd*", NULL },{ "m68*-*-vsta*", |
&sunos_big_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_sunos_big_vec) |
{ "m68*-ericsson-*", |
&sunos_big_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_m68k_vec) |
{ "m68*-cbm-*", |
&bfd_elf32_m68k_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_m68k_vec) |
{ "m68*-*-psos*", |
&bfd_elf32_m68k_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_m88k_vec) |
{ "m88*-harris-cxux*", NULL },{ "m88*-*-dgux*", NULL },{ "m88*-*-sysv4*", |
&bfd_elf32_m88k_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_m88kmach3_vec) |
{ "m88*-*-mach3*", |
&m88kmach3_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_m88kopenbsd_vec) |
{ "m88*-*-openbsd*", |
&m88kopenbsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_m88kbcs_vec) |
{ "m88*-*-*", |
&m88kbcs_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_mcore_big_vec) |
{ "mcore-*-elf", |
&bfd_elf32_mcore_big_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_mcore_pe_big_vec) |
{ "mcore-*-pe", |
&mcore_pe_big_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_mep_vec) |
{ "mep-*-elf", |
&bfd_elf32_mep_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_metag_vec) |
{ "metag-*-*", |
&bfd_elf32_metag_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_microblazeel_vec) |
{ "microblazeel*-*", |
&bfd_elf32_microblazeel_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_microblaze_vec) |
{ "microblaze*-*", |
&bfd_elf32_microblaze_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_ecoff_big_vec) |
{ "mips*-big-*", |
&ecoff_big_vec }, |
#endif |
#ifdef BFD64 |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_tradlittlemips_vec) |
{ "mips*el-*-netbsd*", |
&bfd_elf32_tradlittlemips_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_tradbigmips_vec) |
{ "mips*-*-netbsd*", |
&bfd_elf32_tradbigmips_vec }, |
#endif |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_ecoff_little_vec) |
{ "mips*-dec-*", NULL },{ "mips*el-*-ecoff*", |
&ecoff_little_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_ecoff_big_vec) |
{ "mips*-*-ecoff*", |
&ecoff_big_vec }, |
#endif |
#ifdef BFD64 |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_nbigmips_vec) |
{ "mips*-*-irix6*", |
&bfd_elf32_nbigmips_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_nlittlemips_vec) |
{ "mips64*-ps2-elf*", |
&bfd_elf32_nlittlemips_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_littlemips_vec) |
{ "mips*-ps2-elf*", |
&bfd_elf32_littlemips_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_bigmips_vec) |
{ "mips*-*-irix5*", |
&bfd_elf32_bigmips_vec }, |
#endif |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_ecoff_big_vec) |
{ "mips*-sgi-*", NULL },{ "mips*-*-bsd*", |
&ecoff_big_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_ecoff_biglittle_vec) |
{ "mips*-*-lnews*", |
&ecoff_biglittle_vec }, |
#endif |
#ifdef BFD64 |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_tradbigmips_vec) |
{ "mips*-*-sysv4*", |
&bfd_elf32_tradbigmips_vec }, |
#endif |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_ecoff_big_vec) |
{ "mips*-*-sysv*", NULL },{ "mips*-*-riscos*", |
&ecoff_big_vec }, |
#endif |
#ifdef BFD64 |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_littlemips_vxworks_vec) |
{ "mips*el-*-vxworks*", |
&bfd_elf32_littlemips_vxworks_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_bigmips_vxworks_vec) |
{ "mips*-*-vxworks*", |
&bfd_elf32_bigmips_vxworks_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_tradlittlemips_vec) |
{ "mips*el-sde-elf*", |
&bfd_elf32_tradlittlemips_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_tradbigmips_vec) |
{ "mips*-sde-elf*", NULL },{ "mips*-mti-elf*", |
&bfd_elf32_tradbigmips_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_littlemips_vec) |
{ "mips*el-*-elf*", NULL },{ "mips*el-*-vxworks*", NULL },{ "mips*-*-chorus*", |
&bfd_elf32_littlemips_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_bigmips_vec) |
{ "mips*-*-elf*", NULL },{ "mips*-*-rtems*", NULL },{ "mips*-*-vxworks", NULL },{ "mips*-*-windiss", |
&bfd_elf32_bigmips_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_bigmips_vec) |
{ "mips*-*-none", |
&bfd_elf32_bigmips_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_tradbigmips_vec) |
{ "mips64*-*-openbsd*", |
&bfd_elf64_tradbigmips_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_littlemips_vec) |
{ "mips*el-*-openbsd*", |
&bfd_elf32_littlemips_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_bigmips_vec) |
{ "mips*-*-openbsd*", |
&bfd_elf32_bigmips_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_ntradlittlemips_vec) |
{ "mips64*el-*-linux*", |
&bfd_elf32_ntradlittlemips_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_ntradbigmips_vec) |
{ "mips64*-*-linux*", |
&bfd_elf32_ntradbigmips_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_tradlittlemips_vec) |
{ "mips*el-*-linux*", |
&bfd_elf32_tradlittlemips_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_tradbigmips_vec) |
{ "mips*-*-linux*", |
&bfd_elf32_tradbigmips_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_ntradlittlemips_freebsd_vec) |
{ "mips64*el-*-freebsd*", NULL },{ "mips64*el-*-kfreebsd*-gnu", |
&bfd_elf32_ntradlittlemips_freebsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_ntradbigmips_freebsd_vec) |
{ "mips64*-*-freebsd*", NULL },{ "mips64*-*-kfreebsd*-gnu", |
&bfd_elf32_ntradbigmips_freebsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_tradlittlemips_freebsd_vec) |
{ "mips*el-*-freebsd*", NULL },{ "mips*el-*-kfreebsd*-gnu", |
&bfd_elf32_tradlittlemips_freebsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_tradbigmips_freebsd_vec) |
{ "mips*-*-freebsd*", NULL },{ "mips*-*-kfreebsd*-gnu", |
&bfd_elf32_tradbigmips_freebsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_mmix_vec) |
{ "mmix-*-*", |
&bfd_elf64_mmix_vec }, |
#endif |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_mn10200_vec) |
{ "mn10200-*-*", |
&bfd_elf32_mn10200_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_mn10300_vec) |
{ "mn10300-*-*", |
&bfd_elf32_mn10300_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_mt_vec) |
{ "mt-*-elf", |
&bfd_elf32_mt_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_msp430_vec) |
{ "msp430-*-*", |
&bfd_elf32_msp430_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_pc532machaout_vec) |
{ "ns32k-pc532-mach*", NULL },{ "ns32k-pc532-ux*", |
&pc532machaout_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_pc532netbsd_vec) |
{ "ns32k-*-netbsd*", NULL },{ "ns32k-*-lites*", NULL },{ "ns32k-*-openbsd*", |
&pc532netbsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_bignios2_vec) |
{ "nios2eb-*-*", |
&bfd_elf32_bignios2_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_littlenios2_vec) |
{ "nios2el-*-*", |
&bfd_elf32_littlenios2_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_littlenios2_vec) |
{ "nios2-*-*", |
&bfd_elf32_littlenios2_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_openrisc_vec) |
{ "openrisc-*-elf", |
&bfd_elf32_openrisc_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_or32coff_big_vec) |
{ "or32-*-coff", |
&or32coff_big_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_or32_big_vec) |
{ "or32-*-elf", |
&bfd_elf32_or32_big_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_pdp11_aout_vec) |
{ "pdp11-*-*", |
&pdp11_aout_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_pj_vec) |
{ "pj-*-*", |
&bfd_elf32_pj_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_pjl_vec) |
{ "pjl-*-*", |
&bfd_elf32_pjl_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_rs6000coff_vec) |
{ "powerpc-*-aix5.[01]", NULL },{ "rs6000-*-aix5.[01]", |
&rs6000coff_vec }, |
#endif |
#ifdef BFD64 |
#if !defined (SELECT_VECS) || defined (HAVE_aix5coff64_vec) |
{ "powerpc64-*-aix5.[01]", NULL },{ "rs6000-*-aix5.[01]", |
&aix5coff64_vec }, |
#endif |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_rs6000coff_vec) |
{ "powerpc-*-aix[5-9]*", NULL },{ "rs6000-*-aix[5-9]*", |
&rs6000coff_vec }, |
#endif |
#ifdef BFD64 |
#if !defined (SELECT_VECS) || defined (HAVE_aix5coff64_vec) |
{ "powerpc64-*-aix[5-9]*", NULL },{ "rs6000-*-aix[5-9]*", |
&aix5coff64_vec }, |
#endif |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_rs6000coff_vec) |
{ "powerpc-*-aix*", NULL },{ "powerpc-*-beos*", NULL },{ "rs6000-*-*", |
&rs6000coff_vec }, |
#endif |
#ifdef BFD64 |
#if !defined (SELECT_VECS) || defined (HAVE_rs6000coff64_vec) |
{ "powerpc64-*-aix*", |
&rs6000coff64_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_powerpc_freebsd_vec) |
{ "powerpc64-*-freebsd*", |
&bfd_elf64_powerpc_freebsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_powerpc_vec) |
{ "powerpc64-*-elf*", NULL },{ "powerpc-*-elf64*", NULL },{ "powerpc64-*-linux*", NULL }, |
{ "powerpc64-*-*bsd*", |
&bfd_elf64_powerpc_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_powerpcle_vec) |
{ "powerpc64le-*-elf*", NULL },{ "powerpcle-*-elf64*", NULL },{ "powerpc64le-*-linux*", NULL }, |
{ "powerpc64le-*-*bsd*", |
&bfd_elf64_powerpcle_vec }, |
#endif |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_powerpc_freebsd_vec) |
{ "powerpc-*-*freebsd*", |
&bfd_elf32_powerpc_freebsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_powerpc_vec) |
{ "powerpc-*-*bsd*", NULL },{ "powerpc-*-elf*", NULL },{ "powerpc-*-sysv4*", NULL },{ "powerpc-*-eabi*", NULL }, |
{ "powerpc-*-solaris2*", NULL },{ "powerpc-*-linux-*", NULL },{ "powerpc-*-rtems*", NULL }, |
{ "powerpc-*-chorus*", |
&bfd_elf32_powerpc_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_powerpc_vec) |
{ "powerpc-*-kaos*", |
&bfd_elf32_powerpc_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_mach_o_be_vec) |
{ "powerpc-*-darwin*", NULL },{ "powerpc-*-macos10*", NULL },{ "powerpc-*-rhapsody*", |
&mach_o_be_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_pmac_xcoff_vec) |
{ "powerpc-*-macos*", |
&pmac_xcoff_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_powerpc_vec) |
{ "powerpc-*-lynxos*", |
&bfd_elf32_powerpc_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_powerpc_vec) |
{ "powerpc-*-netware*", |
&bfd_elf32_powerpc_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_powerpc_vec) |
{ "powerpc-*-nto*", |
&bfd_elf32_powerpc_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_powerpc_vxworks_vec) |
{ "powerpc-*-vxworks*", NULL },{ "powerpc-*-windiss*", |
&bfd_elf32_powerpc_vxworks_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_powerpcle_vec) |
{ "powerpcle-*-nto*", |
&bfd_elf32_powerpcle_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_powerpcle_vec) |
{ "powerpcle-*-elf*", NULL },{ "powerpcle-*-sysv4*", NULL },{ "powerpcle-*-eabi*", NULL }, |
{ "powerpcle-*-solaris2*", NULL },{ "powerpcle-*-linux-*", NULL },{ "powerpcle-*-vxworks*", |
&bfd_elf32_powerpcle_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_powerpcle_pe_vec) |
{ "powerpcle-*-pe", NULL },{ "powerpcle-*-winnt*", NULL },{ "powerpcle-*-cygwin*", |
&bfd_powerpcle_pe_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_rl78_vec) |
{ "rl78-*-elf", |
&bfd_elf32_rl78_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_rx_le_vec) |
{ "rx-*-elf", |
&bfd_elf32_rx_le_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_s390_vec) |
{ "s390-*-linux*", |
&bfd_elf32_s390_vec }, |
#endif |
#ifdef BFD64 |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_s390_vec) |
{ "s390x-*-linux*", |
&bfd_elf64_s390_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_s390_vec) |
{ "s390x-*-tpf*", |
&bfd_elf64_s390_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_bigscore_vec) |
{ "score*-*-elf*", |
&bfd_elf32_bigscore_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_sh64l_vec) |
{ "sh64l*-*-elf*", |
&bfd_elf32_sh64l_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_sh64_vec) |
{ "sh64-*-elf*", |
&bfd_elf32_sh64_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_sh64blin_vec) |
{ "sh64eb-*-linux*", |
&bfd_elf32_sh64blin_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_sh64lin_vec) |
{ "sh64-*-linux*", |
&bfd_elf32_sh64lin_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_shblin_vec) |
{ "sh-*-linux*", |
&bfd_elf32_shblin_vec }, |
#endif |
#endif /* BFD64 */ |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_shblin_vec) |
{ "sh*eb-*-linux*", |
&bfd_elf32_shblin_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_shlin_vec) |
{ "sh*-*-linux*", |
&bfd_elf32_shlin_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_sh_vec) |
{ "sh-*-uclinux*", NULL },{ "sh[12]-*-uclinux*", |
&bfd_elf32_sh_vec }, |
#endif |
#ifdef BFD64 |
#endif |
#ifdef BFD64 |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_sh64lnbsd_vec) |
{ "sh5le-*-netbsd*", |
&bfd_elf32_sh64lnbsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_sh64nbsd_vec) |
{ "sh5-*-netbsd*", |
&bfd_elf32_sh64nbsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_sh64lnbsd_vec) |
{ "sh64le-*-netbsd*", |
&bfd_elf64_sh64lnbsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_sh64nbsd_vec) |
{ "sh64-*-netbsd*", |
&bfd_elf64_sh64nbsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_shlnbsd_vec) |
{ "sh*l*-*-netbsdelf*", |
&bfd_elf32_shlnbsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_shnbsd_vec) |
{ "sh-*-netbsdelf*", |
&bfd_elf32_shnbsd_vec }, |
#endif |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_shnbsd_vec) |
{ "sh*-*-netbsdelf*", |
&bfd_elf32_shnbsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_shl_symbian_vec) |
{ "sh*-*-symbianelf*", |
&bfd_elf32_shl_symbian_vec }, |
#endif |
#ifdef BFD64 |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_shl_vec) |
{ "shl*-*-elf*", NULL },{ "sh[1234]l*-*-elf*", NULL },{ "sh3el*-*-elf*", NULL },{ "shl*-*-kaos*", |
&bfd_elf32_shl_vec }, |
#endif |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_shcoff_vec) |
{ "sh-*-rtemscoff*", |
&shcoff_vec }, |
#endif |
#ifdef BFD64 |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_sh_vec) |
{ "sh-*-elf*", NULL },{ "sh[1234]*-elf*", NULL },{ "sh-*-rtems*", NULL },{ "sh-*-kaos*", |
&bfd_elf32_sh_vec }, |
#endif |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_sh_vec) |
{ "sh-*-nto*", |
&bfd_elf32_sh_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_shlnbsd_vec) |
{ "sh*-*-openbsd*", |
&bfd_elf32_shlnbsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_shlpe_vec) |
{ "sh-*-pe", |
&shlpe_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_shvxworks_vec) |
{ "sh-*-vxworks", |
&bfd_elf32_shvxworks_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_shcoff_vec) |
{ "sh-*-*", |
&shcoff_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_sunos_big_vec) |
{ "sparclet-*-aout*", |
&sunos_big_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_sunos_big_vec) |
{ "sparc86x-*-aout*", |
&sunos_big_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_sparc_vec) |
{ "sparclite-*-elf*", NULL },{ "sparc86x-*-elf*", |
&bfd_elf32_sparc_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_sparc_vec) |
{ "sparc*-*-chorus*", |
&bfd_elf32_sparc_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_sparclinux_vec) |
{ "sparc-*-linux*aout*", |
&sparclinux_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_sparc_vec) |
{ "sparc-*-linux-*", NULL },{ "sparcv*-*-linux-*", |
&bfd_elf32_sparc_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_sparc_vec) |
{ "sparc-*-netbsdelf*", |
&bfd_elf32_sparc_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_sparcnetbsd_vec) |
{ "sparc-*-netbsdaout*", NULL },{ "sparc-*-netbsd*", |
&sparcnetbsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_sparcnetbsd_vec) |
{ "sparc-*-openbsd[0-2].*", NULL },{ "sparc-*-openbsd3.[0-1]", |
&sparcnetbsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_sparc_vec) |
{ "sparc-*-openbsd*", |
&bfd_elf32_sparc_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_sparc_vec) |
{ "sparc-*-elf*", |
&bfd_elf32_sparc_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_sparc_sol2_vec) |
{ "sparc-*-solaris2.[0-6]", NULL },{ "sparc-*-solaris2.[0-6].*", |
&bfd_elf32_sparc_sol2_vec }, |
#endif |
#ifdef BFD64 |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_sparc_sol2_vec) |
{ "sparc-*-solaris2*", NULL },{ "sparcv9-*-solaris2*", NULL },{ "sparc64-*-solaris2*", |
&bfd_elf32_sparc_sol2_vec }, |
#endif |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_sparc_vec) |
{ "sparc-*-sysv4*", |
&bfd_elf32_sparc_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_sparc_vxworks_vec) |
{ "sparc-*-vxworks*", |
&bfd_elf32_sparc_vxworks_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_sparc_vec) |
{ "sparc-*-netware*", |
&bfd_elf32_sparc_vec }, |
#endif |
#ifdef BFD64 |
#if !defined (SELECT_VECS) || defined (HAVE_sunos_big_vec) |
{ "sparc64-*-aout*", |
&sunos_big_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_sparc_vec) |
{ "sparc64*-*-linux-*", |
&bfd_elf64_sparc_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_sparc_vec) |
{ "sparc64-*-elf*", NULL },{ "sparc64-*-rtems*", |
&bfd_elf64_sparc_vec }, |
#endif |
#endif /* BFD64 */ |
#if !defined (SELECT_VECS) || defined (HAVE_sparccoff_vec) |
{ "sparc*-*-coff*", |
&sparccoff_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_sparc_vec) |
{ "sparc-*-rtems*", |
&bfd_elf32_sparc_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_sunos_big_vec) |
{ "sparc*-*-*", |
&sunos_big_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_spu_vec) |
{ "spu-*-elf", |
&bfd_elf32_spu_vec }, |
#endif |
#if HAVE_host_aout_vec |
#if !defined (SELECT_VECS) || defined (HAVE_host_aout_vec) |
{ "tahoe-*-*", |
&host_aout_vec }, |
#endif |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_tic6x_elf_le_vec) |
{ "tic6x-*-elf", |
&bfd_elf32_tic6x_elf_le_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_tic6x_linux_le_vec) |
{ "tic6x-*-uclinux", |
&bfd_elf32_tic6x_linux_le_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_tic80coff_vec) |
{ "tic80*-*-*", |
&tic80coff_vec }, |
#endif |
#ifdef BFD64 |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_tilegx_le_vec) |
{ "tilegx-*-*", |
&bfd_elf64_tilegx_le_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf64_tilegx_be_vec) |
{ "tilegxbe-*-*", |
&bfd_elf64_tilegx_be_vec }, |
#endif |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_tilepro_vec) |
{ "tilepro-*-*", |
&bfd_elf32_tilepro_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_v850_vec) |
{ "v850*-*-*", |
&bfd_elf32_v850_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_vax_vec) |
{ "vax-*-netbsdelf*", |
&bfd_elf32_vax_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_vaxnetbsd_vec) |
{ "vax-*-netbsdaout*", NULL },{ "vax-*-netbsd*", |
&vaxnetbsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_vaxbsd_vec) |
{ "vax-*-bsd*", NULL },{ "vax-*-ultrix*", |
&vaxbsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_vaxnetbsd_vec) |
{ "vax-*-openbsd*", |
&vaxnetbsd_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_vax_vec) |
{ "vax-*-linux-*", |
&bfd_elf32_vax_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_we32kcoff_vec) |
{ "we32k-*-*", |
&we32kcoff_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_w65_vec) |
{ "w65-*-*", |
&w65_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_xgate_vec) |
{ "xgate-*-*", |
&bfd_elf32_xgate_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_xstormy16_vec) |
{ "xstormy16-*-elf", |
&bfd_elf32_xstormy16_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_xtensa_le_vec) |
{ "xtensa*-*-*", |
&bfd_elf32_xtensa_le_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_bfd_elf32_xc16x_vec) |
{ "xc16x-*-elf", |
&bfd_elf32_xc16x_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_z80coff_vec) |
{ "z80-*-*", |
&z80coff_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_z8kcoff_vec) |
{ "z8k*-*-*", |
&z8kcoff_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_ieee_vec) |
{ "*-*-ieee*", |
&ieee_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_a_out_adobe_vec) |
{ "*-adobe-*", |
&a_out_adobe_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_newsos3_vec) |
{ "*-sony-*", |
&newsos3_vec }, |
#endif |
#if !defined (SELECT_VECS) || defined (HAVE_m68kcoff_vec) |
{ "*-tandem-*", |
&m68kcoff_vec }, |
#endif |
/contrib/toolchain/binutils/bfd/tekhex.c |
---|
0,0 → 1,1016 |
/* BFD backend for Extended Tektronix Hex Format objects. |
Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, |
2003, 2004, 2005, 2006, 2007, 2009, 2011 Free Software Foundation, Inc. |
Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>. |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* SUBSECTION |
Tektronix Hex Format handling |
DESCRIPTION |
Tek Hex records can hold symbols and data, but not |
relocations. Their main application is communication with |
devices like PROM programmers and ICE equipment. |
It seems that the sections are described as being really big, |
the example I have says that the text section is 0..ffffffff. |
BFD would barf with this, many apps would try to alloc 4GB to |
read in the file. |
Tex Hex may contain many sections, but the data which comes in |
has no tag saying which section it belongs to, so we create |
one section for each block of data, called "blknnnn" which we |
stick all the data into. |
TekHex may come out of order and there is no header, so an |
initial scan is required to discover the minimum and maximum |
addresses used to create the vma and size of the sections we |
create. |
We read in the data into pages of CHUNK_MASK+1 size and read |
them out from that whenever we need to. |
Any number of sections may be created for output, we save them |
up and output them when it's time to close the bfd. |
A TekHex record looks like: |
EXAMPLE |
%<block length><type><checksum><stuff><cr> |
DESCRIPTION |
Where |
o length |
is the number of bytes in the record not including the % sign. |
o type |
is one of: |
3) symbol record |
6) data record |
8) termination record |
The data can come out of order, and may be discontigous. This is a |
serial protocol, so big files are unlikely, so we keep a list of 8k chunks. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
#include "libiberty.h" |
typedef struct |
{ |
bfd_vma low; |
bfd_vma high; |
} addr_range_type; |
typedef struct tekhex_symbol_struct |
{ |
asymbol symbol; |
struct tekhex_symbol_struct *prev; |
} tekhex_symbol_type; |
static const char digs[] = "0123456789ABCDEF"; |
static char sum_block[256]; |
#define NOT_HEX 20 |
#define NIBBLE(x) hex_value(x) |
#define HEX(buffer) ((NIBBLE ((buffer)[0]) << 4) + NIBBLE ((buffer)[1])) |
#define ISHEX(x) hex_p(x) |
#define TOHEX(d, x) \ |
(d)[1] = digs[(x) & 0xf]; \ |
(d)[0] = digs[((x)>>4)&0xf]; |
/* Here's an example |
%3A6C6480004E56FFFC4E717063B0AEFFFC6D0652AEFFFC60F24E5E4E75 |
%1B3709T_SEGMENT1108FFFFFFFF |
%2B3AB9T_SEGMENT7Dgcc_compiled$1087hello$c10 |
%373829T_SEGMENT80int$t1$r1$$214741080char$t2$r2$0$12710 |
%373769T_SEGMENT80long$int$t3$r1$$1080unsigned$int$t4$10 |
%373CA9T_SEGMENT80long$unsigned$in1080short$int$t6$r1$10 |
%373049T_SEGMENT80long$long$int$t71080short$unsigned$i10 |
%373A29T_SEGMENT80long$long$unsign1080signed$char$t10$10 |
%373D69T_SEGMENT80unsigned$char$t11080float$t12$r1$4$010 |
%373D19T_SEGMENT80double$t13$r1$8$1080long$double$t14$10 |
%2734D9T_SEGMENT8Bvoid$t15$151035_main10 |
%2F3CA9T_SEGMENT81$1081$1681$1E81$21487main$F110 |
%2832F9T_SEGMENT83i$18FFFFFFFC81$1481$214 |
%07 8 10 10 |
explanation: |
%3A6C6480004E56FFFC4E717063B0AEFFFC6D0652AEFFFC60F24E5E4E75 |
^ ^^ ^ ^-data |
| || +------ 4 char integer 0x8000 |
| |+-------- checksum |
| +--------- type 6 (data record) |
+----------- length 3a chars |
<---------------------- 3a (58 chars) -------------------> |
%1B3709T_SEGMENT1108FFFFFFFF |
^ ^^ ^- 8 character integer 0xffffffff |
| |+- 1 character integer 0 |
| +-- type 1 symbol (section definition) |
+------------ 9 char symbol T_SEGMENT |
%2B3AB9T_SEGMENT7Dgcc_compiled$1087hello$c10 |
%373829T_SEGMENT80int$t1$r1$$214741080char$t2$r2$0$12710 |
%373769T_SEGMENT80long$int$t3$r1$$1080unsigned$int$t4$10 |
%373CA9T_SEGMENT80long$unsigned$in1080short$int$t6$r1$10 |
%373049T_SEGMENT80long$long$int$t71080short$unsigned$i10 |
%373A29T_SEGMENT80long$long$unsign1080signed$char$t10$10 |
%373D69T_SEGMENT80unsigned$char$t11080float$t12$r1$4$010 |
%373D19T_SEGMENT80double$t13$r1$8$1080long$double$t14$10 |
%2734D9T_SEGMENT8Bvoid$t15$151035_main10 |
%2F3CA9T_SEGMENT81$1081$1681$1E81$21487main$F110 |
%2832F9T_SEGMENT83i$18FFFFFFFC81$1481$214 |
%0781010 |
Turns into |
sac@thepub$ ./objdump -dx -m m68k f |
f: file format tekhex |
-----x--- 9/55728 -134219416 Sep 29 15:13 1995 f |
architecture: UNKNOWN!, flags 0x00000010: |
HAS_SYMS |
start address 0x00000000 |
SECTION 0 [D00000000] : size 00020000 vma 00000000 align 2**0 |
ALLOC, LOAD |
SECTION 1 [D00008000] : size 00002001 vma 00008000 align 2**0 |
SECTION 2 [T_SEGMENT] : size ffffffff vma 00000000 align 2**0 |
SYMBOL TABLE: |
00000000 g T_SEGMENT gcc_compiled$ |
00000000 g T_SEGMENT hello$c |
00000000 g T_SEGMENT int$t1$r1$$21474 |
00000000 g T_SEGMENT char$t2$r2$0$127 |
00000000 g T_SEGMENT long$int$t3$r1$$ |
00000000 g T_SEGMENT unsigned$int$t4$ |
00000000 g T_SEGMENT long$unsigned$in |
00000000 g T_SEGMENT short$int$t6$r1$ |
00000000 g T_SEGMENT long$long$int$t7 |
00000000 g T_SEGMENT short$unsigned$i |
00000000 g T_SEGMENT long$long$unsign |
00000000 g T_SEGMENT signed$char$t10$ |
00000000 g T_SEGMENT unsigned$char$t1 |
00000000 g T_SEGMENT float$t12$r1$4$0 |
00000000 g T_SEGMENT double$t13$r1$8$ |
00000000 g T_SEGMENT long$double$t14$ |
00000000 g T_SEGMENT void$t15$15 |
00000000 g T_SEGMENT _main |
00000000 g T_SEGMENT $ |
00000000 g T_SEGMENT $ |
00000000 g T_SEGMENT $ |
00000010 g T_SEGMENT $ |
00000000 g T_SEGMENT main$F1 |
fcffffff g T_SEGMENT i$1 |
00000000 g T_SEGMENT $ |
00000010 g T_SEGMENT $ |
RELOCATION RECORDS FOR [D00000000]: (none) |
RELOCATION RECORDS FOR [D00008000]: (none) |
RELOCATION RECORDS FOR [T_SEGMENT]: (none) |
Disassembly of section D00000000: |
... |
00008000 ($+)7ff0 linkw fp,#-4 |
00008004 ($+)7ff4 nop |
00008006 ($+)7ff6 movel #99,d0 |
00008008 ($+)7ff8 cmpl fp@(-4),d0 |
0000800c ($+)7ffc blts 00008014 ($+)8004 |
0000800e ($+)7ffe addql #1,fp@(-4) |
00008012 ($+)8002 bras 00008006 ($+)7ff6 |
00008014 ($+)8004 unlk fp |
00008016 ($+)8006 rts |
... */ |
static void |
tekhex_init (void) |
{ |
unsigned int i; |
static bfd_boolean inited = FALSE; |
int val; |
if (! inited) |
{ |
inited = TRUE; |
hex_init (); |
val = 0; |
for (i = 0; i < 10; i++) |
sum_block[i + '0'] = val++; |
for (i = 'A'; i <= 'Z'; i++) |
sum_block[i] = val++; |
sum_block['$'] = val++; |
sum_block['%'] = val++; |
sum_block['.'] = val++; |
sum_block['_'] = val++; |
for (i = 'a'; i <= 'z'; i++) |
sum_block[i] = val++; |
} |
} |
/* The maximum number of bytes on a line is FF. */ |
#define MAXCHUNK 0xff |
/* The number of bytes we fit onto a line on output. */ |
#define CHUNK 21 |
/* We cannot output our tekhexords as we see them, we have to glue them |
together, this is done in this structure : */ |
struct tekhex_data_list_struct |
{ |
unsigned char *data; |
bfd_vma where; |
bfd_size_type size; |
struct tekhex_data_list_struct *next; |
}; |
typedef struct tekhex_data_list_struct tekhex_data_list_type; |
#define CHUNK_MASK 0x1fff |
struct data_struct |
{ |
char chunk_data[CHUNK_MASK + 1]; |
char chunk_init[CHUNK_MASK + 1]; |
bfd_vma vma; |
struct data_struct *next; |
}; |
typedef struct tekhex_data_struct |
{ |
tekhex_data_list_type *head; |
unsigned int type; |
struct tekhex_symbol_struct *symbols; |
struct data_struct *data; |
} tdata_type; |
#define enda(x) (x->vma + x->size) |
static bfd_boolean |
getvalue (char **srcp, bfd_vma *valuep) |
{ |
char *src = *srcp; |
bfd_vma value = 0; |
unsigned int len; |
if (!ISHEX (*src)) |
return FALSE; |
len = hex_value (*src++); |
if (len == 0) |
len = 16; |
while (len--) |
{ |
if (!ISHEX (*src)) |
return FALSE; |
value = value << 4 | hex_value (*src++); |
} |
*srcp = src; |
*valuep = value; |
return TRUE; |
} |
static bfd_boolean |
getsym (char *dstp, char **srcp, unsigned int *lenp) |
{ |
char *src = *srcp; |
unsigned int i; |
unsigned int len; |
if (!ISHEX (*src)) |
return FALSE; |
len = hex_value (*src++); |
if (len == 0) |
len = 16; |
for (i = 0; i < len; i++) |
dstp[i] = src[i]; |
dstp[i] = 0; |
*srcp = src + i; |
*lenp = len; |
return TRUE; |
} |
static struct data_struct * |
find_chunk (bfd *abfd, bfd_vma vma) |
{ |
struct data_struct *d = abfd->tdata.tekhex_data->data; |
vma &= ~CHUNK_MASK; |
while (d && (d->vma) != vma) |
d = d->next; |
if (!d) |
{ |
/* No chunk for this address, so make one up. */ |
d = (struct data_struct *) |
bfd_zalloc (abfd, (bfd_size_type) sizeof (struct data_struct)); |
if (!d) |
return NULL; |
d->next = abfd->tdata.tekhex_data->data; |
d->vma = vma; |
abfd->tdata.tekhex_data->data = d; |
} |
return d; |
} |
static void |
insert_byte (bfd *abfd, int value, bfd_vma addr) |
{ |
/* Find the chunk that this byte needs and put it in. */ |
struct data_struct *d = find_chunk (abfd, addr); |
d->chunk_data[addr & CHUNK_MASK] = value; |
d->chunk_init[addr & CHUNK_MASK] = 1; |
} |
/* The first pass is to find the names of all the sections, and see |
how big the data is. */ |
static bfd_boolean |
first_phase (bfd *abfd, int type, char *src) |
{ |
asection *section = bfd_abs_section_ptr; |
unsigned int len; |
bfd_vma val; |
char sym[17]; /* A symbol can only be 16chars long. */ |
switch (type) |
{ |
case '6': |
/* Data record - read it and store it. */ |
{ |
bfd_vma addr; |
if (!getvalue (&src, &addr)) |
return FALSE; |
while (*src) |
{ |
insert_byte (abfd, HEX (src), addr); |
src += 2; |
addr++; |
} |
} |
return TRUE; |
case '3': |
/* Symbol record, read the segment. */ |
if (!getsym (sym, &src, &len)) |
return FALSE; |
section = bfd_get_section_by_name (abfd, sym); |
if (section == NULL) |
{ |
char *n = (char *) bfd_alloc (abfd, (bfd_size_type) len + 1); |
if (!n) |
return FALSE; |
memcpy (n, sym, len + 1); |
section = bfd_make_section (abfd, n); |
if (section == NULL) |
return FALSE; |
} |
while (*src) |
{ |
switch (*src) |
{ |
case '1': /* Section range. */ |
src++; |
if (!getvalue (&src, §ion->vma)) |
return FALSE; |
if (!getvalue (&src, &val)) |
return FALSE; |
section->size = val - section->vma; |
section->flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC; |
break; |
case '0': |
case '2': |
case '3': |
case '4': |
case '6': |
case '7': |
case '8': |
/* Symbols, add to section. */ |
{ |
bfd_size_type amt = sizeof (tekhex_symbol_type); |
tekhex_symbol_type *new_symbol = (tekhex_symbol_type *) |
bfd_alloc (abfd, amt); |
char stype = (*src); |
if (!new_symbol) |
return FALSE; |
new_symbol->symbol.the_bfd = abfd; |
src++; |
abfd->symcount++; |
abfd->flags |= HAS_SYMS; |
new_symbol->prev = abfd->tdata.tekhex_data->symbols; |
abfd->tdata.tekhex_data->symbols = new_symbol; |
if (!getsym (sym, &src, &len)) |
return FALSE; |
new_symbol->symbol.name = (const char *) |
bfd_alloc (abfd, (bfd_size_type) len + 1); |
if (!new_symbol->symbol.name) |
return FALSE; |
memcpy ((char *) (new_symbol->symbol.name), sym, len + 1); |
new_symbol->symbol.section = section; |
if (stype <= '4') |
new_symbol->symbol.flags = (BSF_GLOBAL | BSF_EXPORT); |
else |
new_symbol->symbol.flags = BSF_LOCAL; |
if (!getvalue (&src, &val)) |
return FALSE; |
new_symbol->symbol.value = val - section->vma; |
break; |
} |
default: |
return FALSE; |
} |
} |
} |
return TRUE; |
} |
/* Pass over a tekhex, calling one of the above functions on each |
record. */ |
static bfd_boolean |
pass_over (bfd *abfd, bfd_boolean (*func) (bfd *, int, char *)) |
{ |
unsigned int chars_on_line; |
bfd_boolean is_eof = FALSE; |
/* To the front of the file. */ |
if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) |
return FALSE; |
while (! is_eof) |
{ |
char src[MAXCHUNK]; |
char type; |
/* Find first '%'. */ |
is_eof = (bfd_boolean) (bfd_bread (src, (bfd_size_type) 1, abfd) != 1); |
while (*src != '%' && !is_eof) |
is_eof = (bfd_boolean) (bfd_bread (src, (bfd_size_type) 1, abfd) != 1); |
if (is_eof) |
break; |
/* Fetch the type and the length and the checksum. */ |
if (bfd_bread (src, (bfd_size_type) 5, abfd) != 5) |
return FALSE; |
type = src[2]; |
if (!ISHEX (src[0]) || !ISHEX (src[1])) |
break; |
/* Already read five chars. */ |
chars_on_line = HEX (src) - 5; |
if (chars_on_line >= MAXCHUNK) |
return FALSE; |
if (bfd_bread (src, (bfd_size_type) chars_on_line, abfd) != chars_on_line) |
return FALSE; |
/* Put a null at the end. */ |
src[chars_on_line] = 0; |
if (!func (abfd, type, src)) |
return FALSE; |
} |
return TRUE; |
} |
static long |
tekhex_canonicalize_symtab (bfd *abfd, asymbol **table) |
{ |
tekhex_symbol_type *p = abfd->tdata.tekhex_data->symbols; |
unsigned int c = bfd_get_symcount (abfd); |
table[c] = 0; |
while (p) |
{ |
table[--c] = &(p->symbol); |
p = p->prev; |
} |
return bfd_get_symcount (abfd); |
} |
static long |
tekhex_get_symtab_upper_bound (bfd *abfd) |
{ |
return (abfd->symcount + 1) * (sizeof (struct tekhex_asymbol_struct *)); |
} |
static bfd_boolean |
tekhex_mkobject (bfd *abfd) |
{ |
tdata_type *tdata; |
tdata = (tdata_type *) bfd_alloc (abfd, (bfd_size_type) sizeof (tdata_type)); |
if (!tdata) |
return FALSE; |
abfd->tdata.tekhex_data = tdata; |
tdata->type = 1; |
tdata->head = NULL; |
tdata->symbols = NULL; |
tdata->data = NULL; |
return TRUE; |
} |
/* Return TRUE if the file looks like it's in TekHex format. Just look |
for a percent sign and some hex digits. */ |
static const bfd_target * |
tekhex_object_p (bfd *abfd) |
{ |
char b[4]; |
tekhex_init (); |
if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 |
|| bfd_bread (b, (bfd_size_type) 4, abfd) != 4) |
return NULL; |
if (b[0] != '%' || !ISHEX (b[1]) || !ISHEX (b[2]) || !ISHEX (b[3])) |
return NULL; |
tekhex_mkobject (abfd); |
if (!pass_over (abfd, first_phase)) |
return NULL; |
return abfd->xvec; |
} |
static void |
move_section_contents (bfd *abfd, |
asection *section, |
const void * locationp, |
file_ptr offset, |
bfd_size_type count, |
bfd_boolean get) |
{ |
bfd_vma addr; |
char *location = (char *) locationp; |
bfd_vma prev_number = 1; /* Nothing can have this as a high bit. */ |
struct data_struct *d = NULL; |
BFD_ASSERT (offset == 0); |
for (addr = section->vma; count != 0; count--, addr++) |
{ |
/* Get high bits of address. */ |
bfd_vma chunk_number = addr & ~(bfd_vma) CHUNK_MASK; |
bfd_vma low_bits = addr & CHUNK_MASK; |
if (chunk_number != prev_number) |
/* Different chunk, so move pointer. */ |
d = find_chunk (abfd, chunk_number); |
if (get) |
{ |
if (d->chunk_init[low_bits]) |
*location = d->chunk_data[low_bits]; |
else |
*location = 0; |
} |
else |
{ |
d->chunk_data[low_bits] = *location; |
d->chunk_init[low_bits] = (*location != 0); |
} |
location++; |
} |
} |
static bfd_boolean |
tekhex_get_section_contents (bfd *abfd, |
asection *section, |
void * locationp, |
file_ptr offset, |
bfd_size_type count) |
{ |
if (section->flags & (SEC_LOAD | SEC_ALLOC)) |
{ |
move_section_contents (abfd, section, locationp, offset, count, TRUE); |
return TRUE; |
} |
return FALSE; |
} |
static bfd_boolean |
tekhex_set_arch_mach (bfd *abfd, |
enum bfd_architecture arch, |
unsigned long machine) |
{ |
return bfd_default_set_arch_mach (abfd, arch, machine); |
} |
/* We have to save up all the Tekhexords for a splurge before output. */ |
static bfd_boolean |
tekhex_set_section_contents (bfd *abfd, |
sec_ptr section, |
const void * locationp, |
file_ptr offset, |
bfd_size_type bytes_to_do) |
{ |
if (! abfd->output_has_begun) |
{ |
/* The first time around, allocate enough sections to hold all the chunks. */ |
asection *s = abfd->sections; |
bfd_vma vma; |
for (s = abfd->sections; s; s = s->next) |
{ |
if (s->flags & SEC_LOAD) |
{ |
for (vma = s->vma & ~(bfd_vma) CHUNK_MASK; |
vma < s->vma + s->size; |
vma += CHUNK_MASK) |
find_chunk (abfd, vma); |
} |
} |
} |
if (section->flags & (SEC_LOAD | SEC_ALLOC)) |
{ |
move_section_contents (abfd, section, locationp, offset, bytes_to_do, |
FALSE); |
return TRUE; |
} |
return FALSE; |
} |
static void |
writevalue (char **dst, bfd_vma value) |
{ |
char *p = *dst; |
int len; |
int shift; |
for (len = 8, shift = 28; shift; shift -= 4, len--) |
{ |
if ((value >> shift) & 0xf) |
{ |
*p++ = len + '0'; |
while (len) |
{ |
*p++ = digs[(value >> shift) & 0xf]; |
shift -= 4; |
len--; |
} |
*dst = p; |
return; |
} |
} |
*p++ = '1'; |
*p++ = '0'; |
*dst = p; |
} |
static void |
writesym (char **dst, const char *sym) |
{ |
char *p = *dst; |
int len = (sym ? strlen (sym) : 0); |
if (len >= 16) |
{ |
*p++ = '0'; |
len = 16; |
} |
else |
{ |
if (len == 0) |
{ |
*p++ = '1'; |
sym = "$"; |
len = 1; |
} |
else |
*p++ = digs[len]; |
} |
while (len--) |
*p++ = *sym++; |
*dst = p; |
} |
static void |
out (bfd *abfd, int type, char *start, char *end) |
{ |
int sum = 0; |
char *s; |
char front[6]; |
bfd_size_type wrlen; |
front[0] = '%'; |
TOHEX (front + 1, end - start + 5); |
front[3] = type; |
for (s = start; s < end; s++) |
sum += sum_block[(unsigned char) *s]; |
sum += sum_block[(unsigned char) front[1]]; /* Length. */ |
sum += sum_block[(unsigned char) front[2]]; |
sum += sum_block[(unsigned char) front[3]]; /* Type. */ |
TOHEX (front + 4, sum); |
if (bfd_bwrite (front, (bfd_size_type) 6, abfd) != 6) |
abort (); |
end[0] = '\n'; |
wrlen = end - start + 1; |
if (bfd_bwrite (start, wrlen, abfd) != wrlen) |
abort (); |
} |
static bfd_boolean |
tekhex_write_object_contents (bfd *abfd) |
{ |
char buffer[100]; |
asymbol **p; |
asection *s; |
struct data_struct *d; |
tekhex_init (); |
/* And the raw data. */ |
for (d = abfd->tdata.tekhex_data->data; |
d != NULL; |
d = d->next) |
{ |
int low; |
const int span = 32; |
int addr; |
/* Write it in blocks of 32 bytes. */ |
for (addr = 0; addr < CHUNK_MASK + 1; addr += span) |
{ |
int need = 0; |
/* Check to see if necessary. */ |
for (low = 0; !need && low < span; low++) |
if (d->chunk_init[addr + low]) |
need = 1; |
if (need) |
{ |
char *dst = buffer; |
writevalue (&dst, addr + d->vma); |
for (low = 0; low < span; low++) |
{ |
TOHEX (dst, d->chunk_data[addr + low]); |
dst += 2; |
} |
out (abfd, '6', buffer, dst); |
} |
} |
} |
/* Write all the section headers for the sections. */ |
for (s = abfd->sections; s != NULL; s = s->next) |
{ |
char *dst = buffer; |
writesym (&dst, s->name); |
*dst++ = '1'; |
writevalue (&dst, s->vma); |
writevalue (&dst, s->vma + s->size); |
out (abfd, '3', buffer, dst); |
} |
/* And the symbols. */ |
if (abfd->outsymbols) |
{ |
for (p = abfd->outsymbols; *p; p++) |
{ |
int section_code = bfd_decode_symclass (*p); |
if (section_code != '?') |
{ |
/* Do not include debug symbols. */ |
asymbol *sym = *p; |
char *dst = buffer; |
writesym (&dst, sym->section->name); |
switch (section_code) |
{ |
case 'A': |
*dst++ = '2'; |
break; |
case 'a': |
*dst++ = '6'; |
break; |
case 'D': |
case 'B': |
case 'O': |
*dst++ = '4'; |
break; |
case 'd': |
case 'b': |
case 'o': |
*dst++ = '8'; |
break; |
case 'T': |
*dst++ = '3'; |
break; |
case 't': |
*dst++ = '7'; |
break; |
case 'C': |
case 'U': |
bfd_set_error (bfd_error_wrong_format); |
return FALSE; |
} |
writesym (&dst, sym->name); |
writevalue (&dst, sym->value + sym->section->vma); |
out (abfd, '3', buffer, dst); |
} |
} |
} |
/* And the terminator. */ |
if (bfd_bwrite ("%0781010\n", (bfd_size_type) 9, abfd) != 9) |
abort (); |
return TRUE; |
} |
static int |
tekhex_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED, |
struct bfd_link_info *info ATTRIBUTE_UNUSED) |
{ |
return 0; |
} |
static asymbol * |
tekhex_make_empty_symbol (bfd *abfd) |
{ |
bfd_size_type amt = sizeof (struct tekhex_symbol_struct); |
tekhex_symbol_type *new_symbol = (tekhex_symbol_type *) bfd_zalloc (abfd, |
amt); |
if (!new_symbol) |
return NULL; |
new_symbol->symbol.the_bfd = abfd; |
new_symbol->prev = NULL; |
return &(new_symbol->symbol); |
} |
static void |
tekhex_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED, |
asymbol *symbol, |
symbol_info *ret) |
{ |
bfd_symbol_info (symbol, ret); |
} |
static void |
tekhex_print_symbol (bfd *abfd, |
void * filep, |
asymbol *symbol, |
bfd_print_symbol_type how) |
{ |
FILE *file = (FILE *) filep; |
switch (how) |
{ |
case bfd_print_symbol_name: |
fprintf (file, "%s", symbol->name); |
break; |
case bfd_print_symbol_more: |
break; |
case bfd_print_symbol_all: |
{ |
const char *section_name = symbol->section->name; |
bfd_print_symbol_vandf (abfd, (void *) file, symbol); |
fprintf (file, " %-5s %s", |
section_name, symbol->name); |
} |
} |
} |
#define tekhex_close_and_cleanup _bfd_generic_close_and_cleanup |
#define tekhex_bfd_free_cached_info _bfd_generic_bfd_free_cached_info |
#define tekhex_new_section_hook _bfd_generic_new_section_hook |
#define tekhex_bfd_is_target_special_symbol ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) |
#define tekhex_bfd_is_local_label_name bfd_generic_is_local_label_name |
#define tekhex_get_lineno _bfd_nosymbols_get_lineno |
#define tekhex_find_nearest_line _bfd_nosymbols_find_nearest_line |
#define tekhex_find_inliner_info _bfd_nosymbols_find_inliner_info |
#define tekhex_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol |
#define tekhex_read_minisymbols _bfd_generic_read_minisymbols |
#define tekhex_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol |
#define tekhex_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents |
#define tekhex_bfd_relax_section bfd_generic_relax_section |
#define tekhex_bfd_gc_sections bfd_generic_gc_sections |
#define tekhex_bfd_lookup_section_flags bfd_generic_lookup_section_flags |
#define tekhex_bfd_merge_sections bfd_generic_merge_sections |
#define tekhex_bfd_is_group_section bfd_generic_is_group_section |
#define tekhex_bfd_discard_group bfd_generic_discard_group |
#define tekhex_section_already_linked _bfd_generic_section_already_linked |
#define tekhex_bfd_define_common_symbol bfd_generic_define_common_symbol |
#define tekhex_bfd_link_hash_table_create _bfd_generic_link_hash_table_create |
#define tekhex_bfd_link_hash_table_free _bfd_generic_link_hash_table_free |
#define tekhex_bfd_link_add_symbols _bfd_generic_link_add_symbols |
#define tekhex_bfd_link_just_syms _bfd_generic_link_just_syms |
#define tekhex_bfd_copy_link_hash_symbol_type \ |
_bfd_generic_copy_link_hash_symbol_type |
#define tekhex_bfd_final_link _bfd_generic_final_link |
#define tekhex_bfd_link_split_section _bfd_generic_link_split_section |
#define tekhex_get_section_contents_in_window _bfd_generic_get_section_contents_in_window |
const bfd_target tekhex_vec = |
{ |
"tekhex", /* Name. */ |
bfd_target_tekhex_flavour, |
BFD_ENDIAN_UNKNOWN, /* Target byte order. */ |
BFD_ENDIAN_UNKNOWN, /* Target headers byte order. */ |
(EXEC_P | /* Object flags. */ |
HAS_SYMS | HAS_LINENO | HAS_DEBUG | |
HAS_RELOC | HAS_LOCALS | WP_TEXT | D_PAGED), |
(SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS |
| SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* Section flags. */ |
0, /* Leading underscore. */ |
' ', /* AR_pad_char. */ |
16, /* AR_max_namelen. */ |
0, /* match priority. */ |
bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Data. */ |
bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Headers. */ |
{ |
_bfd_dummy_target, |
tekhex_object_p, /* bfd_check_format. */ |
_bfd_dummy_target, |
_bfd_dummy_target, |
}, |
{ |
bfd_false, |
tekhex_mkobject, |
_bfd_generic_mkarchive, |
bfd_false, |
}, |
{ /* bfd_write_contents. */ |
bfd_false, |
tekhex_write_object_contents, |
_bfd_write_archive_contents, |
bfd_false, |
}, |
BFD_JUMP_TABLE_GENERIC (tekhex), |
BFD_JUMP_TABLE_COPY (_bfd_generic), |
BFD_JUMP_TABLE_CORE (_bfd_nocore), |
BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), |
BFD_JUMP_TABLE_SYMBOLS (tekhex), |
BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), |
BFD_JUMP_TABLE_WRITE (tekhex), |
BFD_JUMP_TABLE_LINK (tekhex), |
BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), |
NULL, |
NULL |
}; |
/contrib/toolchain/binutils/bfd/verilog.c |
---|
0,0 → 1,375 |
/* BFD back-end for verilog hex memory dump files. |
Copyright 2009, 2010, 2011 |
Free Software Foundation, Inc. |
Written by Anthony Green <green@moxielogic.com> |
This file is part of BFD, the Binary File Descriptor library. |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
/* SUBSECTION |
Verilog hex memory file handling |
DESCRIPTION |
Verilog hex memory files cannot hold anything but addresses |
and data, so that's all that we implement. |
The syntax of the text file is described in the IEEE standard |
for Verilog. Briefly, the file contains two types of tokens: |
data and optional addresses. The tokens are separated by |
whitespace and comments. Comments may be single line or |
multiline, using syntax similar to C++. Addresses are |
specified by a leading "at" character (@) and are always |
hexadecimal strings. Data and addresses may contain |
underscore (_) characters. |
If no address is specified, the data is assumed to start at |
address 0. Similarly, if data exists before the first |
specified address, then that data is assumed to start at |
address 0. |
EXAMPLE |
@1000 |
01 ae 3f 45 12 |
DESCRIPTION |
@1000 specifies the starting address for the memory data. |
The following characters describe the 5 bytes at 0x1000. */ |
#include "sysdep.h" |
#include "bfd.h" |
#include "libbfd.h" |
#include "libiberty.h" |
#include "safe-ctype.h" |
/* Macros for converting between hex and binary. */ |
static const char digs[] = "0123456789ABCDEF"; |
#define NIBBLE(x) hex_value(x) |
#define HEX(buffer) ((NIBBLE ((buffer)[0])<<4) + NIBBLE ((buffer)[1])) |
#define TOHEX(d, x) \ |
d[1] = digs[(x) & 0xf]; \ |
d[0] = digs[((x) >> 4) & 0xf]; |
/* When writing a verilog memory dump file, we write them in the order |
in which they appear in memory. This structure is used to hold them |
in memory. */ |
struct verilog_data_list_struct |
{ |
struct verilog_data_list_struct *next; |
bfd_byte * data; |
bfd_vma where; |
bfd_size_type size; |
}; |
typedef struct verilog_data_list_struct verilog_data_list_type; |
/* The verilog tdata information. */ |
typedef struct verilog_data_struct |
{ |
verilog_data_list_type *head; |
verilog_data_list_type *tail; |
} |
tdata_type; |
static bfd_boolean |
verilog_set_arch_mach (bfd *abfd, enum bfd_architecture arch, unsigned long mach) |
{ |
if (arch != bfd_arch_unknown) |
return bfd_default_set_arch_mach (abfd, arch, mach); |
abfd->arch_info = & bfd_default_arch_struct; |
return TRUE; |
} |
/* We have to save up all the outpu for a splurge before output. */ |
static bfd_boolean |
verilog_set_section_contents (bfd *abfd, |
sec_ptr section, |
const void * location, |
file_ptr offset, |
bfd_size_type bytes_to_do) |
{ |
tdata_type *tdata = abfd->tdata.verilog_data; |
verilog_data_list_type *entry; |
entry = (verilog_data_list_type *) bfd_alloc (abfd, sizeof (* entry)); |
if (entry == NULL) |
return FALSE; |
if (bytes_to_do |
&& (section->flags & SEC_ALLOC) |
&& (section->flags & SEC_LOAD)) |
{ |
bfd_byte *data; |
data = (bfd_byte *) bfd_alloc (abfd, bytes_to_do); |
if (data == NULL) |
return FALSE; |
memcpy ((void *) data, location, (size_t) bytes_to_do); |
entry->data = data; |
entry->where = section->lma + offset; |
entry->size = bytes_to_do; |
/* Sort the records by address. Optimize for the common case of |
adding a record to the end of the list. */ |
if (tdata->tail != NULL |
&& entry->where >= tdata->tail->where) |
{ |
tdata->tail->next = entry; |
entry->next = NULL; |
tdata->tail = entry; |
} |
else |
{ |
verilog_data_list_type **look; |
for (look = &tdata->head; |
*look != NULL && (*look)->where < entry->where; |
look = &(*look)->next) |
; |
entry->next = *look; |
*look = entry; |
if (entry->next == NULL) |
tdata->tail = entry; |
} |
} |
return TRUE; |
} |
static bfd_boolean |
verilog_write_address (bfd *abfd, bfd_vma address) |
{ |
char buffer[12]; |
char *dst = buffer; |
bfd_size_type wrlen; |
/* Write the address. */ |
*dst++ = '@'; |
TOHEX (dst, (address >> 24)); |
dst += 2; |
TOHEX (dst, (address >> 16)); |
dst += 2; |
TOHEX (dst, (address >> 8)); |
dst += 2; |
TOHEX (dst, (address)); |
dst += 2; |
*dst++ = '\r'; |
*dst++ = '\n'; |
wrlen = dst - buffer; |
return bfd_bwrite ((void *) buffer, wrlen, abfd) == wrlen; |
} |
/* Write a record of type, of the supplied number of bytes. The |
supplied bytes and length don't have a checksum. That's worked out |
here. */ |
static bfd_boolean |
verilog_write_record (bfd *abfd, |
const bfd_byte *data, |
const bfd_byte *end) |
{ |
char buffer[48]; |
const bfd_byte *src = data; |
char *dst = buffer; |
bfd_size_type wrlen; |
/* Write the data. */ |
for (src = data; src < end; src++) |
{ |
TOHEX (dst, *src); |
dst += 2; |
*dst++ = ' '; |
} |
*dst++ = '\r'; |
*dst++ = '\n'; |
wrlen = dst - buffer; |
return bfd_bwrite ((void *) buffer, wrlen, abfd) == wrlen; |
} |
static bfd_boolean |
verilog_write_section (bfd *abfd, |
tdata_type *tdata ATTRIBUTE_UNUSED, |
verilog_data_list_type *list) |
{ |
unsigned int octets_written = 0; |
bfd_byte *location = list->data; |
verilog_write_address (abfd, list->where); |
while (octets_written < list->size) |
{ |
unsigned int octets_this_chunk = list->size - octets_written; |
if (octets_this_chunk > 16) |
octets_this_chunk = 16; |
if (! verilog_write_record (abfd, |
location, |
location + octets_this_chunk)) |
return FALSE; |
octets_written += octets_this_chunk; |
location += octets_this_chunk; |
} |
return TRUE; |
} |
static bfd_boolean |
verilog_write_object_contents (bfd *abfd) |
{ |
tdata_type *tdata = abfd->tdata.verilog_data; |
verilog_data_list_type *list; |
/* Now wander though all the sections provided and output them. */ |
list = tdata->head; |
while (list != (verilog_data_list_type *) NULL) |
{ |
if (! verilog_write_section (abfd, tdata, list)) |
return FALSE; |
list = list->next; |
} |
return TRUE; |
} |
/* Initialize by filling in the hex conversion array. */ |
static void |
verilog_init (void) |
{ |
static bfd_boolean inited = FALSE; |
if (! inited) |
{ |
inited = TRUE; |
hex_init (); |
} |
} |
/* Set up the verilog tdata information. */ |
static bfd_boolean |
verilog_mkobject (bfd *abfd) |
{ |
tdata_type *tdata; |
verilog_init (); |
tdata = (tdata_type *) bfd_alloc (abfd, sizeof (tdata_type)); |
if (tdata == NULL) |
return FALSE; |
abfd->tdata.verilog_data = tdata; |
tdata->head = NULL; |
tdata->tail = NULL; |
return TRUE; |
} |
#define verilog_close_and_cleanup _bfd_generic_close_and_cleanup |
#define verilog_bfd_free_cached_info _bfd_generic_bfd_free_cached_info |
#define verilog_new_section_hook _bfd_generic_new_section_hook |
#define verilog_bfd_is_target_special_symbol ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) |
#define verilog_bfd_is_local_label_name bfd_generic_is_local_label_name |
#define verilog_get_lineno _bfd_nosymbols_get_lineno |
#define verilog_find_nearest_line _bfd_nosymbols_find_nearest_line |
#define verilog_find_inliner_info _bfd_nosymbols_find_inliner_info |
#define verilog_make_empty_symbol _bfd_generic_make_empty_symbol |
#define verilog_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol |
#define verilog_read_minisymbols _bfd_generic_read_minisymbols |
#define verilog_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol |
#define verilog_get_section_contents_in_window _bfd_generic_get_section_contents_in_window |
#define verilog_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents |
#define verilog_bfd_relax_section bfd_generic_relax_section |
#define verilog_bfd_gc_sections bfd_generic_gc_sections |
#define verilog_bfd_merge_sections bfd_generic_merge_sections |
#define verilog_bfd_is_group_section bfd_generic_is_group_section |
#define verilog_bfd_discard_group bfd_generic_discard_group |
#define verilog_section_already_linked _bfd_generic_section_already_linked |
#define verilog_bfd_link_hash_table_create _bfd_generic_link_hash_table_create |
#define verilog_bfd_link_hash_table_free _bfd_generic_link_hash_table_free |
#define verilog_bfd_link_add_symbols _bfd_generic_link_add_symbols |
#define verilog_bfd_link_just_syms _bfd_generic_link_just_syms |
#define verilog_bfd_final_link _bfd_generic_final_link |
#define verilog_bfd_link_split_section _bfd_generic_link_split_section |
const bfd_target verilog_vec = |
{ |
"verilog", /* Name. */ |
bfd_target_verilog_flavour, |
BFD_ENDIAN_UNKNOWN, /* Target byte order. */ |
BFD_ENDIAN_UNKNOWN, /* Target headers byte order. */ |
(HAS_RELOC | EXEC_P | /* Object flags. */ |
HAS_LINENO | HAS_DEBUG | |
HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), |
(SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS |
| SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* Section flags. */ |
0, /* Leading underscore. */ |
' ', /* AR_pad_char. */ |
16, /* AR_max_namelen. */ |
0, /* match priority. */ |
bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Data. */ |
bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Hdrs. */ |
{ |
_bfd_dummy_target, |
_bfd_dummy_target, |
_bfd_dummy_target, |
_bfd_dummy_target, |
}, |
{ |
bfd_false, |
verilog_mkobject, |
bfd_false, |
bfd_false, |
}, |
{ /* bfd_write_contents. */ |
bfd_false, |
verilog_write_object_contents, |
bfd_false, |
bfd_false, |
}, |
BFD_JUMP_TABLE_GENERIC (_bfd_generic), |
BFD_JUMP_TABLE_COPY (_bfd_generic), |
BFD_JUMP_TABLE_CORE (_bfd_nocore), |
BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), |
BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols), |
BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), |
BFD_JUMP_TABLE_WRITE (verilog), |
BFD_JUMP_TABLE_LINK (_bfd_nolink), |
BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), |
NULL, |
NULL |
}; |