Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 5196 → Rev 5197

/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, &section, &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 = &section->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, &copy))
{
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,
&section_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,
&section_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, &section_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, &section->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
};