From mboxrd@z Thu Jan 1 00:00:00 1970 Content-Type: multipart/mixed; boundary="===============0334493565604174374==" MIME-Version: 1.0 From: Mark Wielaard To: elfutils-devel@lists.fedorahosted.org Subject: [PATCH] Remove eu-ld and unused code. Date: Wed, 06 Jul 2016 23:10:42 +0200 Message-ID: <1467839442-18684-1-git-send-email-mjw@redhat.com> --===============0334493565604174374== Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Nobody has hacked on eu-ld in a very long time. It didn't really work. And we didn't install it by default in the spec file. Remove sources, the build rules and any (now) unused code. Signed-off-by: Mark Wielaard --- .gitignore | 4 - ChangeLog | 5 + config/ChangeLog | 4 + config/elfutils.spec.in | 2 - configure.ac | 30 - libebl/ChangeLog | 18 + libebl/Makefile.am | 6 +- libebl/ebl-hooks.h | 8 +- libebl/eblgstrtab.c | 365 --- libebl/eblobjecttypename.c | 59 - libebl/eblopenbackend.c | 21 +- libebl/eblshflagscombine.c | 41 - libebl/eblwstrtab.c | 359 --- libebl/libebl.h | 54 +- libelf/ChangeLog | 5 + libelf/elf-knowledge.h | 26 +- po/ChangeLog | 5 + po/POTFILES.in | 5 - src/ChangeLog | 24 + src/Makefile.am | 81 +- src/elf32-i386.script | 229 -- src/i386_ld.c | 1102 ------- src/ld.c | 1607 ---------- src/ld.h | 1135 ------- src/ldgeneric.c | 7132 ----------------------------------------= ---- src/ldlex.l | 353 --- src/ldscript.y | 803 ----- src/libld_elf_i386.map | 7 - src/none_ld.c | 1 - src/sectionhash.c | 73 - src/sectionhash.h | 27 - src/symbolhash.c | 33 - src/symbolhash.h | 28 - src/unaligned.h | 102 - src/versionhash.c | 32 - src/versionhash.h | 26 - src/xelf.h | 391 --- 37 files changed, 72 insertions(+), 14131 deletions(-) delete mode 100644 libebl/eblgstrtab.c delete mode 100644 libebl/eblobjecttypename.c delete mode 100644 libebl/eblshflagscombine.c delete mode 100644 libebl/eblwstrtab.c delete mode 100644 src/elf32-i386.script delete mode 100644 src/i386_ld.c delete mode 100644 src/ld.c delete mode 100644 src/ld.h delete mode 100644 src/ldgeneric.c delete mode 100644 src/ldlex.l delete mode 100644 src/ldscript.y delete mode 100644 src/libld_elf_i386.map delete mode 100644 src/none_ld.c delete mode 100644 src/sectionhash.c delete mode 100644 src/sectionhash.h delete mode 100644 src/symbolhash.c delete mode 100644 src/symbolhash.h delete mode 100644 src/unaligned.h delete mode 100644 src/versionhash.c delete mode 100644 src/versionhash.h delete mode 100644 src/xelf.h diff --git a/.gitignore b/.gitignore index 75043fe..c583347 100644 --- a/.gitignore +++ b/.gitignore @@ -60,10 +60,6 @@ Makefile.in /src/elfcompress /src/elflint /src/findtextrel -/src/ld -/src/ldlex.c -/src/ldscript.c -/src/ldscript.h /src/make-debug-archive /src/nm /src/objdump diff --git a/ChangeLog b/ChangeLog index 5be4c5e..6a038a2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2016-07-06 Mark Wielaard + + * .gitignore: Remove src/ld. ldlex.c, ldscript.c and ldscript.h. + * configure.ac (enable generic): Removed. + 2016-06-28 Richard Henderson = * configure.ac (HAVE_LINUX_BPF_H): New test and conditional. diff --git a/config/ChangeLog b/config/ChangeLog index 5357f22..4ca6fa8 100644 --- a/config/ChangeLog +++ b/config/ChangeLog @@ -1,3 +1,7 @@ +2016-07-06 Mark Wielaard + + * elfutils.spec.in: Remove eu-ld. + 2016-03-31 Mark Wielaard = * elfutils.spec.in: Update for 0.166. diff --git a/config/elfutils.spec.in b/config/elfutils.spec.in index 9b00c47..b62be26 100644 --- a/config/elfutils.spec.in +++ b/config/elfutils.spec.in @@ -134,7 +134,6 @@ chmod +x ${RPM_BUILD_ROOT}%{_prefix}/%{_lib}/elfutils/l= ib*.so* = # XXX Nuke unpackaged files { cd ${RPM_BUILD_ROOT} - rm -f .%{_bindir}/eu-ld rm -f .%{_includedir}/elfutils/libasm.h rm -f .%{_libdir}/libasm.so rm -f .%{_libdir}/libasm.a @@ -176,7 +175,6 @@ rm -rf ${RPM_BUILD_ROOT} %{_bindir}/eu-ar %{_bindir}/eu-unstrip %{_bindir}/eu-make-debug-archive -#%{_bindir}/eu-ld %{_bindir}/eu-elfcompress %{_libdir}/libasm-%{version}.so %{_libdir}/libdw-%{version}.so diff --git a/configure.ac b/configure.ac index 926715c..e753dd9 100644 --- a/configure.ac +++ b/configure.ac @@ -144,36 +144,6 @@ dnl tests, because the choice of the file model can (i= n principle) affect dnl whether functions and headers are available, whether they work, etc. AC_SYS_LARGEFILE = -dnl Enable the linker to be build as a native-only linker. By default it -dnl can handle all architectures but this comes at a cost. A native -dnl will be slightly faster, small, and has fewer dependencies. -native_ld=3Dno -AC_ARG_ENABLE([generic], -AS_HELP_STRING([--disable-generic], [do not build generic linker]), [dnl -if test "$enable_generic" =3D no; then - case "$host_cpu" in - i?86) - AC_DEFINE(NATIVE_ELF, 32) - native_ld=3Dyes - base_cpu=3Di386 - ;; - *) - AC_MSG_ERROR([no machine-specific linker for this configuration availa= ble]) - ;; - esac -fi]) -AH_TEMPLATE([NATIVE_ELF], -[Define to 32 or 64 if a specific implementation is wanted.]) -AM_CONDITIONAL(NATIVE_LD, test "$native_ld" =3D yes) -dnl The automake generated Makefile cannot deal with macros in the name -dnl of files if at any time there is no such file, even if the filename -dnl would not be used. -AS_IF([test -z "$base_cpu"], [base_cpu=3Dnone]) -AC_SUBST(base_cpu) -dnl Support to work around automake's inflexible dependency generation. -dnl See src/Makefile.am for more information. -AM_CONDITIONAL(NEVER, false) - dnl enable debugging of branch prediction. AC_ARG_ENABLE([debugpred], AS_HELP_STRING([--enable-debugpred],[build binaries with support to debug = branch prediction]), diff --git a/libebl/ChangeLog b/libebl/ChangeLog index 8ff4010..fc3cf3b 100644 --- a/libebl/ChangeLog +++ b/libebl/ChangeLog @@ -1,3 +1,21 @@ +2016-07-06 Mark Wielaard + + * Makefile.am (gen_SOURCES): Remove eblobjecttypename.c, + eblshflagscombine.c, eblwstrtab.c and eblgstrtab.c. + * ebl-hooks.h (object_type_name): Removed. + (sh_flags_combine): Likewise. + * eblgstrtab.c: Removed. + * eblobjecttypename.c: Removed. + * eblopenbackend.c (default_object_type_name): Removed. + (default_sh_flags_combine): Likewise. + (fill_defaults): Removed object_type_name and sh_flags_combine. + * eblshflagscombine.c: Removed. + * eblwstrtab.c: Removed. + * libebl.h (ebl_object_type_name): Removed. + (ebl_sh_flags_combine): Likewise. + (ebl_wstrtab*): Removed. + (ebl_gstrtab*): Likewise. + 2016-06-28 Richard Henderson = * ebl-hooks.h (EBLHOOK(disasm)): Add ebl parameter. diff --git a/libebl/Makefile.am b/libebl/Makefile.am index 6b41a3e..3bd4abe 100644 --- a/libebl/Makefile.am +++ b/libebl/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to create Makefile.in ## -## Copyright (C) 2000-2010, 2013 Red Hat, Inc. +## Copyright (C) 2000-2010, 2013, 2016 Red Hat, Inc. ## This file is part of elfutils. ## ## This file is free software; you can redistribute it and/or modify @@ -41,9 +41,7 @@ gen_SOURCES =3D eblopenbackend.c eblclosebackend.c eblstr= tab.c \ eblreloctypename.c eblsegmenttypename.c \ eblsectiontypename.c eblmachineflagname.c \ eblsymboltypename.c ebldynamictagname.c eblsectionname.c \ - eblobjecttypename.c eblsymbolbindingname.c \ - eblbackendname.c eblshflagscombine.c eblwstrtab.c \ - eblgstrtab.c eblosabiname.c \ + eblsymbolbindingname.c eblbackendname.c eblosabiname.c \ eblmachineflagcheck.c eblmachinesectionflagcheck.c \ eblreloctypecheck.c eblrelocvaliduse.c eblrelocsimpletype.c \ ebldynamictagcheck.c eblcorenotetypename.c eblobjnotetypename.c \ diff --git a/libebl/ebl-hooks.h b/libebl/ebl-hooks.h index a7f4755..b725374 100644 --- a/libebl/ebl-hooks.h +++ b/libebl/ebl-hooks.h @@ -1,5 +1,5 @@ /* Backend hook signatures internal interface for libebl. - Copyright (C) 2000-2011, 2013, 2014 Red Hat, Inc. + Copyright (C) 2000-2011, 2013, 2014, 2016 Red Hat, Inc. This file is part of elfutils. = This file is free software; you can redistribute it and/or modify @@ -26,9 +26,6 @@ the GNU Lesser General Public License along with this program. If not, see . */ = -/* Return symbol representaton of object file type. */ -const char *EBLHOOK(object_type_name) (int, char *, size_t); - /* Return symbolic representation of relocation type. */ const char *EBLHOOK(reloc_type_name) (int, char *, size_t); = @@ -80,9 +77,6 @@ const char *EBLHOOK(dynamic_tag_name) (int64_t, char *, s= ize_t); /* Check dynamic tag. */ bool EBLHOOK(dynamic_tag_check) (int64_t); = -/* Combine section header flags values. */ -GElf_Word EBLHOOK(sh_flags_combine) (GElf_Word, GElf_Word); - /* Return symbolic representation of OS ABI. */ const char *EBLHOOK(osabi_name) (int, char *, size_t); = diff --git a/libebl/eblgstrtab.c b/libebl/eblgstrtab.c deleted file mode 100644 index 0d92c00..0000000 --- a/libebl/eblgstrtab.c +++ /dev/null @@ -1,365 +0,0 @@ -/* Generic string table handling. - Copyright (C) 2000, 2001, 2002, 2005 Red Hat, Inc. - This file is part of elfutils. - Written by Ulrich Drepper , 2000. - - This file is free software; you can redistribute it and/or modify - it under the terms of either - - * the GNU Lesser General Public License as published by the Free - Software Foundation; either version 3 of the License, or (at - your option) any later version - - or - - * the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at - your option) any later version - - or both in parallel, as here. - - elfutils 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 copies of the GNU General Public License and - the GNU Lesser General Public License along with this program. If - not, see . */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "libebl.h" - -#ifndef MIN -# define MIN(a, b) ((a) < (b) ? (a) : (b)) -#endif - - -struct Ebl_GStrent -{ - const char *string; - size_t len; - struct Ebl_GStrent *next; - struct Ebl_GStrent *left; - struct Ebl_GStrent *right; - size_t offset; - unsigned int width; - char reverse[0]; -}; - - -struct memoryblock -{ - struct memoryblock *next; - char memory[0]; -}; - - -struct Ebl_GStrtab -{ - struct Ebl_GStrent *root; - struct memoryblock *memory; - char *backp; - size_t left; - size_t total; - unsigned int width; - bool nullstr; - - struct Ebl_GStrent null; -}; - - -/* Cache for the pagesize. We correct this value a bit so that `malloc' - is not allocating more than a page. */ -static size_t ps; - - -struct Ebl_GStrtab * -ebl_gstrtabinit (unsigned int width, bool nullstr) -{ - struct Ebl_GStrtab *ret; - - if (ps =3D=3D 0) - { - ps =3D sysconf (_SC_PAGESIZE) - 2 * sizeof (void *); - assert (sizeof (struct memoryblock) < ps); - } - - ret =3D (struct Ebl_GStrtab *) calloc (1, sizeof (struct Ebl_GStrtab)); - if (ret !=3D NULL) - { - ret->width =3D width; - ret->nullstr =3D nullstr; - - if (nullstr) - { - ret->null.len =3D 1; - ret->null.string =3D (char *) calloc (1, width); - } - } - - return ret; -} - - -static void -morememory (struct Ebl_GStrtab *st, size_t len) -{ - struct memoryblock *newmem; - - if (len < ps) - len =3D ps; - newmem =3D (struct memoryblock *) malloc (len); - if (newmem =3D=3D NULL) - abort (); - - newmem->next =3D st->memory; - st->memory =3D newmem; - st->backp =3D newmem->memory; - st->left =3D len - offsetof (struct memoryblock, memory); -} - - -void -ebl_gstrtabfree (struct Ebl_GStrtab *st) -{ - struct memoryblock *mb =3D st->memory; - - while (mb !=3D NULL) - { - void *old =3D mb; - mb =3D mb->next; - free (old); - } - - if (st->null.string !=3D NULL) - free ((char *) st->null.string); - - free (st); -} - - -static struct Ebl_GStrent * -newstring (struct Ebl_GStrtab *st, const char *str, size_t len) -{ - /* Compute the amount of padding needed to make the structure aligned. = */ - size_t align =3D ((__alignof__ (struct Ebl_GStrent) - - (((uintptr_t) st->backp) - & (__alignof__ (struct Ebl_GStrent) - 1))) - & (__alignof__ (struct Ebl_GStrent) - 1)); - - /* Make sure there is enough room in the memory block. */ - if (st->left < align + sizeof (struct Ebl_GStrent) + len * st->width) - { - morememory (st, sizeof (struct Ebl_GStrent) + len * st->width); - align =3D 0; - } - - /* Create the reserved string. */ - struct Ebl_GStrent *newstr =3D (struct Ebl_GStrent *) (st->backp + align= ); - newstr->string =3D str; - newstr->len =3D len; - newstr->width =3D st->width; - newstr->next =3D NULL; - newstr->left =3D NULL; - newstr->right =3D NULL; - newstr->offset =3D 0; - for (int i =3D len - 2; i >=3D 0; --i) - for (int j =3D st->width - 1; j >=3D 0; --j) - newstr->reverse[i * st->width + j] =3D str[(len - 2 - i) * st->width= + j]; - for (size_t j =3D 0; j < st->width; ++j) - newstr->reverse[(len - 1) * st->width + j] =3D '\0'; - st->backp +=3D align + sizeof (struct Ebl_GStrent) + len * st->width; - st->left -=3D align + sizeof (struct Ebl_GStrent) + len * st->width; - - return newstr; -} - - -/* XXX This function should definitely be rewritten to use a balancing - tree algorith (AVL, red-black trees). For now a simple, correct - implementation is enough. */ -static struct Ebl_GStrent ** -searchstring (struct Ebl_GStrent **sep, struct Ebl_GStrent *newstr) -{ - int cmpres; - - /* More strings? */ - if (*sep =3D=3D NULL) - { - *sep =3D newstr; - return sep; - } - - /* Compare the strings. */ - cmpres =3D memcmp ((*sep)->reverse, newstr->reverse, - (MIN ((*sep)->len, newstr->len) - 1) * (*sep)->width); - if (cmpres =3D=3D 0) - /* We found a matching string. */ - return sep; - else if (cmpres > 0) - return searchstring (&(*sep)->left, newstr); - else - return searchstring (&(*sep)->right, newstr); -} - - -/* Add new string. The actual string is assumed to be permanent. */ -struct Ebl_GStrent * -ebl_gstrtabadd (struct Ebl_GStrtab *st, const char *str, size_t len) -{ - struct Ebl_GStrent *newstr; - struct Ebl_GStrent **sep; - - /* Compute the string length if the caller doesn't know it. */ - if (len =3D=3D 0) - { - size_t j; - - do - for (j =3D 0; j < st->width; ++j) - if (str[len * st->width + j] !=3D '\0') - break; - while (j =3D=3D st->width && ++len); - } - - /* Make sure all "" strings get offset 0 but only if the table was - created with a special null entry in mind. */ - if (len =3D=3D 1 && st->null.string !=3D NULL) - return &st->null; - - /* Allocate memory for the new string and its associated information. */ - newstr =3D newstring (st, str, len); - - /* Search in the array for the place to insert the string. If there - is no string with matching prefix and no string with matching - leading substring, create a new entry. */ - sep =3D searchstring (&st->root, newstr); - if (*sep !=3D newstr) - { - /* This is not the same entry. This means we have a prefix match. = */ - if ((*sep)->len > newstr->len) - { - struct Ebl_GStrent *subs; - - /* Check whether we already know this string. */ - for (subs =3D (*sep)->next; subs !=3D NULL; subs =3D subs->next) - if (subs->len =3D=3D newstr->len) - { - /* We have an exact match with a substring. Free the memory - we allocated. */ - st->left +=3D (st->backp - (char *) newstr) * st->width; - st->backp =3D (char *) newstr; - - return subs; - } - - /* We have a new substring. This means we don't need the reverse - string of this entry anymore. */ - st->backp -=3D newstr->len; - st->left +=3D newstr->len; - - newstr->next =3D (*sep)->next; - (*sep)->next =3D newstr; - } - else if ((*sep)->len !=3D newstr->len) - { - /* When we get here it means that the string we are about to - add has a common prefix with a string we already have but - it is longer. In this case we have to put it first. */ - st->total +=3D newstr->len - (*sep)->len; - newstr->next =3D *sep; - newstr->left =3D (*sep)->left; - newstr->right =3D (*sep)->right; - *sep =3D newstr; - } - else - { - /* We have an exact match. Free the memory we allocated. */ - st->left +=3D (st->backp - (char *) newstr) * st->width; - st->backp =3D (char *) newstr; - - newstr =3D *sep; - } - } - else - st->total +=3D newstr->len; - - return newstr; -} - - -static void -copystrings (struct Ebl_GStrent *nodep, char **freep, size_t *offsetp) -{ - struct Ebl_GStrent *subs; - - if (nodep->left !=3D NULL) - copystrings (nodep->left, freep, offsetp); - - /* Process the current node. */ - nodep->offset =3D *offsetp; - *freep =3D (char *) mempcpy (*freep, nodep->string, nodep->len * nodep->= width); - *offsetp +=3D nodep->len * nodep->width; - - for (subs =3D nodep->next; subs !=3D NULL; subs =3D subs->next) - { - assert (subs->len < nodep->len); - subs->offset =3D nodep->offset + (nodep->len - subs->len) * nodep->w= idth; - assert (subs->offset !=3D 0 || subs->string[0] =3D=3D '\0'); - } - - if (nodep->right !=3D NULL) - copystrings (nodep->right, freep, offsetp); -} - - -void -ebl_gstrtabfinalize (struct Ebl_GStrtab *st, Elf_Data *data) -{ - size_t copylen; - char *endp; - size_t nulllen =3D st->nullstr ? st->width : 0; - - /* Fill in the information. */ - data->d_buf =3D malloc (st->total + nulllen); - if (data->d_buf =3D=3D NULL) - abort (); - - /* The first byte must always be zero if we created the table with a - null string. */ - if (st->nullstr) - memset (data->d_buf, '\0', st->width); - - data->d_type =3D ELF_T_BYTE; - data->d_size =3D st->total + nulllen; - data->d_off =3D 0; - data->d_align =3D 1; - data->d_version =3D EV_CURRENT; - - /* Now run through the tree and add all the string while also updating - the offset members of the elfstrent records. */ - endp =3D (char *) data->d_buf + nulllen; - copylen =3D nulllen; - copystrings (st->root, &endp, ©len); - assert (copylen =3D=3D st->total * st->width + nulllen); -} - - -size_t -ebl_gstrtaboffset (struct Ebl_GStrent *se) -{ - return se->offset; -} diff --git a/libebl/eblobjecttypename.c b/libebl/eblobjecttypename.c deleted file mode 100644 index b0fd372..0000000 --- a/libebl/eblobjecttypename.c +++ /dev/null @@ -1,59 +0,0 @@ -/* Return object file type name. - Copyright (C) 2001, 2002 Red Hat, Inc. - This file is part of elfutils. - Written by Ulrich Drepper , 2001. - - This file is free software; you can redistribute it and/or modify - it under the terms of either - - * the GNU Lesser General Public License as published by the Free - Software Foundation; either version 3 of the License, or (at - your option) any later version - - or - - * the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at - your option) any later version - - or both in parallel, as here. - - elfutils 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 copies of the GNU General Public License and - the GNU Lesser General Public License along with this program. If - not, see . */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include - - -const char * -ebl_object_type_name (Ebl *ebl, int object, char *buf, size_t len) -{ - const char *res; - - res =3D ebl !=3D NULL ? ebl->object_type_name (object, buf, len) : NULL; - if (res =3D=3D NULL) - { - /* Handle OS-specific section names. */ - if (object >=3D ET_LOOS && object <=3D ET_HIOS) - snprintf (buf, len, "LOOS+%x", object - ET_LOOS); - /* Handle processor-specific section names. */ - else if (object >=3D ET_LOPROC && object <=3D ET_HIPROC) - snprintf (buf, len, "LOPROC+%x", object - ET_LOPROC); - else - snprintf (buf, len, "%s: %d", gettext (""), object); - - res =3D buf; - } - - return res; -} diff --git a/libebl/eblopenbackend.c b/libebl/eblopenbackend.c index 16ec1c4..aa75b95 100644 --- a/libebl/eblopenbackend.c +++ b/libebl/eblopenbackend.c @@ -1,5 +1,5 @@ /* Generate ELF backend handle. - Copyright (C) 2000-2015 Red Hat, Inc. + Copyright (C) 2000-2016 Red Hat, Inc. This file is part of elfutils. = This file is free software; you can redistribute it and/or modify @@ -140,8 +140,6 @@ static const struct #define MAX_PREFIX_LEN 16 = /* Default callbacks. Mostly they just return the error value. */ -static const char *default_object_type_name (int ignore, char *buf, - size_t len); static const char *default_reloc_type_name (int ignore, char *buf, size_t = len); static bool default_reloc_type_check (int ignore); static bool default_reloc_valid_use (Elf *elf, int ignore); @@ -163,7 +161,6 @@ static const char *default_symbol_binding_name (int ign= ore, char *buf, static const char *default_dynamic_tag_name (int64_t ignore, char *buf, size_t len); static bool default_dynamic_tag_check (int64_t ignore); -static GElf_Word default_sh_flags_combine (GElf_Word flags1, GElf_Word fla= gs2); static const char *default_osabi_name (int ignore, char *buf, size_t len); static void default_destr (struct ebl *ignore); static const char *default_core_note_type_name (uint32_t, char *buf, @@ -210,7 +207,6 @@ static int default_abi_cfi (Ebl *ebl, Dwarf_CIE *abi_in= fo); static void fill_defaults (Ebl *result) { - result->object_type_name =3D default_object_type_name; result->reloc_type_name =3D default_reloc_type_name; result->reloc_type_check =3D default_reloc_type_check; result->reloc_valid_use =3D default_reloc_valid_use; @@ -227,7 +223,6 @@ fill_defaults (Ebl *result) result->symbol_binding_name =3D default_symbol_binding_name; result->dynamic_tag_name =3D default_dynamic_tag_name; result->dynamic_tag_check =3D default_dynamic_tag_check; - result->sh_flags_combine =3D default_sh_flags_combine; result->osabi_name =3D default_osabi_name; result->core_note_type_name =3D default_core_note_type_name; result->object_note_type_name =3D default_object_note_type_name; @@ -431,14 +426,6 @@ ebl_openbackend_emulation (const char *emulation) = /* Default callbacks. Mostly they just return the error value. */ static const char * -default_object_type_name (int ignore __attribute__ ((unused)), - char *buf __attribute__ ((unused)), - size_t len __attribute__ ((unused))) -{ - return NULL; -} - -static const char * default_reloc_type_name (int ignore __attribute__ ((unused)), char *buf __attribute__ ((unused)), size_t len __attribute__ ((unused))) @@ -555,12 +542,6 @@ default_dynamic_tag_check (int64_t ignore __attribute_= _ ((unused))) return false; } = -static GElf_Word -default_sh_flags_combine (GElf_Word flags1, GElf_Word flags2) -{ - return SH_FLAGS_COMBINE (flags1, flags2); -} - static void default_destr (struct ebl *ignore __attribute__ ((unused))) { diff --git a/libebl/eblshflagscombine.c b/libebl/eblshflagscombine.c deleted file mode 100644 index 4deaaaa..0000000 --- a/libebl/eblshflagscombine.c +++ /dev/null @@ -1,41 +0,0 @@ -/* Return combines section header flags value. - Copyright (C) 2001, 2002 Red Hat, Inc. - This file is part of elfutils. - Written by Ulrich Drepper , 2001. - - This file is free software; you can redistribute it and/or modify - it under the terms of either - - * the GNU Lesser General Public License as published by the Free - Software Foundation; either version 3 of the License, or (at - your option) any later version - - or - - * the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at - your option) any later version - - or both in parallel, as here. - - elfutils 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 copies of the GNU General Public License and - the GNU Lesser General Public License along with this program. If - not, see . */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - - -GElf_Word -ebl_sh_flags_combine (Ebl *ebl, GElf_Word flags1, GElf_Word flags2) -{ - return ebl->sh_flags_combine (flags1, flags2); -} diff --git a/libebl/eblwstrtab.c b/libebl/eblwstrtab.c deleted file mode 100644 index 08e0ba7..0000000 --- a/libebl/eblwstrtab.c +++ /dev/null @@ -1,359 +0,0 @@ -/* ELF string table handling. - Copyright (C) 2000, 2001, 2002 Red Hat, Inc. - This file is part of elfutils. - Written by Ulrich Drepper , 2000. - - This file is free software; you can redistribute it and/or modify - it under the terms of either - - * the GNU Lesser General Public License as published by the Free - Software Foundation; either version 3 of the License, or (at - your option) any later version - - or - - * the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at - your option) any later version - - or both in parallel, as here. - - elfutils 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 copies of the GNU General Public License and - the GNU Lesser General Public License along with this program. If - not, see . */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "libebl.h" -#include - -#ifndef MIN -# define MIN(a, b) ((a) < (b) ? (a) : (b)) -#endif - - -struct Ebl_WStrent -{ - const wchar_t *string; - size_t len; - struct Ebl_WStrent *next; - struct Ebl_WStrent *left; - struct Ebl_WStrent *right; - size_t offset; - wchar_t reverse[0]; -}; - - -struct memoryblock -{ - struct memoryblock *next; - char memory[0]; -}; - - -struct Ebl_WStrtab -{ - struct Ebl_WStrent *root; - struct memoryblock *memory; - char *backp; - size_t left; - size_t total; - bool nullstr; - - struct Ebl_WStrent null; -}; - - -/* Cache for the pagesize. We correct this value a bit so that `malloc' - is not allocating more than a page. */ -static size_t ps; - - -struct Ebl_WStrtab * -ebl_wstrtabinit (bool nullstr) -{ - struct Ebl_WStrtab *ret; - - if (ps =3D=3D 0) - { - ps =3D sysconf (_SC_PAGESIZE) - 2 * sizeof (void *); - assert (sizeof (struct memoryblock) < ps); - } - - ret =3D (struct Ebl_WStrtab *) calloc (1, sizeof (struct Ebl_WStrtab)); - if (ret !=3D NULL) - { - ret->nullstr =3D nullstr; - if (nullstr) - { - ret->null.len =3D 1; - ret->null.string =3D L""; - } - } - return ret; -} - - -static int -morememory (struct Ebl_WStrtab *st, size_t len) -{ - struct memoryblock *newmem; - - if (len < ps) - len =3D ps; - newmem =3D (struct memoryblock *) malloc (len); - if (newmem =3D=3D NULL) - return 1; - - newmem->next =3D st->memory; - st->memory =3D newmem; - st->backp =3D newmem->memory; - st->left =3D len - offsetof (struct memoryblock, memory); - - return 0; -} - - -void -ebl_wstrtabfree (struct Ebl_WStrtab *st) -{ - struct memoryblock *mb =3D st->memory; - - while (mb !=3D NULL) - { - void *old =3D mb; - mb =3D mb->next; - free (old); - } - - free (st); -} - - -static struct Ebl_WStrent * -newstring (struct Ebl_WStrtab *st, const wchar_t *str, size_t len) -{ - struct Ebl_WStrent *newstr; - size_t align; - int i; - - /* Compute the amount of padding needed to make the structure aligned. = */ - align =3D ((__alignof__ (struct Ebl_WStrent) - - (((uintptr_t) st->backp) - & (__alignof__ (struct Ebl_WStrent) - 1))) - & (__alignof__ (struct Ebl_WStrent) - 1)); - - /* Make sure there is enough room in the memory block. */ - if (st->left < align + sizeof (struct Ebl_WStrent) + len * sizeof (wchar= _t)) - { - if (morememory (st, - sizeof (struct Ebl_WStrent) + len * sizeof (wchar_t))) - return NULL; - - align =3D 0; - } - - /* Create the reserved string. */ - newstr =3D (struct Ebl_WStrent *) (st->backp + align); - newstr->string =3D str; - newstr->len =3D len; - newstr->next =3D NULL; - newstr->left =3D NULL; - newstr->right =3D NULL; - newstr->offset =3D 0; - for (i =3D len - 2; i >=3D 0; --i) - newstr->reverse[i] =3D str[len - 2 - i]; - newstr->reverse[len - 1] =3D L'\0'; - st->backp +=3D align + sizeof (struct Ebl_WStrent) + len * sizeof (wchar= _t); - st->left -=3D align + sizeof (struct Ebl_WStrent) + len * sizeof (wchar_= t); - - return newstr; -} - - -/* XXX This function should definitely be rewritten to use a balancing - tree algorith (AVL, red-black trees). For now a simple, correct - implementation is enough. */ -static struct Ebl_WStrent ** -searchstring (struct Ebl_WStrent **sep, struct Ebl_WStrent *newstr) -{ - int cmpres; - - /* More strings? */ - if (*sep =3D=3D NULL) - { - *sep =3D newstr; - return sep; - } - - /* Compare the strings. */ - cmpres =3D wmemcmp ((*sep)->reverse, newstr->reverse, - MIN ((*sep)->len, newstr->len) - 1); - if (cmpres =3D=3D 0) - /* We found a matching string. */ - return sep; - else if (cmpres > 0) - return searchstring (&(*sep)->left, newstr); - else - return searchstring (&(*sep)->right, newstr); -} - - -/* Add new string. The actual string is assumed to be permanent. */ -struct Ebl_WStrent * -ebl_wstrtabadd (struct Ebl_WStrtab *st, const wchar_t *str, size_t len) -{ - struct Ebl_WStrent *newstr; - struct Ebl_WStrent **sep; - - /* Compute the string length if the caller doesn't know it. */ - if (len =3D=3D 0) - len =3D wcslen (str) + 1; - - /* Make sure all "" strings get offset 0 but only if the table was - created with a special null entry in mind. */ - if (len =3D=3D 1 && st->null.string !=3D NULL) - return &st->null; - - /* Allocate memory for the new string and its associated information. */ - newstr =3D newstring (st, str, len); - if (newstr =3D=3D NULL) - return NULL; - - /* Search in the array for the place to insert the string. If there - is no string with matching prefix and no string with matching - leading substring, create a new entry. */ - sep =3D searchstring (&st->root, newstr); - if (*sep !=3D newstr) - { - /* This is not the same entry. This means we have a prefix match. = */ - if ((*sep)->len > newstr->len) - { - struct Ebl_WStrent *subs; - - /* Check whether we already know this string. */ - for (subs =3D (*sep)->next; subs !=3D NULL; subs =3D subs->next) - if (subs->len =3D=3D newstr->len) - { - /* We have an exact match with a substring. Free the memory - we allocated. */ - st->left +=3D st->backp - (char *) newstr; - st->backp =3D (char *) newstr; - - return subs; - } - - /* We have a new substring. This means we don't need the reverse - string of this entry anymore. */ - st->backp -=3D newstr->len; - st->left +=3D newstr->len; - - newstr->next =3D (*sep)->next; - (*sep)->next =3D newstr; - } - else if ((*sep)->len !=3D newstr->len) - { - /* When we get here it means that the string we are about to - add has a common prefix with a string we already have but - it is longer. In this case we have to put it first. */ - st->total +=3D newstr->len - (*sep)->len; - newstr->next =3D *sep; - newstr->left =3D (*sep)->left; - newstr->right =3D (*sep)->right; - *sep =3D newstr; - } - else - { - /* We have an exact match. Free the memory we allocated. */ - st->left +=3D st->backp - (char *) newstr; - st->backp =3D (char *) newstr; - - newstr =3D *sep; - } - } - else - st->total +=3D newstr->len; - - return newstr; -} - - -static void -copystrings (struct Ebl_WStrent *nodep, wchar_t **freep, size_t *offsetp) -{ - struct Ebl_WStrent *subs; - - if (nodep->left !=3D NULL) - copystrings (nodep->left, freep, offsetp); - - /* Process the current node. */ - nodep->offset =3D *offsetp; - *freep =3D wmempcpy (*freep, nodep->string, nodep->len); - *offsetp +=3D nodep->len * sizeof (wchar_t); - - for (subs =3D nodep->next; subs !=3D NULL; subs =3D subs->next) - { - assert (subs->len < nodep->len); - subs->offset =3D nodep->offset + nodep->len - subs->len; - assert (subs->offset !=3D 0 || subs->string[0] =3D=3D '\0'); - } - - if (nodep->right !=3D NULL) - copystrings (nodep->right, freep, offsetp); -} - - -void -ebl_wstrtabfinalize (struct Ebl_WStrtab *st, Elf_Data *data) -{ - size_t copylen; - wchar_t *endp; - size_t nulllen =3D st->nullstr ? 1 : 0; - - /* Fill in the information. */ - data->d_buf =3D malloc ((st->total + nulllen) * sizeof (wchar_t)); - if (data->d_buf =3D=3D NULL) - abort (); - - /* The first byte must always be zero if we created the table with a - null string. */ - if (st->nullstr) - *((wchar_t *) data->d_buf) =3D L'\0'; - - data->d_type =3D ELF_T_BYTE; - data->d_size =3D st->total + nulllen; - data->d_off =3D 0; - data->d_align =3D 1; - data->d_version =3D EV_CURRENT; - - /* Now run through the tree and add all the string while also updating - the offset members of the elfstrent records. */ - endp =3D (wchar_t *) data->d_buf + nulllen; - copylen =3D sizeof (wchar_t) * nulllen; - copystrings (st->root, &endp, ©len); - assert (copylen =3D=3D (st->total + nulllen) * sizeof (wchar_t)); -} - - -size_t -ebl_wstrtaboffset (struct Ebl_WStrent *se) -{ - return se->offset; -} diff --git a/libebl/libebl.h b/libebl/libebl.h index efcb6d6..cef7157 100644 --- a/libebl/libebl.h +++ b/libebl/libebl.h @@ -1,5 +1,5 @@ /* Interface for libebl. - Copyright (C) 2000-2010, 2013, 2014, 2015 Red Hat, Inc. + Copyright (C) 2000-2010, 2013, 2014, 2015, 2016 Red Hat, Inc. This file is part of elfutils. = This file is free software; you can redistribute it and/or modify @@ -89,10 +89,6 @@ extern int ebl_get_elfdata (Ebl *ebl) __attribute__ ((__= pure__)); extern const char *ebl_backend_name (Ebl *ebl); = /* Return relocation type name. */ -extern const char *ebl_object_type_name (Ebl *ebl, int object, - char *buf, size_t len); - -/* Return relocation type name. */ extern const char *ebl_reloc_type_name (Ebl *ebl, int reloc, char *buf, size_t len); = @@ -163,10 +159,6 @@ extern bool ebl_check_special_symbol (Ebl *ebl, GElf_E= hdr *ehdr, /* Check whether only valid bits are set on the st_other symbol flag. */ extern bool ebl_check_st_other_bits (Ebl *ebl, unsigned char st_other); = -/* Return combined section header flags value. */ -extern GElf_Word ebl_sh_flags_combine (Ebl *ebl, GElf_Word flags1, - GElf_Word flags2); - /* Return symbolic representation of OS ABI. */ extern const char *ebl_osabi_name (Ebl *ebl, int osabi, char *buf, size_t = len); = @@ -320,50 +312,6 @@ extern size_t ebl_strtaboffset (struct Ebl_Strent *se); extern const char *ebl_string (struct Ebl_Strent *se); = = -/* ELF wide char string table handling. */ -struct Ebl_WStrtab; -struct Ebl_WStrent; - -/* Create new ELF wide char string table object in memory. */ -extern struct Ebl_WStrtab *ebl_wstrtabinit (bool nullstr); - -/* Free resources allocated for ELF wide char string table ST. */ -extern void ebl_wstrtabfree (struct Ebl_WStrtab *st); - -/* Add string STR (length LEN is !=3D 0) to ELF string table ST. */ -extern struct Ebl_WStrent *ebl_wstrtabadd (struct Ebl_WStrtab *st, - const wchar_t *str, size_t len); - -/* Finalize string table ST and store size and memory location information - in DATA. */ -extern void ebl_wstrtabfinalize (struct Ebl_WStrtab *st, Elf_Data *data); - -/* Get offset in wide char string table for string associated with SE. */ -extern size_t ebl_wstrtaboffset (struct Ebl_WStrent *se); - - -/* Generic string table handling. */ -struct Ebl_GStrtab; -struct Ebl_GStrent; - -/* Create new string table object in memory. */ -extern struct Ebl_GStrtab *ebl_gstrtabinit (unsigned int width, bool nulls= tr); - -/* Free resources allocated for string table ST. */ -extern void ebl_gstrtabfree (struct Ebl_GStrtab *st); - -/* Add string STR (length LEN is !=3D 0) to string table ST. */ -extern struct Ebl_GStrent *ebl_gstrtabadd (struct Ebl_GStrtab *st, - const char *str, size_t len); - -/* Finalize string table ST and store size and memory location information - in DATA. */ -extern void ebl_gstrtabfinalize (struct Ebl_GStrtab *st, Elf_Data *data); - -/* Get offset in wide char string table for string associated with SE. */ -extern size_t ebl_gstrtaboffset (struct Ebl_GStrent *se); - - /* Register map info. */ typedef struct { diff --git a/libelf/ChangeLog b/libelf/ChangeLog index 82a2a9f..721beb4 100644 --- a/libelf/ChangeLog +++ b/libelf/ChangeLog @@ -1,3 +1,8 @@ +2016-07-06 Mark Wielaard + + * elf-knowledge.h (SH_FLAGS_COMBINE): Removed. + (SH_FLAGS_IMPORTANT): Likewise. + 2016-06-24 John Ogness = * elf32_updatenull.c (updatenull_wrlock): Find first section. diff --git a/libelf/elf-knowledge.h b/libelf/elf-knowledge.h index 24534b3..64f5887 100644 --- a/libelf/elf-knowledge.h +++ b/libelf/elf-knowledge.h @@ -1,5 +1,5 @@ /* Accumulation of various pieces of knowledge about ELF. - Copyright (C) 2000-2012, 2014 Red Hat, Inc. + Copyright (C) 2000-2012, 2014, 2016 Red Hat, Inc. This file is part of elfutils. Written by Ulrich Drepper , 2000. = @@ -62,30 +62,6 @@ || ((Shdr)->sh_flags & SHF_INFO_LINK) !=3D 0) = = -/* When combining ELF section flags we must distinguish two kinds: - - - flags which cause problem if not added to the result even if not - present in all input sections - - - flags which cause problem if added to the result if not present - in all input sections - - The following definition is for the general case. There might be - machine specific extensions. */ -#define SH_FLAGS_COMBINE(Flags1, Flags2) \ - (((Flags1 | Flags2) \ - & (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR | SHF_LINK_ORDER \ - | SHF_OS_NONCONFORMING | SHF_GROUP)) \ - | (Flags1 & Flags2 & (SHF_MERGE | SHF_STRINGS | SHF_INFO_LINK))) - -/* Similar macro: return the bits of the flags which necessarily must - match if two sections are automatically combined. Sections still - can be forcefully combined in which case SH_FLAGS_COMBINE can be - used to determine the combined flags. */ -#define SH_FLAGS_IMPORTANT(Flags) \ - ((Flags) & ~((GElf_Xword) 0 | SHF_LINK_ORDER | SHF_OS_NONCONFORMING)) - - /* Size of an entry in the hash table. The ELF specification says all entries are regardless of platform 32-bits in size. Early 64-bit ports (namely Alpha for Linux) got this wrong. The wording was not diff --git a/po/ChangeLog b/po/ChangeLog index c83d53b..6e9900c 100644 --- a/po/ChangeLog +++ b/po/ChangeLog @@ -1,3 +1,8 @@ +2016-07-06 Mark Wielaard + + * po/POTFILES.in: Removed libebl/eblobjecttypename.c, + src/i386_ld.c, src/ld.c, src/ldgeneric.c and src/ldscript.y. + 2016-03-31 Mark Wielaard = * *.po: Update for 0.166. diff --git a/po/POTFILES.in b/po/POTFILES.in index 02433f9..93bcf6e 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -13,7 +13,6 @@ libdwfl/libdwflP.h libebl/eblbackendname.c libebl/eblcorenotetypename.c libebl/ebldynamictagname.c -libebl/eblobjecttypename.c libebl/eblobjnote.c libebl/eblobjnotetypename.c libebl/eblosabiname.c @@ -32,10 +31,6 @@ src/arlib.c src/elfcmp.c src/elflint.c src/findtextrel.c -src/i386_ld.c -src/ld.c -src/ldgeneric.c -src/ldscript.y src/nm.c src/objdump.c src/ranlib.c diff --git a/src/ChangeLog b/src/ChangeLog index 21fc7d5..143e628 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,27 @@ +2016-07-06 Mark Wielaard + + * elf32-i386.script, i386_ld.c, ld.c, ld.h, ldgeneric.c, ldlex.l, + ldscript.y, libld_elf_i386.map, none_ld.c, sectionhash.c, + sectionhash.h, symbolhash.c, symbolhash.h, unaligned.h, + versionhash.c, versionhash.h, xelf.h: Removed. + * Makefile.am (YACC): Removed. + (AM_YFLAGS): Removed. + (AM_LFLAGS): Removed. + (native_ld): Removed. + (base_cpu): Removed. + (bin_PROGRAMS): Removed ld. + (ld_dsos): Removed. + (ld_SOURCES): Removed. + (noinst_LIBRARIES): Only libar.a. + (EXTRA_DIST): Just arlib.h and debugpred.h. + (ld_LDADD): Removed. + (ld_LDFLAGS): Removed. + (ldlex.o): Removed. + (ldscript.h): Removed. + (libld*): Removed. + (CLEANFILES): Just *.gconv. + (MAINTAINERCLEANFILES): Removed. + 2016-06-28 Richard Henderson = * elflint.c (valid_e_machine): Add EM_BPF. diff --git a/src/Makefile.am b/src/Makefile.am index a39df27..6f796b3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to create Makefile.in ## -## Copyright (C) 1996-2014 Red Hat, Inc. +## Copyright (C) 1996-2014, 2016 Red Hat, Inc. ## This file is part of elfutils. ## ## This file is free software; you can redistribute it and/or modify @@ -25,46 +25,14 @@ AM_CPPFLAGS +=3D -I$(srcdir)/../libelf -I$(srcdir)/../l= ibebl \ = AM_LDFLAGS =3D -Wl,-rpath-link,../libelf:../libdw = -YACC =3D @YACC@ -d -AM_YFLAGS =3D -pld -AM_LFLAGS =3D -Pld -olex.yy.c -## Uncomment to enable debugging of linker script parser -##YYDEBUG =3D -DYYDEBUG=3D1 - -native_ld =3D @native_ld@ -base_cpu =3D @base_cpu@ - -bin_PROGRAMS =3D readelf nm size strip ld elflint findtextrel addr2line \ +bin_PROGRAMS =3D readelf nm size strip elflint findtextrel addr2line \ elfcmp objdump ranlib strings ar unstrip stack elfcompress = - -ld_dsos =3D libld_elf_i386_pic.a -if NATIVE_LD -noinst_LIBRARIES =3D libld_elf.a libar.a -native_ld_cflags =3D -DBASE_ELF_NAME=3Delf_$(base_cpu) -else -noinst_LIBRARIES =3D libld_elf.a libar.a $(ld_dsos) -noinst_PROGRAMS =3D $(ld_dsos:_pic.a=3D.so) -endif -if NEVER -# We never build this library but we need to get the dependency files -# of all the linker backends that might be used in a non-generic linker. -noinst_LIBRARIES +=3D libdummy.a -libdummy_a_SOURCES =3D i386_ld.c -endif - - -ld_SOURCES =3D ld.c ldgeneric.c ldlex.l ldscript.y symbolhash.c sectionhas= h.c \ - versionhash.c +noinst_LIBRARIES =3D libar.a = libar_a_SOURCES =3D arlib.c arlib2.c arlib-argp.c = -noinst_HEADERS =3D ld.h symbolhash.h sectionhash.h versionhash.h \ - ldscript.h xelf.h unaligned.h - -EXTRA_DIST =3D elf32-i386.script libld_elf_i386.map $(ld_modules) arlib.h \ - debugpred.h -ld_modules =3D i386_ld.c +EXTRA_DIST =3D arlib.h debugpred.h = bin_SCRIPTS =3D make-debug-archive EXTRA_DIST +=3D make-debug-archive.in @@ -86,11 +54,6 @@ if DEMANGLE demanglelib =3D -lstdc++ endif = -# XXX While the file is not finished, don't warn about this -ldgeneric_no_Wunused =3D yes -ldgeneric_no_Wstack_usage =3D yes -ldlex_no_Wstack_usage =3D yes - # Bad, bad stack usage... readelf_no_Wstack_usage =3D yes nm_no_Wstack_usage =3D yes @@ -109,12 +72,6 @@ nm_LDADD =3D $(libdw) $(libebl) $(libelf) $(libeu) $(ar= gp_LDADD) -ldl \ $(demanglelib) size_LDADD =3D $(libelf) $(libeu) $(argp_LDADD) strip_LDADD =3D $(libebl) $(libelf) $(libeu) $(argp_LDADD) -ldl -ld_LDADD =3D $(libebl) $(libelf) $(libeu) $(argp_LDADD) -ldl -if NATIVE_LD -# -ldl is always needed for libebl. -ld_LDADD +=3D libld_elf.a -endif -ld_LDFLAGS =3D -rdynamic elflint_LDADD =3D $(libebl) $(libelf) $(libeu) $(argp_LDADD) -ldl findtextrel_LDADD =3D $(libdw) $(libelf) $(argp_LDADD) addr2line_LDADD =3D $(libdw) $(libelf) $(argp_LDADD) $(demanglelib) @@ -127,31 +84,6 @@ unstrip_LDADD =3D $(libebl) $(libelf) $(libdw) $(libeu)= $(argp_LDADD) -ldl stack_LDADD =3D $(libebl) $(libelf) $(libdw) $(libeu) $(argp_LDADD) -ldl $= (demanglelib) elfcompress_LDADD =3D $(libebl) $(libelf) $(libdw) $(libeu) $(argp_LDADD) = -ldlex.o: ldscript.c -ldlex_no_Werror =3D yes -ldscript.h: ldscript.c - -if NATIVE_LD -# Machine-specific linker code. -libld_elf_a_SOURCES :=3D $(base_cpu)_ld.c -else -libld_elf_i386_pic_a_SOURCES =3D -am_libld_elf_i386_pic_a_OBJECTS =3D i386_ld.os - -libld_elf_i386_so_SOURCES =3D -libld_elf_i386.so: libld_elf_i386_pic.a libld_elf_i386.map - $(AM_V_CCLD)$(LINK) -shared -o $@ -Wl,--whole-archive,$<,--no-whole-archi= ve \ - $(libelf) $(libeu) \ - -Wl,--version-script,$(srcdir)/libld_elf_i386.map - @$(textrel_check) -endif - -# Special rule to make it possible to define libld_elf_a_SOURCES as we do. -# Otherwise make would complain. -.deps/none_ld.Po: none_ld.os - @-: - - installcheck-binPROGRAMS: $(bin_PROGRAMS) bad=3D0; pid=3D$$$$; list=3D"$(bin_PROGRAMS)"; for p in $$list; do \ case ' $(AM_INSTALLCHECK_STD_OPTIONS_EXEMPT) ' in \ @@ -168,10 +100,7 @@ installcheck-binPROGRAMS: $(bin_PROGRAMS) done; \ done; rm -f c$${pid}_.???; exit $$bad = -CLEANFILES +=3D none_ld.os $(ld_modules:.c=3D.os) *.gconv - -MAINTAINERCLEANFILES =3D ldlex.c ldscript.c ldscript.h - +CLEANFILES +=3D *.gconv = make-debug-archive: $(srcdir)/make-debug-archive.in $(AM_V_GEN)UNSTRIP=3D$(bindir)/`echo unstrip | sed '$(transform)'`; \ diff --git a/src/elf32-i386.script b/src/elf32-i386.script deleted file mode 100644 index 2083278..0000000 --- a/src/elf32-i386.script +++ /dev/null @@ -1,229 +0,0 @@ -ENTRY(_start); - -SEARCH_DIR(/lib); -SEARCH_DIR(/usr/lib); -SEARCH_DIR(/usr/local/lib); -SEARCH_DIR(/usr/i686-pc-linux-gnu/lib); - -INTERP(/lib/ld-linux.so.2); - -PAGESIZE(4k); - -SEGMENT [RX] -{ -#ifdef SHARED - . =3D SIZEOF_HEADERS; -#else - . =3D 0x08048000 + SIZEOF_HEADERS; -#endif - - .interp; - .note.ABI-tag; - .note.gnu.build-id; - .hash; - .gnu.hash; - .dynsym; - .dynstr; - .gnu.version; - .gnu.version_d; - .gnu.version_r; - .rel.dyn; - .rel.plt; - .init { KEEP (*(.init)) } - .plt; - .text - { - *(.text) - *(.text.*) - *(.stub) - *(.gnu.warning) - *(.gnu.linkonce.t.*) - } - .fini { KEEP (*(.fini)) } - PROVIDE (__etext =3D .); - PROVIDE (_etext =3D .); - PROVIDE (etext =3D .); - .rodata - { - *(.rodata) - *(.rodata.*) - *(.gnu.linkonce.r.*) - } - .rodata1; - .eh_frame_hdr; - . =3D ALIGN(32 / 8); - PROVIDE (__preinit_array_start =3D .); - .preinit_array - { - *(.preinit_array) - } - PROVIDE (__preinit_array_end =3D .); - PROVIDE (__init_array_start =3D .); - .init_array - { - *(.init_array) - } - PROVIDE (__init_array_end =3D .); - PROVIDE (__fini_array_start =3D .); - .fini_array - { - *(.fini_array) - } - PROVIDE (__fini_array_end =3D .); -} - -SEGMENT [RW] -{ - .sdata2 - { - *(.sdata2) - *(.sdata2.*) - *(.gnu.linkonce.s2.*) - } - .sbss2 - { - *(.sbss2) - *(.sbss2.*) - *(.gnu.linkonce.sb2.*) - } - /* Adjust the address for the data segment. We want to adjust up to - the same address within the page on the next page up. */ - . =3D ALIGN(PAGESIZE) + (. & (PAGESIZE - 1)); - .eh_frame - { - KEEP (*(.eh_frame)) - } - .gcc_except_table; - .tdata - { - *(.tdata) - *(.tdata.*) - *(.gnu.linkone.td.*) - } - .tbss - { - *(.tbss) - *(.tbss.*) - *(.gnu.linkone.tb.*) - *(.tcommon) - } - .ctors - { - /* gcc uses crtbegin.o to find the start of - the constructors, so we make sure it is - first. Because this is a wildcard, it - doesn't matter if the user does not - actually link against crtbegin.o; the - linker won't look for a file to match a - wildcard. The wildcard also means that it - doesn't matter which directory crtbegin.o - is in. */ - KEEP (*crtbegin.o(.ctors)) - /* We don't want to include the .ctor section from - the crtend.o file until after the sorted ctors. - The .ctor section from the crtend file contains the - end of ctors marker and it must be last */ - KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*(.ctors)) - } - .dtors - { - KEEP (*crtbegin.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*(.dtors)) - } - .jcr; - .dynamic; - .got; - .got.plt; - .data - { - *(.data) - *(.data.*) - *(.gnu.linkonce.d.*) - } - /* We want the small data sections together, so single-instruction offse= ts - can access them all, and initialized data all before uninitialized, so - we can shorten the on-disk segment size. */ - .data1; - .sdata - { - *(.sdata) - *(.sdata.*) - *(.gnu.linkonce.s.*) - } - _edata =3D .; - PROVIDE (edata =3D .); - __bss_start =3D .; - .sbss - { - PROVIDE (__sbss_start =3D .); - PROVIDE (___sbss_start =3D .); - *(.dynsbss) - *(.sbss) - *(.sbss.*) - *(.gnu.linkonce.sb.*) - *(.scommon) - PROVIDE (__sbss_end =3D .); - PROVIDE (___sbss_end =3D .); - } - .bss - { - *(.dynbss) - *(.bss) - *(.bss.*) - *(.gnu.linkonce.b.*) - *(COMMON) - /* Align here to ensure that the .bss section occupies space up to - _end. Align after .bss to ensure correct alignment even if the - .bss section disappears because there are no input sections. */ - . =3D ALIGN(32 / 8); - } - . =3D ALIGN(32 / 8); - _end =3D .; - PROVIDE (end =3D .); -} - -SEGMENT [] -{ - /* Stabs debugging sections. */ - .stab; - .stabstr; - .stab.excl; - .stab.exclstr; - .stab.index; - .stab.indexstr; - .comment; - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug; - .line; - /* GNU DWARF 1 extensions */ - .debug_srcinfo; - .debug_sfnames; - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges; - .debug_pubnames; - /* DWARF 2 */ - .debug_info - { - *(.debug_info) - *(.gnu.linkonce.wi.*) - } - .debug_abbrev; - .debug_line; - .debug_frame; - .debug_str; - .debug_loc; - .debug_macinfo; - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames; - .debug_funcnames; - .debug_typenames; - .debug_varnames; - /* These must appear regardless of . */ -} diff --git a/src/i386_ld.c b/src/i386_ld.c deleted file mode 100644 index d196177..0000000 --- a/src/i386_ld.c +++ /dev/null @@ -1,1102 +0,0 @@ -/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008 Red Hat, Inc. - This file is part of elfutils. - Written by Ulrich Drepper , 2001. - - This file 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. - - elfutils 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, see . = */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include -#include -#include - -// XXX For debugging -#include - -#include -#include "ld.h" -#include "list.h" -/* x86 is little endian. */ -#define UNALIGNED_ACCESS_CLASS LITTLE_ENDIAN -#include "unaligned.h" -#include "xelf.h" - - -/* The old callbacks. */ -static int (*old_open_outfile) (struct ld_state *, int, int, int); - - -static int -elf_i386_open_outfile (struct ld_state *statep, - int machine __attribute__ ((unused)), - int klass __attribute__ ((unused)), - int data __attribute__ ((unused))) -{ - /* This backend only handles 32-bit object files. */ - /* XXX For now just use the generic backend. */ - return old_open_outfile (statep, EM_386, ELFCLASS32, ELFDATA2LSB); -} - - -/* Process relocations for the output in a relocatable file. This - only means adjusting offset and symbol indices. */ -static void -elf_i386_relocate_section (struct ld_state *statep __attribute__ ((unused)= ), - Elf_Scn *outscn, struct scninfo *firstp, - const Elf32_Word *dblindirect) -{ - struct scninfo *runp; - Elf_Data *data; - - /* Iterate over all the input sections. Appropriate data buffers in the - output sections were already created. */ - runp =3D firstp; - data =3D NULL; - do - { - Elf_Data *reltgtdata; - Elf_Data *insymdata; - Elf_Data *inxndxdata =3D NULL; - size_t maxcnt; - size_t cnt; - const Elf32_Word *symindirect; - struct symbol **symref; - struct usedfiles *file =3D runp->fileinfo; - XElf_Shdr *shdr =3D &SCNINFO_SHDR (runp->shdr); - - /* Get the output section data buffer for this input section. */ - data =3D elf_getdata (outscn, data); - assert (data !=3D NULL); - - /* Get the data for section in the input file this relocation - section is relocating. Since these buffers are reused in the - output modifying these buffers has the correct result. */ - reltgtdata =3D elf_getdata (file->scninfo[shdr->sh_info].scn, NULL); - - /* Get the data for the input section symbol table for this - relocation section. */ - insymdata =3D elf_getdata (file->scninfo[shdr->sh_link].scn, NULL); - assert (insymdata !=3D NULL); - - /* And the extended section index table. */ - inxndxdata =3D runp->fileinfo->xndxdata; - - /* Number of relocations. */ - maxcnt =3D shdr->sh_size / shdr->sh_entsize; - - /* Array directing local symbol table offsets to output symbol - table offsets. */ - symindirect =3D file->symindirect; - - /* References to the symbol records. */ - symref =3D file->symref; - - /* Iterate over all the relocations in the section. */ - for (cnt =3D 0; cnt < maxcnt; ++cnt) - { - XElf_Rel_vardef (rel); - Elf32_Word si; - XElf_Sym_vardef (sym); - Elf32_Word xndx; - - /* Get the relocation data itself. x86 uses Rel - relocations. In case we have to handle Rela as well the - whole loop probably should be duplicated. */ - xelf_getrel (data, cnt, rel); - assert (rel !=3D NULL); - - /* Compute the symbol index in the output file. */ - si =3D symindirect[XELF_R_SYM (rel->r_info)]; - if (si =3D=3D 0) - { - /* This happens if the symbol is locally undefined or - superceded by some other definition. */ - assert (symref[XELF_R_SYM (rel->r_info)] !=3D NULL); - si =3D symref[XELF_R_SYM (rel->r_info)]->outsymidx; - } - /* Take reordering performed to sort the symbol table into - account. */ - si =3D dblindirect[si]; - - /* Get the symbol table entry. */ - xelf_getsymshndx (insymdata, inxndxdata, XELF_R_SYM (rel->r_info), - sym, xndx); - if (sym->st_shndx !=3D SHN_XINDEX) - xndx =3D sym->st_shndx; - assert (xndx < SHN_LORESERVE || xndx > SHN_HIRESERVE); - - /* We fortunately don't have to do much. The relocations - mostly get only updates of the offset. Only for a - relocation referring to a section do we have to do - something. In this case the reference to the sections - has no direct equivalent since the part the input section - contributes need not start at the same offset as in the - input file. Therefore we have to adjust the addend which - in the case of Rel relocations is in the target section - itself. */ - if (XELF_ST_TYPE (sym->st_info) =3D=3D STT_SECTION) - { - /* We expect here only R_386_32 relocations. */ - assert (XELF_R_TYPE (rel->r_info) =3D=3D R_386_32); - - /* Avoid writing to the section memory if this is - effectively a no-op since it might save a - copy-on-write operation. */ - Elf32_Word toadd =3D file->scninfo[xndx].offset; - if (toadd !=3D 0) - add_4ubyte_unaligned (reltgtdata->d_buf + rel->r_offset, - toadd); - } - - /* Adjust the offset for the position of the input section - content in the output section. */ - rel->r_offset +=3D file->scninfo[shdr->sh_info].offset; - - /* And finally adjust the index of the symbol in the output - symbol table. */ - rel->r_info =3D XELF_R_INFO (si, XELF_R_TYPE (rel->r_info)); - - /* Store the result. */ - (void) xelf_update_rel (data, cnt, rel); - } - - runp =3D runp->next; - } - while (runp !=3D firstp); -} - - -/* Each PLT entry has 16 bytes. We need one entry as overhead for - the code to set up the call into the runtime relocation. */ -#define PLT_ENTRY_SIZE 16 - -static void -elf_i386_initialize_plt (struct ld_state *statep, Elf_Scn *scn) -{ - Elf_Data *data; - XElf_Shdr_vardef (shdr); - - /* Change the entry size in the section header. */ - xelf_getshdr (scn, shdr); - assert (shdr !=3D NULL); - shdr->sh_entsize =3D PLT_ENTRY_SIZE; - (void) xelf_update_shdr (scn, shdr); - - data =3D elf_newdata (scn); - if (data =3D=3D NULL) - error (EXIT_FAILURE, 0, gettext ("cannot allocate PLT section: %s"), - elf_errmsg (-1)); - - /* We need one special PLT entry (performing the jump to the runtime - relocation routines) and one for each function we call in a DSO. */ - data->d_size =3D (1 + statep->nplt) * PLT_ENTRY_SIZE; - data->d_buf =3D xcalloc (1, data->d_size); - assert (data->d_type =3D=3D ELF_T_BYTE); - data->d_off =3D 0; - data->d_align =3D 8; - - statep->nplt_used =3D 1; -} - - -static void -elf_i386_initialize_pltrel (struct ld_state *statep, Elf_Scn *scn) -{ - Elf_Data *data; - - data =3D elf_newdata (scn); - if (data =3D=3D NULL) - error (EXIT_FAILURE, 0, gettext ("cannot allocate PLTREL section: %s"), - elf_errmsg (-1)); - - /* One relocation per PLT entry. */ - size_t size =3D statep->nplt * sizeof (Elf32_Rel); - data->d_buf =3D xcalloc (1, size); - data->d_type =3D ELF_T_REL; - data->d_size =3D size; - data->d_align =3D 4; - data->d_off =3D 0; -} - - -static void -elf_i386_initialize_got (struct ld_state *statep, Elf_Scn *scn) -{ - /* If we come here we better need a GOT. */ - assert (statep->ngot !=3D 0); - - Elf_Data *data =3D elf_newdata (scn); - if (data =3D=3D NULL) - error (EXIT_FAILURE, 0, gettext ("cannot allocate GOT section: %s"), - elf_errmsg (-1)); - - /* Just a single word per GOT entry is needed. */ - size_t size =3D statep->ngot * sizeof (Elf32_Addr); - data->d_buf =3D xcalloc (1, size); - data->d_size =3D size; - data->d_type =3D ELF_T_WORD; - data->d_off =3D 0; - data->d_align =3D sizeof (Elf32_Addr); -} - - -static void -elf_i386_initialize_gotplt (struct ld_state *statep, Elf_Scn *scn) -{ - /* If we come here we better need a PLT. */ - assert (statep->nplt !=3D 0); - - Elf_Data *data =3D elf_newdata (scn); - if (data =3D=3D NULL) - error (EXIT_FAILURE, 0, gettext ("cannot allocate GOTPLT section: %s"), - elf_errmsg (-1)); - - /* We construct the .got.plt section in pieces. Here we only add the da= ta - structures which are used by the PLT. This includes three reserved - entries at the beginning (the first will contain a pointer to the - .dynamic section), and one word for each PLT entry. */ - size_t size =3D (3 + statep->nplt) * sizeof (Elf32_Addr); - data->d_buf =3D xcalloc (1, size); - data->d_type =3D ELF_T_WORD; - data->d_size =3D size; - data->d_off =3D 0; - data->d_align =3D sizeof (Elf32_Addr); -} - - -/* The first entry in an absolute procedure linkage table looks like - this. See the SVR4 ABI i386 supplement to see how this works. */ -static const unsigned char elf_i386_plt0_entry[PLT_ENTRY_SIZE] =3D -{ - 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. */ - 0x0f, 0x0b, /* ud2a, to prevent further decoding. */ - 0, 0 /* pad out to 16 bytes. */ -}; - -/* Type describing the first PLT entry in non-PIC. */ -struct plt0_entry -{ - /* First a 'push' of the second GOT entry. */ - unsigned char push_instr[2]; - uint32_t gotp4_addr; - /* Second, a 'jmp indirect' to the third GOT entry. */ - unsigned char jmp_instr[2]; - uint32_t gotp8_addr; - /* Padding. */ - unsigned char padding[4]; -} __attribute__ ((packed)); - -/* The first entry in a PIC procedure linkage table look like this. */ -static const unsigned char elf_i386_pic_plt0_entry[PLT_ENTRY_SIZE] =3D -{ - 0xff, 0xb3, 4, 0, 0, 0, /* pushl 4(%ebx) */ - 0xff, 0xa3, 8, 0, 0, 0, /* jmp *8(%ebx) */ - 0x0f, 0x0b, /* ud2a, to prevent further decoding. */ - 0, 0 /* pad out to 16 bytes. */ -}; - -/* Contents of all but the first PLT entry in executable. */ -static const unsigned char elf_i386_plt_entry[PLT_ENTRY_SIZE] =3D -{ - 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. */ -}; - -/* Contents of all but the first PLT entry in DSOs. */ -static const unsigned char elf_i386_pic_plt_entry[PLT_ENTRY_SIZE] =3D -{ - 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. */ -}; - -/* Type describing a PLT entry. */ -struct plt_entry -{ - /* The first instruction is 'jmp indirect' or 'jmp *offset(%ebs)'. */ - unsigned char jmp_instr[2]; - uint32_t offset_got; - /* The second instruction is 'push immediate'. */ - unsigned char push_instr; - uint32_t push_imm; - /* Finally a 'jmp relative'. */ - unsigned char jmp_instr2; - uint32_t plt0_offset; -} __attribute__ ((packed)); - - -static void -elf_i386_finalize_plt (struct ld_state *statep, size_t nsym, - size_t nsym_local, struct symbol **ndxtosym) -{ - if (unlikely (statep->nplt + statep->ngot =3D=3D 0)) - /* Nothing to be done. */ - return; - - Elf_Scn *scn; - XElf_Shdr_vardef (shdr); - Elf_Data *data; - const bool build_dso =3D statep->file_type =3D=3D dso_file_type; - - /* Get the address of the .got.plt section. */ - scn =3D elf_getscn (statep->outelf, statep->gotpltscnidx); - xelf_getshdr (scn, shdr); - data =3D elf_getdata (scn, NULL); - assert (shdr !=3D NULL && data !=3D NULL); - /* The address points to the .got.plt section, not the .got section. */ - Elf32_Addr gotaddr =3D shdr->sh_addr; - - /* Now create the initial values for the .got.plt section. The - first word contains the address of the .dynamic section. The - second and third entry are left empty for use by the dynamic - linker. The following entries are pointers to the instructions - following the initial jmp instruction in the corresponding PLT - entry. */ - xelf_getshdr (elf_getscn (statep->outelf, statep->dynamicscnidx), shdr); - assert (shdr !=3D NULL); - ((Elf32_Word *) data->d_buf)[0] =3D shdr->sh_addr; - - /* The PLT contains code which a user of a function jumps to. The first - PLT entry is special, so the first used one has the index 1. */ - scn =3D elf_getscn (statep->outelf, statep->pltscnidx); - XElf_Shdr_vardef (pltshdr); - xelf_getshdr (scn, pltshdr); - assert (pltshdr !=3D NULL); - - Elf_Data *dynsymdata =3D elf_getdata (elf_getscn (statep->outelf, - statep->dynsymscnidx), NULL); - assert (dynsymdata !=3D NULL); - - Elf_Data *symdata =3D NULL; - if (statep->symscnidx !=3D 0) - { - symdata =3D elf_getdata (elf_getscn (statep->outelf, statep->symscni= dx), - NULL); - assert (symdata !=3D NULL); - } - - /* Create the .plt section. */ - scn =3D elf_getscn (statep->outelf, statep->pltscnidx); - Elf_Data *pltdata =3D elf_getdata (scn, NULL); - assert (pltdata !=3D NULL); - - /* Also create the .rel.plt section data. It simply means relocations - addressing the corresponding entry in the .got.plt section. The - section name is misleading. */ - scn =3D elf_getscn (statep->outelf, statep->pltrelscnidx); - xelf_getshdr (scn, shdr); - Elf_Data *reldata =3D elf_getdata (scn, NULL); - assert (shdr !=3D NULL && reldata !=3D NULL); - - /* Update the sh_link to point to the section being modified. We - point it here (correctly) to the .got.plt section. Some linkers - (e.g., the GNU binutils linker) point to the .plt section. This - is wrong since the .plt section isn't modified even though the - name .rel.plt suggests that this is correct. */ - shdr->sh_link =3D statep->dynsymscnidx; - shdr->sh_info =3D statep->gotpltscnidx; - (void) xelf_update_shdr (scn, shdr); - - /* Create the first entry of the .plt section. */ - assert (pltdata->d_size >=3D PLT_ENTRY_SIZE); - if (build_dso) - /* Copy the entry. It's complete, no relocation needed. */ - memcpy (pltdata->d_buf, elf_i386_pic_plt0_entry, PLT_ENTRY_SIZE); - else - { - /* Copy the skeleton. */ - memcpy (pltdata->d_buf, elf_i386_plt0_entry, PLT_ENTRY_SIZE); - - /* And fill in the addresses. */ - struct plt0_entry *addr =3D (struct plt0_entry *) pltdata->d_buf; - addr->gotp4_addr =3D target_bswap_32 (gotaddr + 4); - addr->gotp8_addr =3D target_bswap_32 (gotaddr + 8); - } - - /* For DSOs we need GOT offsets, otherwise the GOT address. */ - Elf32_Addr gotaddr_off =3D build_dso ? 0 : gotaddr; - - /* Create the remaining entries. */ - const unsigned char *plt_template - =3D build_dso ? elf_i386_pic_plt_entry : elf_i386_plt_entry; - - for (size_t idx =3D nsym_local; idx < nsym; ++idx) - { - struct symbol *symbol =3D ndxtosym[idx]; - if (symbol =3D=3D NULL || symbol->type !=3D STT_FUNC - || ndxtosym[idx]->outdynsymidx =3D=3D 0 - // XXX is the following test correct? - || ! ndxtosym[idx]->in_dso) - continue; - - size_t pltidx =3D symbol->merge.value; - - assert (pltidx > 0); - assert ((3 + pltidx) * sizeof (Elf32_Word) <=3D data->d_size); - - /* Address in the PLT. */ - Elf32_Addr pltentryaddr =3D (pltshdr->sh_addr + pltidx * PLT_ENTRY_S= IZE); - - /* Point the GOT entry at the PLT entry, after the initial jmp. */ - ((Elf32_Word *) data->d_buf)[2 + pltidx] =3D pltentryaddr + 6; - - /* If the symbol is defined, adjust the address. */ - if (((Elf32_Sym *) dynsymdata->d_buf)[ndxtosym[idx]->outdynsymidx].s= t_shndx !=3D SHN_UNDEF) - { - /* The value of the symbol is the address of the corresponding PLT - entry. Store the address, also for the normal symbol table if - this is necessary. */ - ((Elf32_Sym *) dynsymdata->d_buf)[pltidx].st_value =3D pltentryaddr; - - if (symdata !=3D NULL) - { - assert(nsym - statep->nplt + (pltidx - 1) =3D=3D idx); - ((Elf32_Sym *) symdata->d_buf)[nsym - statep->nplt - + (pltidx - 1)].st_value - =3D pltentryaddr; - } - } - - /* Copy the PLT entry template. */ - assert (pltdata->d_size >=3D (1 + pltidx) * PLT_ENTRY_SIZE); - struct plt_entry *addr =3D (struct plt_entry *) ((char *) pltdata->d= _buf - + (pltidx - * PLT_ENTRY_SIZE)); - memcpy (addr, plt_template, PLT_ENTRY_SIZE); - - /* And once more, fill in the addresses. First the address of - this symbol in .got. */ - addr->offset_got =3D target_bswap_32 (gotaddr_off - + (2 + pltidx) * sizeof (Elf32_Addr)); - /* Offset into relocation table. */ - addr->push_imm =3D target_bswap_32 ((pltidx - 1) * sizeof (Elf32_Rel= )); - /* Offset to start of .plt. */ - addr->plt0_offset =3D target_bswap_32 (-(1 + pltidx) * PLT_ENTRY_SIZ= E); - - - XElf_Rel_vardef (rel); - assert (pltidx * sizeof (Elf32_Rel) <=3D reldata->d_size); - xelf_getrel_ptr (reldata, pltidx - 1, rel); - rel->r_offset =3D gotaddr + (2 + pltidx) * sizeof (Elf32_Addr); - /* The symbol table entries for the functions from DSOs are at - the beginning of the symbol table. */ - rel->r_info =3D XELF_R_INFO (ndxtosym[idx]->outdynsymidx, R_386_JMP_= SLOT); - (void) xelf_update_rel (reldata, pltidx - 1, rel); - } -} - - -static int -elf_i386_rel_type (struct ld_state *statep __attribute__ ((__unused__))) -{ - /* ELF/i386 uses REL. */ - return DT_REL; -} - - -static void -elf_i386_count_relocations (struct ld_state *statep, struct scninfo *scnin= fo) -{ - /* We go through the list of input sections and count those relocations - which are not handled by the linker. At the same time we have to - see how many GOT entries we need and how much .bss space is needed - for copy relocations. */ - Elf_Data *data =3D elf_getdata (scninfo->scn, NULL); - XElf_Shdr *shdr =3D &SCNINFO_SHDR (scninfo->shdr); - size_t maxcnt =3D shdr->sh_size / shdr->sh_entsize; - size_t relsize =3D 0; - size_t cnt; - struct symbol *sym; - - assert (shdr->sh_type =3D=3D SHT_REL); - - for (cnt =3D 0; cnt < maxcnt; ++cnt) - { - XElf_Rel_vardef (rel); - - xelf_getrel (data, cnt, rel); - /* XXX Should we complain about failing accesses? */ - if (rel !=3D NULL) - { - Elf32_Word r_sym =3D XELF_R_SYM (rel->r_info); - - /* Symbols in COMDAT group sections which are discarded do - not have to be relocated. */ - if (r_sym >=3D scninfo->fileinfo->nlocalsymbols - && unlikely (scninfo->fileinfo->symref[r_sym] =3D=3D NULL)) - continue; - - switch (XELF_R_TYPE (rel->r_info)) - { - case R_386_GOT32: - if (! scninfo->fileinfo->symref[r_sym]->defined - || scninfo->fileinfo->symref[r_sym]->in_dso - || statep->file_type =3D=3D dso_file_type) - { - relsize +=3D sizeof (Elf32_Rel); - ++statep->nrel_got; - } - - /* Even if this relocation is not emitted in the output - file it requires a GOT entry. */ - ++statep->ngot; - - /* FALLTHROUGH */ - - case R_386_GOTOFF: - case R_386_GOTPC: - statep->need_got =3D true; - break; - - case R_386_32: - case R_386_PC32: - /* These relocations cause text relocations in DSOs. */ - if (linked_from_dso_p (scninfo, r_sym)) - { - if (statep->file_type =3D=3D dso_file_type) - { - relsize +=3D sizeof (Elf32_Rel); - // XXX Do we have to check whether the target - // XXX section is read-only first? - statep->dt_flags |=3D DF_TEXTREL; - } - else - { - /* Non-function objects from a DSO need to get a - copy relocation. */ - sym =3D scninfo->fileinfo->symref[r_sym]; - - /* Only do this if we have not requested a copy - relocation already. */ - if (unlikely (sym->type !=3D STT_FUNC) && ! sym->need_copy) - { - sym->need_copy =3D 1; - ++statep->ncopy; - relsize +=3D sizeof (Elf32_Rel); - } - } - } - else if (statep->file_type =3D=3D dso_file_type - && XELF_R_TYPE (rel->r_info) =3D=3D R_386_32) - relsize +=3D sizeof (Elf32_Rel); - - break; - - case R_386_PLT32: - /* We might need a PLT entry. But we cannot say for sure - here since one of the symbols might turn up being - defined in the executable (if we create such a thing). - If a DSO is created we still might use a local - definition. - - If the symbol is not defined and we are not creating - a statically linked binary, then we need in any case - a PLT entry. */ - if (! scninfo->fileinfo->symref[r_sym]->defined - && !statep->statically) - { - sym =3D scninfo->fileinfo->symref[r_sym]; - sym->type =3D STT_FUNC; - sym->in_dso =3D 1; - sym->defined =3D 1; - - /* Remove from the list of unresolved symbols. */ - --statep->nunresolved; - if (! sym->weak) - --statep->nunresolved_nonweak; - CDBL_LIST_DEL (statep->unresolved, sym); - - /* Add to the list of symbols we expect from a DSO. */ - ++statep->nplt; - ++statep->nfrom_dso; - CDBL_LIST_ADD_REAR (statep->from_dso, sym); - } - break; - - case R_386_TLS_LDO_32: - if (statep->file_type !=3D executable_file_type) - abort (); - /* We do not need a relocation in the output file. */ - break; - - case R_386_TLS_LE: - /* We never need a relocation in the output file. */ - break; - - case R_386_TLS_IE: - if (statep->file_type =3D=3D dso_file_type) - error (EXIT_FAILURE, 0, gettext ("initial-executable TLS relocation cann= ot be used ")); - if (!scninfo->fileinfo->symref[r_sym]->defined - || scninfo->fileinfo->symref[r_sym]->in_dso) - { - abort (); - } - break; - - case R_386_TLS_GD: - if (statep->file_type !=3D executable_file_type - || !scninfo->fileinfo->symref[r_sym]->defined - || scninfo->fileinfo->symref[r_sym]->in_dso) - { - abort (); - } - break; - - case R_386_TLS_GOTIE: - case R_386_TLS_LDM: - case R_386_TLS_GD_32: - case R_386_TLS_GD_PUSH: - case R_386_TLS_GD_CALL: - case R_386_TLS_GD_POP: - case R_386_TLS_LDM_32: - case R_386_TLS_LDM_PUSH: - case R_386_TLS_LDM_CALL: - case R_386_TLS_LDM_POP: - case R_386_TLS_IE_32: - case R_386_TLS_LE_32: - /* XXX */ - abort (); - break; - - case R_386_NONE: - /* Nothing to be done. */ - break; - - /* These relocation should never be generated by an - assembler. */ - case R_386_COPY: - case R_386_GLOB_DAT: - case R_386_JMP_SLOT: - case R_386_RELATIVE: - case R_386_TLS_DTPMOD32: - case R_386_TLS_DTPOFF32: - case R_386_TLS_TPOFF32: - /* Unknown relocation. */ - default: - abort (); - } - } - } - - scninfo->relsize =3D relsize; -} - - -static void -elf_i386_create_relocations (struct ld_state *statep, - const Elf32_Word *dblindirect __attribute__ ((unused))) -{ - /* Get the address of the got section. */ - Elf_Scn *pltscn =3D elf_getscn (statep->outelf, statep->pltscnidx); - Elf32_Shdr *shdr =3D elf32_getshdr (pltscn); - assert (shdr !=3D NULL); - Elf32_Addr pltaddr =3D shdr->sh_addr; - - Elf_Scn *gotscn =3D elf_getscn (statep->outelf, statep->gotscnidx); - // XXX Adjust the address, if necessary, for relro - Elf_Data *gotdata =3D NULL; - if (statep->need_got) - { - gotdata =3D elf_getdata (gotscn, NULL); - assert (gotdata !=3D NULL); - } - - Elf_Scn *gotpltscn =3D elf_getscn (statep->outelf, statep->gotpltscnidx); - shdr =3D elf32_getshdr (gotpltscn); - assert (shdr !=3D NULL); - Elf32_Addr gotaddr =3D shdr->sh_addr; - - Elf_Scn *reldynscn =3D elf_getscn (statep->outelf, statep->reldynscnidx); - Elf_Data *reldyndata =3D elf_getdata (reldynscn, NULL); - assert (reldyndata !=3D NULL); - - size_t nreldyn =3D 0; - size_t ngotconst =3D statep->nrel_got; - - struct scninfo *first =3D statep->rellist->next; - struct scninfo *runp =3D first; - do - { - XElf_Shdr *rshdr =3D &SCNINFO_SHDR (runp->shdr); - Elf_Data *reldata =3D elf_getdata (runp->scn, NULL); - int nrels =3D rshdr->sh_size / rshdr->sh_entsize; - - /* We will need the following values a couple of times. Help - the compiler and improve readability. */ - struct symbol **symref =3D runp->fileinfo->symref; - struct scninfo *scninfo =3D runp->fileinfo->scninfo; - - /* This is the offset of the input section we are looking at in - the output file. */ - XElf_Addr inscnoffset =3D scninfo[rshdr->sh_info].offset; - - /* The target section. We use the data from the input file. */ - Elf_Data *data =3D elf_getdata (scninfo[rshdr->sh_info].scn, NULL); - - /* We cannot handle relocations against merge-able sections. */ - assert ((SCNINFO_SHDR (scninfo[rshdr->sh_link].shdr).sh_flags - & SHF_MERGE) =3D=3D 0); - - /* Cache the access to the symbol table data. */ - Elf_Data *symdata =3D elf_getdata (scninfo[rshdr->sh_link].scn, NULL= ); - - for (int cnt =3D 0; cnt < nrels; ++cnt) - { - XElf_Rel_vardef (rel); - XElf_Rel *rel2; - xelf_getrel (reldata, cnt, rel); - assert (rel !=3D NULL); - XElf_Addr reladdr =3D inscnoffset + rel->r_offset; - XElf_Addr value; - - size_t idx =3D XELF_R_SYM (rel->r_info); - if (idx < runp->fileinfo->nlocalsymbols) - { - XElf_Sym_vardef (sym); - xelf_getsym (symdata, idx, sym); - - /* The value only depends on the position of the referenced - section in the output file and the addend. */ - value =3D scninfo[sym->st_shndx].offset + sym->st_value; - } - else - { - if (symref[idx] =3D=3D NULL) - /* Symbol in ignored COMDAT group section. */ - continue; - - value =3D symref[idx]->merge.value; - if (symref[idx]->in_dso) - { - /* MERGE.VALUE contains the PLT index. If this is not for - a function the actual value will be computed later. */ - assert (value !=3D 0 || symref[idx]->type !=3D STT_FUNC); - value =3D pltaddr + value * PLT_ENTRY_SIZE; - } - } - - /* Address of the relocated memory in the data buffer. */ - unsigned char *relloc =3D (unsigned char *) data->d_buf + rel->r_offset; - - uint32_t thisgotidx; - switch (XELF_R_TYPE (rel->r_info)) - { - /* These three cases can be handled together since the - symbol associated with the R_386_GOTPC relocation is - _GLOBAL_OFFSET_TABLE_ which has a value corresponding - to the address of the GOT and the address of the PLT - entry required for R_386_PLT32 is computed above. */ - case R_386_PC32: - case R_386_GOTPC: - case R_386_PLT32: - value -=3D reladdr; - /* FALLTHROUGH */ - - case R_386_32: - if (linked_from_dso_p (scninfo, idx) - && statep->file_type !=3D dso_file_type - && symref[idx]->type !=3D STT_FUNC) - { - value =3D (ld_state.copy_section->offset - + symref[idx]->merge.value); - - if (unlikely (symref[idx]->need_copy)) - { - /* Add a relocation to initialize the GOT entry. */ - assert (symref[idx]->outdynsymidx !=3D 0); -#if NATIVE_ELF !=3D 0 - xelf_getrel_ptr (reldyndata, nreldyn, rel2); -#else - rel2 =3D &rel_mem; -#endif - rel2->r_offset =3D value; - rel2->r_info - =3D XELF_R_INFO (symref[idx]->outdynsymidx, R_386_COPY); - (void) xelf_update_rel (reldyndata, nreldyn, rel2); - ++nreldyn; - assert (nreldyn <=3D statep->nrel_got); - - /* Update the symbol table record for the new - address. */ - Elf32_Word symidx =3D symref[idx]->outdynsymidx; - Elf_Scn *symscn =3D elf_getscn (statep->outelf, - statep->dynsymscnidx); - Elf_Data *outsymdata =3D elf_getdata (symscn, NULL); - assert (outsymdata !=3D NULL); - XElf_Sym_vardef (sym); - xelf_getsym (outsymdata, symidx, sym); - sym->st_value =3D value; - sym->st_shndx =3D statep->copy_section->outscnndx; - (void) xelf_update_sym (outsymdata, symidx, sym); - - symidx =3D symref[idx]->outsymidx; - if (symidx !=3D 0) - { - symidx =3D statep->dblindirect[symidx]; - symscn =3D elf_getscn (statep->outelf, - statep->symscnidx); - outsymdata =3D elf_getdata (symscn, NULL); - assert (outsymdata !=3D NULL); - xelf_getsym (outsymdata, symidx, sym); - sym->st_value =3D value; - sym->st_shndx =3D statep->copy_section->outscnndx; - (void) xelf_update_sym (outsymdata, symidx, sym); - } - - /* Remember that we set up the copy relocation. */ - symref[idx]->need_copy =3D 0; - } - } - else if (statep->file_type =3D=3D dso_file_type - && XELF_R_TYPE (rel->r_info) =3D=3D R_386_32) - { -#if NATIVE_ELF !=3D 0 - xelf_getrel_ptr (reldyndata, nreldyn, rel2); -#else - rel2 =3D &rel_mem; -#endif - rel2->r_offset =3D value; - - /* For symbols we do not export we generate a relative - relocation. */ - if (idx < SCNINFO_SHDR (scninfo[rshdr->sh_link].shdr).sh_info - || symref[idx]->outdynsymidx =3D=3D 0) - rel2->r_info =3D XELF_R_INFO (0, R_386_RELATIVE); - else - rel2->r_info - =3D XELF_R_INFO (symref[idx]->outdynsymidx, R_386_32); - (void) xelf_update_rel (reldyndata, nreldyn, rel2); - ++nreldyn; - assert (nreldyn <=3D statep->nrel_got); - - value =3D 0; - } - add_4ubyte_unaligned (relloc, value); - break; - - case R_386_GOT32: - if (! symref[idx]->defined || symref[idx]->in_dso) - { - thisgotidx =3D nreldyn++; - assert (thisgotidx < statep->nrel_got); - - /* Add a relocation to initialize the GOT entry. */ -#if NATIVE_ELF !=3D 0 - xelf_getrel_ptr (reldyndata, thisgotidx, rel2); -#else - rel2 =3D &rel_mem; -#endif - rel2->r_offset =3D gotaddr + ((thisgotidx - statep->ngot) - * sizeof (Elf32_Addr)); - rel2->r_info - =3D XELF_R_INFO (symref[idx]->outdynsymidx, R_386_GLOB_DAT); - (void) xelf_update_rel (reldyndata, thisgotidx, rel2); - } - else if (statep->file_type !=3D dso_file_type) - { - thisgotidx =3D ngotconst++; - assert (thisgotidx < statep->ngot); - - /* We have to use a GOT since the generated code - requires it but we know the address and therefore - do not need a relocation. */ - ((uint32_t *) gotdata->d_buf)[thisgotidx] =3D value; - } - else - { - thisgotidx =3D nreldyn++; - assert (thisgotidx < statep->nrel_got); - - // XXX generate a relative relocation. - abort (); - } - - store_4ubyte_unaligned (relloc, - (thisgotidx - statep->ngot) - * sizeof (Elf32_Addr)); - break; - - case R_386_GOTOFF: - add_4ubyte_unaligned (relloc, value - gotaddr); - break; - - case R_386_TLS_LE: - value =3D symref[idx]->merge.value - ld_state.tls_tcb; - store_4ubyte_unaligned (relloc, value); - break; - - case R_386_TLS_IE: - if (symref[idx]->defined && !symref[idx]->in_dso) - { - /* The symbol is defined in the executable. - Perform the IE->LE optimization. - There are multiple versions, though. - - First version: mov ADDR,REG. */ - if (relloc[-2] =3D=3D 0x8b - && ((relloc[-1] & 0xc7) =3D=3D 0x05)) - { - relloc[-2] =3D 0xc7; - relloc[-1] =3D 0xc0 | ((relloc[-1] >> 3) & 7); - store_4ubyte_unaligned (relloc, (symref[idx]->merge.value - - ld_state.tls_tcb)); - } - else - { - abort (); - } - } - else - { - abort (); - } - break; - - case R_386_TLS_LDO_32: - value =3D symref[idx]->merge.value - ld_state.tls_start; - store_4ubyte_unaligned (relloc, value); - break; - - case R_386_TLS_GD: - if (ld_state.file_type =3D=3D executable_file_type) - { - if (symref[idx]->defined && !symref[idx]->in_dso) - { - /* The symbol is defined in the executable. - Perform the GD->LE optimization. */ - static const char gd_to_le[] =3D - { - /* mov %gs:0x0,%eax */ - 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, - /* sub $OFFSET,%eax */ - 0x81, 0xe8 - }; -#ifndef NDEBUG - static const char gd_text[] =3D - { - /* lea 0x0(,%ebx,1),%eax */ - 0x8d, 0x04, 0x1d, 0x00, 0x00, 0x00, 0x00, - /* call ___tls_get_addr */ - 0xe8 - }; - assert (memcmp (relloc - 3, gd_text, sizeof (gd_text)) - =3D=3D 0); -#endif - relloc =3D mempcpy (relloc - 3, gd_to_le, - sizeof (gd_to_le)); - value =3D ld_state.tls_tcb- symref[idx]->merge.value; - store_4ubyte_unaligned (relloc, value); - - /* We have to skip over the next relocation which is - the matching R_i386_PLT32 for __tls_get_addr. */ - ++cnt; -#ifndef NDEBUG - assert (cnt < nrels); - XElf_Off old_offset =3D rel->r_offset; - xelf_getrel (reldata, cnt, rel); - assert (rel !=3D NULL); - assert (XELF_R_TYPE (rel->r_info) =3D=3D R_386_PLT32); - idx =3D XELF_R_SYM (rel->r_info); - assert (strcmp (symref[idx]->name, "___tls_get_addr") - =3D=3D 0); - assert (old_offset + 5 =3D=3D rel->r_offset); -#endif - - break; - } - } - abort (); - break; - - case R_386_32PLT: - case R_386_TLS_TPOFF: - case R_386_TLS_GOTIE: - case R_386_TLS_LDM: - case R_386_16: - case R_386_PC16: - case R_386_8: - case R_386_PC8: - case R_386_TLS_GD_32: - case R_386_TLS_GD_PUSH: - case R_386_TLS_GD_CALL: - case R_386_TLS_GD_POP: - case R_386_TLS_LDM_32: - case R_386_TLS_LDM_PUSH: - case R_386_TLS_LDM_CALL: - case R_386_TLS_LDM_POP: - case R_386_TLS_IE_32: - case R_386_TLS_LE_32: - // XXX For now fall through - break; - - case R_386_NONE: - /* Nothing to do. */ - break; - - case R_386_COPY: - case R_386_JMP_SLOT: - case R_386_RELATIVE: - case R_386_GLOB_DAT: - case R_386_TLS_DTPMOD32: - case R_386_TLS_DTPOFF32: - case R_386_TLS_TPOFF32: - default: - /* Should not happen. */ - abort (); - } - } - } - while ((runp =3D runp->next) !=3D first); -} - - -int -elf_i386_ld_init (struct ld_state *statep) -{ - /* We have a few callbacks available. */ - old_open_outfile =3D statep->callbacks.open_outfile; - statep->callbacks.open_outfile =3D elf_i386_open_outfile; - - statep->callbacks.relocate_section =3D elf_i386_relocate_section; - - statep->callbacks.initialize_plt =3D elf_i386_initialize_plt; - statep->callbacks.initialize_pltrel =3D elf_i386_initialize_pltrel; - - statep->callbacks.initialize_got =3D elf_i386_initialize_got; - statep->callbacks.initialize_gotplt =3D elf_i386_initialize_gotplt; - - statep->callbacks.finalize_plt =3D elf_i386_finalize_plt; - - statep->callbacks.rel_type =3D elf_i386_rel_type; - - statep->callbacks.count_relocations =3D elf_i386_count_relocations; - - statep->callbacks.create_relocations =3D elf_i386_create_relocations; - - return 0; -} diff --git a/src/ld.c b/src/ld.c deleted file mode 100644 index 59dccb5..0000000 --- a/src/ld.c +++ /dev/null @@ -1,1607 +0,0 @@ -/* Copyright (C) 2001-2010, 2012 Red Hat, Inc. - This file is part of elfutils. - Written by Ulrich Drepper , 2001. - - This file 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. - - elfutils 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, see . = */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "ld.h" -#include "list.h" - - -/* Name and version of program. */ -static void print_version (FILE *stream, struct argp_state *state); -ARGP_PROGRAM_VERSION_HOOK_DEF =3D print_version; - -/* Bug report address. */ -ARGP_PROGRAM_BUG_ADDRESS_DEF =3D PACKAGE_BUGREPORT; - - -/* Values for the various options. */ -enum - { - ARGP_whole_archive =3D 300, - ARGP_no_whole_archive, - ARGP_static, - ARGP_dynamic, - ARGP_pagesize, - ARGP_rpath_link, - ARGP_runpath, - ARGP_runpath_link, - ARGP_version_script, - ARGP_gc_sections, - ARGP_no_gc_sections, - ARGP_no_undefined, - ARGP_conserve, - ARGP_as_needed, - ARGP_no_as_needed, - ARGP_eh_frame_hdr, - ARGP_hash_style, - ARGP_build_id, -#if YYDEBUG - ARGP_yydebug, -#endif - }; - - -/* Definitions of arguments for argp functions. */ -static const struct argp_option options[] =3D -{ - { NULL, 0, NULL, 0, N_("Input File Control:"), 0 }, - { "whole-archive", ARGP_whole_archive, NULL, 0, - N_("Include whole archives in the output from now on."), 0 }, - { "no-whole-archive", ARGP_no_whole_archive, NULL, 0, - N_("Stop including the whole archives in the output."), 0 }, - { NULL, 'l', N_("FILE"), OPTION_HIDDEN, NULL, 0 }, - { "start-group", '(', NULL, 0, N_("Start a group."), 0 }, - { "end-group", ')', NULL, 0, N_("End a group."), 0 }, - { NULL, 'L', N_("PATH"), 0, - N_("Add PATH to list of directories files are searched in."), 0 }, - { "as-needed", ARGP_as_needed, NULL, 0, - N_("Only set DT_NEEDED for following dynamic libs if actually used"), = 0 }, - { "no-as-needed", ARGP_no_as_needed, NULL, 0, - N_("Always set DT_NEEDED for following dynamic libs"), 0 }, - { "rpath-link", ARGP_rpath_link, "PATH", OPTION_HIDDEN, NULL, 0 }, - { NULL, 'i', NULL, 0, N_("Ignore LD_LIBRARY_PATH environment variable."), - 0 }, - - { NULL, 0, NULL, 0, N_("Output File Control:"), 0 }, - { "output", 'o', N_("FILE"), 0, N_("Place output in FILE."), 0 }, - { NULL, 'z', "KEYWORD", OPTION_HIDDEN, NULL, 0 }, - { "-z nodefaultlib", '\0', NULL, OPTION_DOC, - N_("Object is marked to not use default search path at runtime."), 0 }, - { "-z allextract", '\0', NULL, OPTION_DOC, - N_("Same as --whole-archive."), 0 }, - { "-z defaultextract", '\0', NULL, OPTION_DOC, N_("\ -Default rules of extracting from archive; weak references are not enough."= ), - 0 }, - { "-z weakextract", '\0', NULL, OPTION_DOC, - N_("Weak references cause extraction from archive."), 0 }, - { "-z muldefs", '\0', NULL, OPTION_DOC, - N_("Allow multiple definitions; first is used."), 0 }, - { "-z defs | nodefs", '\0', NULL, OPTION_DOC, - N_("Disallow/allow undefined symbols in DSOs."), 0 }, - { "no-undefined", ARGP_no_undefined, NULL, OPTION_HIDDEN, NULL, 0 }, - { "-z origin", '\0', NULL, OPTION_DOC, - N_("Object requires immediate handling of $ORIGIN."), 0 }, - { "-z now", '\0', NULL, OPTION_DOC, - N_("Relocation will not be processed lazily."), 0 }, - { "-z nodelete", '\0', NULL, OPTION_DOC, - N_("Object cannot be unloaded at runtime."), 0 }, - { "-z initfirst", '\0', NULL, OPTION_DOC, - N_("Mark object to be initialized first."), 0 }, - { "-z lazyload | nolazyload", '\0', NULL, OPTION_DOC, - N_("Enable/disable lazy-loading flag for following dependencies."), 0 = }, - { "-z nodlopen", '\0', NULL, OPTION_DOC, - N_("Mark object as not loadable with 'dlopen'."), 0 }, - { "-z ignore | record", '\0', NULL, OPTION_DOC, - N_("Ignore/record dependencies on unused DSOs."), 0 }, - { "-z systemlibrary", '\0', NULL, OPTION_DOC, - N_("Generated DSO will be a system library."), 0 }, - { "entry", 'e', N_("ADDRESS"), 0, N_("Set entry point address."), 0 }, - { "static", ARGP_static, NULL, OPTION_HIDDEN, NULL, 0 }, - { "-B static", ARGP_static, NULL, OPTION_DOC, - N_("Do not link against shared libraries."), 0 }, - { "dynamic", ARGP_dynamic, NULL, OPTION_HIDDEN, NULL, 0 }, - { "-B dynamic", ARGP_dynamic, NULL, OPTION_DOC, - N_("Prefer linking against shared libraries."), 0 }, - { "export-dynamic", 'E', NULL, 0, N_("Export all dynamic symbols."), 0 }, - { "strip-all", 's', NULL, 0, N_("Strip all symbols."), 0 }, - { "strip-debug", 'S', NULL, 0, N_("Strip debugging symbols."), 0 }, - { "pagesize", ARGP_pagesize, "SIZE", 0, - N_("Assume pagesize for the target system to be SIZE."), 0 }, - { "rpath", 'R', "PATH", OPTION_HIDDEN, NULL, 0 }, - { "runpath", ARGP_runpath, "PATH", 0, N_("Set runtime DSO search path."), - 0 }, - { "runpath-link", ARGP_runpath_link, "PATH", 0, - N_("Set link time DSO search path."), 0 }, - { "shared", 'G', NULL, 0, N_("Generate dynamic shared object."), 0 }, - { NULL, 'r', NULL, 0L, N_("Generate relocatable object."), 0 }, - { NULL, 'B', "KEYWORD", OPTION_HIDDEN, "", 0 }, - { "-B local", 'B', NULL, OPTION_DOC, - N_("Causes symbol not assigned to a version be reduced to local."), 0 = }, - { "gc-sections", ARGP_gc_sections, NULL, 0, N_("Remove unused sections."= ), - 0 }, - { "no-gc-sections", ARGP_no_gc_sections, NULL, 0, - N_("Don't remove unused sections."), 0 }, - { "soname", 'h', "NAME", 0, N_("Set soname of shared object."), 0 }, - { "dynamic-linker", 'I', "NAME", 0, N_("Set the dynamic linker name."), = 0 }, - { NULL, 'Q', "YN", OPTION_HIDDEN, NULL, 0 }, - { "-Q y | n", 'Q', NULL, OPTION_DOC, - N_("Add/suppress addition indentifying link-editor to .comment section= ."), - 0 }, - { "eh-frame-hdr", ARGP_eh_frame_hdr, NULL, 0, - N_("Create .eh_frame_hdr section"), 0 }, - { "hash-style", ARGP_hash_style, "STYLE", 0, - N_("Set hash style to sysv, gnu or both."), 0 }, - { "build-id", ARGP_build_id, "STYLE", OPTION_ARG_OPTIONAL, - N_("Generate build ID note (md5, sha1 (default), uuid)."), 0 }, - - { NULL, 0, NULL, 0, N_("Linker Operation Control:"), 0 }, - { "verbose", 'v', NULL, 0, N_("Verbose messages."), 0 }, - { "trace", 't', NULL, 0, N_("Trace file opens."), 0 }, - { "conserve-memory", ARGP_conserve, NULL, 0, - N_("Trade speed for less memory usage"), 0 }, - { NULL, 'O', N_("LEVEL"), OPTION_ARG_OPTIONAL, - N_("Set optimization level to LEVEL."), 0 }, - { NULL, 'c', N_("FILE"), 0, N_("Use linker script in FILE."), 0 }, -#if YYDEBUG - { "yydebug", ARGP_yydebug, NULL, 0, - N_("Select to get parser debug information"), 0 }, -#endif - { "version-script", ARGP_version_script, "FILE", 0, - N_("Read version information from FILE."), 0 }, - { "emulation", 'm', "NAME", 0, N_("Set emulation to NAME."), 0 }, - - { NULL, 0, NULL, 0, NULL, 0 } -}; - -/* Short description of program. */ -static const char doc[] =3D N_("Combine object and archive files."); - -/* Strings for arguments in help texts. */ -static const char args_doc[] =3D N_("[FILE]..."); - -/* Prototype for option handler. */ -static void replace_args (int argc, char *argv[]); -static error_t parse_opt_1st (int key, char *arg, struct argp_state *state= ); -static error_t parse_opt_2nd (int key, char *arg, struct argp_state *state= ); - -/* Data structure to communicate with argp functions. */ -static struct argp argp_1st =3D -{ - options, parse_opt_1st, args_doc, doc, NULL, NULL, NULL -}; -static struct argp argp_2nd =3D -{ - options, parse_opt_2nd, args_doc, doc, NULL, NULL, NULL -}; - - -/* Linker state. This contains all global information. */ -struct ld_state ld_state; - -/* List of the input files. */ -static struct file_list -{ - const char *name; - struct file_list *next; -} *input_file_list; - -/* If nonzero be verbose. */ -int verbose; - -/* If nonzero, trade speed for less memory/address space usage. */ -int conserve_memory; - -/* The emulation name to use. */ -static const char *emulation; - -/* Keep track of the nesting level. Even though we don't handle nested - groups we still keep track to improve the error messages. */ -static int group_level; - -/* The last file we processed. */ -static struct usedfiles *last_file; - -/* The default linker script. */ -/* XXX We'll do this a bit different in the real solution. */ -static const char *linker_script =3D SRCDIR "/elf32-i386.script"; - -/* Nonzero if an error occurred while loading the input files. */ -static int error_loading; - - -/* Intermediate storage for the LD_LIBRARY_PATH information from the - environment. */ -static char *ld_library_path1; - -/* Flag used to communicate with the scanner. */ -int ld_scan_version_script; - -/* Name of the input file. */ -const char *ldin_fname; - -/* Define by parser if required. */ -extern int lddebug; - - -/* Prototypes for local functions. */ -static void parse_z_option (const char *arg); -static void parse_z_option_2 (const char *arg); -static void parse_B_option (const char *arg); -static void parse_B_option_2 (const char *arg); -static void determine_output_format (void); -static void load_needed (void); -static void collect_sections (void); -static void add_rxxpath (struct pathelement **pathp, const char *str); -static void gen_rxxpath_data (void); -static void read_version_script (const char *fname); -static void create_lscript_symbols (void); -static void create_special_section_symbol (struct symbol **symp, - const char *name); - - -int -main (int argc, char *argv[]) -{ - int remaining; - int err; - - /* Sanity check. We always want to use the LFS functionality. */ - if (sizeof (off_t) !=3D 8) - abort (); - - /* We use no threads here which can interfere with handling a stream. */ - __fsetlocking (stdin, FSETLOCKING_BYCALLER); - __fsetlocking (stdout, FSETLOCKING_BYCALLER); - __fsetlocking (stderr, FSETLOCKING_BYCALLER); - - /* Set locale. */ - setlocale (LC_ALL, ""); - - /* Make sure the message catalog can be found. */ - bindtextdomain (PACKAGE_TARNAME, LOCALEDIR); - - /* Initialize the message catalog. */ - textdomain (PACKAGE_TARNAME); - - /* Before we start tell the ELF library which version we are using. */ - elf_version (EV_CURRENT); - - /* The user can use the LD_LIBRARY_PATH environment variable to add - additional lookup directories. */ - ld_library_path1 =3D getenv ("LD_LIBRARY_PATH"); - - /* Initialize the memory handling. */ -#define obstack_chunk_alloc xmalloc -#define obstack_chunk_free free - obstack_init (&ld_state.smem); - - /* Recognize old-style parameters for compatibility. */ - replace_args (argc, argv); - - /* One quick pass over the parameters which allows us to scan for options - with global effect which influence the rest of the processing. */ - argp_parse (&argp_1st, argc, argv, ARGP_IN_ORDER, &remaining, NULL); - - /* We need at least one input file. */ - if (input_file_list =3D=3D NULL) - { - error (0, 0, gettext ("At least one input file needed")); - argp_help (&argp_1st, stderr, ARGP_HELP_SEE, "ld"); - exit (EXIT_FAILURE); - } - - /* Determine which ELF backend to use. */ - determine_output_format (); - - /* If no hash style was specific default to the oldand slow SysV - method. */ - if (unlikely (ld_state.hash_style =3D=3D hash_style_none)) - ld_state.hash_style =3D hash_style_sysv; - - /* Prepare state. */ - err =3D ld_prepare_state (emulation); - if (err !=3D 0) - error (EXIT_FAILURE, 0, gettext ("error while preparing linking")); - - /* XXX Read the linker script now. Since we later will have the linker - script built in we don't go into trouble to make sure we handle GROUP - statements in the script. This simply must not happen. */ - ldin =3D fopen (linker_script, "r"); - if (ldin =3D=3D NULL) - error (EXIT_FAILURE, errno, gettext ("cannot open linker script '%s'"), - linker_script); - /* No need for locking. */ - __fsetlocking (ldin, FSETLOCKING_BYCALLER); - - ld_state.srcfiles =3D NULL; - ldlineno =3D 1; - ld_scan_version_script =3D 0; - ldin_fname =3D linker_script; - if (ldparse () !=3D 0) - /* Something went wrong during parsing. */ - exit (EXIT_FAILURE); - fclose (ldin); - - /* We now might have a list of directories to look for libraries in - named by the linker script. Put them in a different list so that - they are searched after all paths given by the user on the - command line. */ - ld_state.default_paths =3D ld_state.paths; - ld_state.paths =3D ld_state.tailpaths =3D NULL; - - /* Get runpath/rpath information in usable form. */ - gen_rxxpath_data (); - - /* Parse and process arguments for real. */ - argp_parse (&argp_2nd, argc, argv, ARGP_IN_ORDER, &remaining, NULL); - /* All options should have been processed by the argp parser. */ - assert (remaining =3D=3D argc); - - /* Process the last file. */ - while (last_file !=3D NULL) - /* Try to open the file. */ - error_loading |=3D FILE_PROCESS (-1, last_file, &ld_state, &last_file); - - /* Stop if there has been a problem while reading the input files. */ - if (error_loading) - exit (error_loading); - - /* See whether all opened -( were closed. */ - if (group_level > 0) - { - error (0, 0, gettext ("-( without matching -)")); - argp_help (&argp_1st, stderr, ARGP_HELP_SEE, "ld"); - exit (EXIT_FAILURE); - } - - /* When we create a relocatable file we don't have to look for the - DT_NEEDED DSOs and we also don't test for undefined symbols. */ - if (ld_state.file_type !=3D relocatable_file_type) - { - /* At this point we have loaded all the direct dependencies. What - remains to be done is find the indirect dependencies. These are - DSOs which are referenced by the DT_NEEDED entries in the DSOs - which are direct dependencies. We have to transitively find and - load all these dependencies. */ - load_needed (); - - /* At this point all object files and DSOs are read. If there - are still undefined symbols left they might have to be - synthesized from the linker script. */ - create_lscript_symbols (); - - /* Now that we have loaded all the object files we can determine - whether we have any non-weak unresolved references left. If - there are any we stop. If the user used the '-z nodefs' option - and we are creating a DSO don't perform the tests. */ - if (FLAG_UNRESOLVED (&ld_state) !=3D 0) - exit (1); - } - - /* Collect information about the relocations which will be carried - forward into the output. We have to do this here and now since - we need to know which sections have to be created. */ - if (ld_state.file_type !=3D relocatable_file_type) - { - void *p ; - struct scnhead *h; - - p =3D NULL; - while ((h =3D ld_section_tab_iterate (&ld_state.section_tab, &p)) != =3D NULL) - if (h->type =3D=3D SHT_REL || h->type =3D=3D SHT_RELA) - { - struct scninfo *runp =3D h->last; - do - { - /* If we are processing the relocations determine how - many will be in the output file. Also determine - how many GOT entries are needed. */ - COUNT_RELOCATIONS (&ld_state, runp); - - ld_state.relsize_total +=3D runp->relsize; - } - while ((runp =3D runp->next) !=3D h->last); - } - } - - /* Not part of the gABI, but part of every psABI: the symbols for the - GOT section. Add the symbol if necessary. */ - if (ld_state.need_got) - create_special_section_symbol (&ld_state.got_symbol, - "_GLOBAL_OFFSET_TABLE_"); - /* Similarly for the _DYNAMIC symbol which points to the dynamic - section. */ - if (dynamically_linked_p ()) - create_special_section_symbol (&ld_state.dyn_symbol, "_DYNAMIC"); - - /* We are ready to start working on the output file. Not all - information has been gather or created yet. This will be done as - we go. Open the file now. */ - if (OPEN_OUTFILE (&ld_state, EM_NONE, ELFCLASSNONE, ELFDATANONE) !=3D 0) - exit (1); - - /* Create the sections which are generated by the linker and are not - present in the input file. The output file must already have - been opened since we need the ELF descriptor to deduce type - sizes. */ - GENERATE_SECTIONS (&ld_state); - - /* At this point we have read all the files and know all the - sections which have to be linked into the application. We do now - create an array listing all the sections. We will than pass this - array to a system specific function which can reorder it at will. - The functions can also merge sections if this is what is - wanted. */ - collect_sections (); - - /* Create the output sections now. This may requires sorting them - first. */ - CREATE_SECTIONS (&ld_state); - - /* Create the output file data. Appropriate code for the selected - output file type is called. */ - if (CREATE_OUTFILE (&ld_state) !=3D 0) - exit (1); - - /* Finalize the output file, write the data out. */ - err |=3D FINALIZE (&ld_state); - - /* Return with an non-zero exit status also if any error message has - been printed. */ - return err | (error_message_count !=3D 0); -} - - -static void -replace_args (int argc, char *argv[]) -{ - static const struct - { - const char *from; - const char *to; - } args[] =3D - { - { "-export-dynamic", "--export-dynamic" }, - { "-dynamic-linker", "--dynamic-linker" }, - { "-static", "--static" }, - }; - const size_t nargs =3D sizeof (args) / sizeof (args[0]); - - for (int i =3D 1; i < argc; ++i) - if (argv[i][0] =3D=3D '-' && islower (argv[i][1]) && argv[i][2] !=3D '= \0') - for (size_t j =3D 0; j < nargs; ++j) - if (strcmp (argv[i], args[j].from) =3D=3D 0) - { - argv[i] =3D (char *) args[j].to; - break; - } -} - - -static int -valid_hexarg (const char *arg) -{ - if (strncasecmp (arg, "0x", 2) !=3D 0) - return 0; - - arg +=3D 2; - do - { - if (isxdigit (arg[0]) && isxdigit (arg[1])) - { - arg +=3D 2; - if (arg[0] =3D=3D '-' || arg[0] =3D=3D ':') - ++arg; - } - else - return 0; - } - while (*arg !=3D '\0'); - - return 1; -} - - -/* Quick scan of the parameter list for options with global effect. */ -static error_t -parse_opt_1st (int key, char *arg, - struct argp_state *state __attribute__ ((unused))) -{ - switch (key) - { - case 'B': - parse_B_option (arg); - break; - - case 'c': - linker_script =3D arg; - break; - - case 'E': - ld_state.export_all_dynamic =3D true; - break; - - case 'G': - if (ld_state.file_type !=3D no_file_type) - error (EXIT_FAILURE, 0, - gettext ("only one option of -G and -r is allowed")); - ld_state.file_type =3D dso_file_type; - - /* If we generate a DSO we have to export all symbols. */ - ld_state.export_all_dynamic =3D true; - break; - - case 'h': - ld_state.soname =3D arg; - break; - - case 'i': - /* Discard the LD_LIBRARY_PATH value we found. */ - ld_library_path1 =3D NULL; - break; - - case 'I': - ld_state.interp =3D arg; - break; - - case 'm': - if (emulation !=3D NULL) - error (EXIT_FAILURE, 0, gettext ("more than one '-m' parameter")); - emulation =3D arg; - break; - - case 'Q': - if (arg[1] =3D=3D '\0' && (arg[0] =3D=3D 'y' || arg[0] =3D=3D 'Y')) - ld_state.add_ld_comment =3D true; - else if (arg[1] =3D=3D '\0' && (arg[0] =3D=3D 'n' || arg[0] =3D=3D '= N')) - ld_state.add_ld_comment =3D true; - else - error (EXIT_FAILURE, 0, gettext ("unknown option `-%c %s'"), 'Q', arg); - break; - - case 'r': - if (ld_state.file_type !=3D no_file_type) - error (EXIT_FAILURE, 0, - gettext ("only one option of -G and -r is allowed")); - ld_state.file_type =3D relocatable_file_type; - break; - - case 'S': - ld_state.strip =3D strip_debug; - break; - - case 't': - ld_state.trace_files =3D true; - break; - - case 'v': - verbose =3D 1; - break; - - case 'z': - /* The SysV linker used 'z' to pass various flags to the linker. - We follow this. See 'parse_z_option' for the options we - recognize. */ - parse_z_option (arg); - break; - - case ARGP_pagesize: - { - char *endp; - ld_state.pagesize =3D strtoul (arg, &endp, 0); - if (*endp !=3D '\0') - { - if (endp[1] =3D=3D '\0' && tolower (*endp) =3D=3D 'k') - ld_state.pagesize *=3D 1024; - else if (endp[1] =3D=3D '\0' && tolower (*endp) =3D=3D 'm') - ld_state.pagesize *=3D 1024 * 1024; - else - { - error (0, 0, - gettext ("invalid page size value '%s': ignored"), - arg); - ld_state.pagesize =3D 0; - } - } - } - break; - - case 'R': - add_rxxpath (&ld_state.rpath, arg); - break; - - case ARGP_rpath_link: - add_rxxpath (&ld_state.rpath_link, arg); - break; - - case ARGP_runpath: - add_rxxpath (&ld_state.runpath, arg); - break; - - case ARGP_runpath_link: - add_rxxpath (&ld_state.runpath_link, arg); - break; - - case ARGP_gc_sections: - case ARGP_no_gc_sections: - ld_state.gc_sections =3D key =3D=3D ARGP_gc_sections; - break; - - case ARGP_eh_frame_hdr: - ld_state.eh_frame_hdr =3D true; - break; - - case ARGP_hash_style: - if (strcmp (arg, "gnu") =3D=3D 0) - ld_state.hash_style =3D hash_style_gnu; - else if (strcmp (arg, "both") =3D=3D 0) - ld_state.hash_style =3D hash_style_gnu | hash_style_sysv; - else if (strcmp (arg, "sysv") =3D=3D 0) - ld_state.hash_style =3D hash_style_sysv; - else - error (EXIT_FAILURE, 0, gettext ("invalid hash style '%s'"), arg); - break; - - case ARGP_build_id: - if (arg =3D=3D NULL) - ld_state.build_id =3D "sha1"; - else if (strcmp (arg, "uuid") !=3D 0 - && strcmp (arg, "md5") !=3D 0 - && strcmp (arg, "sha1") !=3D 0 - && !valid_hexarg (arg)) - error (EXIT_FAILURE, 0, gettext ("invalid build-ID style '%s'"), arg); - else - ld_state.build_id =3D arg; - break; - - case 's': - if (arg =3D=3D NULL) - { - if (ld_state.strip =3D=3D strip_all) - ld_state.strip =3D strip_everything; - else - ld_state.strip =3D strip_all; - break; - } - /* FALLTHROUGH */ - - case 'e': - case 'o': - case 'O': - case ARGP_whole_archive: - case ARGP_no_whole_archive: - case ARGP_as_needed: - case ARGP_no_as_needed: - case 'L': - case '(': - case ')': - case 'l': - case ARGP_static: - case ARGP_dynamic: - case ARGP_version_script: - /* We'll handle these in the second pass. */ - break; - - case ARGP_KEY_ARG: - { - struct file_list *newp; - - newp =3D (struct file_list *) xmalloc (sizeof (struct file_list)); - newp->name =3D arg; -#ifndef NDEBUG - newp->next =3D NULL; -#endif - CSNGL_LIST_ADD_REAR (input_file_list, newp); - } - break; - -#if YYDEBUG - case ARGP_yydebug: - lddebug =3D 1; - break; -#endif - - case ARGP_no_undefined: - ld_state.nodefs =3D false; - break; - - case ARGP_conserve: - conserve_memory =3D 1; - break; - - default: - return ARGP_ERR_UNKNOWN; - } - return 0; -} - - -/* Handle program arguments for real. */ -static error_t -parse_opt_2nd (int key, char *arg, - struct argp_state *state __attribute__ ((unused))) -{ - static bool group_start_requested; - static bool group_end_requested; - - switch (key) - { - case 'B': - parse_B_option_2 (arg); - break; - - case 'e': - ld_state.entry =3D arg; - break; - - case 'o': - if (ld_state.outfname !=3D NULL) - { - error (0, 0, gettext ("More than one output file name given.")); - see_help: - argp_help (&argp_2nd, stderr, ARGP_HELP_SEE, "ld"); - exit (EXIT_FAILURE); - } - ld_state.outfname =3D arg; - break; - - case 'O': - if (arg =3D=3D NULL) - ld_state.optlevel =3D 1; - else - { - char *endp; - unsigned long int level =3D strtoul (arg, &endp, 10); - if (*endp !=3D '\0') - { - error (0, 0, gettext ("Invalid optimization level `%s'"), arg); - goto see_help; - } - ld_state.optlevel =3D level; - } - break; - - case ARGP_whole_archive: - ld_state.extract_rule =3D allextract; - break; - case ARGP_no_whole_archive: - ld_state.extract_rule =3D defaultextract; - break; - - case ARGP_as_needed: - ld_state.as_needed =3D true; - break; - case ARGP_no_as_needed: - ld_state.as_needed =3D false; - break; - - case ARGP_static: - case ARGP_dynamic: - /* Enable/disable use for DSOs. */ - ld_state.statically =3D key =3D=3D ARGP_static; - break; - - case 'z': - /* The SysV linker used 'z' to pass various flags to the linker. - We follow this. See 'parse_z_option' for the options we - recognize. */ - parse_z_option_2 (arg); - break; - - case ARGP_version_script: - read_version_script (arg); - break; - - case 'L': - /* Add a new search directory. */ - ld_new_searchdir (arg); - break; - - case '(': - /* Start a link group. We have to be able to determine the object - file which is named next. Do this by remembering a pointer to - the pointer which will point to the next object. */ - if (verbose && (group_start_requested || !group_end_requested)) - error (0, 0, gettext ("nested -( -) groups are not allowed")); - - /* Increment the nesting level. */ - ++group_level; - - /* Record group start. */ - group_start_requested =3D true; - group_end_requested =3D false; - break; - - case ')': - /* End a link group. If there is no group open this is clearly - a bug. If there is a group open insert a back reference - pointer in the record for the last object of the group. If - there is no new object or just one don't do anything. */ - if (!group_end_requested) - { - if (group_level =3D=3D 0) - { - error (0, 0, gettext ("-) without matching -(")); - goto see_help; - } - } - else - last_file->group_end =3D true; - - if (group_level > 0) - --group_level; - break; - - case 'l': - case ARGP_KEY_ARG: - { - while (last_file !=3D NULL) - /* Try to open the file. */ - error_loading |=3D FILE_PROCESS (-1, last_file, &ld_state, &last_file); - - last_file =3D ld_new_inputfile (arg, - key =3D=3D 'l' - ? archive_file_type - : relocatable_file_type); - if (group_start_requested) - { - last_file->group_start =3D true; - - group_start_requested =3D false; - group_end_requested =3D true; - } - } - break; - - default: - /* We can catch all other options here. They either have - already been handled or, if the parameter was not correct, - the error has been reported. */ - break; - } - return 0; -} - - -/* Load all the DSOs named as dependencies in other DSOs we already - loaded. */ -static void -load_needed (void) -{ - struct usedfiles *first; - struct usedfiles *runp; - - /* XXX There is one problem here: do we allow references from - regular object files to be satisfied by these implicit - dependencies? The old linker allows this and several libraries - depend on this. Solaris' linker does not allow this; it provides - the user with a comprehensive error message explaining the - situation. - - XXX IMO the old ld behavior is correct since this is also how the - dynamic linker will work. It will look for unresolved references - in all loaded DSOs. - - XXX Should we add an option to get Solaris compatibility? */ - if (ld_state.needed =3D=3D NULL) - return; - - runp =3D first =3D ld_state.needed->next; - do - { - struct usedfiles *ignore; - struct usedfiles *next =3D runp->next; - int err; - - err =3D FILE_PROCESS (-1, runp, &ld_state, &ignore); - if (err !=3D 0) - /* Something went wrong. */ - exit (err); - - runp =3D next; - } - while (runp !=3D first); -} - - -/* Print the version information. */ -static void -print_version (FILE *stream, struct argp_state *state __attribute__ ((unus= ed))) -{ - fprintf (stream, "ld (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION); - fprintf (stream, gettext ("\ -Copyright (C) %s Red Hat, Inc.\n\ -This is free software; see the source for copying conditions. There is NO= \n\ -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE= .\n\ -"), "2012"); - fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); -} - - -/* There are a lot of -z options, parse them here. Some of them have - to be parsed in the first pass, others must be handled in the - second pass. */ -static void -parse_z_option (const char *arg) -{ - if (strcmp (arg, "nodefaultlib") =3D=3D 0 - /* This is only meaningful if we create a DSO. */ - && ld_state.file_type =3D=3D dso_file_type) - ld_state.dt_flags_1 |=3D DF_1_NODEFLIB; - else if (strcmp (arg, "muldefs") =3D=3D 0) - ld_state.muldefs =3D true; - else if (strcmp (arg, "nodefs") =3D=3D 0) - ld_state.nodefs =3D true; - else if (strcmp (arg, "defs") =3D=3D 0) - ld_state.nodefs =3D false; - else if (strcmp (arg, "now") =3D=3D 0) - /* We could also set the DF_1_NOW flag in DT_FLAGS_1 but this isn't - necessary. */ - ld_state.dt_flags |=3D DF_BIND_NOW; - else if (strcmp (arg, "origin") =3D=3D 0) - /* We could also set the DF_1_ORIGIN flag in DT_FLAGS_1 but this isn't - necessary. */ - ld_state.dt_flags |=3D DF_ORIGIN; - else if (strcmp (arg, "nodelete") =3D=3D 0 - /* This is only meaningful if we create a DSO. */ - && ld_state.file_type =3D=3D dso_file_type) - ld_state.dt_flags_1 |=3D DF_1_NODELETE; - else if (strcmp (arg, "initfirst") =3D=3D 0) - ld_state.dt_flags_1 |=3D DF_1_INITFIRST; - else if (strcmp (arg, "nodlopen") =3D=3D 0 - /* This is only meaningful if we create a DSO. */ - && ld_state.file_type =3D=3D dso_file_type) - ld_state.dt_flags_1 |=3D DF_1_NOOPEN; - else if (strcmp (arg, "systemlibrary") =3D=3D 0) - ld_state.is_system_library =3D true; - else if (strcmp (arg, "execstack") =3D=3D 0) - ld_state.execstack =3D execstack_true; - else if (strcmp (arg, "noexecstack") =3D=3D 0) - ld_state.execstack =3D execstack_false_force; - else if (strcmp (arg, "allextract") !=3D 0 - && strcmp (arg, "defaultextract") !=3D 0 - && strcmp (arg, "weakextract") !=3D 0 - && strcmp (arg, "lazyload") !=3D 0 - && strcmp (arg, "nolazyload") !=3D 0 - && strcmp (arg, "ignore") !=3D 0 - && strcmp (arg, "record") !=3D 0) - error (0, 0, gettext ("unknown option `-%c %s'"), 'z', arg); -} - - -static void -parse_z_option_2 (const char *arg) -{ - if (strcmp (arg, "allextract") =3D=3D 0) - ld_state.extract_rule =3D allextract; - else if (strcmp (arg, "defaultextract") =3D=3D 0) - ld_state.extract_rule =3D defaultextract; - else if (strcmp (arg, "weakextract") =3D=3D 0) - ld_state.extract_rule =3D weakextract; - else if (strcmp (arg, "lazyload") =3D=3D 0) - ld_state.lazyload =3D true; - else if (strcmp (arg, "nolazyload") =3D=3D 0) - ld_state.lazyload =3D false; - else if (strcmp (arg, "ignore") =3D=3D 0) - ld_state.as_needed =3D true; - else if (strcmp (arg, "record") =3D=3D 0) - ld_state.as_needed =3D false; -} - - -/* There are a lot of -B options, parse them here. */ -static void -parse_B_option (const char *arg) -{ - if (strcmp (arg, "local") =3D=3D 0) - ld_state.default_bind_local =3D true; - else if (strcmp (arg, "symbolic") !=3D 0 - && strcmp (arg, "static") !=3D 0 - && strcmp (arg, "dynamic") !=3D 0) - error (0, 0, gettext ("unknown option '-%c %s'"), 'B', arg); -} - - -/* The same functionality, but called in the second pass over the - parameters. */ -static void -parse_B_option_2 (const char *arg) -{ - if (strcmp (arg, "static") =3D=3D 0) - ld_state.statically =3D true; - else if (strcmp (arg, "dynamic") =3D=3D 0) - ld_state.statically =3D false; - else if (strcmp (arg, "symbolic") =3D=3D 0 - /* This is only meaningful if we create a DSO. */ - && ld_state.file_type =3D=3D dso_file_type) - ld_state.dt_flags |=3D DF_SYMBOLIC; -} - - -static inline int -try (int fd, Elf *elf) -{ - int result =3D 0; - - if (elf =3D=3D NULL) - return 0; - - if (elf_kind (elf) =3D=3D ELF_K_ELF) - { - /* We have an ELF file. We now can find out - what the output format should be. */ - XElf_Ehdr_vardef(ehdr); - - /* Get the ELF header of the object. */ - xelf_getehdr (elf, ehdr); - if (ehdr !=3D NULL) - ld_state.ebl =3D - ebl_openbackend_machine (ehdr->e_machine); - - result =3D 1; - } - else if (elf_kind (elf) =3D=3D ELF_K_AR) - { - /* Try the archive members. This could - potentially lead to wrong results if the - archive contains files for more than one - architecture. But this is the user's - problem. */ - Elf *subelf; - Elf_Cmd cmd =3D ELF_C_READ_MMAP; - - while ((subelf =3D elf_begin (fd, cmd, elf)) !=3D NULL) - { - cmd =3D elf_next (subelf); - - if (try (fd, subelf) !=3D 0) - break; - } - } - - elf_end (elf); - - return result; -} - - -static void -determine_output_format (void) -{ - /* First change the 'input_file_list' variable in a simple - single-linked list. */ - struct file_list *last =3D input_file_list; - input_file_list =3D input_file_list->next; - last->next =3D NULL; - - /* Determine the target configuration which we are supposed to use. - The user can use the '-m' option to select one. If this is - missing we are trying to load one file and determine the - architecture from that. */ - if (emulation !=3D NULL) - { - ld_state.ebl =3D ebl_openbackend_emulation (emulation); - - assert (ld_state.ebl !=3D NULL); - } - else - { - /* Find an ELF input file and let it determine the ELf backend. */ - struct file_list *runp =3D input_file_list; - - while (runp !=3D NULL) - { - int fd =3D open (runp->name, O_RDONLY); - if (fd !=3D -1) - { - if (try (fd, elf_begin (fd, ELF_C_READ_MMAP, NULL)) !=3D 0) - /* Found a file. */ - break; - } - - runp =3D runp->next; - } - - if (ld_state.ebl =3D=3D NULL) - { - error (0, 0, gettext ("\ -could not find input file to determine output file format")); - error (EXIT_FAILURE, 0, gettext ("\ -try again with an appropriate '-m' parameter")); - } - } - - /* We don't need the list of input files anymore. The second run over - the parameters will handle them. */ - while (input_file_list !=3D NULL) - { - struct file_list *oldp =3D input_file_list; - input_file_list =3D input_file_list->next; - free (oldp); - } - - /* We also know now what kind of file we are supposed to create. If - the user hasn't selected anythign we create and executable. */ - if (ld_state.file_type =3D=3D no_file_type) - ld_state.file_type =3D executable_file_type; -} - -/* Add DIR to the list of directories searched for object files and - libraries. */ -void -ld_new_searchdir (const char *dir) -{ - struct pathelement *newpath; - - newpath =3D (struct pathelement *) - obstack_calloc (&ld_state.smem, sizeof (struct pathelement)); - - newpath->pname =3D dir; - - /* Enqueue the file. */ - if (ld_state.tailpaths =3D=3D NULL) - ld_state.paths =3D ld_state.tailpaths =3D newpath->next =3D newpath; - else - { - ld_state.tailpaths->next =3D newpath; - ld_state.tailpaths =3D newpath; - newpath->next =3D ld_state.paths; - } -} - - -struct usedfiles * -ld_new_inputfile (const char *fname, enum file_type type) -{ - struct usedfiles *newfile =3D (struct usedfiles *) - obstack_calloc (&ld_state.smem, sizeof (struct usedfiles)); - - newfile->soname =3D newfile->fname =3D newfile->rfname =3D fname; - newfile->file_type =3D type; - newfile->extract_rule =3D ld_state.extract_rule; - newfile->as_needed =3D ld_state.as_needed; - newfile->lazyload =3D ld_state.lazyload; - newfile->status =3D not_opened; - - return newfile; -} - - -/* Create an array listing all the sections. We will than pass this - array to a system specific function which can reorder it at will. - The functions can also merge sections if this is what is - wanted. */ -static void -collect_sections (void) -{ - void *p ; - struct scnhead *h; - size_t cnt; - - /* We have that many sections. At least for now. */ - ld_state.nallsections =3D ld_state.section_tab.filled; - - /* Allocate the array. We allocate one more entry than computed so - far since we might need a new section for the copy relocations. */ - ld_state.allsections =3D - (struct scnhead **) obstack_alloc (&ld_state.smem, - (ld_state.nallsections + 1) - * sizeof (struct scnhead *)); - - /* Fill the array. We rely here on the hash table iterator to - return the entries in the order they were added. */ - cnt =3D 0; - p =3D NULL; - while ((h =3D ld_section_tab_iterate (&ld_state.section_tab, &p)) !=3D N= ULL) - { - struct scninfo *runp; - bool used =3D false; - - if (h->kind =3D=3D scn_normal) - { - runp =3D h->last; - do - { - if (h->type =3D=3D SHT_REL || h->type =3D=3D SHT_RELA) - { - if (runp->used) - /* This is a relocation section. If the section - it is relocating is used in the result so must - the relocation section. */ - runp->used - =3D runp->fileinfo->scninfo[SCNINFO_SHDR (runp->shdr).sh_info].use= d; - } - - /* Accumulate the result. */ - used |=3D runp->used; - - /* Next input section. */ - runp =3D runp->next; - } - while (runp !=3D h->last); - - h->used =3D used; - } - - ld_state.allsections[cnt++] =3D h; - } - ld_state.nusedsections =3D cnt; - - assert (cnt =3D=3D ld_state.nallsections); -} - - -/* Add given path to the end of list. */ -static void -add_rxxpath (struct pathelement **pathp, const char *str) -{ - struct pathelement *newp; - - /* The path elements can in theory be freed after we read all the - files. But the amount of memory we are talking about is small - and the cost of free() calls is not neglectable. */ - newp =3D (struct pathelement *) obstack_alloc (&ld_state.smem, sizeof (*= newp)); - newp->pname =3D str; - newp->exist =3D 0; -#ifndef NDEBUG - newp->next =3D NULL; -#endif - - CSNGL_LIST_ADD_REAR (*pathp, newp); -} - - -/* Convert lists of possibly colon-separated directory lists into lists - where each entry is for a single directory. */ -static void -normalize_dirlist (struct pathelement **pathp) -{ - struct pathelement *firstp =3D *pathp; - - do - { - const char *pname =3D (*pathp)->pname; - const char *colonp =3D strchrnul (pname, ':'); - - if (colonp !=3D NULL) - { - struct pathelement *lastp =3D *pathp; - struct pathelement *newp; - - while (1) - { - if (colonp =3D=3D pname) - lastp->pname =3D "."; - else - lastp->pname =3D obstack_strndup (&ld_state.smem, pname, - colonp - pname); - - if (*colonp =3D=3D '\0') - break; - pname =3D colonp + 1; - - newp =3D (struct pathelement *) obstack_alloc (&ld_state.smem, - sizeof (*newp)); - newp->next =3D lastp->next; - newp->exist =3D 0; - lastp =3D lastp->next =3D newp; - - colonp =3D strchrnul (pname, ':'); - } - - pathp =3D &lastp->next; - } - else - pathp =3D &(*pathp)->next; - } - while (*pathp !=3D firstp); -} - - -/* Called after all parameters are parsed to bring the runpath/rpath - information into a usable form. */ -static void -gen_rxxpath_data (void) -{ - char *ld_library_path2; - - /* Convert the information in true single-linked lists for easy use. - At this point we also discard the rpath information if runpath - information is provided. rpath is deprecated and should not be - used (or ever be invented for that matter). */ - if (ld_state.rpath !=3D NULL) - { - struct pathelement *endp =3D ld_state.rpath; - ld_state.rpath =3D ld_state.rpath->next; - endp->next =3D NULL; - } - if (ld_state.rpath_link !=3D NULL) - { - struct pathelement *endp =3D ld_state.rpath_link; - ld_state.rpath_link =3D ld_state.rpath_link->next; - endp->next =3D NULL; - } - - if (ld_state.runpath !=3D NULL) - { - struct pathelement *endp =3D ld_state.runpath; - ld_state.runpath =3D ld_state.runpath->next; - endp->next =3D NULL; - - /* If rpath information is also available discard it. - XXX Should there be a possibility to avoid this? */ - while (ld_state.rpath !=3D NULL) - { - struct pathelement *old =3D ld_state.rpath; - ld_state.rpath =3D ld_state.rpath->next; - free (old); - } - } - if (ld_state.runpath_link !=3D NULL) - { - struct pathelement *endp =3D ld_state.runpath_link; - ld_state.runpath_link =3D ld_state.runpath_link->next; - endp->next =3D NULL; - - /* If rpath information is also available discard it. - XXX Should there be a possibility to avoid this? */ - while (ld_state.rpath_link !=3D NULL) - { - struct pathelement *old =3D ld_state.rpath_link; - ld_state.rpath_link =3D ld_state.rpath_link->next; - free (old); - } - - /* The information in the strings in the list can actually be - directory lists themselves, with entries separated by colons. - Convert the list now to a list with one list entry for each - directory. */ - normalize_dirlist (&ld_state.runpath_link); - } - else if (ld_state.rpath_link !=3D NULL) - /* Same as for the runpath_link above. */ - normalize_dirlist (&ld_state.rpath_link); - - - /* As a related task, handle the LD_LIBRARY_PATH value here. First - we have to possibly split the value found (if it contains a - semicolon). Then we have to split the value in list of - directories, i.e., split at the colons. */ - if (ld_library_path1 !=3D NULL) - { - ld_library_path2 =3D strchr (ld_library_path1, ';'); - if (ld_library_path2 =3D=3D NULL) - { - /* If no semicolon is present the directories are looked at - after the -L parameters (-> ld_library_path2). */ - ld_library_path2 =3D ld_library_path1; - ld_library_path1 =3D NULL; - } - else - { - /* NUL terminate the first part. */ - *ld_library_path2++ =3D '\0'; - - /* Convert the string value in a list. */ - add_rxxpath (&ld_state.ld_library_path1, ld_library_path1); - normalize_dirlist (&ld_state.ld_library_path1); - } - - add_rxxpath (&ld_state.ld_library_path2, ld_library_path2); - normalize_dirlist (&ld_state.ld_library_path2); - } -} - - -static void -read_version_script (const char *fname) -{ - /* Open the file. The name is supposed to be the complete (relative - or absolute) path. No search along a path will be performed. */ - ldin =3D fopen (fname, "r"); - if (ldin =3D=3D NULL) - error (EXIT_FAILURE, errno, gettext ("cannot read version script '%s'"= ), - fname); - /* No need for locking. */ - __fsetlocking (ldin, FSETLOCKING_BYCALLER); - - /* Tell the parser that this is a version script. */ - ld_scan_version_script =3D 1; - - ldlineno =3D 1; - ldin_fname =3D fname; - if (ldparse () !=3D 0) - /* Something went wrong during parsing. */ - exit (EXIT_FAILURE); - - fclose (ldin); -} - - -static void -create_lscript_symbols (void) -{ - /* Walk through the data from the linker script and generate all the - symbols which are required to be present and those marked - with PROVIDE if there is a undefined reference. */ - if (ld_state.output_segments =3D=3D NULL) - return; - - struct output_segment *segment =3D ld_state.output_segments->next; - do - { - struct output_rule *orule; - - for (orule =3D segment->output_rules; orule !=3D NULL; orule =3D oru= le->next) - if (orule->tag =3D=3D output_assignment - /* The assignments to "." (i.e., the PC) have to be - ignored here. */ - && strcmp (orule->val.assignment->variable, ".") !=3D 0) - { - struct symbol *s =3D ld_state.unresolved; - - /* Check whether the symbol is needed. */ - if (likely (s !=3D NULL)) - { - struct symbol *first =3D s; - const char *providename =3D orule->val.assignment->variable; - - /* Determine whether the provided symbol is still - undefined. */ - // XXX TODO Loop inside a loop. Gag! Must rewrite. */ - do - if (strcmp (s->name, providename) =3D=3D 0) - { - /* Not defined but referenced. */ - if (unlikely (!s->defined)) - { - /* Put on the list of symbols. First remove it from - whatever list it currently is on. */ - CDBL_LIST_DEL (ld_state.unresolved, s); - --ld_state.nunresolved; - goto use_it; - } - - if (unlikely (!orule->val.assignment->provide_flag)) - { - /* The symbol is already defined and now again - in the linker script. This is an error. */ - error (0, 0, gettext ("\ -duplicate definition of '%s' in linker script"), - providename); - goto next_rule; - } - } - while ((s =3D s->next) !=3D first); - } - - /* If the symbol only has to be provided if it is needed, - ignore it here since it is not undefined. */ - if (orule->val.assignment->provide_flag) - continue; - - /* Allocate memory for this new symbol. */ - s =3D (struct symbol *) - obstack_calloc (&ld_state.smem, sizeof (struct symbol)); - - /* Initialize it. */ - s->name =3D orule->val.assignment->variable; - - /* Insert it into the symbol hash table. */ - unsigned long int hval =3D elf_hash (s->name); - if (unlikely (ld_symbol_tab_insert (&ld_state.symbol_tab, - hval, s) !=3D 0)) - { - /* This means the symbol is defined somewhere else. - Maybe it comes from a DSO or so. Get the - definition. */ - free (s); - struct symbol *old =3D ld_symbol_tab_find (&ld_state.symbol_tab, - hval, s); - assert (old !=3D NULL); - free (s); - - /* If this is a definition from the application itself - this means a duplicate definition. */ - if (! old->in_dso) - { - error (0, 0, gettext ("\ -duplicate definition of '%s' in linker script"), - s->name); - goto next_rule; - } - - /* We use the definition from the linker script. */ - s =3D old; - } - - use_it: - /* The symbol is (now) defined. */ - s->defined =3D 1; - s->type =3D STT_NOTYPE; - - /* Add a reference to the symbol record. We will come - across it when creating the output file. */ - orule->val.assignment->sym =3D s; - - SNGL_LIST_PUSH (ld_state.lscript_syms, s); - ++ld_state.nlscript_syms; - - next_rule: - ; - } - - segment =3D segment->next; - } - while (segment !=3D ld_state.output_segments->next); -} - - -/* Create creation of spection section symbols representing sections in the - output file. This is done for symbols like _GLOBAL_OFFSET_TABLE_ and - _DYNAMIC. */ -static void -create_special_section_symbol (struct symbol **symp, const char *name) -{ - if (*symp =3D=3D NULL) - { - /* No symbol defined found yet. Create one. */ - struct symbol *newsym =3D (struct symbol *) - obstack_calloc (&ld_state.smem, sizeof (*newsym)); - - newsym->name =3D name; - // XXX Should we mark the symbol hidden? They are hardly useful - // used outside the current object. - - /* Add to the symbol table. */ - if (unlikely (ld_symbol_tab_insert (&ld_state.symbol_tab, - elf_hash (name), newsym) !=3D 0)) - abort (); - - *symp =3D newsym; - } - else if ((*symp)->defined) - /* Cannot happen. We do use this symbol from any input file. */ - abort (); - - (*symp)->defined =3D 1; - (*symp)->local =3D 1; - (*symp)->hidden =3D 1; - (*symp)->type =3D STT_OBJECT; - - ++ld_state.nsymtab; -} - - -#include "debugpred.h" diff --git a/src/ld.h b/src/ld.h deleted file mode 100644 index 29f4031..0000000 --- a/src/ld.h +++ /dev/null @@ -1,1135 +0,0 @@ -/* Copyright (C) 2001, 2002, 2003, 2005, 2006, 2008, 2009 Red Hat, Inc. - This file is part of elfutils. - Written by Ulrich Drepper , 2001. - - This file 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. - - elfutils 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, see . = */ - -#ifndef LD_H -#define LD_H 1 - -#include -#include -#include -#include -#include "xelf.h" - - -/* Recommended size of the buffer passed to ld_strerror. */ -#define ERRBUFSIZE (512) - -/* Character used to introduce version name after symbol. */ -#define VER_CHR '@' - - -/* Methods for handling archives. */ -enum extract_rule - { - defaultextract, /* Weak references don't cause archive member to - be used. */ - weakextract, /* Weak references cause archive member to be - extracted. */ - allextract /* Extract all archive members regardless of - references (aka whole-archive). */ - }; - - -/* Type of output file. */ -enum file_type - { - no_file_type =3D 0, /* None selected so far. */ - executable_file_type, /* Executable. */ - dso_file_type, /* DSO. */ - dso_needed_file_type, /* DSO introduced by DT_NEEDED. */ - relocatable_file_type, /* Relocatable object file. */ - archive_file_type /* Archive (input only). */ - }; - - -struct usedfiles -{ - /* The next file given at the command line. */ - struct usedfiles *next; - /* Nonzero if this file is the beginning of a group. */ - bool group_start; - /* Nonzero if this file is the end of a group. */ - bool group_end; - /* Pointer to the beginning of the group. It is necessary to - explain why we cannot simply use the 'next' pointer and have a - circular single-linked list like in many cases. The problem is - that the last archive of the group, if it is the last file of the - group, contains the only existing pointer to the next file we - have to look at. All files are initially connected via the - 'next' pointer in a single-linked list. Therefore we cannot - overwrite this value. It instead will be used once the group is - handled and we go on processing the rest of the files. */ - struct usedfiles *group_backref; - - /* Name/path of the file. */ - const char *fname; - /* Resolved file name. */ - const char *rfname; - /* Name used as reference in DT_NEEDED entries. This is normally - the SONAME. If it is missing it's normally the fname above. */ - const char *soname; - /* Handle for the SONAME in the string table. */ - struct Ebl_Strent *sonameent; - - /* Help to identify duplicates. */ - dev_t dev; - ino_t ino; - - enum - { - not_opened, - opened, - in_archive, - closed - } status; - - /* How to extract elements from archives. */ - enum extract_rule extract_rule; - - /* Lazy-loading rule. */ - bool lazyload; - - /* If this is a DSO the flag indicates whether the file is directly - used in a reference. */ - bool used; - - /* True when file should be added to DT_NEEDED list only when - directly referenced. */ - bool as_needed; - - /* If nonzero this is the archive sequence number which can be used to - determine whether back refernces from -( -) or GROUP statements - have to be followed. */ - int archive_seq; - - /* Pointer to the record for the archive containing this file. */ - struct usedfiles *archive_file; - - /* Type of file. We have to distinguish these types since they - are searched for differently. */ - enum file_type file_type; - /* This is the ELF library handle for this file. */ - Elf *elf; - - /* The ELF header. */ -#if NATIVE_ELF !=3D 0 - XElf_Ehdr *ehdr; -# define FILEINFO_EHDR(fi) (*(fi)) -#else - XElf_Ehdr ehdr; -# define FILEINFO_EHDR(fi) (fi) -#endif - - /* Index of the section header string table section. We use a - separate field and not the e_shstrndx field in the ELF header - since in case of a file with more than 64000 sections the index - might be stored in the section header of section zero. The - elf_getshdrstrndx() function can find the value but it is too - costly to repeat this call over and over. */ - size_t shstrndx; - - /* Info about the sections of the file. */ - struct scninfo - { - /* Handle for the section. Note that we can store a section - handle here because the file is not changing. This together - with the knowledge about the libelf library is enough for us to - assume the section reference remains valid at all times. */ - Elf_Scn *scn; - /* Section header. */ -#if NATIVE_ELF !=3D 0 - XElf_Shdr *shdr; -# define SCNINFO_SHDR(si) (*(si)) -#else - XElf_Shdr shdr; -# define SCNINFO_SHDR(si) (si) -#endif - /* Offset of this files section in the combined section. */ - XElf_Off offset; - /* Index of the section in the output file. */ - Elf32_Word outscnndx; - /* Index of the output section in the 'allsection' array. */ - Elf32_Word allsectionsidx; - /* True if the section is used. */ - bool used; - /* True if section is an unused COMDAT section. */ - bool unused_comdat; - /* True if this is a COMDAT group section. */ - bool comdat_group; - /* Section group number. This is the index of the SHT_GROUP section. = */ - Elf32_Word grpid; - /* Pointer back to the containing file information structure. */ - struct usedfiles *fileinfo; - /* List of symbols in this section (set only for merge-able sections - and group sections). */ - struct symbol *symbols; - /* Size of relocations in this section. Only used for relocation - sections. */ - size_t relsize; - /* Pointer to next section which is put in the given output - section. */ - struct scninfo *next; - } *scninfo; - - /* List of section group sections. */ - struct scninfo *groups; - - /* The symbol table section. - - XXX Maybe support for more than one symbol table is needed. */ - Elf_Data *symtabdata; - /* Extra section index table section. */ - Elf_Data *xndxdata; - /* Dynamic symbol table section. */ - Elf_Data *dynsymtabdata; - /* The version number section. */ - Elf_Data *versymdata; - /* The defined versions. */ - Elf_Data *verdefdata; - /* Number of versions defined. */ - size_t nverdef; - /* True if the version with the given index number is used in the - output. */ - XElf_Versym *verdefused; - /* How many versions are used. */ - size_t nverdefused; - /* Handle for name of the version. */ - struct Ebl_Strent **verdefent; - /* The needed versions. */ - Elf_Data *verneeddata; - /* String table section associated with the symbol table. */ - Elf32_Word symstridx; - /* String table section associated with the dynamic symbol table. */ - Elf32_Word dynsymstridx; - /* Number of entries in the symbol table. */ - size_t nsymtab; - size_t nlocalsymbols; - size_t ndynsymtab; - /* Dynamic section. */ - Elf_Scn *dynscn; - - /* Indirection table for the symbols defined here. */ - Elf32_Word *symindirect; - Elf32_Word *dynsymindirect; - /* For undefined or common symbols we need a reference to the symbol - record. */ - struct symbol **symref; - struct symbol **dynsymref; - - /* This is the file descriptor. The value is -1 if the descriptor - was already closed. This can happen if we needed file descriptors - to open new files. */ - int fd; - /* This flag is true if the descriptor was passed to the generic - functions from somewhere else. This is an implementation detail; - no machine-specific code must use this flag. */ - bool fd_passed; - - /* True if any of the sections is merge-able. */ - bool has_merge_sections; -}; - - -/* Functions to test for the various types of files we handle. */ -static inline int -ld_file_rel_p (struct usedfiles *file) -{ - return (elf_kind (file->elf) =3D=3D ELF_K_ELF - && FILEINFO_EHDR (file->ehdr).e_type =3D=3D ET_REL); -} - -static inline int -ld_file_dso_p (struct usedfiles *file) -{ - return (elf_kind (file->elf) =3D=3D ELF_K_ELF - && FILEINFO_EHDR (file->ehdr).e_type =3D=3D ET_DYN); -} - -static inline int -ld_file_ar_p (struct usedfiles *file) -{ - return elf_kind (file->elf) =3D=3D ELF_K_AR; -} - - -struct pathelement -{ - /* The next path to search. */ - struct pathelement *next; - /* The path name. */ - const char *pname; - /* Larger than zero if the directory exists, smaller than zero if not, - zero if it is not yet known. */ - int exist; -}; - - -/* Forward declaration. */ -struct ld_state; - - -/* Callback functions. */ -struct callbacks -{ - /* Library names passed to the linker as -lXXX represent files named - libXXX.YY. The YY part can have different forms, depending on the - architecture. The generic set is .so and .a (in this order). */ - const char **(*lib_extensions) (struct ld_state *) - __attribute__ ((__const__)); -#define LIB_EXTENSION(state) \ - DL_CALL_FCT ((state)->callbacks.lib_extensions, (state)) - - /* Process the given file. If the file is not yet open, open it. - The first parameter is a file descriptor for the file which can - be -1 to indicate the file has not yet been found. The second - parameter describes the file to be opened, the last one is the - state of the linker which among other information contain the - paths we look at.*/ - int (*file_process) (int fd, struct usedfiles *, struct ld_state *, - struct usedfiles **); -#define FILE_PROCESS(fd, file, state, nextp) \ - DL_CALL_FCT ((state)->callbacks.file_process, (fd, file, state, nextp)) - - /* Close the given file. */ - int (*file_close) (struct usedfiles *, struct ld_state *); -#define FILE_CLOSE(file, state) \ - DL_CALL_FCT ((state)->callbacks.file_close, (file, state)) - - /* Create the output sections now. This requires knowledge about - all the sections we will need. It may be necessary to sort the - sections in the order they are supposed to appear in the - executable. The sorting use many different kinds of information - to optimize the resulting binary. Important is to respect - segment boundaries and the needed alignment. The mode of the - segments will be determined afterwards automatically by the - output routines. */ - void (*create_sections) (struct ld_state *); -#define CREATE_SECTIONS(state) \ - DL_CALL_FCT ((state)->callbacks.create_sections, (state)) - - /* Determine whether we have any non-weak unresolved references left. */ - int (*flag_unresolved) (struct ld_state *); -#define FLAG_UNRESOLVED(state) \ - DL_CALL_FCT ((state)->callbacks.flag_unresolved, (state)) - - /* Create the sections which are generated by the linker and are not - present in the input file. */ - void (*generate_sections) (struct ld_state *); -#define GENERATE_SECTIONS(state) \ - DL_CALL_FCT ((state)->callbacks.generate_sections, (state)) - - /* Open the output file. The file name is given or "a.out". We - create as much of the ELF structure as possible. */ - int (*open_outfile) (struct ld_state *, int, int, int); -#define OPEN_OUTFILE(state, machine, class, data) \ - DL_CALL_FCT ((state)->callbacks.open_outfile, (state, machine, class, da= ta)) - - /* Create the data for the output file. */ - int (*create_outfile) (struct ld_state *); -#define CREATE_OUTFILE(state) \ - DL_CALL_FCT ((state)->callbacks.create_outfile, (state)) - - /* Process a relocation section. */ - void (*relocate_section) (struct ld_state *, Elf_Scn *, struct scninfo *, - const Elf32_Word *); -#define RELOCATE_SECTION(state, outscn, first, dblindirect) \ - DL_CALL_FCT ((state)->callbacks.relocate_section, (state, outscn, first,= \ - dblindirect)) - - /* Allocate a data buffer for the relocations of the given output - section. */ - void (*count_relocations) (struct ld_state *, struct scninfo *); -#define COUNT_RELOCATIONS(state, scninfo) \ - DL_CALL_FCT ((state)->callbacks.count_relocations, (state, scninfo)) - - /* Create relocations for executable or DSO. */ - void (*create_relocations) (struct ld_state *, const Elf32_Word *); -#define CREATE_RELOCATIONS(state, dlbindirect) \ - DL_CALL_FCT ((state)->callbacks.create_relocations, (state, dblindirect)) - - /* Finalize the output file. */ - int (*finalize) (struct ld_state *); -#define FINALIZE(state) \ - DL_CALL_FCT ((state)->callbacks.finalize, (state)) - - /* Check whether special section number is known. */ - bool (*special_section_number_p) (struct ld_state *, size_t); -#define SPECIAL_SECTION_NUMBER_P(state, number) \ - DL_CALL_FCT ((state)->callbacks.special_section_number_p, (state, number= )) - - /* Check whether section type is known. */ - bool (*section_type_p) (struct ld_state *, XElf_Word); -#define SECTION_TYPE_P(state, type) \ - DL_CALL_FCT ((state)->callbacks.section_type_p, (state, type)) - - /* Return section flags for .dynamic section. */ - XElf_Xword (*dynamic_section_flags) (struct ld_state *); -#define DYNAMIC_SECTION_FLAGS(state) \ - DL_CALL_FCT ((state)->callbacks.dynamic_section_flags, (state)) - - /* Create the data structures for the .plt section and initialize it. */ - void (*initialize_plt) (struct ld_state *, Elf_Scn *scn); -#define INITIALIZE_PLT(state, scn) \ - DL_CALL_FCT ((state)->callbacks.initialize_plt, (state, scn)) - - /* Create the data structures for the .rel.plt section and initialize it= . */ - void (*initialize_pltrel) (struct ld_state *, Elf_Scn *scn); -#define INITIALIZE_PLTREL(state, scn) \ - DL_CALL_FCT ((state)->callbacks.initialize_pltrel, (state, scn)) - - /* Finalize the .plt section the what belongs to them. */ - void (*finalize_plt) (struct ld_state *, size_t, size_t, struct symbol *= *); -#define FINALIZE_PLT(state, nsym, nsym_dyn, ndxtosym) \ - DL_CALL_FCT ((state)->callbacks.finalize_plt, (state, nsym, nsym_dyn, \ - ndxtosym)) - - /* Create the data structures for the .got section and initialize it. */ - void (*initialize_got) (struct ld_state *, Elf_Scn *scn); -#define INITIALIZE_GOT(state, scn) \ - DL_CALL_FCT ((state)->callbacks.initialize_got, (state, scn)) - - /* Create the data structures for the .got.plt section and initialize it= . */ - void (*initialize_gotplt) (struct ld_state *, Elf_Scn *scn); -#define INITIALIZE_GOTPLT(state, scn) \ - DL_CALL_FCT ((state)->callbacks.initialize_gotplt, (state, scn)) - - /* Return the tag corresponding to the native relocation type for - the platform. */ - int (*rel_type) (struct ld_state *); -#define REL_TYPE(state) \ - DL_CALL_FCT ((state)->callbacks.rel_type, (state)) -}; - - -/* Structure for symbol representation. This data structure is used a - lot, so size is important. */ -struct symbol -{ - /* Symbol name. */ - const char *name; - /* Size of the object. */ - XElf_Xword size; - /* Index of the symbol in the symbol table of the object. */ - size_t symidx; - /* Index of the symbol in the symbol table of the output file. */ - size_t outsymidx; - - /* Description where the symbol is found/needed. */ - size_t scndx; - struct usedfiles *file; - /* Index of the symbol table. */ - Elf32_Word symscndx; - - /* Index of the symbol in the dynamic symbol table of the output - file. Note that the value only needs to be 16 bit wide since - there cannot be more sections in an executable or DSO. */ - unsigned int outdynsymidx:16; - - /* Type of the symbol. */ - unsigned int type:4; - /* Various flags. */ - unsigned int defined:1; - unsigned int common:1; - unsigned int weak:1; - unsigned int added:1; - unsigned int merged:1; - unsigned int local:1; - unsigned int hidden:1; - /* Nonzero if the symbol is on the from_dso list. */ - unsigned int on_dsolist:1; - /* Nonzero if symbol needs copy relocation, reset when the - relocation has been created. */ - unsigned int need_copy:1; - unsigned int in_dso:1; - - union - { - /* Pointer to the handle created by the functions which create - merged section contents. We use 'void *' because there are - different implementations used. */ - void *handle; - XElf_Addr value; - } merge; - - /* Pointer to next/previous symbol on whatever list the symbol is. */ - struct symbol *next; - struct symbol *previous; - /* Pointer to next symbol of the same section (only set for merge-able - sections). */ - struct symbol *next_in_scn; -}; - - -/* Get the definition for the symbol table. */ -#include - -/* Simple single linked list of file names. */ -struct filename_list -{ - const char *name; - struct usedfiles *real; - struct filename_list *next; - bool group_start; - bool group_end; - bool as_needed; -}; - - -/* Data structure to describe expression in linker script. */ -struct expression -{ - enum expression_tag - { - exp_num, - exp_sizeof_headers, - exp_pagesize, - exp_id, - exp_mult, - exp_div, - exp_mod, - exp_plus, - exp_minus, - exp_and, - exp_or, - exp_align - } tag; - - union - { - uintmax_t num; - struct expression *child; - struct - { - struct expression *left; - struct expression *right; - } binary; - const char *str; - } val; -}; - - -/* Data structure for section name with flags. */ -struct input_section_name -{ - const char *name; - bool sort_flag; -}; - -/* File name mask with section name. */ -struct filemask_section_name -{ - const char *filemask; - const char *excludemask; - struct input_section_name *section_name; - bool keep_flag; -}; - -/* Data structure for assignments. */ -struct assignment -{ - const char *variable; - struct expression *expression; - struct symbol *sym; - bool provide_flag; -}; - - -/* Data structure describing input for an output section. */ -struct input_rule -{ - enum - { - input_section, - input_assignment - } tag; - - union - { - struct assignment *assignment; - struct filemask_section_name *section; - } val; - - struct input_rule *next; -}; - - -/* Data structure to describe output section. */ -struct output_section -{ - const char *name; - struct input_rule *input; - XElf_Addr max_alignment; - bool ignored; -}; - - -/* Data structure to describe output file format. */ -struct output_rule -{ - enum - { - output_section, - output_assignment - } tag; - - union - { - struct assignment *assignment; - struct output_section section; - } val; - - struct output_rule *next; -}; - - -/* List of all the segments the linker script describes. */ -struct output_segment -{ - int mode; - struct output_rule *output_rules; - struct output_segment *next; - - XElf_Off offset; - XElf_Addr addr; - XElf_Xword align; -}; - - -/* List of identifiers. */ -struct id_list -{ - union - { - enum id_type - { - id_str, /* Normal string. */ - id_all, /* "*", matches all. */ - id_wild /* Globbing wildcard string. */ - } id_type; - struct - { - bool local; - const char *versionname; - } s; - } u; - const char *id; - struct id_list *next; -}; - - -/* Version information. */ -struct version -{ - struct version *next; - struct id_list *local_names; - struct id_list *global_names; - const char *versionname; - const char *parentname; -}; - - -/* Head for list of sections. */ -struct scnhead -{ - /* Name of the sections. */ - const char *name; - - /* Accumulated flags for the sections. */ - XElf_Xword flags; - - /* Type of the sections. */ - XElf_Word type; - - /* Entry size. If there are differencs between the sections with - the same name this field contains 1. */ - XElf_Word entsize; - - /* If non-NULL pointer to group signature. */ - const char *grp_signature; - - /* Maximum alignment for all sections. */ - XElf_Word align; - - /* Distinguish between normal sections coming from the input file - and sections generated by the linker. */ - enum scn_kind - { - scn_normal, /* Section from the input file(s). */ - scn_dot_interp, /* Generated .interp section. */ - scn_dot_got, /* Generated .got section. */ - scn_dot_gotplt, /* Generated .got.plt section. */ - scn_dot_dynrel, /* Generated .rel.dyn section. */ - scn_dot_dynamic, /* Generated .dynamic section. */ - scn_dot_dynsym, /* Generated .dynsym section. */ - scn_dot_dynstr, /* Generated .dynstr section. */ - scn_dot_hash, /* Generated .hash section. */ - scn_dot_gnu_hash, /* Generated .gnu.hash section. */ - scn_dot_plt, /* Generated .plt section. */ - scn_dot_pltrel, /* Generated .rel.plt section. */ - scn_dot_version, /* Generated .gnu.version section. */ - scn_dot_version_r, /* Generated .gnu.version_r section. */ - scn_dot_note_gnu_build_id /* Generated .note.gnu.build-id section. = */ - } kind; - - /* True is the section is used in the output. */ - bool used; - - /* Total size (only determined this way for relocation sections). */ - size_t relsize; - - /* Filled in by the section sorting to indicate which segment the - section goes in. */ - int segment_nr; - - /* Index of the output section. We cannot store the section handle - directly here since the handle is a pointer in a dynamically - allocated table which might move if it becomes too small for all - the sections. Using the index the correct value can be found at - all times. */ - XElf_Word scnidx; - - /* Index of the STT_SECTION entry for this section in the symbol - table. */ - XElf_Word scnsymidx; - - /* Address of the section in the output file. */ - XElf_Addr addr; - - /* Handle for the section name in the output file's section header - string table. */ - struct Ebl_Strent *nameent; - - /* Tail of list of symbols for this section. Only set if the - section is merge-able. */ - struct symbol *symbols; - - /* Pointer to last section. */ - struct scninfo *last; -}; - - -/* Define hash table for sections. */ -#include - -/* Define hash table for version symbols. */ -#include - - -/* State of the linker. */ -struct ld_state -{ - /* ELF backend library handle. */ - Ebl *ebl; - - /* List of all archives participating, in this order. */ - struct usedfiles *archives; - /* End of the list. */ - struct usedfiles *tailarchives; - /* If nonzero we are looking for the beginning of a group. */ - bool group_start_requested; - /* Pointer to the archive starting the group. */ - struct usedfiles *group_start_archive; - - /* List of the DSOs we found. */ - struct usedfiles *dsofiles; - /* Number of DSO files. */ - size_t ndsofiles; - /* Ultimate list of object files which are linked in. */ - struct usedfiles *relfiles; - - /* List the DT_NEEDED DSOs. */ - struct usedfiles *needed; - - /* Temporary storage for the parser. */ - struct filename_list *srcfiles; - - /* List of all the paths to look at. */ - struct pathelement *paths; - /* Tail of the list. */ - struct pathelement *tailpaths; - - /* User provided paths for lookup of DSOs. */ - struct pathelement *rpath; - struct pathelement *rpath_link; - struct pathelement *runpath; - struct pathelement *runpath_link; - struct Ebl_Strent *rxxpath_strent; - int rxxpath_tag; - - /* From the environment variable LD_LIBRARY_PATH. */ - struct pathelement *ld_library_path1; - struct pathelement *ld_library_path2; - - /* Name of the output file. */ - const char *outfname; - /* Name of the temporary file we initially create. */ - const char *tempfname; - /* File descriptor opened for the output file. */ - int outfd; - /* The ELF descriptor for the output file. */ - Elf *outelf; - - /* Type of output file. */ - enum file_type file_type; - - /* Is this a system library or not. */ - bool is_system_library; - - /* Page size to be assumed for the binary. */ - size_t pagesize; - - /* Name of the interpreter for dynamically linked objects. */ - const char *interp; - /* Index of the .interp section. */ - Elf32_Word interpscnidx; - - /* Optimization level. */ - unsigned long int optlevel; - - /* If true static linking is requested. */ - bool statically; - - /* If true, add DT_NEEDED entries for following files if they are - needed. */ - bool as_needed; - - /* How to extract elements from archives. */ - enum extract_rule extract_rule; - - /* Sequence number of the last archive we used. */ - int last_archive_used; - - /* If true print to stdout information about the files we are - trying to open. */ - bool trace_files; - - /* If true multiple definitions are not considered an error; the - first is used. */ - bool muldefs; - - /* If true undefined symbols when building DSOs are not fatal. */ - bool nodefs; - - /* If true add line indentifying link-editor to .comment section. */ - bool add_ld_comment; - - /* Stripping while linking. */ - enum - { - strip_none, - strip_debug, - strip_all, - strip_everything - } strip; - - /* The callback function vector. */ - struct callbacks callbacks; - - /* Name of the entry symbol. Can also be a numeric value. */ - const char *entry; - - /* The description of the segments in the output file. */ - struct output_segment *output_segments; - - /* List of the symbols we created from linker script definitions. */ - struct symbol *lscript_syms; - size_t nlscript_syms; - - /* Table with known symbols. */ - ld_symbol_tab symbol_tab; - - /* Table with used sections. */ - ld_section_tab section_tab; - - /* The list of sections once we collected them. */ - struct scnhead **allsections; - size_t nallsections; - size_t nusedsections; - size_t nnotesections; - - /* Beginning of the list of symbols which are still unresolved. */ - struct symbol *unresolved; - /* Number of truely unresolved entries in the list. */ - size_t nunresolved; - /* Number of truely unresolved, non-weak entries in the list. */ - size_t nunresolved_nonweak; - - /* List of common symbols. */ - struct symbol *common_syms; - /* Section for the common symbols. */ - struct scninfo *common_section; - - /* List of symbols defined in DSOs and used in a relocatable file. - DSO symbols not referenced in the relocatable files are not on - the list. If a symbol is on the list the on_dsolist field in the - 'struct symbol' is nonzero. */ - struct symbol *from_dso; - /* Number of entries in from_dso. */ - size_t nfrom_dso; - /* Number of entries in the dynamic symbol table. */ - size_t ndynsym; - /* Number of PLT entries from DSO references. */ - size_t nplt; - /* Number of PLT entries from DSO references. */ - size_t ngot; - /* Number of copy relocations. */ - size_t ncopy; - /* Section for copy relocations. */ - struct scninfo *copy_section; - - /* Keeping track of the number of symbols in the output file. */ - size_t nsymtab; - size_t nlocalsymbols; - - /* Special symbols. */ - struct symbol *init_symbol; - struct symbol *fini_symbol; - - /* The description of the segments in the output file as described - in the default linker script. This information will be used in - addition to the user-provided information. */ - struct output_segment *default_output_segments; - /* Search paths added by the default linker script. */ - struct pathelement *default_paths; - -#ifndef BASE_ELF_NAME - /* The handle of the ld backend library. */ - void *ldlib; -#endif - - /* String table for the section headers. */ - struct Ebl_Strtab *shstrtab; - - /* True if output file should contain symbol table. */ - bool need_symtab; - /* Symbol table section. */ - Elf32_Word symscnidx; - /* Extended section table section. */ - Elf32_Word xndxscnidx; - /* Symbol string table section. */ - Elf32_Word strscnidx; - - /* True if output file should contain dynamic symbol table. */ - bool need_dynsym; - /* Dynamic symbol table section. */ - Elf32_Word dynsymscnidx; - /* Dynamic symbol string table section. */ - Elf32_Word dynstrscnidx; - /* Dynamic symbol hash tables. */ - size_t hashscnidx; - size_t gnuhashscnidx; - - /* Procedure linkage table section. */ - Elf32_Word pltscnidx; - /* Number of entries already in the PLT section. */ - size_t nplt_used; - /* Relocation for procedure linkage table section. */ - Elf32_Word pltrelscnidx; - - /* Global offset table section. */ - Elf32_Word gotscnidx; - /* And the part of the PLT. */ - Elf32_Word gotpltscnidx; - - /* This section will hole all non-PLT relocations. */ - Elf32_Word reldynscnidx; - - /* Index of the sections to handle versioning. */ - Elf32_Word versymscnidx; - Elf32_Word verneedscnidx; - /* XXX Should the following names be verneed...? */ - /* Number of version definitions in input DSOs used. */ - int nverdefused; - /* Number of input DSOs using versioning. */ - int nverdeffile; - /* Index of next version. */ - int nextveridx; - - /* TLS segment. */ - bool need_tls; - XElf_Addr tls_start; - XElf_Addr tls_tcb; - - /* Hash table for version symbol strings. Only strings without - special characters are hashed here. */ - ld_version_str_tab version_str_tab; - /* At most one of the following two variables is set to true if either - global or local symbol binding is selected as the default. */ - bool default_bind_local; - bool default_bind_global; - - /* Execuatable stack selection. */ - enum execstack - { - execstack_false =3D 0, - execstack_true, - execstack_false_force - } execstack; - - /* True if only used sections are used. */ - bool gc_sections; - - /* Array to determine final index of symbol. */ - Elf32_Word *dblindirect; - - /* Section group handling. */ - struct scngroup - { - Elf32_Word outscnidx; - int nscns; - struct member - { - struct scnhead *scn; - struct member *next; - } *member; - struct Ebl_Strent *nameent; - struct symbol *symbol; - struct scngroup *next; - } *groups; - - /* True if the output file needs a .got section. */ - bool need_got; - /* Number of relocations for GOT section caused. */ - size_t nrel_got; - - /* Number of entries needed in the .dynamic section. */ - int ndynamic; - /* To keep track of added entries. */ - int ndynamic_filled; - /* Index for the dynamic section. */ - Elf32_Word dynamicscnidx; - - /* Flags set in the DT_FLAGS word. */ - Elf32_Word dt_flags; - /* Flags set in the DT_FLAGS_1 word. */ - Elf32_Word dt_flags_1; - /* Flags set in the DT_FEATURE_1 word. */ - Elf32_Word dt_feature_1; - - /* Lazy-loading state for dependencies. */ - bool lazyload; - - /* True if an .eh_frame_hdr section should be generated. */ - bool eh_frame_hdr; - - /* What hash style to generate. */ - enum - { - hash_style_none =3D 0, - hash_style_sysv =3D 1, -#define GENERATE_SYSV_HASH ((ld_state.hash_style & hash_style_sysv) !=3D 0) - hash_style_gnu =3D 2 -#define GENERATE_GNU_HASH ((ld_state.hash_style & hash_style_gnu) !=3D 0) - } - hash_style; - - - /* True if in executables all global symbols should be exported in - the dynamic symbol table. */ - bool export_all_dynamic; - - /* Build-ID style. NULL is none. */ - const char *build_id; - Elf32_Word buildidscnidx; - - /* If DSO is generated, this is the SONAME. */ - const char *soname; - - /* List of all relocation sections. */ - struct scninfo *rellist; - /* Total size of non-PLT relocations. */ - size_t relsize_total; - - /* Record for the GOT symbol, if known. */ - struct symbol *got_symbol; - /* Record for the dynamic section symbol, if known. */ - struct symbol *dyn_symbol; - - /* Obstack used for small objects which will not be deleted. */ - struct obstack smem; -}; - - -/* The interface to the scanner. */ - -/* Parser entry point. */ -extern int ldparse (void); - -/* The input file. */ -extern FILE *ldin; - -/* Name of the input file. */ -extern const char *ldin_fname; - -/* Current line number. Must be reset for a new file. */ -extern int ldlineno; - -/* If nonzero we are currently parsing a version script. */ -extern int ld_scan_version_script; - -/* Flags defined in ld.c. */ -extern int verbose; -extern int conserve_memory; - - -/* Linker state. This contains all global information. */ -extern struct ld_state ld_state; - - -/* Generic ld helper functions. */ - -/* Append a new directory to search libraries in. */ -extern void ld_new_searchdir (const char *dir); - -/* Append a new file to the list of input files. */ -extern struct usedfiles *ld_new_inputfile (const char *fname, - enum file_type type); - - -/* These are the generic implementations for the callbacks used by ld. */ - -/* Initialize state object. This callback function is called after the - parameters are parsed but before any file is searched for. */ -extern int ld_prepare_state (const char *emulation); - - -/* Function to determine whether an object will be dynamically linked. */ -extern bool dynamically_linked_p (void); - -/* Helper functions for the architecture specific code. */ - -/* Checked whether the symbol is undefined and referenced from a DSO. */ -extern bool linked_from_dso_p (struct scninfo *scninfo, size_t symidx); -#ifdef __GNUC_STDC_INLINE__ -__attribute__ ((__gnu_inline__)) -#endif -extern inline bool -linked_from_dso_p (struct scninfo *scninfo, size_t symidx) -{ - struct usedfiles *file =3D scninfo->fileinfo; - - /* If this symbol is not undefined in this file it cannot come from - a DSO. */ - if (symidx < file->nlocalsymbols) - return false; - - struct symbol *sym =3D file->symref[symidx]; - - return sym->defined && sym->in_dso; -} - -#endif /* ld.h */ diff --git a/src/ldgeneric.c b/src/ldgeneric.c deleted file mode 100644 index 1b5d0f9..0000000 --- a/src/ldgeneric.c +++ /dev/null @@ -1,7132 +0,0 @@ -/* Copyright (C) 2001-2011 Red Hat, Inc. - This file is part of elfutils. - Written by Ulrich Drepper , 2001. - - This file 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. - - elfutils 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, see . = */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "ld.h" -#include "list.h" -#include -#include -#include - - -/* Header of .eh_frame_hdr section. */ -struct unw_eh_frame_hdr -{ - unsigned char version; - unsigned char eh_frame_ptr_enc; - unsigned char fde_count_enc; - unsigned char table_enc; -}; -#define EH_FRAME_HDR_VERSION 1 - - -/* Prototypes for local functions. */ -static const char **ld_generic_lib_extensions (struct ld_state *) - __attribute__ ((__const__)); -static int ld_generic_file_close (struct usedfiles *fileinfo, - struct ld_state *statep); -static int ld_generic_file_process (int fd, struct usedfiles *fileinfo, - struct ld_state *statep, - struct usedfiles **nextp); -static void ld_generic_generate_sections (struct ld_state *statep); -static void ld_generic_create_sections (struct ld_state *statep); -static int ld_generic_flag_unresolved (struct ld_state *statep); -static int ld_generic_open_outfile (struct ld_state *statep, int machine, - int class, int data); -static int ld_generic_create_outfile (struct ld_state *statep); -static void ld_generic_relocate_section (struct ld_state *statep, - Elf_Scn *outscn, - struct scninfo *firstp, - const Elf32_Word *dblindirect); -static int ld_generic_finalize (struct ld_state *statep); -static bool ld_generic_special_section_number_p (struct ld_state *statep, - size_t number); -static bool ld_generic_section_type_p (struct ld_state *statep, - XElf_Word type); -static XElf_Xword ld_generic_dynamic_section_flags (struct ld_state *state= p); -static void ld_generic_initialize_plt (struct ld_state *statep, Elf_Scn *s= cn); -static void ld_generic_initialize_pltrel (struct ld_state *statep, - Elf_Scn *scn); -static void ld_generic_initialize_got (struct ld_state *statep, Elf_Scn *s= cn); -static void ld_generic_initialize_gotplt (struct ld_state *statep, - Elf_Scn *scn); -static void ld_generic_finalize_plt (struct ld_state *statep, size_t nsym, - size_t nsym_dyn, - struct symbol **ndxtosymp); -static int ld_generic_rel_type (struct ld_state *statep); -static void ld_generic_count_relocations (struct ld_state *statep, - struct scninfo *scninfo); -static void ld_generic_create_relocations (struct ld_state *statep, - const Elf32_Word *dblindirect); - -static int file_process2 (struct usedfiles *fileinfo); -static void mark_section_used (struct scninfo *scninfo, Elf32_Word shndx, - struct scninfo **grpscnp); - - -/* Map symbol index to struct symbol record. */ -static struct symbol **ndxtosym; - -/* String table reference to all symbols in the symbol table. */ -static struct Ebl_Strent **symstrent; - - -/* Check whether file associated with FD is a DSO. */ -static bool -is_dso_p (int fd) -{ - /* We have to read the 'e_type' field. It has the same size (16 - bits) in 32- and 64-bit ELF. */ - XElf_Half e_type; - - return (pread (fd, &e_type, sizeof (e_type), offsetof (XElf_Ehdr, e_type= )) - =3D=3D sizeof (e_type) - && e_type =3D=3D ET_DYN); -} - - -/* Print the complete name of a file, including the archive it is - contained in. */ -static int -print_file_name (FILE *s, struct usedfiles *fileinfo, int first_level, - int newline) -{ - int npar =3D 0; - - if (fileinfo->archive_file !=3D NULL) - { - npar =3D print_file_name (s, fileinfo->archive_file, 0, 0) + 1; - fputc_unlocked ('(', s); - fputs_unlocked (fileinfo->rfname, s); - - if (first_level) - while (npar-- > 0) - fputc_unlocked (')', s); - } - else - fputs_unlocked (fileinfo->rfname, s); - - if (first_level && newline) - fputc_unlocked ('\n', s); - - return npar; -} - - -/* Function to determine whether an object will be dynamically linked. */ -bool -dynamically_linked_p (void) -{ - return (ld_state.file_type =3D=3D dso_file_type || ld_state.nplt > 0 - || ld_state.ngot > 0); -} - - -bool -linked_from_dso_p (struct scninfo *scninfo, size_t symidx) -{ - struct usedfiles *file =3D scninfo->fileinfo; - - /* If this symbol is not undefined in this file it cannot come from - a DSO. */ - if (symidx < file->nlocalsymbols) - return false; - - struct symbol *sym =3D file->symref[symidx]; - - return sym->defined && sym->in_dso; -} - - -/* Initialize state object. This callback function is called after the - parameters are parsed but before any file is searched for. */ -int -ld_prepare_state (const char *emulation) -{ - /* When generating DSO we normally allow undefined symbols. */ - ld_state.nodefs =3D true; - - /* To be able to detect problems we add a .comment section entry by - default. */ - ld_state.add_ld_comment =3D true; - - /* XXX We probably should find a better place for this. The index - of the first user-defined version is 2. */ - ld_state.nextveridx =3D 2; - - /* Pick an not too small number for the initial size of the tables. */ - ld_symbol_tab_init (&ld_state.symbol_tab, 1027); - ld_section_tab_init (&ld_state.section_tab, 67); - ld_version_str_tab_init (&ld_state.version_str_tab, 67); - - /* Initialize the section header string table. */ - ld_state.shstrtab =3D ebl_strtabinit (true); - if (ld_state.shstrtab =3D=3D NULL) - error (EXIT_FAILURE, errno, gettext ("cannot create string table")); - - /* Initialize the callbacks. These are the defaults, the appropriate - backend can later install its own callbacks. */ - ld_state.callbacks.lib_extensions =3D ld_generic_lib_extensions; - ld_state.callbacks.file_process =3D ld_generic_file_process; - ld_state.callbacks.file_close =3D ld_generic_file_close; - ld_state.callbacks.generate_sections =3D ld_generic_generate_sections; - ld_state.callbacks.create_sections =3D ld_generic_create_sections; - ld_state.callbacks.flag_unresolved =3D ld_generic_flag_unresolved; - ld_state.callbacks.open_outfile =3D ld_generic_open_outfile; - ld_state.callbacks.create_outfile =3D ld_generic_create_outfile; - ld_state.callbacks.relocate_section =3D ld_generic_relocate_section; - ld_state.callbacks.finalize =3D ld_generic_finalize; - ld_state.callbacks.special_section_number_p =3D - ld_generic_special_section_number_p; - ld_state.callbacks.section_type_p =3D ld_generic_section_type_p; - ld_state.callbacks.dynamic_section_flags =3D ld_generic_dynamic_section_= flags; - ld_state.callbacks.initialize_plt =3D ld_generic_initialize_plt; - ld_state.callbacks.initialize_pltrel =3D ld_generic_initialize_pltrel; - ld_state.callbacks.initialize_got =3D ld_generic_initialize_got; - ld_state.callbacks.initialize_gotplt =3D ld_generic_initialize_gotplt; - ld_state.callbacks.finalize_plt =3D ld_generic_finalize_plt; - ld_state.callbacks.rel_type =3D ld_generic_rel_type; - ld_state.callbacks.count_relocations =3D ld_generic_count_relocations; - ld_state.callbacks.create_relocations =3D ld_generic_create_relocations; - -#ifndef BASE_ELF_NAME - /* Find the ld backend library. Use EBL to determine the name if - the user hasn't provided one on the command line. */ - if (emulation =3D=3D NULL) - { - emulation =3D ebl_backend_name (ld_state.ebl); - assert (emulation !=3D NULL); - } - size_t emulation_len =3D strlen (emulation); - - /* Construct the file name. */ - char *fname =3D (char *) alloca (sizeof "libld_" - 1 + emulation_len - + sizeof ".so"); - strcpy (mempcpy (stpcpy (fname, "libld_"), emulation, emulation_len), ".= so"); - - /* Try loading. */ - void *h =3D dlopen (fname, RTLD_LAZY); - if (h =3D=3D NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot load ld backend library '%s': %s"), - fname, dlerror ()); - - /* Find the initializer. It must be present. */ - char *initname =3D (char *) alloca (emulation_len + sizeof "_ld_init"); - strcpy (mempcpy (initname, emulation, emulation_len), "_ld_init"); - int (*initfct) (struct ld_state *) - =3D (int (*) (struct ld_state *)) dlsym (h, initname); - - if (initfct =3D=3D NULL) - error (EXIT_FAILURE, 0, gettext ("\ -cannot find init function in ld backend library '%s': %s"), - fname, dlerror ()); - - /* Store the handle. */ - ld_state.ldlib =3D h; - - /* Call the init function. */ - return initfct (&ld_state); -#else -# define INIT_FCT_NAME(base) _INIT_FCT_NAME(base) -# define _INIT_FCT_NAME(base) base##_ld_init - /* Declare and call the initialization function. */ - extern int INIT_FCT_NAME(BASE_ELF_NAME) (struct ld_state *); - return INIT_FCT_NAME(BASE_ELF_NAME) (&ld_state); -#endif -} - - -static int -check_for_duplicate2 (struct usedfiles *newp, struct usedfiles *list) -{ - struct usedfiles *first; - - if (list =3D=3D NULL) - return 0; - - list =3D first =3D list->next; - do - { - /* When searching the needed list we might come across entries - for files which are not yet opened. Stop then, there is - nothing more to test. */ - if (likely (list->status =3D=3D not_opened)) - break; - - if (unlikely (list->ino =3D=3D newp->ino) - && unlikely (list->dev =3D=3D newp->dev)) - { - close (newp->fd); - newp->fd =3D -1; - newp->status =3D closed; - if (newp->file_type =3D=3D relocatable_file_type) - error (0, 0, gettext ("%s listed more than once as input"), - newp->rfname); - - return 1; - } - list =3D list->next; - } - while (likely (list !=3D first)); - - return 0; -} - - -static int -check_for_duplicate (struct usedfiles *newp) -{ - struct stat st; - - if (unlikely (fstat (newp->fd, &st) < 0)) - { - close (newp->fd); - return errno; - } - - newp->dev =3D st.st_dev; - newp->ino =3D st.st_ino; - - return (check_for_duplicate2 (newp, ld_state.relfiles) - || check_for_duplicate2 (newp, ld_state.dsofiles) - || check_for_duplicate2 (newp, ld_state.needed)); -} - - -/* Find a file along the path described in the state. */ -static int -open_along_path2 (struct usedfiles *fileinfo, struct pathelement *path) -{ - const char *fname =3D fileinfo->fname; - size_t fnamelen =3D strlen (fname); - int err =3D ENOENT; - struct pathelement *firstp =3D path; - - if (path =3D=3D NULL) - /* Cannot find anything since we have no path. */ - return ENOENT; - - do - { - if (likely (path->exist >=3D 0)) - { - /* Create the file name. */ - char *rfname =3D NULL; - size_t dirlen =3D strlen (path->pname); - int fd =3D -1; - - if (fileinfo->file_type =3D=3D archive_file_type) - { - const char **exts =3D (ld_state.statically - ? (const char *[2]) { ".a", NULL } - : LIB_EXTENSION (&ld_state)); - - /* We have to create the actual file name. We prepend "lib" - and add one of the extensions the platform has. */ - while (*exts !=3D NULL) - { - size_t extlen =3D strlen (*exts); - rfname =3D (char *) alloca (dirlen + 5 + fnamelen + extlen); - memcpy (mempcpy (stpcpy (mempcpy (rfname, path->pname, - dirlen), - "/lib"), - fname, fnamelen), - *exts, extlen + 1); - - fd =3D open (rfname, O_RDONLY); - if (likely (fd !=3D -1) || errno !=3D ENOENT) - { - err =3D fd =3D=3D -1 ? errno : 0; - break; - } - - /* Next extension. */ - ++exts; - } - } - else - { - assert (fileinfo->file_type =3D=3D dso_file_type - || fileinfo->file_type =3D=3D dso_needed_file_type); - - rfname =3D (char *) alloca (dirlen + 1 + fnamelen + 1); - memcpy (stpcpy (mempcpy (rfname, path->pname, dirlen), "/"), - fname, fnamelen + 1); - - fd =3D open (rfname, O_RDONLY); - if (unlikely (fd =3D=3D -1)) - err =3D errno; - } - - if (likely (fd !=3D -1)) - { - /* We found the file. This also means the directory - exists. */ - fileinfo->fd =3D fd; - path->exist =3D 1; - - /* Check whether we have this file already loaded. */ - if (unlikely (check_for_duplicate (fileinfo) !=3D 0)) - return EAGAIN; - - /* Make a copy of the name. */ - fileinfo->rfname =3D obstack_strdup (&ld_state.smem, rfname); - - if (unlikely (ld_state.trace_files)) - printf (fileinfo->file_type =3D=3D archive_file_type - ? gettext ("%s (for -l%s)\n") - : gettext ("%s (for DT_NEEDED %s)\n"), - rfname, fname); - - return 0; - } - - /* The file does not exist. Maybe the whole directory doesn't. - Check it unless we know it exists. */ - if (unlikely (path->exist =3D=3D 0)) - { - struct stat st; - - /* Keep only the directory name. Note that the path - might be relative. This doesn't matter here. We do - the test in any case even if there is the chance that - somebody wants to change the programs working - directory at some point which would make the result - of this test void. Since changing the working - directory is completely wrong we are not taking this - case into account. */ - rfname[dirlen] =3D '\0'; - if (unlikely (stat (rfname, &st) < 0) || ! S_ISDIR (st.st_mode)) - /* The directory does not exist or the named file is no - directory. */ - path->exist =3D -1; - else - path->exist =3D 1; - } - } - - /* Next path element. */ - path =3D path->next; - } - while (likely (err =3D=3D ENOENT && path !=3D firstp)); - - return err; -} - - -static int -open_along_path (struct usedfiles *fileinfo) -{ - const char *fname =3D fileinfo->fname; - int err =3D ENOENT; - - if (fileinfo->file_type =3D=3D relocatable_file_type) - { - /* Only libraries are searched along the path. */ - fileinfo->fd =3D open (fname, O_RDONLY); - - if (likely (fileinfo->fd !=3D -1)) - { - /* We found the file. */ - if (unlikely (ld_state.trace_files)) - print_file_name (stdout, fileinfo, 1, 1); - - return check_for_duplicate (fileinfo); - } - - /* If the name is an absolute path we are done. */ - err =3D errno; - } - else - { - /* If the user specified two parts to the LD_LIBRARY_PATH variable - try the first part now. */ - err =3D open_along_path2 (fileinfo, ld_state.ld_library_path1); - - /* Try the user-specified path next. */ - if (err =3D=3D ENOENT) - err =3D open_along_path2 (fileinfo, - fileinfo->file_type =3D=3D archive_file_type - ? ld_state.paths : ld_state.rpath_link); - - /* Then the second part of the LD_LIBRARY_PATH value. */ - if (unlikely (err =3D=3D ENOENT)) - { - err =3D open_along_path2 (fileinfo, ld_state.ld_library_path2); - - /* In case we look for a DSO handle now the RUNPATH. */ - if (err =3D=3D ENOENT) - { - if (fileinfo->file_type =3D=3D dso_file_type) - err =3D open_along_path2 (fileinfo, ld_state.runpath_link); - - /* Finally the path from the default linker script. */ - if (err =3D=3D ENOENT) - err =3D open_along_path2 (fileinfo, ld_state.default_paths); - } - } - } - - if (unlikely (err !=3D 0) - && (err !=3D EAGAIN || fileinfo->file_type =3D=3D relocatable_file_t= ype)) - error (0, err, gettext ("cannot open %s"), fileinfo->fname); - - return err; -} - - -static int -matching_group_comdat_scn (const XElf_Sym *sym, size_t shndx, - struct usedfiles *fileinfo, struct symbol *oldp) -{ - if ((shndx >=3D SHN_LORESERVE && shndx <=3D SHN_HIRESERVE) - || (oldp->scndx >=3D SHN_LORESERVE && oldp->scndx <=3D SHN_HIRESERVE= )) - /* Cannot be a group COMDAT section. */ - return 0; - - size_t newgrpid =3D fileinfo->scninfo[shndx].grpid; - size_t oldgrpid =3D oldp->file->scninfo[oldp->scndx].grpid; - if (newgrpid =3D=3D 0 || oldgrpid =3D=3D 0) - return 0; - - assert (SCNINFO_SHDR (fileinfo->scninfo[newgrpid].shdr).sh_type - =3D=3D SHT_GROUP); - assert (SCNINFO_SHDR (oldp->file->scninfo[oldgrpid].shdr).sh_type - =3D=3D SHT_GROUP); - - if (! fileinfo->scninfo[newgrpid].comdat_group - || ! oldp->file->scninfo[oldgrpid].comdat_group) - return 0; - - if (strcmp (fileinfo->scninfo[newgrpid].symbols->name, - oldp->file->scninfo[oldgrpid].symbols->name) !=3D 0) - return 0; - - /* This is a matching, duplicate COMDAT group section. Ignore it. */ - return 1; -} - - -static void -check_type_and_size (const XElf_Sym *sym, struct usedfiles *fileinfo, - struct symbol *oldp) -{ - /* We check the type and size of the symbols. In both cases the - information can be missing (size is zero, type is STT_NOTYPE) in - which case we issue no warnings. Otherwise everything must - match. If the type does not match there is no point in checking - the size. */ - - if (XELF_ST_TYPE (sym->st_info) !=3D STT_NOTYPE && oldp->type !=3D STT_N= OTYPE - && unlikely (oldp->type !=3D XELF_ST_TYPE (sym->st_info))) - { - char buf1[64]; - char buf2[64]; - - error (0, 0, gettext ("\ -Warning: type of `%s' changed from %s in %s to %s in %s"), - oldp->name, - ebl_symbol_type_name (ld_state.ebl, oldp->type, - buf1, sizeof (buf1)), - oldp->file->rfname, - ebl_symbol_type_name (ld_state.ebl, XELF_ST_TYPE (sym->st_info), - buf2, sizeof (buf2)), - fileinfo->rfname); - } - else if (XELF_ST_TYPE (sym->st_info) =3D=3D STT_OBJECT - && oldp->size !=3D 0 - && unlikely (oldp->size !=3D sym->st_size)) - error (0, 0, gettext ("\ -Warning: size of `%s' changed from %" PRIu64 " in %s to %" PRIu64 " in %s"= ), - oldp->name, (uint64_t) oldp->size, oldp->file->rfname, - (uint64_t) sym->st_size, fileinfo->rfname); -} - - -static int -check_definition (const XElf_Sym *sym, size_t shndx, size_t symidx, - struct usedfiles *fileinfo, struct symbol *oldp) -{ - int result =3D 0; - bool old_in_dso =3D FILEINFO_EHDR (oldp->file->ehdr).e_type =3D=3D ET_DY= N; - bool new_in_dso =3D FILEINFO_EHDR (fileinfo->ehdr).e_type =3D=3D ET_DYN; - bool use_new_def =3D false; - - if (shndx !=3D SHN_UNDEF - && (! oldp->defined - || (shndx !=3D SHN_COMMON && oldp->common && ! new_in_dso) - || (old_in_dso && ! new_in_dso))) - { - /* We found a definition for a previously undefined symbol or a - real definition for a previous common-only definition or a - redefinition of a symbol definition in an object file - previously defined in a DSO. First perform some tests which - will show whether the common is really matching the - definition. */ - check_type_and_size (sym, fileinfo, oldp); - - /* We leave the next element intact to not interrupt the list - with the unresolved symbols. Whoever walks the list will - have to check the `defined' flag. But we remember that this - list element is not unresolved anymore. */ - if (! oldp->defined) - { - /* Remove from the list. */ - --ld_state.nunresolved; - if (! oldp->weak) - --ld_state.nunresolved_nonweak; - CDBL_LIST_DEL (ld_state.unresolved, oldp); - } - else if (oldp->common) - /* Remove from the list. */ - CDBL_LIST_DEL (ld_state.common_syms, oldp); - - /* Use the values of the definition from now on. */ - use_new_def =3D true; - } - else if (shndx !=3D SHN_UNDEF - && oldp->defined - && matching_group_comdat_scn (sym, shndx, fileinfo, oldp)) - /* The duplicate symbol is in a group COMDAT section with the same - signature as the one containing the original definition. - Just ignore the second definition. */ - /* nothing */; - else if (shndx !=3D SHN_UNDEF - && unlikely (! oldp->common) - && oldp->defined - && shndx !=3D SHN_COMMON - /* Multiple definitions are no fatal errors if the -z muldefs flag - is used. We don't warn about the multiple definition unless we - are told to be verbose. */ - && (!ld_state.muldefs || verbose) - && ! old_in_dso && fileinfo->file_type =3D=3D relocatable_file_type) - { - /* We have a double definition. This is a problem. */ - char buf[64]; - XElf_Sym_vardef (oldsym); - struct usedfiles *oldfile; - const char *scnname; - Elf32_Word xndx; - size_t shnum; - - if (elf_getshdrnum (fileinfo->elf, &shnum) < 0) - error (EXIT_FAILURE, 0, - gettext ("cannot determine number of sections: %s"), - elf_errmsg (-1)); - - /* XXX Use only ebl_section_name. */ - if (shndx < SHN_LORESERVE || (shndx > SHN_HIRESERVE && shndx < shnum= )) - scnname =3D elf_strptr (fileinfo->elf, - fileinfo->shstrndx, - SCNINFO_SHDR (fileinfo->scninfo[shndx].shdr).sh_name); - else - // XXX extended section - scnname =3D ebl_section_name (ld_state.ebl, shndx, 0, buf, sizeof (buf), - NULL, shnum); - - /* XXX Print source file and line number. */ - print_file_name (stderr, fileinfo, 1, 0); - fprintf (stderr, - gettext ("(%s+%#" PRIx64 "): multiple definition of %s `%s'\n"), - scnname, - (uint64_t) sym->st_value, - ebl_symbol_type_name (ld_state.ebl, XELF_ST_TYPE (sym->st_info), - buf, sizeof (buf)), - oldp->name); - - oldfile =3D oldp->file; - xelf_getsymshndx (oldfile->symtabdata, oldfile->xndxdata, oldp->symi= dx, - oldsym, xndx); - assert (oldsym !=3D NULL); - - /* XXX Use only ebl_section_name. */ - if (oldp->scndx < SHN_LORESERVE || oldp->scndx > SHN_HIRESERVE) - scnname =3D elf_strptr (oldfile->elf, - oldfile->shstrndx, - SCNINFO_SHDR (oldfile->scninfo[shndx].shdr).sh_name); - else - scnname =3D ebl_section_name (ld_state.ebl, oldp->scndx, oldp->scndx, - buf, sizeof (buf), NULL, shnum); - - /* XXX Print source file and line number. */ - print_file_name (stderr, oldfile, 1, 0); - fprintf (stderr, gettext ("(%s+%#" PRIx64 "): first defined here\n"), - scnname, (uint64_t) oldsym->st_value); - - if (likely (!ld_state.muldefs)) - result =3D 1; - } - else if (old_in_dso && fileinfo->file_type =3D=3D relocatable_file_type - && shndx !=3D SHN_UNDEF) - /* We use the definition from a normal relocatable file over the - definition in a DSO. This is what the dynamic linker would - do, too. */ - use_new_def =3D true; - else if (old_in_dso && !new_in_dso && oldp->defined && !oldp->on_dsolist) - { - CDBL_LIST_ADD_REAR (ld_state.from_dso, oldp); - ++ld_state.nfrom_dso; - - /* If the object is a function we allocate a PLT entry, - otherwise only a GOT entry. */ - if (oldp->type =3D=3D STT_FUNC) - ++ld_state.nplt; - else - ++ld_state.ngot; - - oldp->on_dsolist =3D 1; - } - else if (oldp->common && shndx =3D=3D SHN_COMMON) - { - /* The symbol size is the largest of all common definitions. */ - oldp->size =3D MAX (oldp->size, sym->st_size); - /* Similarly for the alignment. */ - oldp->merge.value =3D MAX (oldp->merge.value, sym->st_value); - } - - if (unlikely (use_new_def)) - { - /* Adjust the symbol record appropriately and remove - the symbol from the list of symbols which are taken from DSOs. */ - if (old_in_dso && fileinfo->file_type =3D=3D relocatable_file_type) - { - CDBL_LIST_DEL (ld_state.from_dso, oldp); - --ld_state.nfrom_dso; - - if (likely (oldp->type =3D=3D STT_FUNC)) - --ld_state.nplt; - else - --ld_state.ngot; - - oldp->on_dsolist =3D 0; - } - - /* Use the values of the definition from now on. */ - oldp->size =3D sym->st_size; - oldp->type =3D XELF_ST_TYPE (sym->st_info); - oldp->symidx =3D symidx; - oldp->scndx =3D shndx; - //oldp->symscndx =3D THESYMSCNDX must be passed; - oldp->file =3D fileinfo; - oldp->defined =3D 1; - oldp->in_dso =3D new_in_dso; - oldp->common =3D shndx =3D=3D SHN_COMMON; - if (likely (fileinfo->file_type =3D=3D relocatable_file_type)) - { - /* If the definition comes from a DSO we pertain the weak flag - and it's indicating whether the reference is weak or not. */ - oldp->weak =3D XELF_ST_BIND (sym->st_info) =3D=3D STB_WEAK; - - // XXX Really exclude SHN_ABS? - if (shndx !=3D SHN_COMMON && shndx !=3D SHN_ABS) - { - struct scninfo *ignore; - mark_section_used (&fileinfo->scninfo[shndx], shndx, &ignore); - } - } - - /* Add to the list of symbols used from DSOs if necessary. */ - if (new_in_dso && !old_in_dso) - { - CDBL_LIST_ADD_REAR (ld_state.from_dso, oldp); - ++ld_state.nfrom_dso; - - /* If the object is a function we allocate a PLT entry, - otherwise only a GOT entry. */ - if (oldp->type =3D=3D STT_FUNC) - ++ld_state.nplt; - else - ++ld_state.ngot; - - oldp->on_dsolist =3D 1; - } - else if (shndx =3D=3D SHN_COMMON) - { - /* Store the alignment. */ - oldp->merge.value =3D sym->st_value; - - CDBL_LIST_ADD_REAR (ld_state.common_syms, oldp); - } - } - - return result; -} - - -static struct scninfo * -find_section_group (struct usedfiles *fileinfo, Elf32_Word shndx, - Elf_Data **datap) -{ - struct scninfo *runp; - - for (runp =3D fileinfo->groups; runp !=3D NULL; runp =3D runp->next) - if (!runp->used) - { - Elf32_Word *grpref; - size_t cnt; - Elf_Data *data; - - data =3D elf_getdata (runp->scn, NULL); - if (data =3D=3D NULL) - error (EXIT_FAILURE, 0, - gettext ("%s: cannot get section group data: %s"), - fileinfo->fname, elf_errmsg (-1)); - - /* There cannot be another data block. */ - assert (elf_getdata (runp->scn, data) =3D=3D NULL); - - grpref =3D (Elf32_Word *) data->d_buf; - cnt =3D data->d_size / sizeof (Elf32_Word); - /* Note that we stop after looking at index 1 since index 0 - contains the flags for the section group. */ - while (cnt > 1) - if (grpref[--cnt] =3D=3D shndx) - { - *datap =3D data; - return runp; - } - } - - /* If we come here no section group contained the given section - despite the SHF_GROUP flag. This is an error in the input - file. */ - error (EXIT_FAILURE, 0, gettext ("\ -%s: section '%s' with group flag set does not belong to any group"), - fileinfo->fname, - elf_strptr (fileinfo->elf, fileinfo->shstrndx, - SCNINFO_SHDR (fileinfo->scninfo[shndx].shdr).sh_name)); - return NULL; -} - - -/* Mark all sections which belong to the same group as section SHNDX - as used. */ -static void -mark_section_group (struct usedfiles *fileinfo, Elf32_Word shndx, - struct scninfo **grpscnp) -{ - /* First locate the section group. There can be several (many) of - them. */ - size_t cnt; - Elf32_Word *grpref; - Elf_Data *data; - struct scninfo *grpscn =3D find_section_group (fileinfo, shndx, &data); - *grpscnp =3D grpscn; - - /* Mark all the sections as used. - - XXX Two possible problems here: - - - the gABI says "The section must be referenced by a section of type - SHT_GROUP". I hope everybody reads this as "exactly one section". - - - section groups are also useful to mark the debugging section which - belongs to a text section. Unconditionally adding debugging sectio= ns - is therefore probably not what is wanted if stripping is required. = */ - - /* Mark the section group as handled. */ - grpscn->used =3D true; - - grpref =3D (Elf32_Word *) data->d_buf; - cnt =3D data->d_size / sizeof (Elf32_Word); - while (cnt > 1) - { - Elf32_Word idx =3D grpref[--cnt]; - XElf_Shdr *shdr =3D &SCNINFO_SHDR (fileinfo->scninfo[idx].shdr); - - if (fileinfo->scninfo[idx].grpid !=3D grpscn->grpid) - error (EXIT_FAILURE, 0, gettext ("\ -%s: section [%2d] '%s' is not in the correct section group"), - fileinfo->fname, (int) idx, - elf_strptr (fileinfo->elf, fileinfo->shstrndx, shdr->sh_name)); - - if (ld_state.strip =3D=3D strip_none - /* If we are stripping, remove debug sections. */ - || (!ebl_debugscn_p (ld_state.ebl, - elf_strptr (fileinfo->elf, fileinfo->shstrndx, - shdr->sh_name)) - /* And the relocation sections for the debug sections. */ - && ((shdr->sh_type !=3D SHT_RELA && shdr->sh_type !=3D SHT_REL) - || !ebl_debugscn_p (ld_state.ebl, - elf_strptr (fileinfo->elf, - fileinfo->shstrndx, - SCNINFO_SHDR (fileinfo->scninfo[shdr->sh_info].shdr).sh_name))))) - { - struct scninfo *ignore; - - mark_section_used (&fileinfo->scninfo[idx], idx, &ignore); - } - } -} - - -static void -mark_section_used (struct scninfo *scninfo, Elf32_Word shndx, - struct scninfo **grpscnp) -{ - if (likely (scninfo->used)) - /* Nothing to be done. */ - return; - - /* We need this section. */ - scninfo->used =3D true; - - /* Make sure the section header has been read from the file. */ - XElf_Shdr *shdr =3D &SCNINFO_SHDR (scninfo->shdr); -#if NATIVE_ELF - if (unlikely (scninfo->shdr =3D=3D NULL)) -#else - if (unlikely (scninfo->shdr.sh_type =3D=3D SHT_NULL)) -#endif - { -#if NATIVE_ELF !=3D 0 - shdr =3D xelf_getshdr (scninfo->scn, scninfo->shdr); -#else - xelf_getshdr_copy (scninfo->scn, shdr, scninfo->shdr); -#endif - if (unlikely (shdr =3D=3D NULL)) - /* Something is very wrong. The calling code will notice it - soon and print a message. */ - return; - } - - /* Handle section linked by 'sh_link'. */ - if (unlikely (shdr->sh_link !=3D 0)) - { - struct scninfo *ignore; - mark_section_used (&scninfo->fileinfo->scninfo[shdr->sh_link], - shdr->sh_link, &ignore); - } - - /* Handle section linked by 'sh_info'. */ - if (unlikely (shdr->sh_info !=3D 0) && (shdr->sh_flags & SHF_INFO_LINK)) - { - struct scninfo *ignore; - mark_section_used (&scninfo->fileinfo->scninfo[shdr->sh_info], - shdr->sh_info, &ignore); - } - - if (unlikely (shdr->sh_flags & SHF_GROUP) && ld_state.gc_sections) - /* Find the section group which contains this section. */ - mark_section_group (scninfo->fileinfo, shndx, grpscnp); -} - - -/* We collect all sections in a hashing table. All sections with the - same name are collected in a list. Note that we do not determine - which sections are finally collected in the same output section - here. This would be terribly inefficient. It will be done later. */ -static void -add_section (struct usedfiles *fileinfo, struct scninfo *scninfo) -{ - struct scnhead *queued; - struct scnhead search; - unsigned long int hval; - XElf_Shdr *shdr =3D &SCNINFO_SHDR (scninfo->shdr); - struct scninfo *grpscn =3D NULL; - Elf_Data *grpscndata =3D NULL; - - /* See whether we can determine right away whether we need this - section in the output. - - XXX I assume here that --gc-sections only affects extraction - from an archive. If it also affects objects files given on - the command line then somebody must explain to me how the - dependency analysis should work. Should the entry point be - the root? What if it is a numeric value? */ - if (!scninfo->used - && (ld_state.strip =3D=3D strip_none - || (shdr->sh_flags & SHF_ALLOC) !=3D 0 - || shdr->sh_type =3D=3D SHT_NOTE - || (shdr->sh_type =3D=3D SHT_PROGBITS - && strcmp (elf_strptr (fileinfo->elf, - fileinfo->shstrndx, - shdr->sh_name), ".comment") =3D=3D 0)) - && (fileinfo->status !=3D in_archive || !ld_state.gc_sections)) - /* Mark as used and handle reference recursively if necessary. */ - mark_section_used (scninfo, elf_ndxscn (scninfo->scn), &grpscn); - - if ((shdr->sh_flags & SHF_GROUP) && grpscn =3D=3D NULL) - /* Determine the symbol which name constitutes the signature - for the section group. */ - grpscn =3D find_section_group (fileinfo, elf_ndxscn (scninfo->scn), - &grpscndata); - assert (grpscn =3D=3D NULL || grpscn->symbols->name !=3D NULL); - - /* Determine the section name. */ - search.name =3D elf_strptr (fileinfo->elf, fileinfo->shstrndx, shdr->sh_= name); - search.type =3D shdr->sh_type; - search.flags =3D shdr->sh_flags; - search.entsize =3D shdr->sh_entsize; - search.grp_signature =3D grpscn !=3D NULL ? grpscn->symbols->name : NULL; - search.kind =3D scn_normal; - hval =3D elf_hash (search.name); - - /* Find already queued sections. */ - queued =3D ld_section_tab_find (&ld_state.section_tab, hval, &search); - if (queued !=3D NULL) - { - bool is_comdat =3D false; - - /* If this section is part of a COMDAT section group we simply - ignore it since we already have a copy. */ - if (unlikely (shdr->sh_flags & SHF_GROUP)) - { - /* Get the data of the section group section. */ - if (grpscndata =3D=3D NULL) - { - grpscndata =3D elf_getdata (grpscn->scn, NULL); - assert (grpscndata !=3D NULL); - } - - /* XXX Possibly unaligned memory access. */ - if ((((Elf32_Word *) grpscndata->d_buf)[0] & GRP_COMDAT) !=3D 0) - { - /* We have to compare the group signatures. There might - be sections with the same name but belonging to - groups with different signatures. This means we have - to compare the new group signature with all those - already collected. There might also be some - non-group sections in the mix. */ - struct scninfo *runp =3D queued->last; - do - { - if (SCNINFO_SHDR (runp->shdr).sh_flags & SHF_GROUP) - { - struct scninfo *grpscn2 - =3D find_section_group (runp->fileinfo, - elf_ndxscn (runp->scn), - &grpscndata); - - if (strcmp (grpscn->symbols->name, - grpscn2->symbols->name) =3D=3D 0) - { - scninfo->unused_comdat =3D is_comdat =3D true; - break; - } - } - - runp =3D runp->next; - } - while (runp !=3D queued->last); - } - } - - if (!is_comdat) - { - /* No COMDAT section, we use the data. */ - scninfo->next =3D queued->last->next; - queued->last =3D queued->last->next =3D scninfo; - - queued->flags =3D ebl_sh_flags_combine (ld_state.ebl, queued->flags, - shdr->sh_flags); - queued->align =3D MAX (queued->align, shdr->sh_addralign); - } - } - else - { - /* We do not use obstacks here since the memory might be - deallocated. */ - queued =3D (struct scnhead *) xcalloc (sizeof (struct scnhead), 1); - queued->kind =3D scn_normal; - queued->name =3D search.name; - queued->type =3D shdr->sh_type; - queued->flags =3D shdr->sh_flags; - queued->align =3D shdr->sh_addralign; - queued->entsize =3D shdr->sh_entsize; - queued->grp_signature =3D grpscn !=3D NULL ? grpscn->symbols->name := NULL; - queued->segment_nr =3D ~0; - queued->last =3D scninfo->next =3D scninfo; - - /* Check whether we need a TLS segment. */ - ld_state.need_tls |=3D (shdr->sh_flags & SHF_TLS) !=3D 0; - - /* Add to the hash table and possibly overwrite existing value. */ - ld_section_tab_insert (&ld_state.section_tab, hval, queued); - } -} - - -static int -add_relocatable_file (struct usedfiles *fileinfo, GElf_Word secttype) -{ - size_t scncnt; - size_t cnt; - Elf_Data *symtabdata =3D NULL; - Elf_Data *xndxdata =3D NULL; - Elf_Data *versymdata =3D NULL; - Elf_Data *verdefdata =3D NULL; - Elf_Data *verneeddata =3D NULL; - size_t symstridx =3D 0; - size_t nsymbols =3D 0; - size_t nlocalsymbols =3D 0; - bool has_merge_sections =3D false; - bool has_tls_symbols =3D false; - /* Unless we have different information we assume the code needs - an executable stack. */ - enum execstack execstack =3D execstack_true; - - /* Prerequisites. */ - assert (fileinfo->elf !=3D NULL); - - /* Allocate memory for the sections. */ - if (unlikely (elf_getshdrnum (fileinfo->elf, &scncnt) < 0)) - error (EXIT_FAILURE, 0, - gettext ("cannot determine number of sections: %s"), - elf_errmsg (-1)); - - fileinfo->scninfo =3D (struct scninfo *) - obstack_calloc (&ld_state.smem, scncnt * sizeof (struct scninfo)); - - /* Read all the section headers and find the symbol table. Note - that we don't skip the section with index zero. Even though the - section itself is always empty the section header contains - informaton for the case when the section index for the section - header string table is too large to fit in the ELF header. */ - for (cnt =3D 0; cnt < scncnt; ++cnt) - { - /* Store the handle for the section. */ - fileinfo->scninfo[cnt].scn =3D elf_getscn (fileinfo->elf, cnt); - - /* Get the ELF section header and data. */ - XElf_Shdr *shdr; -#if NATIVE_ELF !=3D 0 - if (fileinfo->scninfo[cnt].shdr =3D=3D NULL) -#else - if (fileinfo->scninfo[cnt].shdr.sh_type =3D=3D SHT_NULL) -#endif - { -#if NATIVE_ELF !=3D 0 - shdr =3D xelf_getshdr (fileinfo->scninfo[cnt].scn, - fileinfo->scninfo[cnt].shdr); -#else - xelf_getshdr_copy (fileinfo->scninfo[cnt].scn, shdr, - fileinfo->scninfo[cnt].shdr); -#endif - if (shdr =3D=3D NULL) - { - /* This should never happen. */ - fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"), - fileinfo->rfname, __FILE__, __LINE__); - return 1; - } - } - else - shdr =3D &SCNINFO_SHDR (fileinfo->scninfo[cnt].shdr); - - Elf_Data *data =3D elf_getdata (fileinfo->scninfo[cnt].scn, NULL); - - /* Check whether this section is marked as merge-able. */ - has_merge_sections |=3D (shdr->sh_flags & SHF_MERGE) !=3D 0; - has_tls_symbols |=3D (shdr->sh_flags & SHF_TLS) !=3D 0; - - /* Get the ELF section header and data. */ - /* Make the file structure available. */ - fileinfo->scninfo[cnt].fileinfo =3D fileinfo; - - if (unlikely (shdr->sh_type =3D=3D SHT_SYMTAB) - || unlikely (shdr->sh_type =3D=3D SHT_DYNSYM)) - { - if (shdr->sh_type =3D=3D SHT_SYMTAB) - { - assert (fileinfo->symtabdata =3D=3D NULL); - fileinfo->symtabdata =3D data; - fileinfo->nsymtab =3D shdr->sh_size / shdr->sh_entsize; - fileinfo->nlocalsymbols =3D shdr->sh_info; - fileinfo->symstridx =3D shdr->sh_link; - } - else - { - assert (fileinfo->dynsymtabdata =3D=3D NULL); - fileinfo->dynsymtabdata =3D data; - fileinfo->ndynsymtab =3D shdr->sh_size / shdr->sh_entsize; - fileinfo->dynsymstridx =3D shdr->sh_link; - } - - /* If we are looking for the normal symbol table we just - found it. */ - if (secttype =3D=3D shdr->sh_type) - { - assert (symtabdata =3D=3D NULL); - symtabdata =3D data; - symstridx =3D shdr->sh_link; - nsymbols =3D shdr->sh_size / shdr->sh_entsize; - nlocalsymbols =3D shdr->sh_info; - } - } - else if (unlikely (shdr->sh_type =3D=3D SHT_SYMTAB_SHNDX)) - { - assert (xndxdata =3D=3D NULL); - fileinfo->xndxdata =3D xndxdata =3D data; - } - else if (unlikely (shdr->sh_type =3D=3D SHT_GNU_versym)) - { - assert (versymdata =3D=3D 0); - fileinfo->versymdata =3D versymdata =3D data; - } - else if (unlikely (shdr->sh_type =3D=3D SHT_GNU_verdef)) - { - size_t nversions; - - assert (verdefdata =3D=3D 0); - fileinfo->verdefdata =3D verdefdata =3D data; - - /* Allocate the arrays flagging the use of the version and - to track of allocated names. */ - fileinfo->nverdef =3D nversions =3D shdr->sh_info; - /* We have NVERSIONS + 1 because the indeces used to access the - sectino start with one; zero represents local binding. */ - fileinfo->verdefused =3D (XElf_Versym *) - obstack_calloc (&ld_state.smem, - sizeof (XElf_Versym) * (nversions + 1)); - fileinfo->verdefent =3D (struct Ebl_Strent **) - obstack_alloc (&ld_state.smem, - sizeof (struct Ebl_Strent *) * (nversions + 1)); - } - else if (unlikely (shdr->sh_type =3D=3D SHT_GNU_verneed)) - { - assert (verneeddata =3D=3D 0); - fileinfo->verneeddata =3D verneeddata =3D data; - } - else if (unlikely (shdr->sh_type =3D=3D SHT_DYNAMIC)) - { - assert (fileinfo->dynscn =3D=3D NULL); - fileinfo->dynscn =3D fileinfo->scninfo[cnt].scn; - } - else if (unlikely (shdr->sh_type =3D=3D SHT_GROUP)) - { - Elf_Scn *symscn; - XElf_Shdr_vardef (symshdr); - Elf_Data *symdata; - - if (FILEINFO_EHDR (fileinfo->ehdr).e_type !=3D ET_REL) - error (EXIT_FAILURE, 0, gettext ("\ -%s: only files of type ET_REL might contain section groups"), - fileinfo->fname); - - fileinfo->scninfo[cnt].next =3D fileinfo->groups; - fileinfo->scninfo[cnt].grpid =3D cnt; - fileinfo->groups =3D &fileinfo->scninfo[cnt]; - - /* Determine the signature. We create a symbol record for - it. Only the name element is important. */ - fileinfo->scninfo[cnt].symbols =3D (struct symbol *) - obstack_calloc (&ld_state.smem, sizeof (struct symbol)); - - symscn =3D elf_getscn (fileinfo->elf, shdr->sh_link); - xelf_getshdr (symscn, symshdr); - symdata =3D elf_getdata (symscn, NULL); - - if (symshdr !=3D NULL) - { - XElf_Sym_vardef (sym); - - /* We don't need the section index and therefore we don't - have to use 'xelf_getsymshndx'. */ - xelf_getsym (symdata, shdr->sh_info, sym); - if (sym !=3D NULL) - { - struct symbol *symbol =3D fileinfo->scninfo[cnt].symbols; - -#ifndef NO_HACKS - if (XELF_ST_TYPE (sym->st_info) =3D=3D STT_SECTION) - { - XElf_Shdr_vardef (buggyshdr); - xelf_getshdr (elf_getscn (fileinfo->elf, sym->st_shndx), - buggyshdr); - - symbol->name =3D elf_strptr (fileinfo->elf, - FILEINFO_EHDR (fileinfo->ehdr).e_shstrndx, - buggyshdr->sh_name); - symbol->symidx =3D -1; - } - else -#endif - { - symbol->name =3D elf_strptr (fileinfo->elf, - symshdr->sh_link, - sym->st_name); - symbol->symidx =3D shdr->sh_info; - } - symbol->file =3D fileinfo; - } - } - if (fileinfo->scninfo[cnt].symbols->name =3D=3D NULL) - error (EXIT_FAILURE, 0, gettext ("\ -%s: cannot determine signature of section group [%2zd] '%s': %s"), - fileinfo->fname, - elf_ndxscn (fileinfo->scninfo[cnt].scn), - elf_strptr (fileinfo->elf, fileinfo->shstrndx, - shdr->sh_name), - elf_errmsg (-1)); - - - /* For all the sections which are part of this group, add - the reference. */ - if (data =3D=3D NULL) - error (EXIT_FAILURE, 0, gettext ("\ -%s: cannot get content of section group [%2zd] '%s': %s'"), - fileinfo->fname, elf_ndxscn (fileinfo->scninfo[cnt].scn), - elf_strptr (fileinfo->elf, fileinfo->shstrndx, - shdr->sh_name), - elf_errmsg (-1)); - - Elf32_Word *grpdata =3D (Elf32_Word *) data->d_buf; - if (grpdata[0] & GRP_COMDAT) - fileinfo->scninfo[cnt].comdat_group =3D true; - for (size_t inner =3D 1; inner < data->d_size / sizeof (Elf32_Word); - ++inner) - { - if (grpdata[inner] >=3D scncnt) - error (EXIT_FAILURE, 0, gettext ("\ -%s: group member %zu of section group [%2zd] '%s' has too high index: %" P= RIu32), - fileinfo->fname, - inner, elf_ndxscn (fileinfo->scninfo[cnt].scn), - elf_strptr (fileinfo->elf, fileinfo->shstrndx, - shdr->sh_name), - grpdata[inner]); - - fileinfo->scninfo[grpdata[inner]].grpid =3D cnt; - } - - /* The 'used' flag is used to indicate when the information - in the section group is used to mark all other sections - as used. So it must not be true yet. */ - assert (fileinfo->scninfo[cnt].used =3D=3D false); - } - else if (! SECTION_TYPE_P (&ld_state, shdr->sh_type) - && unlikely ((shdr->sh_flags & SHF_OS_NONCONFORMING) !=3D 0)) - /* According to the gABI it is a fatal error if the file contains - a section with unknown type and the SHF_OS_NONCONFORMING flag - set. */ - error (EXIT_FAILURE, 0, - gettext ("%s: section '%s' has unknown type: %d"), - fileinfo->fname, - elf_strptr (fileinfo->elf, fileinfo->shstrndx, - shdr->sh_name), - (int) shdr->sh_type); - /* We don't have to add a few section types here. These will be - generated from scratch for the new output file. We also - don't add the sections of DSOs here since these sections are - not used in the resulting object file. */ - else if (likely (fileinfo->file_type =3D=3D relocatable_file_type) - && likely (cnt > 0) - && likely (shdr->sh_type =3D=3D SHT_PROGBITS - || shdr->sh_type =3D=3D SHT_RELA - || shdr->sh_type =3D=3D SHT_REL - || shdr->sh_type =3D=3D SHT_NOTE - || shdr->sh_type =3D=3D SHT_NOBITS - || shdr->sh_type =3D=3D SHT_INIT_ARRAY - || shdr->sh_type =3D=3D SHT_FINI_ARRAY - || shdr->sh_type =3D=3D SHT_PREINIT_ARRAY)) - { - /* Check whether the section needs to be executable. */ - if (shdr->sh_type =3D=3D SHT_PROGBITS - && (shdr->sh_flags & SHF_EXECINSTR) =3D=3D 0 - && strcmp (elf_strptr (fileinfo->elf, fileinfo->shstrndx, - shdr->sh_name), - ".note.GNU-stack") =3D=3D 0) - execstack =3D execstack_false; - - add_section (fileinfo, &fileinfo->scninfo[cnt]); - } - } - - /* Now we know more about the requirements for an executable stack - of the result. */ - if (fileinfo->file_type =3D=3D relocatable_file_type - && execstack =3D=3D execstack_true - && ld_state.execstack !=3D execstack_false_force) - ld_state.execstack =3D execstack_true; - - /* Handle the symbols. Record defined and undefined symbols in the - hash table. In theory there can be a file without any symbol - table. */ - if (likely (symtabdata !=3D NULL)) - { - /* In case this file contains merge-able sections we have to - locate the symbols which are in these sections. */ - fileinfo->has_merge_sections =3D has_merge_sections; - if (likely (has_merge_sections || has_tls_symbols)) - { - fileinfo->symref =3D (struct symbol **) - obstack_calloc (&ld_state.smem, - nsymbols * sizeof (struct symbol *)); - - /* Only handle the local symbols here. */ - for (cnt =3D 0; cnt < nlocalsymbols; ++cnt) - { - Elf32_Word shndx; - XElf_Sym_vardef (sym); - - xelf_getsymshndx (symtabdata, xndxdata, cnt, sym, shndx); - if (sym =3D=3D NULL) - { - /* This should never happen. */ - fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"), - fileinfo->rfname, __FILE__, __LINE__); - return 1; - } - - if (likely (shndx !=3D SHN_XINDEX)) - shndx =3D sym->st_shndx; - else if (unlikely (shndx =3D=3D 0)) - { - fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"), - fileinfo->rfname, __FILE__, __LINE__); - return 1; - } - - if (XELF_ST_TYPE (sym->st_info) !=3D STT_SECTION - && (shndx < SHN_LORESERVE || shndx > SHN_HIRESERVE) - && ((SCNINFO_SHDR (fileinfo->scninfo[shndx].shdr).sh_flags - & SHF_MERGE) - || XELF_ST_TYPE (sym->st_info) =3D=3D STT_TLS)) - { - /* Create a symbol record for this symbol and add it - to the list for this section. */ - struct symbol *newp; - - newp =3D (struct symbol *) - obstack_calloc (&ld_state.smem, sizeof (struct symbol)); - - newp->symidx =3D cnt; - newp->scndx =3D shndx; - newp->file =3D fileinfo; - newp->defined =3D 1; - fileinfo->symref[cnt] =3D newp; - - if (fileinfo->scninfo[shndx].symbols =3D=3D NULL) - fileinfo->scninfo[shndx].symbols =3D newp->next_in_scn - =3D newp; - else - { - newp->next_in_scn - =3D fileinfo->scninfo[shndx].symbols->next_in_scn; - fileinfo->scninfo[shndx].symbols - =3D fileinfo->scninfo[shndx].symbols->next_in_scn =3D newp; - } - } - } - } - else - /* Create array with pointers to the symbol definitions. Note - that we only allocate memory for the non-local symbols - since we have no merge-able sections. But we store the - pointer as if it was for the whole symbol table. This - saves some memory. */ - fileinfo->symref =3D (struct symbol **) - obstack_calloc (&ld_state.smem, ((nsymbols - nlocalsymbols) - * sizeof (struct symbol *))) - - nlocalsymbols; - - /* Don't handle local symbols here. It's either not necessary - at all or has already happened. */ - for (cnt =3D nlocalsymbols; cnt < nsymbols; ++cnt) - { - XElf_Sym_vardef (sym); - Elf32_Word shndx; - xelf_getsymshndx (symtabdata, xndxdata, cnt, sym, shndx); - - if (sym =3D=3D NULL) - { - /* This should never happen. */ - fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"), - fileinfo->rfname, __FILE__, __LINE__); - return 1; - } - - if (likely (shndx !=3D SHN_XINDEX)) - shndx =3D sym->st_shndx; - else if (unlikely (shndx =3D=3D 0)) - { - fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"), - fileinfo->rfname, __FILE__, __LINE__); - return 1; - } - - /* We ignore ABS symbols from DSOs. */ - // XXX Is this correct? - if (unlikely (shndx =3D=3D SHN_ABS) && secttype =3D=3D SHT_DYNSYM) - continue; - - if ((shndx < SHN_LORESERVE || shndx > SHN_HIRESERVE) - && fileinfo->scninfo[shndx].unused_comdat) - /* The symbol is not used. */ - continue; - - /* If the DSO uses symbol versions determine whether this is - the default version. Otherwise we'll ignore the symbol. */ - if (versymdata !=3D NULL) - { - XElf_Versym versym; - - if (xelf_getversym_copy (versymdata, cnt, versym) =3D=3D NULL) - /* XXX Should we handle faulty input files more graceful? */ - assert (! "xelf_getversym failed"); - - if ((versym & 0x8000) !=3D 0) - /* Ignore the symbol, it's not the default version. */ - continue; - } - - /* See whether we know anything about this symbol. */ - struct symbol search; - search.name =3D elf_strptr (fileinfo->elf, symstridx, sym->st_name); - unsigned long int hval =3D elf_hash (search.name); - - /* We ignore the symbols the linker generates. This are - _GLOBAL_OFFSET_TABLE_, _DYNAMIC. */ - // XXX This loop is hot and the following tests hardly ever match. - // XXX Maybe move the tests somewhere they are executed less often. - if (((unlikely (hval =3D=3D 165832675ul) - && strcmp (search.name, "_DYNAMIC") =3D=3D 0) - || (unlikely (hval =3D=3D 102264335ul) - && strcmp (search.name, "_GLOBAL_OFFSET_TABLE_") =3D=3D 0)) - && sym->st_shndx !=3D SHN_UNDEF - /* If somebody defines such a variable in a relocatable we - don't ignore it. Let the user get what s/he deserves. */ - && fileinfo->file_type !=3D relocatable_file_type) - continue; - - struct symbol *oldp =3D ld_symbol_tab_find (&ld_state.symbol_tab, - hval, &search); - struct symbol *newp; - if (likely (oldp =3D=3D NULL)) - { - /* No symbol of this name known. Add it. */ - newp =3D (struct symbol *) obstack_alloc (&ld_state.smem, - sizeof (*newp)); - newp->name =3D search.name; - newp->size =3D sym->st_size; - newp->type =3D XELF_ST_TYPE (sym->st_info); - newp->symidx =3D cnt; - newp->outsymidx =3D 0; - newp->outdynsymidx =3D 0; - newp->scndx =3D shndx; - newp->file =3D fileinfo; - newp->defined =3D newp->scndx !=3D SHN_UNDEF; - newp->common =3D newp->scndx =3D=3D SHN_COMMON; - newp->weak =3D XELF_ST_BIND (sym->st_info) =3D=3D STB_WEAK; - newp->added =3D 0; - newp->merged =3D 0; - newp->local =3D 0; - newp->hidden =3D 0; - newp->need_copy =3D 0; - newp->on_dsolist =3D 0; - newp->in_dso =3D secttype =3D=3D SHT_DYNSYM; - newp->next_in_scn =3D NULL; -#ifndef NDEBUG - newp->next =3D NULL; - newp->previous =3D NULL; -#endif - - if (newp->scndx =3D=3D SHN_UNDEF) - { - CDBL_LIST_ADD_REAR (ld_state.unresolved, newp); - ++ld_state.nunresolved; - if (! newp->weak) - ++ld_state.nunresolved_nonweak; - } - else if (newp->scndx =3D=3D SHN_COMMON) - { - /* Store the alignment requirement. */ - newp->merge.value =3D sym->st_value; - - CDBL_LIST_ADD_REAR (ld_state.common_syms, newp); - } - - /* Insert the new symbol. */ - if (unlikely (ld_symbol_tab_insert (&ld_state.symbol_tab, - hval, newp) !=3D 0)) - /* This cannot happen. */ - abort (); - - fileinfo->symref[cnt] =3D newp; - - /* We have a few special symbols to recognize. The symbols - _init and _fini are the initialization and finalization - functions respectively. They have to be made known in - the dynamic section and therefore we have to find out - now whether these functions exist or not. */ - if (hval =3D=3D 6685956 && strcmp (newp->name, "_init") =3D=3D 0) - ld_state.init_symbol =3D newp; - else if (hval =3D=3D 6672457 && strcmp (newp->name, "_fini") =3D=3D= 0) - ld_state.fini_symbol =3D newp; - } - else if (unlikely (check_definition (sym, shndx, cnt, fileinfo, oldp) - !=3D 0)) - /* A fatal error (multiple definition of a symbol) - occurred, no need to continue. */ - return 1; - else - /* Use the previously allocated symbol record. It has - been updated in check_definition(), if necessary. */ - newp =3D fileinfo->symref[cnt] =3D oldp; - - /* Mark the section the symbol we need comes from as used. */ - if (shndx !=3D SHN_UNDEF - && (shndx < SHN_LORESERVE || shndx > SHN_HIRESERVE)) - { - struct scninfo *ignore; - -#ifndef NDEBUG - size_t shnum; - assert (elf_getshdrnum (fileinfo->elf, &shnum) =3D=3D 0); - assert (shndx < shnum); -#endif - - /* Mark section (and all dependencies) as used. */ - mark_section_used (&fileinfo->scninfo[shndx], shndx, &ignore); - - /* Check whether the section is merge-able. In this case we - have to record the symbol. */ - if (SCNINFO_SHDR (fileinfo->scninfo[shndx].shdr).sh_flags - & SHF_MERGE) - { - if (fileinfo->scninfo[shndx].symbols =3D=3D NULL) - fileinfo->scninfo[shndx].symbols =3D newp->next_in_scn - =3D newp; - else - { - newp->next_in_scn - =3D fileinfo->scninfo[shndx].symbols->next_in_scn; - fileinfo->scninfo[shndx].symbols - =3D fileinfo->scninfo[shndx].symbols->next_in_scn =3D newp; - } - } - } - } - - /* This file is used. */ - if (likely (fileinfo->file_type =3D=3D relocatable_file_type)) - { - if (unlikely (ld_state.relfiles =3D=3D NULL)) - ld_state.relfiles =3D fileinfo->next =3D fileinfo; - else - { - fileinfo->next =3D ld_state.relfiles->next; - ld_state.relfiles =3D ld_state.relfiles->next =3D fileinfo; - } - - /* Update some summary information in the state structure. */ - ld_state.nsymtab +=3D fileinfo->nsymtab; - ld_state.nlocalsymbols +=3D fileinfo->nlocalsymbols; - } - else if (likely (fileinfo->file_type =3D=3D dso_file_type)) - { - CSNGL_LIST_ADD_REAR (ld_state.dsofiles, fileinfo); - ++ld_state.ndsofiles; - - if (fileinfo->lazyload) - /* We have to create another dynamic section entry for the - DT_POSFLAG_1 entry. - - XXX Once more functionality than the lazyloading flag - are suppported the test must be extended. */ - ++ld_state.ndsofiles; - } - } - - return 0; -} - - -int -ld_handle_filename_list (struct filename_list *fnames) -{ - struct filename_list *runp; - int res =3D 0; - - for (runp =3D fnames; runp !=3D NULL; runp =3D runp->next) - { - struct usedfiles *curp; - - /* Create a record for the new file. */ - curp =3D runp->real =3D ld_new_inputfile (runp->name, relocatable_fi= le_type); - - /* Set flags for group handling. */ - curp->group_start =3D runp->group_start; - curp->group_end =3D runp->group_end; - - /* Set as-needed flag from the file, not the command line. */ - curp->as_needed =3D runp->as_needed; - - /* Read the file and everything else which comes up, including - handling groups. */ - do - res |=3D FILE_PROCESS (-1, curp, &ld_state, &curp); - while (curp !=3D NULL); - } - - /* Free the list. */ - while (fnames !=3D NULL) - { - runp =3D fnames; - fnames =3D fnames->next; - free (runp); - } - - return res; -} - - -/* Handle opening of the given file with ELF descriptor. */ -static int -open_elf (struct usedfiles *fileinfo, Elf *elf) -{ - int res =3D 0; - - if (elf =3D=3D NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot get descriptor for ELF file (%s:%d): %s\n"), - __FILE__, __LINE__, elf_errmsg (-1)); - - if (unlikely (elf_kind (elf) =3D=3D ELF_K_NONE)) - { - struct filename_list *fnames; - - /* We don't have to look at this file again. */ - fileinfo->status =3D closed; - - /* Let's see whether this is a linker script. */ - if (fileinfo->fd !=3D -1) - /* Create a stream from the file handle we know. */ - ldin =3D fdopen (fileinfo->fd, "r"); - else - { - /* Get the memory for the archive member. */ - char *content; - size_t contentsize; - - /* Get the content of the file. */ - content =3D elf_rawfile (elf, &contentsize); - if (content =3D=3D NULL) - { - fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"), - fileinfo->rfname, __FILE__, __LINE__); - return 1; - } - - /* The content of the file is available in memory. Read the - memory region as a stream. */ - ldin =3D fmemopen (content, contentsize, "r"); - } - - /* No need for locking. */ - __fsetlocking (ldin, FSETLOCKING_BYCALLER); - - if (ldin =3D=3D NULL) - error (EXIT_FAILURE, errno, gettext ("cannot open '%s'"), - fileinfo->rfname); - - /* Parse the file. If it is a linker script no problems will be - reported. */ - ld_state.srcfiles =3D NULL; - ldlineno =3D 1; - ld_scan_version_script =3D 0; - ldin_fname =3D fileinfo->rfname; - res =3D ldparse (); - - fclose (ldin); - if (fileinfo->fd !=3D -1 && !fileinfo->fd_passed) - { - /* We won't need the file descriptor again. */ - close (fileinfo->fd); - fileinfo->fd =3D -1; - } - - elf_end (elf); - - if (unlikely (res !=3D 0)) - /* Something went wrong during parsing. */ - return 1; - - /* This is no ELF file. */ - fileinfo->elf =3D NULL; - - /* Now we have to handle eventual INPUT and GROUP statements in - the script. Read the files mentioned. */ - fnames =3D ld_state.srcfiles; - if (fnames !=3D NULL) - { - struct filename_list *oldp; - - /* Convert the list into a normal single-linked list. */ - oldp =3D fnames; - fnames =3D fnames->next; - oldp->next =3D NULL; - - /* Remove the list from the state structure. */ - ld_state.srcfiles =3D NULL; - - if (unlikely (ld_handle_filename_list (fnames) !=3D 0)) - return 1; - } - - return 0; - } - - /* Store the file info. */ - fileinfo->elf =3D elf; - - /* The file is ready for action. */ - fileinfo->status =3D opened; - - return 0; -} - - -static int -add_whole_archive (struct usedfiles *fileinfo) -{ - Elf *arelf; - Elf_Cmd cmd =3D ELF_C_READ_MMAP_PRIVATE; - int res =3D 0; - - while ((arelf =3D elf_begin (fileinfo->fd, cmd, fileinfo->elf)) !=3D NUL= L) - { - Elf_Arhdr *arhdr =3D elf_getarhdr (arelf); - struct usedfiles *newp; - - if (arhdr =3D=3D NULL) - abort (); - - /* Just to be sure; since these are no files in the archive - these names should never be returned. */ - assert (strcmp (arhdr->ar_name, "/") !=3D 0); - assert (strcmp (arhdr->ar_name, "//") !=3D 0); - - newp =3D ld_new_inputfile (arhdr->ar_name, relocatable_file_type); - newp->archive_file =3D fileinfo; - - if (unlikely (ld_state.trace_files)) - print_file_name (stdout, newp, 1, 1); - - /* This shows that this file is contained in an archive. */ - newp->fd =3D -1; - /* Store the ELF descriptor. */ - newp->elf =3D arelf; - /* Show that we are open for business. */ - newp->status =3D opened; - - /* Proces the file, add all the symbols etc. */ - res =3D file_process2 (newp); - if (unlikely (res !=3D 0)) - break; - - /* Advance to the next archive element. */ - cmd =3D elf_next (arelf); - } - - return res; -} - - -static int -extract_from_archive (struct usedfiles *fileinfo) -{ - static int archive_seq; - int res =3D 0; - - if (fileinfo->archive_seq =3D=3D 0) - /* This is an archive we are not using completely. Give it a - unique number. */ - fileinfo->archive_seq =3D ++archive_seq; - - /* If there are no unresolved symbols don't do anything. */ - assert (ld_state.extract_rule =3D=3D defaultextract - || ld_state.extract_rule =3D=3D weakextract); - if ((likely (ld_state.extract_rule =3D=3D defaultextract) - ? ld_state.nunresolved_nonweak : ld_state.nunresolved) =3D=3D 0) - return 0; - - Elf_Arsym *syms; - size_t nsyms; - - /* Get all the symbols. */ - syms =3D elf_getarsym (fileinfo->elf, &nsyms); - if (syms =3D=3D NULL) - { - cannot_read_archive: - error (0, 0, gettext ("cannot read archive `%s': %s"), - fileinfo->rfname, elf_errmsg (-1)); - - /* We cannot use this archive anymore. */ - fileinfo->status =3D closed; - - return 1; - } - - /* Now add all the symbols to the hash table. Note that there - can potentially be duplicate definitions. We'll always use - the first definition. */ - // XXX Is this a compatible behavior? - bool any_used; - do - { - any_used =3D false; - - size_t cnt; - for (cnt =3D 0; cnt < nsyms; ++cnt) - { - struct symbol search =3D { .name =3D syms[cnt].as_name }; - struct symbol *sym =3D ld_symbol_tab_find (&ld_state.symbol_tab, - syms[cnt].as_hash, &search); - if (sym !=3D NULL && ! sym->defined) - { - /* The symbol is referenced and not defined. */ - Elf *arelf; - Elf_Arhdr *arhdr; - struct usedfiles *newp; - - /* Find the archive member for this symbol. */ - if (unlikely (elf_rand (fileinfo->elf, syms[cnt].as_off) - !=3D syms[cnt].as_off)) - goto cannot_read_archive; - - /* Note: no test of a failing 'elf_begin' call. That's fine - since 'elf'getarhdr' will report the problem. */ - arelf =3D elf_begin (fileinfo->fd, ELF_C_READ_MMAP_PRIVATE, - fileinfo->elf); - arhdr =3D elf_getarhdr (arelf); - if (arhdr =3D=3D NULL) - goto cannot_read_archive; - - /* We have all the information and an ELF handle for the - archive member. Create the normal data structure for - a file now. */ - newp =3D ld_new_inputfile (obstack_strdup (&ld_state.smem, - arhdr->ar_name), - relocatable_file_type); - newp->archive_file =3D fileinfo; - - if (unlikely (ld_state.trace_files)) - print_file_name (stdout, newp, 1, 1); - - /* This shows that this file is contained in an archive. */ - newp->fd =3D -1; - /* Store the ELF descriptor. */ - newp->elf =3D arelf; - /* Show that we are open for business. */ - newp->status =3D in_archive; - - /* Now read the file and add all the symbols. */ - res =3D file_process2 (newp); - if (unlikely (res !=3D 0)) - return res; - - any_used =3D true; - } - } - - if (any_used) - { - /* This is an archive therefore it must have a number. */ - assert (fileinfo->archive_seq !=3D 0); - ld_state.last_archive_used =3D fileinfo->archive_seq; - } - } - while (any_used); - - return res; -} - - -static int -file_process2 (struct usedfiles *fileinfo) -{ - int res; - - if (likely (elf_kind (fileinfo->elf) =3D=3D ELF_K_ELF)) - { - /* The first time we get here we read the ELF header. */ -#if NATIVE_ELF !=3D 0 - if (likely (fileinfo->ehdr =3D=3D NULL)) -#else - if (likely (FILEINFO_EHDR (fileinfo->ehdr).e_type =3D=3D ET_NONE)) -#endif - { - XElf_Ehdr *ehdr; -#if NATIVE_ELF !=3D 0 - ehdr =3D xelf_getehdr (fileinfo->elf, fileinfo->ehdr); -#else - xelf_getehdr_copy (fileinfo->elf, ehdr, fileinfo->ehdr); -#endif - if (ehdr =3D=3D NULL) - { - fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"), - fileinfo->rfname, __FILE__, __LINE__); - fileinfo->status =3D closed; - return 1; - } - - if (FILEINFO_EHDR (fileinfo->ehdr).e_type !=3D ET_REL - && unlikely (FILEINFO_EHDR (fileinfo->ehdr).e_type !=3D ET_DYN)) - /* XXX Add ebl* function to query types which are allowed - to link in. */ - { - char buf[64]; - - print_file_name (stderr, fileinfo, 1, 0); - fprintf (stderr, - gettext ("file of type %s cannot be linked in\n"), - ebl_object_type_name (ld_state.ebl, - FILEINFO_EHDR (fileinfo->ehdr).e_type, - buf, sizeof (buf))); - fileinfo->status =3D closed; - return 1; - } - - /* Make sure the file type matches the backend. */ - if (FILEINFO_EHDR (fileinfo->ehdr).e_machine - !=3D ebl_get_elfmachine (ld_state.ebl)) - { - fprintf (stderr, gettext ("\ -%s: input file incompatible with ELF machine type %s\n"), - fileinfo->rfname, - ebl_backend_name (ld_state.ebl)); - fileinfo->status =3D closed; - return 1; - } - - /* Determine the section header string table section index. */ - if (unlikely (elf_getshdrstrndx (fileinfo->elf, &fileinfo->shstrndx) - < 0)) - { - fprintf (stderr, gettext ("\ -%s: cannot get section header string table index: %s\n"), - fileinfo->rfname, elf_errmsg (-1)); - fileinfo->status =3D closed; - return 1; - } - } - - /* Now handle the different types of files. */ - if (FILEINFO_EHDR (fileinfo->ehdr).e_type =3D=3D ET_REL) - { - /* Add all the symbol. Relocatable files have symbol - tables. */ - res =3D add_relocatable_file (fileinfo, SHT_SYMTAB); - } - else - { - bool has_l_name =3D fileinfo->file_type =3D=3D archive_file_type; - - assert (FILEINFO_EHDR (fileinfo->ehdr).e_type =3D=3D ET_DYN); - - /* If the file is a DT_NEEDED dependency then the type is - already correctly specified. */ - if (fileinfo->file_type !=3D dso_needed_file_type) - fileinfo->file_type =3D dso_file_type; - - /* We cannot use DSOs when generating relocatable objects. */ - if (ld_state.file_type =3D=3D relocatable_file_type) - { - error (0, 0, gettext ("\ -cannot use DSO '%s' when generating relocatable object file"), - fileinfo->fname); - return 1; - } - - /* Add all the symbols. For DSOs we are looking at the - dynamic symbol table. */ - res =3D add_relocatable_file (fileinfo, SHT_DYNSYM); - - /* We always have to have a dynamic section. */ - assert (fileinfo->dynscn !=3D NULL); - - /* We have to remember the dependencies for this object. It - is necessary to look them up. */ - XElf_Shdr_vardef (dynshdr); - xelf_getshdr (fileinfo->dynscn, dynshdr); - - Elf_Data *dyndata =3D elf_getdata (fileinfo->dynscn, NULL); - /* XXX Should we flag the failure to get the dynamic section? */ - if (dynshdr !=3D NULL) - { - int cnt =3D dynshdr->sh_size / dynshdr->sh_entsize; - XElf_Dyn_vardef (dyn); - - while (--cnt >=3D 0) - { - xelf_getdyn (dyndata, cnt, dyn); - if (dyn !=3D NULL) - { - if(dyn->d_tag =3D=3D DT_NEEDED) - { - struct usedfiles *newp; - - newp =3D ld_new_inputfile (elf_strptr (fileinfo->elf, - dynshdr->sh_link, - dyn->d_un.d_val), - dso_needed_file_type); - - /* Enqueue the newly found dependencies. */ - // XXX Check that there not already a file with the - // same name. - CSNGL_LIST_ADD_REAR (ld_state.needed, newp); - } - else if (dyn->d_tag =3D=3D DT_SONAME) - { - /* We use the DT_SONAME (this is what's there - for). */ - fileinfo->soname =3D elf_strptr (fileinfo->elf, - dynshdr->sh_link, - dyn->d_un.d_val); - has_l_name =3D false; - } - } - } - } - - /* Construct the file name if the DSO has no SONAME and the - file name comes from a -lXX parameter on the comment - line. */ - if (unlikely (has_l_name)) - { - /* The FNAME is the parameter the user specified on the - command line. We prepend "lib" and append ".so". */ - size_t len =3D strlen (fileinfo->fname) + 7; - char *newp; - - newp =3D (char *) obstack_alloc (&ld_state.smem, len); - strcpy (stpcpy (stpcpy (newp, "lib"), fileinfo->fname), ".so"); - - fileinfo->soname =3D newp; - } - } - } - else if (likely (elf_kind (fileinfo->elf) =3D=3D ELF_K_AR)) - { - if (unlikely (ld_state.extract_rule =3D=3D allextract)) - /* Which this option enabled we have to add all the object - files in the archive. */ - res =3D add_whole_archive (fileinfo); - else if (ld_state.file_type =3D=3D relocatable_file_type) - { - /* When generating a relocatable object we don't find files - in archives. */ - if (verbose) - error (0, 0, gettext ("input file '%s' ignored"), fileinfo->fname); - - res =3D 0; - } - else - { - if (ld_state.group_start_requested - && ld_state.group_start_archive =3D=3D NULL) - ld_state.group_start_archive =3D fileinfo; - - if (ld_state.archives =3D=3D NULL) - ld_state.archives =3D fileinfo; - - if (ld_state.tailarchives !=3D NULL) - ld_state.tailarchives->next =3D fileinfo; - ld_state.tailarchives =3D fileinfo; - - /* Extract only the members from the archive which are - currently referenced by unresolved symbols. */ - res =3D extract_from_archive (fileinfo); - } - } - else - /* This should never happen, we know about no other types. */ - abort (); - - return res; -} - - -/* Process a given file. The first parameter is a file descriptor for - the file which can be -1 to indicate the file has not yet been - found. The second parameter describes the file to be opened, the - last one is the state of the linker which among other information - contain the paths we look at. */ -static int -ld_generic_file_process (int fd, struct usedfiles *fileinfo, - struct ld_state *statep, struct usedfiles **nextp) -{ - int res =3D 0; - - /* By default we go to the next file in the list. */ - *nextp =3D fileinfo->next; - - /* Set the flag to signal we are looking for a group start. */ - if (unlikely (fileinfo->group_start)) - { - ld_state.group_start_requested =3D true; - fileinfo->group_start =3D false; - } - - /* If the file isn't open yet, open it now. */ - if (likely (fileinfo->status =3D=3D not_opened)) - { - bool fd_passed =3D true; - - if (likely (fd =3D=3D -1)) - { - /* Find the file ourselves. */ - int err =3D open_along_path (fileinfo); - if (unlikely (err !=3D 0)) - /* We allow libraries and DSOs to be named more than once. - Don't report an error to the caller. */ - return err =3D=3D EAGAIN ? 0 : err; - - fd_passed =3D false; - } - else - fileinfo->fd =3D fd; - - /* Remember where we got the descriptor from. */ - fileinfo->fd_passed =3D fd_passed; - - /* We found the file. Now test whether it is a file type we can - handle. - - XXX Do we need to have the ability to start from a given - position in the search path again to look for another file if - the one found has not the right type? */ - res =3D open_elf (fileinfo, elf_begin (fileinfo->fd, - is_dso_p (fileinfo->fd) - ? ELF_C_READ_MMAP - : ELF_C_READ_MMAP_PRIVATE, NULL)); - if (unlikely (res !=3D 0)) - return res; - } - - /* Now that we have opened the file start processing it. */ - if (likely (fileinfo->status !=3D closed)) - res =3D file_process2 (fileinfo); - - /* Determine which file to look at next. */ - if (unlikely (fileinfo->group_backref !=3D NULL)) - { - /* We only go back if an archive other than the one we would go - back to has been used in the last round. */ - if (ld_state.last_archive_used > fileinfo->group_backref->archive_se= q) - { - *nextp =3D fileinfo->group_backref; - ld_state.last_archive_used =3D 0; - } - else - { - /* If we come here this means that the archives we read so - far are not needed anymore. We can free some of the data - now. */ - struct usedfiles *runp =3D ld_state.archives; - - do - { - /* We don't need the ELF descriptor anymore. Unless there - are no files from the archive used this will not free - the whole file but only some data structures. */ - elf_end (runp->elf); - runp->elf =3D NULL; - - runp =3D runp->next; - } - while (runp !=3D fileinfo->next); - - /* Do not do this again. */ - ld_state.archives =3D NULL; - - /* Do not move on to the next archive. */ - *nextp =3D fileinfo->next =3D NULL; - } - } - else if (unlikely (fileinfo->group_end)) - { - /* This is the end of a group. We possibly have to go back. - Determine which file we would go back to and see whether it - makes sense. If there has not been an archive we don't have - to do anything. */ - if (ld_state.group_start_requested) - { - if (ld_state.group_start_archive !=3D ld_state.tailarchives) - /* The loop includes more than one archive, add the pointer. */ - { - *nextp =3D ld_state.tailarchives->group_backref =3D - ld_state.group_start_archive; - ld_state.last_archive_used =3D 0; - } - else - /* We might still have to go back to the beginning of the - group if since the last archive other files have been - added. But we go back exactly once. */ - if (ld_state.tailarchives !=3D fileinfo) - { - *nextp =3D ld_state.group_start_archive; - ld_state.last_archive_used =3D 0; - } - } - - /* Clear the flags. */ - ld_state.group_start_requested =3D false; - ld_state.group_start_archive =3D NULL; - fileinfo->group_end =3D false; - } - - return res; -} - - -/* Library names passed to the linker as -lXX represent files named - libXX.YY. The YY part can have different forms, depending on the - platform. The generic set is .so and .a (in this order). */ -static const char ** -ld_generic_lib_extensions (struct ld_state *statep __attribute__ ((__unuse= d__))) -{ - static const char *exts[] =3D - { - ".so", ".a", NULL - }; - - return exts; -} - - -/* Flag unresolved symbols. */ -static int -ld_generic_flag_unresolved (struct ld_state *statep) -{ - int retval =3D 0; - - if (ld_state.nunresolved_nonweak > 0) - { - /* Go through the list and determine the unresolved symbols. */ - struct symbol *first; - struct symbol *s; - - s =3D first =3D ld_state.unresolved->next; - do - { - if (! s->defined && ! s->weak) - { - /* Two special symbol we recognize: the symbol for the - GOT and the dynamic section. */ - if (strcmp (s->name, "_GLOBAL_OFFSET_TABLE_") =3D=3D 0 - || strcmp (s->name, "_DYNAMIC") =3D=3D 0) - { - /* We will have to fill in more information later. */ - ld_state.need_got =3D true; - - /* Remember that we found it. */ - if (s->name[1] =3D=3D 'G') - ld_state.got_symbol =3D s; - else - ld_state.dyn_symbol =3D s; - } - else if (ld_state.file_type !=3D dso_file_type || !ld_state.nodefs) - { - /* XXX The error message should get better. It should use - the debugging information if present to tell where in the - sources the undefined reference is. */ - error (0, 0, gettext ("undefined symbol `%s' in %s"), - s->name, s->file->fname); - - retval =3D 1; - } - } - - /* We cannot decide here what to do with undefined - references which will come from DSO since we do not know - what kind of symbol we expect. Only when looking at the - relocations we can see whether we need a PLT entry or - only a GOT entry. */ - - s =3D s->next; - } - while (s !=3D first); - } - - return retval; -} - - -/* Close the given file. */ -static int -ld_generic_file_close (struct usedfiles *fileinfo, struct ld_state *statep) -{ - /* Close the ELF descriptor. */ - elf_end (fileinfo->elf); - - /* If we have opened the file descriptor close it. But we might - have done this already in which case FD is -1. */ - if (!fileinfo->fd_passed && fileinfo->fd !=3D -1) - close (fileinfo->fd); - - /* We allocated the resolved file name. */ - if (fileinfo->fname !=3D fileinfo->rfname) - free ((char *) fileinfo->rfname); - - return 0; -} - - -static void -new_generated_scn (enum scn_kind kind, const char *name, int type, int fla= gs, - int entsize, int align) -{ - struct scnhead *newp; - - newp =3D (struct scnhead *) obstack_calloc (&ld_state.smem, - sizeof (struct scnhead)); - newp->kind =3D kind; - newp->name =3D name; - newp->nameent =3D ebl_strtabadd (ld_state.shstrtab, name, 0); - newp->type =3D type; - newp->flags =3D flags; - newp->entsize =3D entsize; - newp->align =3D align; - newp->grp_signature =3D NULL; - newp->used =3D true; - - /* All is well. Create now the data for the section and insert it - into the section table. */ - ld_section_tab_insert (&ld_state.section_tab, elf_hash (name), newp); -} - - -/* Create the sections which are generated by the linker and are not - present in the input file. */ -static void -ld_generic_generate_sections (struct ld_state *statep) -{ - /* The relocation section type. */ - int rel_type =3D REL_TYPE (&ld_state) =3D=3D DT_REL ? SHT_REL : SHT_RELA; - - /* When requested, every output file will have a build ID section. */ - if (statep->build_id !=3D NULL) - new_generated_scn (scn_dot_note_gnu_build_id, ".note.gnu.build-id", - SHT_NOTE, SHF_ALLOC, 0, 4); - - /* When building dynamically linked object we have to include a - section containing a string describing the interpreter. This - should be at the very beginning of the file together with the - other information the ELF loader (kernel or wherever) has to look - at. We put it as the first section in the file. - - We also have to create the dynamic segment which is a special - section the dynamic linker locates through an entry in the - program header. */ - if (dynamically_linked_p ()) - { - /* Use any versioning (defined or required)? */ - bool use_versioning =3D false; - /* Use version requirements? */ - bool need_version =3D false; - - /* First the .interp section. */ - if (ld_state.interp !=3D NULL || ld_state.file_type !=3D dso_file_ty= pe) - new_generated_scn (scn_dot_interp, ".interp", SHT_PROGBITS, SHF_ALLOC, - 0, 1); - - /* Now the .dynamic section. */ - new_generated_scn (scn_dot_dynamic, ".dynamic", SHT_DYNAMIC, - DYNAMIC_SECTION_FLAGS (&ld_state), - xelf_fsize (ld_state.outelf, ELF_T_DYN, 1), - xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1)); - - /* We will need in any case the dynamic symbol table (even in - the unlikely case that no symbol is exported or referenced - from a DSO). */ - ld_state.need_dynsym =3D true; - new_generated_scn (scn_dot_dynsym, ".dynsym", SHT_DYNSYM, SHF_ALLOC, - xelf_fsize (ld_state.outelf, ELF_T_SYM, 1), - xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1)); - /* It comes with a string table. */ - new_generated_scn (scn_dot_dynstr, ".dynstr", SHT_STRTAB, SHF_ALLOC, - 0, 1); - /* And a hashing table. */ - // XXX For Linux/Alpha we need other sizes unless they change... - if (GENERATE_SYSV_HASH) - new_generated_scn (scn_dot_hash, ".hash", SHT_HASH, SHF_ALLOC, - sizeof (Elf32_Word), sizeof (Elf32_Word)); - if (GENERATE_GNU_HASH) - new_generated_scn (scn_dot_gnu_hash, ".gnu.hash", SHT_GNU_HASH, - SHF_ALLOC, sizeof (Elf32_Word), - sizeof (Elf32_Word)); - - /* Create the section associated with the PLT if necessary. */ - if (ld_state.nplt > 0) - { - /* Create the .plt section. */ - /* XXX We might need a function which returns the section flags. */ - new_generated_scn (scn_dot_plt, ".plt", SHT_PROGBITS, - SHF_ALLOC | SHF_EXECINSTR, - /* XXX Is the size correct? */ - xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1), - xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1)); - - /* Create the relocation section for the .plt. This is always - separate even if the other relocation sections are combined. */ - new_generated_scn (scn_dot_pltrel, ".rel.plt", rel_type, SHF_ALLOC, - rel_type =3D=3D SHT_REL - ? xelf_fsize (ld_state.outelf, ELF_T_REL, 1) - : xelf_fsize (ld_state.outelf, ELF_T_RELA, 1), - xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1)); - - /* XXX We might need a function which returns the section flags. */ - new_generated_scn (scn_dot_gotplt, ".got.plt", SHT_PROGBITS, - SHF_ALLOC | SHF_WRITE, - xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1), - xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1)); - - /* Mark all used DSOs as used. Determine whether any referenced - object uses symbol versioning. */ - if (ld_state.from_dso !=3D NULL) - { - struct symbol *srunp =3D ld_state.from_dso; - - do - { - srunp->file->used =3D true; - - if (srunp->file->verdefdata !=3D NULL) - { - XElf_Versym versym; - - /* The input DSO uses versioning. */ - use_versioning =3D true; - /* We reference versions. */ - need_version =3D true; - - if (xelf_getversym_copy (srunp->file->versymdata, - srunp->symidx, versym) =3D=3D NULL) - assert (! "xelf_getversym failed"); - - /* We cannot link explicitly with an older - version of a symbol. */ - assert ((versym & 0x8000) =3D=3D 0); - /* We cannot reference local (index 0) or plain - global (index 1) versions. */ - assert (versym > 1); - - /* Check whether we have already seen the - version and if not add it to the referenced - versions in the output file. */ - if (! srunp->file->verdefused[versym]) - { - srunp->file->verdefused[versym] =3D 1; - - if (++srunp->file->nverdefused =3D=3D 1) - /* Count the file if it is using versioning. */ - ++ld_state.nverdeffile; - ++ld_state.nverdefused; - } - } - } - while ((srunp =3D srunp->next) !=3D ld_state.from_dso); - } - - /* Create the sections used to record version dependencies. */ - if (need_version) - new_generated_scn (scn_dot_version_r, ".gnu.version_r", - SHT_GNU_verneed, SHF_ALLOC, 0, - xelf_fsize (ld_state.outelf, ELF_T_WORD, 1)); - } - - /* Now count the used DSOs since this is what the user - wants. */ - int ndt_needed =3D 0; - if (ld_state.ndsofiles > 0) - { - struct usedfiles *frunp =3D ld_state.dsofiles; - - do - if (! frunp->as_needed || frunp->used) - { - ++ndt_needed; - if (frunp->lazyload) - /* We have to create another dynamic section - entry for the DT_POSFLAG_1 entry. - - XXX Once more functionality than the lazyloading - flag are suppported the test must be - extended. */ - ++ndt_needed; - } - while ((frunp =3D frunp->next) !=3D ld_state.dsofiles); - } - - if (use_versioning) - new_generated_scn (scn_dot_version, ".gnu.version", SHT_GNU_versym, - SHF_ALLOC, - xelf_fsize (ld_state.outelf, ELF_T_HALF, 1), - xelf_fsize (ld_state.outelf, ELF_T_HALF, 1)); - - /* We need some entries all the time. */ - ld_state.ndynamic =3D (7 + (ld_state.runpath !=3D NULL - || ld_state.rpath !=3D NULL) - + ndt_needed - + (ld_state.init_symbol !=3D NULL ? 1 : 0) - + (ld_state.fini_symbol !=3D NULL ? 1 : 0) - + (use_versioning ? 1 : 0) - + (need_version ? 2 : 0) - + (ld_state.nplt > 0 ? 4 : 0) - + (ld_state.relsize_total > 0 ? 3 : 0)); - } - - /* When creating a relocatable file or when we are not stripping the - output file we create a symbol table. */ - ld_state.need_symtab =3D (ld_state.file_type =3D=3D relocatable_file_type - || ld_state.strip =3D=3D strip_none); - - /* Add the .got section if needed. */ - if (ld_state.need_got) - /* XXX We might need a function which returns the section flags. */ - new_generated_scn (scn_dot_got, ".got", SHT_PROGBITS, - SHF_ALLOC | SHF_WRITE, - xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1), - xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1)); - - /* Add the .rel.dyn section. */ - if (ld_state.relsize_total > 0) - new_generated_scn (scn_dot_dynrel, ".rel.dyn", rel_type, SHF_ALLOC, - rel_type =3D=3D SHT_REL - ? xelf_fsize (ld_state.outelf, ELF_T_REL, 1) - : xelf_fsize (ld_state.outelf, ELF_T_RELA, 1), - xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1)); -} - - -/* Callback function registered with on_exit to make sure the temporary - files gets removed if something goes wrong. */ -static void -remove_tempfile (int status, void *arg) -{ - if (status !=3D 0 && ld_state.tempfname !=3D NULL) - unlink (ld_state.tempfname); -} - - -/* Create the output file. The file name is given or "a.out". We - create as much of the ELF structure as possible. */ -static int -ld_generic_open_outfile (struct ld_state *statep, int machine, int klass, - int data) -{ - /* We do not create the new file right away with the final name. - This would destroy an existing file with this name before a - replacement is finalized. We create instead a temporary file in - the same directory. */ - if (ld_state.outfname =3D=3D NULL) - ld_state.outfname =3D "a.out"; - - size_t outfname_len =3D strlen (ld_state.outfname); - char *tempfname =3D (char *) obstack_alloc (&ld_state.smem, - outfname_len + sizeof (".XXXXXX")); - ld_state.tempfname =3D tempfname; - - int fd; - int try =3D 0; - while (1) - { - strcpy (mempcpy (tempfname, ld_state.outfname, outfname_len), ".XXXX= XX"); - - /* The use of mktemp() here is fine. We do not want to use - mkstemp() since then the umask isn't used. And the output - file will have these permissions anyhow. Any intruder could - change the file later if it would be possible now. */ - if (mktemp (tempfname) !=3D NULL - && (fd =3D open (tempfname, O_RDWR | O_EXCL | O_CREAT | O_NOFOLLOW, - ld_state.file_type =3D=3D relocatable_file_type - ? DEFFILEMODE : ACCESSPERMS)) !=3D -1) - break; - - /* Failed this round. We keep trying a number of times. */ - if (++try >=3D 10) - error (EXIT_FAILURE, errno, gettext ("cannot create output file")); - } - ld_state.outfd =3D fd; - - /* Make sure we remove the temporary file in case something goes - wrong. */ - on_exit (remove_tempfile, NULL); - - /* Create the ELF file data for the output file. */ - Elf *elf =3D ld_state.outelf =3D elf_begin (fd, - conserve_memory - ? ELF_C_WRITE : ELF_C_WRITE_MMAP, - NULL); - if (elf =3D=3D NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create ELF descriptor for output file: %s"), - elf_errmsg (-1)); - - /* Create the basic data structures. */ - if (! xelf_newehdr (elf, klass)) - /* Couldn't create the ELF header. Very bad. */ - error (EXIT_FAILURE, 0, - gettext ("could not create ELF header for output file: %s"), - elf_errmsg (-1)); - - /* And get the current header so that we can modify it. */ - XElf_Ehdr_vardef (ehdr); - xelf_getehdr (elf, ehdr); - assert (ehdr !=3D NULL); - - /* Set the machine type. */ - ehdr->e_machine =3D machine; - - /* Modify it according to the info we have here and now. */ - if (ld_state.file_type =3D=3D executable_file_type) - ehdr->e_type =3D ET_EXEC; - else if (ld_state.file_type =3D=3D dso_file_type) - ehdr->e_type =3D ET_DYN; - else - { - assert (ld_state.file_type =3D=3D relocatable_file_type); - ehdr->e_type =3D ET_REL; - } - - /* Set the ELF version. */ - ehdr->e_version =3D EV_CURRENT; - - /* Set the endianness. */ - ehdr->e_ident[EI_DATA] =3D data; - - /* Write the ELF header information back. */ - (void) xelf_update_ehdr (elf, ehdr); - - return 0; -} - - -/* We compute the offsets of the various copied objects and the total - size of the memory needed. */ -// XXX The method used here is simple: go from front to back and pack -// the objects in this order. A more space efficient way would -// actually trying to pack the objects as dense as possible. But this -// is more expensive. -static void -compute_copy_reloc_offset (XElf_Shdr *shdr) -{ - struct symbol *runp =3D ld_state.from_dso; - assert (runp !=3D NULL); - - XElf_Off maxalign =3D 1; - XElf_Off offset =3D 0; - - do - if (runp->need_copy) - { - /* Determine alignment for the symbol. */ - // XXX The question is how? The symbol record itself does not - // have the information. So we have to be conservative and - // assume the alignment of the section the symbol is in. - - // XXX We can be more precise. Use the offset from the beginning - // of the section and determine the largest power of two with - // module zero. - XElf_Off symalign =3D MAX (SCNINFO_SHDR (runp->file->scninfo[runp->scndx]= .shdr).sh_addralign, 1); - /* Keep track of the maximum alignment requirement. */ - maxalign =3D MAX (maxalign, symalign); - - /* Align current position. */ - offset =3D (offset + symalign - 1) & ~(symalign - 1); - - runp->merge.value =3D offset; - - offset +=3D runp->size; - } - while ((runp =3D runp->next) !=3D ld_state.from_dso); - - shdr->sh_type =3D SHT_NOBITS; - shdr->sh_size =3D offset; - shdr->sh_addralign =3D maxalign; -} - - -static void -compute_common_symbol_offset (XElf_Shdr *shdr) -{ - struct symbol *runp =3D ld_state.common_syms; - assert (runp !=3D NULL); - - XElf_Off maxalign =3D 1; - XElf_Off offset =3D 0; - - do - { - /* Determine alignment for the symbol. */ - XElf_Off symalign =3D runp->merge.value; - - /* Keep track of the maximum alignment requirement. */ - maxalign =3D MAX (maxalign, symalign); - - /* Align current position. */ - offset =3D (offset + symalign - 1) & ~(symalign - 1); - - runp->merge.value =3D offset; - - offset +=3D runp->size; - } - while ((runp =3D runp->next) !=3D ld_state.common_syms); - - shdr->sh_type =3D SHT_NOBITS; - shdr->sh_size =3D offset; - shdr->sh_addralign =3D maxalign; -} - - -static void -sort_sections_generic (void) -{ - /* XXX TBI */ - abort (); -} - - -static int -match_section (const char *osectname, struct filemask_section_name *sectma= sk, - struct scnhead **scnhead, bool new_section, size_t segment_nr) -{ - struct scninfo *prevp; - struct scninfo *runp; - struct scninfo *notused; - - if (fnmatch (sectmask->section_name->name, (*scnhead)->name, 0) !=3D 0) - /* The section name does not match. */ - return new_section; - - /* If this is a section generated by the linker it doesn't contain - the regular information (i.e., input section data etc) and must - be handle special. */ - if ((*scnhead)->kind !=3D scn_normal) - { - (*scnhead)->name =3D osectname; - (*scnhead)->segment_nr =3D segment_nr; - - /* We have to count note section since they get their own - program header entry. */ - if ((*scnhead)->type =3D=3D SHT_NOTE) - ++ld_state.nnotesections; - - ld_state.allsections[ld_state.nallsections++] =3D (*scnhead); - return true; - } - - /* Now we have to match the file names of the input files. Some of - the sections here might not match. */ - runp =3D (*scnhead)->last->next; - prevp =3D (*scnhead)->last; - notused =3D NULL; - - do - { - /* Base of the file name the section comes from. */ - const char *brfname =3D basename (runp->fileinfo->rfname); - - /* If the section isn't used, the name doesn't match the positive - inclusion list, or the name does match the negative inclusion - list, ignore the section. */ - if (!runp->used - || (sectmask->filemask !=3D NULL - && fnmatch (sectmask->filemask, brfname, 0) !=3D 0) - || (sectmask->excludemask !=3D NULL - && fnmatch (sectmask->excludemask, brfname, 0) =3D=3D 0)) - { - /* This file does not match the file name masks. */ - if (notused =3D=3D NULL) - notused =3D runp; - - prevp =3D runp; - runp =3D runp->next; - if (runp =3D=3D notused) - runp =3D NULL; - } - /* The section fulfills all requirements, add it to the output - file with the correct section name etc. */ - else - { - struct scninfo *found =3D runp; - - /* Remove this input section data buffer from the list. */ - if (prevp !=3D runp) - runp =3D prevp->next =3D runp->next; - else - { - free (*scnhead); - *scnhead =3D NULL; - runp =3D NULL; - } - - /* Create a new section for the output file if the 'new_section' - flag says so. Otherwise append the buffer to the last - section which we created in one of the last calls. */ - if (new_section) - { - struct scnhead *newp; - - newp =3D (struct scnhead *) obstack_calloc (&ld_state.smem, - sizeof (*newp)); - newp->kind =3D scn_normal; - newp->name =3D osectname; - newp->type =3D SCNINFO_SHDR (found->shdr).sh_type; - /* Executable or DSO do not have section groups. Drop that - information. */ - newp->flags =3D SCNINFO_SHDR (found->shdr).sh_flags & ~SHF_GROUP; - newp->segment_nr =3D segment_nr; - newp->last =3D found->next =3D found; - newp->used =3D true; - newp->relsize =3D found->relsize; - newp->entsize =3D SCNINFO_SHDR (found->shdr).sh_entsize; - - /* We have to count note section since they get their own - program header entry. */ - if (newp->type =3D=3D SHT_NOTE) - ++ld_state.nnotesections; - - ld_state.allsections[ld_state.nallsections++] =3D newp; - new_section =3D false; - } - else - { - struct scnhead *queued; - - queued =3D ld_state.allsections[ld_state.nallsections - 1]; - - found->next =3D queued->last->next; - queued->last =3D queued->last->next =3D found; - - /* If the linker script forces us to add incompatible - sections together do so. But reflect this in the - type and flags of the resulting file. */ - if (queued->type !=3D SCNINFO_SHDR (found->shdr).sh_type) - /* XXX Any better choice? */ - queued->type =3D SHT_PROGBITS; - if (queued->flags !=3D SCNINFO_SHDR (found->shdr).sh_flags) - /* Executable or DSO do not have section groups. Drop that - information. */ - queued->flags =3D ebl_sh_flags_combine (ld_state.ebl, - queued->flags, - SCNINFO_SHDR (found->shdr).sh_flags - & ~SHF_GROUP); - - /* Accumulate the relocation section size. */ - queued->relsize +=3D found->relsize; - } - } - } - while (runp !=3D NULL); - - return new_section; -} - - -static void -sort_sections_lscript (void) -{ - struct scnhead *temp[ld_state.nallsections]; - - /* Make a copy of the section head pointer array. */ - memcpy (temp, ld_state.allsections, - ld_state.nallsections * sizeof (temp[0])); - size_t nallsections =3D ld_state.nallsections; - - /* Convert the output segment list in a single-linked list. */ - struct output_segment *segment =3D ld_state.output_segments->next; - ld_state.output_segments->next =3D NULL; - ld_state.output_segments =3D segment; - - /* Put the sections in the correct order in the array in the state - structure. This might involve merging of sections and also - renaming the containing section in the output file. */ - ld_state.nallsections =3D 0; - size_t segment_nr; - size_t last_writable =3D ~0ul; - for (segment_nr =3D 0; segment !=3D NULL; segment =3D segment->next, ++s= egment_nr) - { - struct output_rule *orule; - - for (orule =3D segment->output_rules; orule !=3D NULL; orule =3D oru= le->next) - if (orule->tag =3D=3D output_section) - { - struct input_rule *irule; - bool new_section =3D true; - - for (irule =3D orule->val.section.input; irule !=3D NULL; - irule =3D irule->next) - if (irule->tag =3D=3D input_section) - { - size_t cnt; - - for (cnt =3D 0; cnt < nallsections; ++cnt) - if (temp[cnt] !=3D NULL) - new_section =3D - match_section (orule->val.section.name, - irule->val.section, &temp[cnt], - new_section, segment_nr); - } - } - - if ((segment->mode & PF_W) !=3D 0) - last_writable =3D ld_state.nallsections - 1; - } - - /* In case we have to create copy relocations or we have common - symbols, find the last writable segment and add one more data - block. It will be a NOBITS block and take up no disk space. - This is why it is important to get the last block. */ - if (ld_state.ncopy > 0 || ld_state.common_syms !=3D NULL) - { - if (last_writable =3D=3D ~0ul) - error (EXIT_FAILURE, 0, "no writable segment"); - - if (ld_state.allsections[last_writable]->type !=3D SHT_NOBITS) - { - /* Make room in the ALLSECTIONS array for a new section. - There is guaranteed room in the array. We add the new - entry after the last writable section. */ - ++last_writable; - memmove (&ld_state.allsections[last_writable + 1], - &ld_state.allsections[last_writable], - (ld_state.nallsections - last_writable) - * sizeof (ld_state.allsections[0])); - - ld_state.allsections[last_writable] =3D (struct scnhead *) - obstack_calloc (&ld_state.smem, sizeof (struct scnhead)); - - /* Name for the new section. */ - ld_state.allsections[last_writable]->name =3D ".bss"; - /* Type: NOBITS. */ - ld_state.allsections[last_writable]->type =3D SHT_NOBITS; - /* Same segment as the last writable section. */ - ld_state.allsections[last_writable]->segment_nr - =3D ld_state.allsections[last_writable - 1]->segment_nr; - } - } - - /* Create common symbol data block. */ - if (ld_state.ncopy > 0) - { -#if NATIVE_ELF - struct scninfo *si =3D (struct scninfo *) - obstack_calloc (&ld_state.smem, sizeof (*si) + sizeof (XElf_Shdr)); - si->shdr =3D (XElf_Shdr *) (si + 1); -#else - struct scninfo *si =3D (struct scninfo *) obstack_calloc (&ld_state.= smem, - sizeof (*si)); -#endif - - /* Get the information regarding the symbols with copy relocations. = */ - compute_copy_reloc_offset (&SCNINFO_SHDR (si->shdr)); - - /* This section is needed. */ - si->used =3D true; - /* Remember for later the section data structure. */ - ld_state.copy_section =3D si; - - if (likely (ld_state.allsections[last_writable]->last !=3D NULL)) - { - si->next =3D ld_state.allsections[last_writable]->last->next; - ld_state.allsections[last_writable]->last->next =3D si; - ld_state.allsections[last_writable]->last =3D si; - } - else - ld_state.allsections[last_writable]->last =3D si->next =3D si; - } - - /* Create common symbol data block. */ - if (ld_state.common_syms !=3D NULL) - { -#if NATIVE_ELF - struct scninfo *si =3D (struct scninfo *) - obstack_calloc (&ld_state.smem, sizeof (*si) + sizeof (XElf_Shdr)); - si->shdr =3D (XElf_Shdr *) (si + 1); -#else - struct scninfo *si =3D (struct scninfo *) obstack_calloc (&ld_state.= smem, - sizeof (*si)); -#endif - - /* Get the information regarding the symbols with copy relocations. = */ - compute_common_symbol_offset (&SCNINFO_SHDR (si->shdr)); - - /* This section is needed. */ - si->used =3D true; - /* Remember for later the section data structure. */ - ld_state.common_section =3D si; - - if (likely (ld_state.allsections[last_writable]->last !=3D NULL)) - { - si->next =3D ld_state.allsections[last_writable]->last->next; - ld_state.allsections[last_writable]->last->next =3D si; - ld_state.allsections[last_writable]->last =3D si; - } - else - ld_state.allsections[last_writable]->last =3D si->next =3D si; - } -} - - -/* Create the output sections now. This requires knowledge about all - the sections we will need. It may be necessary to sort sections in - the order they are supposed to appear in the executable. The - sorting use many different kinds of information to optimize the - resulting binary. Important is to respect segment boundaries and - the needed alignment. The mode of the segments will be determined - afterwards automatically by the output routines. - - The generic sorting routines work in one of two possible ways: - - - if a linker script specifies the sections to be used in the - output and assigns them to a segment this information is used; - - - otherwise the linker will order the sections based on permissions - and some special knowledge about section names.*/ -static void -ld_generic_create_sections (struct ld_state *statep) -{ - struct scngroup *groups; - size_t cnt; - - /* For relocatable object we don't have to bother sorting the - sections and we do want to preserve the relocation sections as - they appear in the input files. */ - if (ld_state.file_type !=3D relocatable_file_type) - { - /* Collect all the relocation sections. They are handled - separately. */ - struct scninfo *list =3D NULL; - for (cnt =3D 0; cnt < ld_state.nallsections; ++cnt) - if ((ld_state.allsections[cnt]->type =3D=3D SHT_REL - || ld_state.allsections[cnt]->type =3D=3D SHT_RELA) - /* The generated relocation sections are not of any - interest here. */ - && ld_state.allsections[cnt]->last !=3D NULL) - { - if (list =3D=3D NULL) - list =3D ld_state.allsections[cnt]->last; - else - { - /* Merge the sections list. */ - struct scninfo *first =3D list->next; - list->next =3D ld_state.allsections[cnt]->last->next; - ld_state.allsections[cnt]->last->next =3D first; - list =3D ld_state.allsections[cnt]->last; - } - - /* Remove the entry from the section list. */ - ld_state.allsections[cnt] =3D NULL; - } - ld_state.rellist =3D list; - - if (ld_state.output_segments =3D=3D NULL) - /* Sort using builtin rules. */ - sort_sections_generic (); - else - sort_sections_lscript (); - } - - /* Now iterate over the input sections and create the sections in the - order they are required in the output file. */ - for (cnt =3D 0; cnt < ld_state.nallsections; ++cnt) - { - struct scnhead *head =3D ld_state.allsections[cnt]; - Elf_Scn *scn; - XElf_Shdr_vardef (shdr); - - /* Don't handle unused sections. */ - if (!head->used) - continue; - - /* We first have to create the section group if necessary. - Section group sections must come (in section index order) - before any of the section contained. This all is necessary - only for relocatable object as other object types are not - allowed to contain section groups. */ - if (ld_state.file_type =3D=3D relocatable_file_type - && unlikely (head->flags & SHF_GROUP)) - { - /* There is at least one section which is contained in a - section group in the input file. This means we must - create a section group here as well. The only problem is - that not all input files have to have to same kind of - partitioning of the sections. I.e., sections A and B in - one input file and sections B and C in another input file - can be in one group. That will result in a group - containing the sections A, B, and C in the output - file. */ - struct scninfo *runp; - Elf32_Word here_groupidx =3D 0; - struct scngroup *here_group; - struct member *newp; - - /* First check whether any section is already in a group. - In this case we have to add this output section, too. */ - runp =3D head->last; - do - { - assert (runp->grpid !=3D 0); - - here_groupidx =3D runp->fileinfo->scninfo[runp->grpid].outscnndx; - if (here_groupidx !=3D 0) - break; - } - while ((runp =3D runp->next) !=3D head->last); - - if (here_groupidx =3D=3D 0) - { - /* We need a new section group section. */ - scn =3D elf_newscn (ld_state.outelf); - xelf_getshdr (scn, shdr); - if (shdr =3D=3D NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create section for output file: %s"), - elf_errmsg (-1)); - - here_group =3D (struct scngroup *) xmalloc (sizeof (*here_group)); - here_group->outscnidx =3D here_groupidx =3D elf_ndxscn (scn); - here_group->nscns =3D 0; - here_group->member =3D NULL; - here_group->next =3D ld_state.groups; - /* Pick a name for the section. To keep it meaningful - we use a name used in the input files. If the - section group in the output file should contain - section which were in section groups of different - names in the input files this is the users - problem. */ - here_group->nameent - =3D ebl_strtabadd (ld_state.shstrtab, - elf_strptr (runp->fileinfo->elf, - runp->fileinfo->shstrndx, - SCNINFO_SHDR (runp->shdr).sh_name), - 0); - /* Signature symbol. */ - here_group->symbol - =3D runp->fileinfo->scninfo[runp->grpid].symbols; - - ld_state.groups =3D here_group; - } - else - { - /* Search for the group with this index. */ - here_group =3D ld_state.groups; - while (here_group->outscnidx !=3D here_groupidx) - here_group =3D here_group->next; - } - - /* Add the new output section. */ - newp =3D (struct member *) alloca (sizeof (*newp)); - newp->scn =3D head; -#ifndef NDT_NEEDED - newp->next =3D NULL; -#endif - CSNGL_LIST_ADD_REAR (here_group->member, newp); - ++here_group->nscns; - - /* Store the section group index in all input files. */ - runp =3D head->last; - do - { - assert (runp->grpid !=3D 0); - - if (runp->fileinfo->scninfo[runp->grpid].outscnndx =3D=3D 0) - runp->fileinfo->scninfo[runp->grpid].outscnndx =3D here_groupidx; - else - assert (runp->fileinfo->scninfo[runp->grpid].outscnndx - =3D=3D here_groupidx); - } - while ((runp =3D runp->next) !=3D head->last); - } - - /* We'll use this section so get it's name in the section header - string table. */ - if (head->kind =3D=3D scn_normal) - head->nameent =3D ebl_strtabadd (ld_state.shstrtab, head->name, 0); - - /* Create a new section in the output file and add all data - from all the sections we read. */ - scn =3D elf_newscn (ld_state.outelf); - head->scnidx =3D elf_ndxscn (scn); - xelf_getshdr (scn, shdr); - if (shdr =3D=3D NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create section for output file: %s"), - elf_errmsg (-1)); - - assert (head->type !=3D SHT_NULL); - assert (head->type !=3D SHT_SYMTAB); - assert (head->type !=3D SHT_DYNSYM || head->kind !=3D scn_normal); - assert (head->type !=3D SHT_STRTAB || head->kind !=3D scn_normal); - assert (head->type !=3D SHT_GROUP); - shdr->sh_type =3D head->type; - shdr->sh_flags =3D head->flags; - shdr->sh_addralign =3D head->align; - shdr->sh_entsize =3D head->entsize; - assert (shdr->sh_entsize !=3D 0 || (shdr->sh_flags & SHF_MERGE) =3D= =3D 0); - (void) xelf_update_shdr (scn, shdr); - - /* We have to know the section index of the dynamic symbol table - right away. */ - if (head->kind =3D=3D scn_dot_dynsym) - ld_state.dynsymscnidx =3D elf_ndxscn (scn); - } - - /* Actually create the section group sections. */ - groups =3D ld_state.groups; - while (groups !=3D NULL) - { - Elf_Scn *scn; - Elf_Data *data; - Elf32_Word *grpdata; - struct member *runp; - - scn =3D elf_getscn (ld_state.outelf, groups->outscnidx); - assert (scn !=3D NULL); - - data =3D elf_newdata (scn); - if (data =3D=3D NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create section for output file: %s"), - elf_errmsg (-1)); - - data->d_size =3D (groups->nscns + 1) * sizeof (Elf32_Word); - data->d_buf =3D grpdata =3D (Elf32_Word *) xmalloc (data->d_size); - data->d_type =3D ELF_T_WORD; - data->d_version =3D EV_CURRENT; - data->d_off =3D 0; - /* XXX What better to use? */ - data->d_align =3D sizeof (Elf32_Word); - - /* The first word in the section is the flag word. */ - /* XXX Set COMDATA flag is necessary. */ - grpdata[0] =3D 0; - - runp =3D groups->member->next; - cnt =3D 1; - do - /* Fill in the index of the section. */ - grpdata[cnt++] =3D runp->scn->scnidx; - while ((runp =3D runp->next) !=3D groups->member->next); - - groups =3D groups->next; - } -} - - -static bool -reduce_symbol_p (XElf_Sym *sym, struct Ebl_Strent *strent) -{ - const char *str; - const char *version; - struct id_list search; - struct id_list *verp; - bool result =3D ld_state.default_bind_local; - - if (XELF_ST_BIND (sym->st_info) =3D=3D STB_LOCAL || sym->st_shndx =3D=3D= SHN_UNDEF) - /* We don't have to do anything to local symbols here. */ - /* XXX Any section value in [SHN_LORESERVER,SHN_XINDEX) need - special treatment? */ - return false; - - /* XXX Handle other symbol bindings. */ - assert (XELF_ST_BIND (sym->st_info) =3D=3D STB_GLOBAL - || XELF_ST_BIND (sym->st_info) =3D=3D STB_WEAK); - - str =3D ebl_string (strent); - version =3D strchr (str, VER_CHR); - if (version !=3D NULL) - { - search.id =3D strndupa (str, version - str); - if (*++version =3D=3D VER_CHR) - /* Skip the second '@' signaling a default definition. */ - ++version; - } - else - { - search.id =3D str; - version =3D ""; - } - - verp =3D ld_version_str_tab_find (&ld_state.version_str_tab, - elf_hash (search.id), &search); - while (verp !=3D NULL) - { - /* We have this symbol in the version hash table. Now match the - version name. */ - if (strcmp (verp->u.s.versionname, version) =3D=3D 0) - /* Match! */ - return verp->u.s.local; - - verp =3D verp->next; - } - - /* XXX Add test for wildcard version symbols. */ - - return result; -} - - -static XElf_Addr -eval_expression (struct expression *expr, XElf_Addr addr) -{ - XElf_Addr val =3D ~((XElf_Addr) 0); - - switch (expr->tag) - { - case exp_num: - val =3D expr->val.num; - break; - - case exp_sizeof_headers: - { - /* The 'elf_update' call determine the offset of the first - section. The the size of the header. */ - XElf_Shdr_vardef (shdr); - - xelf_getshdr (elf_getscn (ld_state.outelf, 1), shdr); - assert (shdr !=3D NULL); - - val =3D shdr->sh_offset; - } - break; - - case exp_pagesize: - val =3D ld_state.pagesize; - break; - - case exp_id: - /* We are here computing only address expressions. It seems not - to be necessary to handle any variable but ".". Let's avoid - the complication. If it turns up to be needed we can add - it. */ - if (strcmp (expr->val.str, ".") !=3D 0) - error (EXIT_FAILURE, 0, gettext ("\ -address computation expression contains variable '%s'"), - expr->val.str); - - val =3D addr; - break; - - case exp_mult: - val =3D (eval_expression (expr->val.binary.left, addr) - * eval_expression (expr->val.binary.right, addr)); - break; - - case exp_div: - val =3D (eval_expression (expr->val.binary.left, addr) - / eval_expression (expr->val.binary.right, addr)); - break; - - case exp_mod: - val =3D (eval_expression (expr->val.binary.left, addr) - % eval_expression (expr->val.binary.right, addr)); - break; - - case exp_plus: - val =3D (eval_expression (expr->val.binary.left, addr) - + eval_expression (expr->val.binary.right, addr)); - break; - - case exp_minus: - val =3D (eval_expression (expr->val.binary.left, addr) - - eval_expression (expr->val.binary.right, addr)); - break; - - case exp_and: - val =3D (eval_expression (expr->val.binary.left, addr) - & eval_expression (expr->val.binary.right, addr)); - break; - - case exp_or: - val =3D (eval_expression (expr->val.binary.left, addr) - | eval_expression (expr->val.binary.right, addr)); - break; - - case exp_align: - val =3D eval_expression (expr->val.child, addr); - if ((val & (val - 1)) !=3D 0) - error (EXIT_FAILURE, 0, gettext ("argument '%" PRIuMAX "' of ALIGN in add= ress computation expression is no power of two"), - (uintmax_t) val); - val =3D (addr + val - 1) & ~(val - 1); - break; - } - - return val; -} - - -/* Find a good as possible size for the hash table so that all the - non-zero entries in HASHCODES don't collide too much and the table - isn't too large. There is no exact formular for this so we use a - heuristic. Depending on the optimization level the search is - longer or shorter. */ -static size_t -optimal_bucket_size (Elf32_Word *hashcodes, size_t maxcnt, int optlevel) -{ - size_t minsize; - size_t maxsize; - size_t bestsize; - uint64_t bestcost; - size_t size; - uint32_t *counts; - uint32_t *lengths; - - if (maxcnt =3D=3D 0) - return 0; - - /* When we are not optimizing we run only very few tests. */ - if (optlevel <=3D 0) - { - minsize =3D maxcnt; - maxsize =3D maxcnt + 10000 / maxcnt; - } - else - { - /* Does not make much sense to start with a smaller table than - one which has at least four collisions. */ - minsize =3D MAX (1, maxcnt / 4); - /* We look for a best fit in the range of up to eigth times the - number of elements. */ - maxsize =3D 2 * maxcnt + (6 * MIN (optlevel, 100) * maxcnt) / 100; - } - bestsize =3D maxcnt; - bestcost =3D UINT_MAX; - - /* Array for counting the collisions and chain lengths. */ - counts =3D (uint32_t *) xmalloc ((maxcnt + 1 + maxsize) * sizeof (uint32= _t)); - lengths =3D &counts[maxcnt + 1]; - - for (size =3D minsize; size <=3D maxsize; ++size) - { - size_t inner; - uint64_t cost; - uint32_t maxlength; - uint64_t success; - uint32_t acc; - double factor; - - memset (lengths, '\0', size * sizeof (uint32_t)); - memset (counts, '\0', (maxcnt + 1) * sizeof (uint32_t)); - - /* Determine how often each hash bucket is used. */ - assert (hashcodes[0] =3D=3D 0); - for (inner =3D 1; inner < maxcnt; ++inner) - ++lengths[hashcodes[inner] % size]; - - /* Determine the lengths. */ - maxlength =3D 0; - for (inner =3D 0; inner < size; ++inner) - { - ++counts[lengths[inner]]; - - if (lengths[inner] > maxlength) - maxlength =3D lengths[inner]; - } - - /* Determine successful lookup length. */ - acc =3D 0; - success =3D 0; - for (inner =3D 0; inner <=3D maxlength; ++inner) - { - acc +=3D inner; - success +=3D counts[inner] * acc; - } - - /* We can compute two factors now: the average length of a - positive search and the average length of a negative search. - We count the number of comparisons which have to look at the - names themselves. Recognizing that the chain ended is not - accounted for since it's almost for free. - - Which lookup is more important depends on the kind of DSO. - If it is a system DSO like libc it is expected that most - lookups succeed. Otherwise most lookups fail. */ - if (ld_state.is_system_library) - factor =3D (1.0 * (double) success / (double) maxcnt - + 0.3 * (double) maxcnt / (double) size); - else - factor =3D (0.3 * (double) success / (double) maxcnt - + 1.0 * (double) maxcnt / (double) size); - - /* Combine the lookup cost factor. The 1/16th addend adds - penalties for too large table sizes. */ - cost =3D (2 + maxcnt + size) * (factor + 1.0 / 16.0); - -#if 0 - printf ("maxcnt =3D %d, size =3D %d, cost =3D %Ld, success =3D %g, f= ail =3D %g, factor =3D %g\n", - maxcnt, size, cost, (double) success / (double) maxcnt, (double) ma= xcnt / (double) size, factor); -#endif - - /* Compare with current best results. */ - if (cost < bestcost) - { - bestcost =3D cost; - bestsize =3D size; - } - } - - free (counts); - - return bestsize; -} - - -static void -optimal_gnu_hash_size (Elf32_Word *hashcodes, size_t maxcnt, int optlevel, - size_t *bitmask_nwords, size_t *shift, size_t *nbuckets) -{ - // XXX Implement something real - *bitmask_nwords =3D 256; - *shift =3D 6; - *nbuckets =3D 3 * maxcnt / 2; -} - - -static XElf_Addr -find_entry_point (void) -{ - XElf_Addr result; - - if (ld_state.entry !=3D NULL) - { - struct symbol search =3D { .name =3D ld_state.entry }; - struct symbol *syment; - - syment =3D ld_symbol_tab_find (&ld_state.symbol_tab, - elf_hash (ld_state.entry), &search); - if (syment !=3D NULL && syment->defined) - { - /* We found the symbol. */ - Elf_Data *data =3D elf_getdata (elf_getscn (ld_state.outelf, - ld_state.symscnidx), NULL); - - XElf_Sym_vardef (sym); - - sym =3D NULL; - if (data !=3D NULL) - xelf_getsym (data, ld_state.dblindirect[syment->outsymidx], sym); - - if (sym =3D=3D NULL && ld_state.need_dynsym && syment->outdynsymidx != =3D 0) - { - /* Use the dynamic symbol table if available. */ - data =3D elf_getdata (elf_getscn (ld_state.outelf, - ld_state.dynsymscnidx), NULL); - - sym =3D NULL; - if (data !=3D NULL) - xelf_getsym (data, syment->outdynsymidx, sym); - } - - if (sym !=3D NULL) - return sym->st_value; - - /* XXX What to do if the output has no non-dynamic symbol - table and the dynamic symbol table does not contain the - symbol? */ - assert (ld_state.need_symtab); - assert (ld_state.symscnidx !=3D 0); - } - } - - /* We couldn't find the symbol or none was given. Use the first - address of the ".text" section then. */ - - - result =3D 0; - - /* In DSOs this is no fatal error. They usually have no entry - points. In this case we set the entry point to zero, which makes - sure it will always fail. */ - if (ld_state.file_type =3D=3D executable_file_type) - { - if (ld_state.entry !=3D NULL) - error (0, 0, gettext ("\ -cannot find entry symbol '%s': defaulting to %#0*" PRIx64), - ld_state.entry, - xelf_getclass (ld_state.outelf) =3D=3D ELFCLASS32 ? 10 : 18, - (uint64_t) result); - else - error (0, 0, gettext ("\ -no entry symbol specified: defaulting to %#0*" PRIx64), - xelf_getclass (ld_state.outelf) =3D=3D ELFCLASS32 ? 10 : 18, - (uint64_t) result); - } - - return result; -} - - -static void -fillin_special_symbol (struct symbol *symst, size_t scnidx, size_t nsym, - Elf_Data *symdata, struct Ebl_Strtab *strtab) -{ - assert (ld_state.file_type !=3D relocatable_file_type); - - XElf_Sym_vardef (sym); - xelf_getsym_ptr (symdata, nsym, sym); - - /* The name offset will be filled in later. */ - sym->st_name =3D 0; - /* Traditionally: globally visible. */ - sym->st_info =3D XELF_ST_INFO (symst->local ? STB_LOCAL : STB_GLOBAL, - symst->type); - sym->st_other =3D symst->hidden ? STV_HIDDEN : STV_DEFAULT; - /* Reference to the GOT or dynamic section. Since the GOT and - dynamic section are only created for executables and DSOs it - cannot be that the section index is too large. */ - assert (scnidx !=3D 0); - assert (scnidx < SHN_LORESERVE || scnidx =3D=3D SHN_ABS); - sym->st_shndx =3D scnidx; - /* We want the beginning of the section. */ - sym->st_value =3D 0; - // XXX What size? - sym->st_size =3D 0; - - /* Determine the size of the section. */ - if (scnidx !=3D SHN_ABS) - { - Elf_Data *data =3D elf_getdata (elf_getscn (ld_state.outelf, scnidx), - NULL); - assert (data !=3D NULL); - sym->st_size =3D data->d_size; - /* Make sure there is no second data block. */ - assert (elf_getdata (elf_getscn (ld_state.outelf, scnidx), data) - =3D=3D NULL); - } - - /* Insert symbol into the symbol table. Note that we do not have to - use xelf_update_symshdx. */ - (void) xelf_update_sym (symdata, nsym, sym); - - /* Cross-references. */ - ndxtosym[nsym] =3D symst; - symst->outsymidx =3D nsym; - - /* Add the name to the string table. */ - symstrent[nsym] =3D ebl_strtabadd (strtab, symst->name, 0); -} - - -static void -new_dynamic_entry (Elf_Data *data, int idx, XElf_Sxword tag, XElf_Addr val) -{ - XElf_Dyn_vardef (dyn); - xelf_getdyn_ptr (data, idx, dyn); - dyn->d_tag =3D tag; - dyn->d_un.d_ptr =3D val; - (void) xelf_update_dyn (data, idx, dyn); -} - - -static void -allocate_version_names (struct usedfiles *runp, struct Ebl_Strtab *dynstrt= ab) -{ - /* If this DSO has no versions skip it. */ - if (runp->status !=3D opened || runp->verdefdata =3D=3D NULL) - return; - - /* Add the object name. */ - int offset =3D 0; - while (1) - { - XElf_Verdef_vardef (def); - XElf_Verdaux_vardef (aux); - - /* Get data at the next offset. */ - xelf_getverdef (runp->verdefdata, offset, def); - assert (def !=3D NULL); - xelf_getverdaux (runp->verdefdata, offset + def->vd_aux, aux); - assert (aux !=3D NULL); - - assert (def->vd_ndx <=3D runp->nverdef); - if (def->vd_ndx =3D=3D 1 || runp->verdefused[def->vd_ndx] !=3D 0) - { - runp->verdefent[def->vd_ndx] - =3D ebl_strtabadd (dynstrtab, elf_strptr (runp->elf, - runp->dynsymstridx, - aux->vda_name), 0); - - if (def->vd_ndx > 1) - runp->verdefused[def->vd_ndx] =3D ld_state.nextveridx++; - } - - if (def->vd_next =3D=3D 0) - /* That were all versions. */ - break; - - offset +=3D def->vd_next; - } -} - - -static XElf_Off -create_verneed_data (XElf_Off offset, Elf_Data *verneeddata, - struct usedfiles *runp, int *ntotal) -{ - size_t verneed_size =3D xelf_fsize (ld_state.outelf, ELF_T_VNEED, 1); - size_t vernaux_size =3D xelf_fsize (ld_state.outelf, ELF_T_VNAUX, 1); - int need_offset; - bool filled =3D false; - GElf_Verneed verneed; - GElf_Vernaux vernaux; - int ndef =3D 0; - size_t cnt; - - /* If this DSO has no versions skip it. */ - if (runp->nverdefused =3D=3D 0) - return offset; - - /* We fill in the Verneed record last. Remember the offset. */ - need_offset =3D offset; - offset +=3D verneed_size; - - for (cnt =3D 2; cnt <=3D runp->nverdef; ++cnt) - if (runp->verdefused[cnt] !=3D 0) - { - assert (runp->verdefent[cnt] !=3D NULL); - - if (filled) - { - vernaux.vna_next =3D vernaux_size; - (void) gelf_update_vernaux (verneeddata, offset, &vernaux); - offset +=3D vernaux_size; - } - - vernaux.vna_hash =3D elf_hash (ebl_string (runp->verdefent[cnt])); - vernaux.vna_flags =3D 0; - vernaux.vna_other =3D runp->verdefused[cnt]; - vernaux.vna_name =3D ebl_strtaboffset (runp->verdefent[cnt]); - filled =3D true; - ++ndef; - } - - assert (filled); - vernaux.vna_next =3D 0; - (void) gelf_update_vernaux (verneeddata, offset, &vernaux); - offset +=3D vernaux_size; - - verneed.vn_version =3D VER_NEED_CURRENT; - verneed.vn_cnt =3D ndef; - verneed.vn_file =3D ebl_strtaboffset (runp->verdefent[1]); - /* The first auxiliary entry is always found directly - after the verneed entry. */ - verneed.vn_aux =3D verneed_size; - verneed.vn_next =3D --*ntotal > 0 ? offset - need_offset : 0; - (void) gelf_update_verneed (verneeddata, need_offset, &verneed); - - return offset; -} - - -/* Callback for qsort to sort dynamic string table. */ -static Elf32_Word *global_hashcodes; -static size_t global_nbuckets; -static int -sortfct_hashval (const void *p1, const void *p2) -{ - size_t idx1 =3D *(size_t *) p1; - size_t idx2 =3D *(size_t *) p2; - - int def1 =3D ndxtosym[idx1]->defined && !ndxtosym[idx1]->in_dso; - int def2 =3D ndxtosym[idx2]->defined && !ndxtosym[idx2]->in_dso; - - if (! def1 && def2) - return -1; - if (def1 && !def2) - return 1; - if (! def1) - return 0; - - Elf32_Word hval1 =3D (global_hashcodes[ndxtosym[idx1]->outdynsymidx] - % global_nbuckets); - Elf32_Word hval2 =3D (global_hashcodes[ndxtosym[idx2]->outdynsymidx] - % global_nbuckets); - - if (hval1 < hval2) - return -1; - if (hval1 > hval2) - return 1; - return 0; -} - - -/* Sort the dynamic symbol table. The GNU hash table lookup assumes - that all symbols with the same hash value module the bucket table - size follow one another. This avoids the extra hash chain table. - There is no need (and no way) to perform this operation if we do - not use the new hash table format. */ -static void -create_gnu_hash (size_t nsym_local, size_t nsym, size_t nsym_dyn, - Elf32_Word *gnuhashcodes) -{ - size_t gnu_bitmask_nwords =3D 0; - size_t gnu_shift =3D 0; - size_t gnu_nbuckets =3D 0; - Elf32_Word *gnu_bitmask =3D NULL; - Elf32_Word *gnu_buckets =3D NULL; - Elf32_Word *gnu_chain =3D NULL; - XElf_Shdr_vardef (shdr); - - /* Determine the "optimal" bucket size. */ - optimal_gnu_hash_size (gnuhashcodes, nsym_dyn, ld_state.optlevel, - &gnu_bitmask_nwords, &gnu_shift, &gnu_nbuckets); - - /* Create the .gnu.hash section data structures. */ - Elf_Scn *hashscn =3D elf_getscn (ld_state.outelf, ld_state.gnuhashscnidx= ); - xelf_getshdr (hashscn, shdr); - Elf_Data *hashdata =3D elf_newdata (hashscn); - if (shdr =3D=3D NULL || hashdata =3D=3D NULL) - error (EXIT_FAILURE, 0, gettext ("\ -cannot create GNU hash table section for output file: %s"), - elf_errmsg (-1)); - - shdr->sh_link =3D ld_state.dynsymscnidx; - (void) xelf_update_shdr (hashscn, shdr); - - hashdata->d_size =3D (xelf_fsize (ld_state.outelf, ELF_T_ADDR, - gnu_bitmask_nwords) - + (4 + gnu_nbuckets + nsym_dyn) * sizeof (Elf32_Word)); - hashdata->d_buf =3D xcalloc (1, hashdata->d_size); - hashdata->d_align =3D sizeof (Elf32_Word); - hashdata->d_type =3D ELF_T_WORD; - hashdata->d_off =3D 0; - - ((Elf32_Word *) hashdata->d_buf)[0] =3D gnu_nbuckets; - ((Elf32_Word *) hashdata->d_buf)[2] =3D gnu_bitmask_nwords; - ((Elf32_Word *) hashdata->d_buf)[3] =3D gnu_shift; - gnu_bitmask =3D &((Elf32_Word *) hashdata->d_buf)[4]; - gnu_buckets =3D &gnu_bitmask[xelf_fsize (ld_state.outelf, ELF_T_ADDR, - gnu_bitmask_nwords) - / sizeof (*gnu_buckets)]; - gnu_chain =3D &gnu_buckets[gnu_nbuckets]; -#ifndef NDEBUG - void *endp =3D &gnu_chain[nsym_dyn]; -#endif - assert (endp =3D=3D (void *) ((char *) hashdata->d_buf + hashdata->d_siz= e)); - - - size_t *remap =3D xmalloc (nsym_dyn * sizeof (size_t)); -#ifndef NDEBUG - size_t nsym_dyn_cnt =3D 1; -#endif - for (size_t cnt =3D nsym_local; cnt < nsym; ++cnt) - if (symstrent[cnt] !=3D NULL) - { - assert (ndxtosym[cnt]->outdynsymidx > 0); - assert (ndxtosym[cnt]->outdynsymidx < nsym_dyn); - remap[ndxtosym[cnt]->outdynsymidx] =3D cnt; -#ifndef NDEBUG - ++nsym_dyn_cnt; -#endif - } - assert (nsym_dyn_cnt =3D=3D nsym_dyn); - - // XXX Until we can rely on qsort_r use global variables. - global_hashcodes =3D gnuhashcodes; - global_nbuckets =3D gnu_nbuckets; - qsort (remap + 1, nsym_dyn - 1, sizeof (size_t), sortfct_hashval); - - bool bm32 =3D (xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1) - =3D=3D sizeof (Elf32_Word)); - - size_t first_defined =3D 0; - Elf64_Word bitmask_idxbits =3D gnu_bitmask_nwords - 1; - Elf32_Word last_bucket =3D 0; - for (size_t cnt =3D 1; cnt < nsym_dyn; ++cnt) - { - if (first_defined =3D=3D 0) - { - if (! ndxtosym[remap[cnt]]->defined - || ndxtosym[remap[cnt]]->in_dso) - goto next; - - ((Elf32_Word *) hashdata->d_buf)[1] =3D first_defined =3D cnt; - } - - Elf32_Word hval =3D gnuhashcodes[ndxtosym[remap[cnt]]->outdynsymidx]; - - if (bm32) - { - Elf32_Word *bsw =3D &gnu_bitmask[(hval / 32) & bitmask_idxbits]; - assert ((void *) gnu_bitmask <=3D (void *) bsw); - assert ((void *) bsw < (void *) gnu_buckets); - *bsw |=3D 1 << (hval & 31); - *bsw |=3D 1 << ((hval >> gnu_shift) & 31); - } - else - { - Elf64_Word *bsw =3D &((Elf64_Word *) gnu_bitmask)[(hval / 64) - & bitmask_idxbits]; - assert ((void *) gnu_bitmask <=3D (void *) bsw); - assert ((void *) bsw < (void *) gnu_buckets); - *bsw |=3D 1 << (hval & 63); - *bsw |=3D 1 << ((hval >> gnu_shift) & 63); - } - - size_t this_bucket =3D hval % gnu_nbuckets; - if (cnt =3D=3D first_defined || this_bucket !=3D last_bucket) - { - if (cnt !=3D first_defined) - { - /* Terminate the previous chain. */ - assert ((void *) &gnu_chain[cnt - first_defined - 1] < endp); - gnu_chain[cnt - first_defined - 1] |=3D 1; - } - - assert (this_bucket < gnu_nbuckets); - gnu_buckets[this_bucket] =3D cnt; - last_bucket =3D this_bucket; - } - - assert (cnt >=3D first_defined); - assert (cnt - first_defined < nsym_dyn); - gnu_chain[cnt - first_defined] =3D hval & ~1u; - - next: - ndxtosym[remap[cnt]]->outdynsymidx =3D cnt; - } - - /* Terminate the last chain. */ - if (first_defined !=3D 0) - { - assert (nsym_dyn > first_defined); - assert (nsym_dyn - first_defined - 1 < nsym_dyn); - gnu_chain[nsym_dyn - first_defined - 1] |=3D 1; - - hashdata->d_size -=3D first_defined * sizeof (Elf32_Word); - } - else - /* We do not need any hash table. */ - // XXX - do { } while (0); - - free (remap); -} - - -/* Create the SysV-style hash table. */ -static void -create_hash (size_t nsym_local, size_t nsym, size_t nsym_dyn, - Elf32_Word *hashcodes) -{ - size_t nbucket =3D 0; - Elf32_Word *bucket =3D NULL; - Elf32_Word *chain =3D NULL; - XElf_Shdr_vardef (shdr); - - /* Determine the "optimal" bucket size. If we also generate the - new-style hash function there is no need to waste effort and - space on the old one which should not be used. Make it as small - as possible. */ - if (GENERATE_GNU_HASH) - nbucket =3D 1; - else - nbucket =3D optimal_bucket_size (hashcodes, nsym_dyn, ld_state.optleve= l); - /* Create the .hash section data structures. */ - Elf_Scn *hashscn =3D elf_getscn (ld_state.outelf, ld_state.hashscnidx); - xelf_getshdr (hashscn, shdr); - Elf_Data *hashdata =3D elf_newdata (hashscn); - if (shdr =3D=3D NULL || hashdata =3D=3D NULL) - error (EXIT_FAILURE, 0, gettext ("\ -cannot create hash table section for output file: %s"), - elf_errmsg (-1)); - - shdr->sh_link =3D ld_state.dynsymscnidx; - (void) xelf_update_shdr (hashscn, shdr); - - hashdata->d_size =3D (2 + nsym_dyn + nbucket) * sizeof (Elf32_Word); - hashdata->d_buf =3D xcalloc (1, hashdata->d_size); - hashdata->d_align =3D sizeof (Elf32_Word); - hashdata->d_type =3D ELF_T_WORD; - hashdata->d_off =3D 0; - - ((Elf32_Word *) hashdata->d_buf)[0] =3D nbucket; - ((Elf32_Word *) hashdata->d_buf)[1] =3D nsym_dyn; - bucket =3D &((Elf32_Word *) hashdata->d_buf)[2]; - chain =3D &((Elf32_Word *) hashdata->d_buf)[2 + nbucket]; - - for (size_t cnt =3D nsym_local; cnt < nsym; ++cnt) - if (symstrent[cnt] !=3D NULL) - { - size_t dynidx =3D ndxtosym[cnt]->outdynsymidx; - size_t hashidx =3D hashcodes[dynidx] % nbucket; - if (bucket[hashidx] =3D=3D 0) - bucket[hashidx] =3D dynidx; - else - { - hashidx =3D bucket[hashidx]; - while (chain[hashidx] !=3D 0) - hashidx =3D chain[hashidx]; - - chain[hashidx] =3D dynidx; - } - } -} - - -static void -create_build_id_section (Elf_Scn *scn) -{ - /* We know how large the section will be so we can create it now. */ - Elf_Data *d =3D elf_newdata (scn); - if (d =3D=3D NULL) - error (EXIT_FAILURE, 0, gettext ("cannot create build ID section: %s"), - elf_errmsg (-1)); - - d->d_type =3D ELF_T_BYTE; - d->d_version =3D EV_CURRENT; - - /* The note section header. */ - assert (sizeof (Elf32_Nhdr) =3D=3D sizeof (Elf64_Nhdr)); - d->d_size =3D sizeof (GElf_Nhdr); - /* The string is four bytes long. */ - d->d_size +=3D sizeof (ELF_NOTE_GNU); - assert (d->d_size % 4 =3D=3D 0); - - if (strcmp (ld_state.build_id, "md5") =3D=3D 0 - || strcmp (ld_state.build_id, "uuid") =3D=3D 0) - d->d_size +=3D 16; - else if (strcmp (ld_state.build_id, "sha1") =3D=3D 0) - d->d_size +=3D 20; - else - { - assert (ld_state.build_id[0] =3D=3D '0' && ld_state.build_id[1] =3D= =3D 'x'); - /* Use an upper limit of the possible number of bytes generated - from the string. */ - d->d_size +=3D strlen (ld_state.build_id) / 2; - } - - d->d_buf =3D xcalloc (d->d_size, 1); - d->d_off =3D 0; - d->d_align =3D 0; -} - - -static void -compute_hash_sum (void (*hashfct) (const void *, size_t, void *), void *ct= x) -{ - /* The call cannot fail. */ - size_t shstrndx; - (void) elf_getshdrstrndx (ld_state.outelf, &shstrndx); - - const char *ident =3D elf_getident (ld_state.outelf, NULL); - bool same_byte_order =3D ((ident[EI_DATA] =3D=3D ELFDATA2LSB - && __BYTE_ORDER =3D=3D __LITTLE_ENDIAN) - || (ident[EI_DATA] =3D=3D ELFDATA2MSB - && __BYTE_ORDER =3D=3D __BIG_ENDIAN)); - - /* Iterate over all sections to find those which are not strippable. */ - Elf_Scn *scn =3D NULL; - while ((scn =3D elf_nextscn (ld_state.outelf, scn)) !=3D NULL) - { - /* Get the section header. */ - GElf_Shdr shdr_mem; - GElf_Shdr *shdr =3D gelf_getshdr (scn, &shdr_mem); - assert (shdr !=3D NULL); - - if (SECTION_STRIP_P (shdr, elf_strptr (ld_state.outelf, shstrndx, - shdr->sh_name), true)) - /* The section can be stripped. Don't use it. */ - continue; - - /* Do not look at NOBITS sections. */ - if (shdr->sh_type =3D=3D SHT_NOBITS) - continue; - - /* Iterate through the list of data blocks. */ - Elf_Data *data =3D NULL; - while ((data =3D INTUSE(elf_getdata) (scn, data)) !=3D NULL) - /* If the file byte order is the same as the host byte order - process the buffer directly. If the data is just a stream - of bytes which the library will not convert we can use it - as well. */ - if (likely (same_byte_order) || data->d_type =3D=3D ELF_T_BYTE) - hashfct (data->d_buf, data->d_size, ctx); - else - { - /* Convert the data to file byte order. */ - if (gelf_xlatetof (ld_state.outelf, data, data, ident[EI_DATA]) - =3D=3D NULL) - error (EXIT_FAILURE, 0, gettext ("\ -cannot convert section data to file format: %s"), - elf_errmsg (-1)); - - hashfct (data->d_buf, data->d_size, ctx); - - /* And convert it back. */ - if (gelf_xlatetom (ld_state.outelf, data, data, ident[EI_DATA]) - =3D=3D NULL) - error (EXIT_FAILURE, 0, gettext ("\ -cannot convert section data to memory format: %s"), - elf_errmsg (-1)); - } - } -} - - -/* Iterate over the sections */ -static void -compute_build_id (void) -{ - Elf_Data *d =3D elf_getdata (elf_getscn (ld_state.outelf, - ld_state.buildidscnidx), NULL); - assert (d !=3D NULL); - - GElf_Nhdr *hdr =3D d->d_buf; - hdr->n_namesz =3D sizeof (ELF_NOTE_GNU); - hdr->n_type =3D NT_GNU_BUILD_ID; - char *dp =3D mempcpy (hdr + 1, ELF_NOTE_GNU, sizeof (ELF_NOTE_GNU)); - - if (strcmp (ld_state.build_id, "sha1") =3D=3D 0) - { - /* Compute the SHA1 sum of various parts of the generated file. - We compute the hash sum over the external representation. */ - struct sha1_ctx ctx; - sha1_init_ctx (&ctx); - - /* Compute the hash sum by running over all sections. */ - compute_hash_sum ((void (*) (const void *, size_t, void *)) sha1_pro= cess_bytes, - &ctx); - - /* We are done computing the checksum. */ - (void) sha1_finish_ctx (&ctx, dp); - - hdr->n_descsz =3D SHA1_DIGEST_SIZE; - } - else if (strcmp (ld_state.build_id, "md5") =3D=3D 0) - { - /* Compute the MD5 sum of various parts of the generated file. - We compute the hash sum over the external representation. */ - struct md5_ctx ctx; - md5_init_ctx (&ctx); - - /* Compute the hash sum by running over all sections. */ - compute_hash_sum ((void (*) (const void *, size_t, void *)) md5_proc= ess_bytes, - &ctx); - - /* We are done computing the checksum. */ - (void) md5_finish_ctx (&ctx, dp); - - hdr->n_descsz =3D MD5_DIGEST_SIZE; - } - else if (strcmp (ld_state.build_id, "uuid") =3D=3D 0) - { - int fd =3D open ("/dev/urandom", O_RDONLY); - if (fd =3D=3D -1) - error (EXIT_FAILURE, errno, gettext ("cannot open '%s'"), - "/dev/urandom"); - - if (TEMP_FAILURE_RETRY (read (fd, dp, 16)) !=3D 16) - error (EXIT_FAILURE, 0, gettext ("cannot read enough data for UUID")); - - close (fd); - - hdr->n_descsz =3D 16; - } - else - { - const char *cp =3D ld_state.build_id + 2; - - /* The form of the string has been verified before so here we can - simplify the scanning. */ - do - { - if (isxdigit (cp[0])) - { - char ch1 =3D tolower (cp[0]); - char ch2 =3D tolower (cp[1]); - - *dp++ =3D (((isdigit (ch1) ? ch1 - '0' : ch1 - 'a' + 10) << 4) - | (isdigit (ch2) ? ch2 - '0' : ch2 - 'a' + 10)); - } - else - ++cp; - } - while (*cp !=3D '\0'); - } -} - - -/* Create the output file. - - For relocatable files what basically has to happen is that all - sections from all input files are written into the output file. - Sections with the same name are combined (offsets adjusted - accordingly). The symbol tables are combined in one single table. - When stripping certain symbol table entries are omitted. - - For executables (shared or not) we have to create the program header, - additional sections like the .interp, eventually (in addition) create - a dynamic symbol table and a dynamic section. Also the relocations - have to be processed differently. */ -static int -ld_generic_create_outfile (struct ld_state *statep) -{ - struct scnlist - { - size_t scnidx; - struct scninfo *scninfo; - struct scnlist *next; - }; - struct scnlist *rellist =3D NULL; - size_t cnt; - Elf_Scn *symscn =3D NULL; - Elf_Scn *xndxscn =3D NULL; - Elf_Scn *strscn =3D NULL; - struct Ebl_Strtab *strtab =3D NULL; - struct Ebl_Strtab *dynstrtab =3D NULL; - XElf_Shdr_vardef (shdr); - Elf_Data *data; - Elf_Data *symdata =3D NULL; - Elf_Data *xndxdata =3D NULL; - struct usedfiles *file; - size_t nsym; - size_t nsym_local; - size_t nsym_allocated; - size_t nsym_dyn =3D 0; - Elf32_Word *dblindirect =3D NULL; -#ifndef NDEBUG - bool need_xndx; -#endif - Elf_Scn *shstrtab_scn; - size_t shstrtab_ndx; - XElf_Ehdr_vardef (ehdr); - struct Ebl_Strent *symtab_ent =3D NULL; - struct Ebl_Strent *xndx_ent =3D NULL; - struct Ebl_Strent *strtab_ent =3D NULL; - struct Ebl_Strent *shstrtab_ent; - struct scngroup *groups; - Elf_Scn *dynsymscn =3D NULL; - Elf_Data *dynsymdata =3D NULL; - Elf_Data *dynstrdata =3D NULL; - Elf32_Word *hashcodes =3D NULL; - Elf32_Word *gnuhashcodes =3D NULL; - size_t nsym_dyn_allocated =3D 0; - Elf_Scn *versymscn =3D NULL; - Elf_Data *versymdata =3D NULL; - - if (ld_state.need_symtab) - { - /* First create the symbol table. We need the symbol section itself - and the string table for it. */ - symscn =3D elf_newscn (ld_state.outelf); - ld_state.symscnidx =3D elf_ndxscn (symscn); - symdata =3D elf_newdata (symscn); - if (symdata =3D=3D NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create symbol table for output file: %s"), - elf_errmsg (-1)); - - symdata->d_type =3D ELF_T_SYM; - /* This is an estimated size, but it will definitely cap the real va= lue. - We might have to adjust the number later. */ - nsym_allocated =3D (1 + ld_state.nsymtab + ld_state.nplt + ld_state.= ngot - + ld_state.nusedsections + ld_state.nlscript_syms); - symdata->d_size =3D xelf_fsize (ld_state.outelf, ELF_T_SYM, - nsym_allocated); - - /* Optionally the extended section table. */ - /* XXX Is SHN_LORESERVE correct? Do we need some other sections? */ - if (unlikely (ld_state.nusedsections >=3D SHN_LORESERVE)) - { - xndxscn =3D elf_newscn (ld_state.outelf); - ld_state.xndxscnidx =3D elf_ndxscn (xndxscn); - - xndxdata =3D elf_newdata (xndxscn); - if (xndxdata =3D=3D NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create symbol table for output file: %s"), - elf_errmsg (-1)); - - /* The following relies on the fact that Elf32_Word and Elf64_Word - have the same size. */ - xndxdata->d_type =3D ELF_T_WORD; - /* This is an estimated size, but it will definitely cap the - real value. we might have to adjust the number later. */ - xndxdata->d_size =3D xelf_fsize (ld_state.outelf, ELF_T_WORD, - nsym_allocated); - /* The first entry is left empty, clear it here and now. */ - xndxdata->d_buf =3D memset (xmalloc (xndxdata->d_size), '\0', - xelf_fsize (ld_state.outelf, ELF_T_WORD, - 1)); - xndxdata->d_off =3D 0; - /* XXX Should use an ebl function. */ - xndxdata->d_align =3D sizeof (Elf32_Word); - } - } - else - { - assert (ld_state.need_dynsym); - - /* First create the symbol table. We need the symbol section itself - and the string table for it. */ - symscn =3D elf_getscn (ld_state.outelf, ld_state.dynsymscnidx); - symdata =3D elf_newdata (symscn); - if (symdata =3D=3D NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create symbol table for output file: %s"), - elf_errmsg (-1)); - - symdata->d_version =3D EV_CURRENT; - symdata->d_type =3D ELF_T_SYM; - /* This is an estimated size, but it will definitely cap the real va= lue. - We might have to adjust the number later. */ - nsym_allocated =3D (1 + ld_state.nsymtab + ld_state.nplt + ld_state.= ngot - - ld_state.nlocalsymbols + ld_state.nlscript_syms); - symdata->d_size =3D xelf_fsize (ld_state.outelf, ELF_T_SYM, - nsym_allocated); - } - - /* The first entry is left empty, clear it here and now. */ - symdata->d_buf =3D memset (xmalloc (symdata->d_size), '\0', - xelf_fsize (ld_state.outelf, ELF_T_SYM, 1)); - symdata->d_off =3D 0; - /* XXX This is ugly but how else can it be done. */ - symdata->d_align =3D xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1); - - /* Allocate another array to keep track of the handles for the symbol - names. */ - symstrent =3D (struct Ebl_Strent **) xcalloc (nsym_allocated, - sizeof (struct Ebl_Strent *)); - - /* By starting at 1 we effectively add a null entry. */ - nsym =3D 1; - - /* Iteration over all sections. */ - for (cnt =3D 0; cnt < ld_state.nallsections; ++cnt) - { - struct scnhead *head =3D ld_state.allsections[cnt]; - Elf_Scn *scn; - struct scninfo *runp; - XElf_Off offset; - Elf32_Word xndx; - - /* Don't handle unused sections at all. */ - if (!head->used) - continue; - - /* Get the section handle. */ - scn =3D elf_getscn (ld_state.outelf, head->scnidx); - - if (unlikely (head->kind =3D=3D scn_dot_interp)) - { - Elf_Data *outdata =3D elf_newdata (scn); - if (outdata =3D=3D NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create section for output file: %s"), - elf_errmsg (-1)); - - /* This is the string we'll put in the section. */ - const char *interp =3D ld_state.interp ?: "/lib/ld.so.1"; - - /* Create the section data. */ - outdata->d_buf =3D (void *) interp; - outdata->d_size =3D strlen (interp) + 1; - outdata->d_type =3D ELF_T_BYTE; - outdata->d_off =3D 0; - outdata->d_align =3D 1; - outdata->d_version =3D EV_CURRENT; - - /* Remember the index of this section. */ - ld_state.interpscnidx =3D head->scnidx; - - continue; - } - - if (unlikely (head->kind =3D=3D scn_dot_got)) - { - /* Remember the index of this section. */ - ld_state.gotscnidx =3D elf_ndxscn (scn); - - /* Give the backend the change to initialize the section. */ - INITIALIZE_GOT (&ld_state, scn); - - continue; - } - - if (unlikely (head->kind =3D=3D scn_dot_gotplt)) - { - /* Remember the index of this section. */ - ld_state.gotpltscnidx =3D elf_ndxscn (scn); - - /* Give the backend the change to initialize the section. */ - INITIALIZE_GOTPLT (&ld_state, scn); - - continue; - } - - if (unlikely (head->kind =3D=3D scn_dot_dynrel)) - { - Elf_Data *outdata; - - outdata =3D elf_newdata (scn); - if (outdata =3D=3D NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create section for output file: %s"), - elf_errmsg (-1)); - - outdata->d_size =3D ld_state.relsize_total; - outdata->d_buf =3D xmalloc (outdata->d_size); - outdata->d_type =3D (REL_TYPE (&ld_state) =3D=3D DT_REL - ? ELF_T_REL : ELF_T_RELA); - outdata->d_off =3D 0; - outdata->d_align =3D xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1); - - /* Remember the index of this section. */ - ld_state.reldynscnidx =3D elf_ndxscn (scn); - - continue; - } - - if (unlikely (head->kind =3D=3D scn_dot_dynamic)) - { - /* Only create the data for now. */ - Elf_Data *outdata; - - /* Account for a few more entries we have to add. */ - if (ld_state.dt_flags !=3D 0) - ++ld_state.ndynamic; - if (ld_state.dt_flags_1 !=3D 0) - ++ld_state.ndynamic; - if (ld_state.dt_feature_1 !=3D 0) - ++ld_state.ndynamic; - - outdata =3D elf_newdata (scn); - if (outdata =3D=3D NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create section for output file: %s"), - elf_errmsg (-1)); - - /* Create the section data. */ - outdata->d_size =3D xelf_fsize (ld_state.outelf, ELF_T_DYN, - ld_state.ndynamic); - outdata->d_buf =3D xcalloc (1, outdata->d_size); - outdata->d_type =3D ELF_T_DYN; - outdata->d_off =3D 0; - outdata->d_align =3D xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1); - - /* Remember the index of this section. */ - ld_state.dynamicscnidx =3D elf_ndxscn (scn); - - continue; - } - - if (unlikely (head->kind =3D=3D scn_dot_dynsym)) - { - /* We already know the section index. */ - assert (ld_state.dynsymscnidx =3D=3D elf_ndxscn (scn)); - - continue; - } - - if (unlikely (head->kind =3D=3D scn_dot_dynstr)) - { - /* Remember the index of this section. */ - ld_state.dynstrscnidx =3D elf_ndxscn (scn); - - /* Create the string table. */ - dynstrtab =3D ebl_strtabinit (true); - - /* XXX TBI - We have to add all the strings which are needed in the - dynamic section here. This means DT_FILTER, - DT_AUXILIARY, ... entries. */ - if (ld_state.ndsofiles > 0) - { - struct usedfiles *frunp =3D ld_state.dsofiles; - - do - if (! frunp->as_needed || frunp->used) - frunp->sonameent =3D ebl_strtabadd (dynstrtab, frunp->soname, - 0); - while ((frunp =3D frunp->next) !=3D ld_state.dsofiles); - } - - - /* Add the runtime path information. The strings are stored - in the .dynstr section. If both rpath and runpath are defined - the runpath information is used. */ - if (ld_state.runpath !=3D NULL || ld_state.rpath !=3D NULL) - { - struct pathelement *startp; - struct pathelement *prunp; - int tag; - size_t len; - char *str; - char *cp; - - if (ld_state.runpath !=3D NULL) - { - startp =3D ld_state.runpath; - tag =3D DT_RUNPATH; - } - else - { - startp =3D ld_state.rpath; - tag =3D DT_RPATH; - } - - /* Determine how long the string will be. */ - for (len =3D 0, prunp =3D startp; prunp !=3D NULL; prunp =3D prunp-= >next) - len +=3D strlen (prunp->pname) + 1; - - cp =3D str =3D (char *) obstack_alloc (&ld_state.smem, len); - /* Copy the string. */ - for (prunp =3D startp; prunp !=3D NULL; prunp =3D prunp->next) - { - cp =3D stpcpy (cp, prunp->pname); - *cp++ =3D ':'; - } - /* Remove the last colon. */ - cp[-1] =3D '\0'; - - /* Remember the values until we can generate the dynamic - section. */ - ld_state.rxxpath_strent =3D ebl_strtabadd (dynstrtab, str, len); - ld_state.rxxpath_tag =3D tag; - } - - continue; - } - - if (unlikely (head->kind =3D=3D scn_dot_hash)) - { - /* Remember the index of this section. */ - ld_state.hashscnidx =3D elf_ndxscn (scn); - - continue; - } - - if (unlikely (head->kind =3D=3D scn_dot_gnu_hash)) - { - /* Remember the index of this section. */ - ld_state.gnuhashscnidx =3D elf_ndxscn (scn); - - continue; - } - - if (unlikely (head->kind =3D=3D scn_dot_plt)) - { - /* Remember the index of this section. */ - ld_state.pltscnidx =3D elf_ndxscn (scn); - - /* Give the backend the change to initialize the section. */ - INITIALIZE_PLT (&ld_state, scn); - - continue; - } - - if (unlikely (head->kind =3D=3D scn_dot_pltrel)) - { - /* Remember the index of this section. */ - ld_state.pltrelscnidx =3D elf_ndxscn (scn); - - /* Give the backend the change to initialize the section. */ - INITIALIZE_PLTREL (&ld_state, scn); - - continue; - } - - if (unlikely (head->kind =3D=3D scn_dot_version)) - { - /* Remember the index of this section. */ - ld_state.versymscnidx =3D elf_ndxscn (scn); - - continue; - } - - if (unlikely (head->kind =3D=3D scn_dot_version_r)) - { - /* Remember the index of this section. */ - ld_state.verneedscnidx =3D elf_ndxscn (scn); - - continue; - } - - if (unlikely (head->kind =3D=3D scn_dot_note_gnu_build_id)) - { - /* Remember the index of this section. */ - ld_state.buildidscnidx =3D elf_ndxscn (scn); - - create_build_id_section (scn); - - continue; - } - - /* If we come here we must be handling a normal section. */ - assert (head->kind =3D=3D scn_normal); - - /* Create an STT_SECTION entry in the symbol table. But not for - the symbolic symbol table. */ - if (ld_state.need_symtab) - { - /* XXX Can we be cleverer and do this only if needed? */ - XElf_Sym_vardef (sym); - - /* Optimization ahead: in the native linker we get a pointer - to the final location so that the following code writes - directly in the correct place. Otherwise we write into - the local variable first. */ - xelf_getsym_ptr (symdata, nsym, sym); - - /* Usual section symbol: local, no specific information, - except the section index. The offset here is zero, the - start address will later be added. */ - sym->st_name =3D 0; - sym->st_info =3D XELF_ST_INFO (STB_LOCAL, STT_SECTION); - sym->st_other =3D 0; - sym->st_value =3D 0; - sym->st_size =3D 0; - /* In relocatable files the section index can be too big for - the ElfXX_Sym struct. we have to deal with the extended - symbol table. */ - if (likely (head->scnidx < SHN_LORESERVE)) - { - sym->st_shndx =3D head->scnidx; - xndx =3D 0; - } - else - { - sym->st_shndx =3D SHN_XINDEX; - xndx =3D head->scnidx; - } - /* Commit the change. See the optimization above, this does - not change the symbol table entry. But the extended - section index table entry is always written, if there is - such a table. */ - assert (nsym < nsym_allocated); - xelf_update_symshndx (symdata, xndxdata, nsym, sym, xndx, 0); - - /* Remember the symbol's index in the symbol table. */ - head->scnsymidx =3D nsym++; - } - - if (head->type =3D=3D SHT_REL || head->type =3D=3D SHT_RELA) - { - /* Remember that we have to fill in the symbol table section - index. */ - if (ld_state.file_type =3D=3D relocatable_file_type) - { - struct scnlist *newp; - - newp =3D (struct scnlist *) alloca (sizeof (*newp)); - newp->scnidx =3D head->scnidx; - newp->scninfo =3D head->last->next; -#ifndef NDEBUG - newp->next =3D NULL; -#endif - SNGL_LIST_PUSH (rellist, newp); - } - else - { - /* When we create an executable or a DSO we don't simply - copy the existing relocations. Instead many will be - resolved, others will be converted. Create a data buffer - large enough to contain the contents which we will fill - in later. */ - int type =3D head->type =3D=3D SHT_REL ? ELF_T_REL : ELF_T_RELA; - - data =3D elf_newdata (scn); - if (data =3D=3D NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create section for output file: %s"), - elf_errmsg (-1)); - - data->d_size =3D xelf_fsize (ld_state.outelf, type, head->relsize); - data->d_buf =3D xcalloc (data->d_size, 1); - data->d_type =3D type; - data->d_align =3D xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1); - data->d_off =3D 0; - - continue; - } - } - - /* Recognize string and merge flag and handle them. */ - if (head->flags & SHF_MERGE) - { - /* We merge the contents of the sections. For this we do - not look at the contents of section directly. Instead we - look at the symbols of the section. */ - Elf_Data *outdata; - - /* Concatenate the lists of symbols for all sections. - - XXX In case any input section has no symbols associated - (this happens for debug sections) we cannot use this - method. Implement parsing the other debug sections and - find the string pointers. For now we don't merge. */ - runp =3D head->last->next; - if (runp->symbols =3D=3D NULL) - { - head->flags &=3D ~SHF_MERGE; - goto no_merge; - } - head->symbols =3D runp->symbols; - - while ((runp =3D runp->next) !=3D head->last->next) - { - if (runp->symbols =3D=3D NULL) - { - head->flags &=3D ~SHF_MERGE; - head->symbols =3D NULL; - goto no_merge; - } - - struct symbol *oldhead =3D head->symbols->next_in_scn; - - head->symbols->next_in_scn =3D runp->symbols->next_in_scn; - runp->symbols->next_in_scn =3D oldhead; - head->symbols =3D runp->symbols; - } - - /* Create the output section. */ - outdata =3D elf_newdata (scn); - if (outdata =3D=3D NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create section for output file: %s"), - elf_errmsg (-1)); - - /* We use different merging algorithms for performance - reasons. We can easily handle single-byte and - wchar_t-wide character strings. All other cases (which - really should happen in real life) are handled by the - generic code. */ - if (SCNINFO_SHDR (head->last->shdr).sh_entsize =3D=3D 1 - && (head->flags & SHF_STRINGS)) - { - /* Simple, single-byte string matching. */ - struct Ebl_Strtab *mergestrtab; - struct symbol *symrunp; - Elf_Data *locsymdata =3D NULL; - Elf_Data *locdata =3D NULL; - - mergestrtab =3D ebl_strtabinit (false); - - symrunp =3D head->symbols->next_in_scn; - file =3D NULL; - do - { - /* Accelarate the loop. We cache the file - information since it might very well be the case - that the previous entry was from the same - file. */ - if (symrunp->file !=3D file) - { - /* Remember the file. */ - file =3D symrunp->file; - /* Symbol table data from that file. */ - locsymdata =3D file->symtabdata; - /* String section data. */ - locdata =3D elf_rawdata (file->scninfo[symrunp->scndx].scn, - NULL); - assert (locdata !=3D NULL); - /* While we are at it, remember the output - section. If we don't access the string data - section the section won't be in the output - file. So it is sufficient to do the work - here. */ - file->scninfo[symrunp->scndx].outscnndx =3D head->scnidx; - } - - /* Get the symbol information. This provides us the - offset into the string data section. */ - XElf_Sym_vardef (sym); - xelf_getsym (locsymdata, symrunp->symidx, sym); - assert (sym !=3D NULL); - - /* Get the data from the file. Note that we access - the raw section data; no endian-ness issues with - single-byte strings. */ - symrunp->merge.handle - =3D ebl_strtabadd (mergestrtab, - (char *) locdata->d_buf + sym->st_value, - 0); - } - while ((symrunp =3D symrunp->next_in_scn) - !=3D head->symbols->next_in_scn); - - /* All strings have been added. Create the final table. */ - ebl_strtabfinalize (mergestrtab, outdata); - - /* Compute the final offsets in the section. */ - symrunp =3D runp->symbols; - do - { - symrunp->merge.value - =3D ebl_strtaboffset (symrunp->merge.handle); - symrunp->merged =3D 1; - } - while ((symrunp =3D symrunp->next_in_scn) !=3D runp->symbols); - - /* We don't need the string table anymore. */ - ebl_strtabfree (mergestrtab); - } - else if (likely (SCNINFO_SHDR (head->last->shdr).sh_entsize - =3D=3D sizeof (wchar_t)) - && likely (head->flags & SHF_STRINGS)) - { - /* Simple, wchar_t string merging. */ - struct Ebl_WStrtab *mergestrtab; - struct symbol *symrunp; - Elf_Data *locsymdata =3D NULL; - Elf_Data *locdata =3D NULL; - - mergestrtab =3D ebl_wstrtabinit (false); - - symrunp =3D runp->symbols; - file =3D NULL; - do - { - /* Accelarate the loop. We cache the file - information since it might very well be the case - that the previous entry was from the same - file. */ - if (symrunp->file !=3D file) - { - /* Remember the file. */ - file =3D symrunp->file; - /* Symbol table data from that file. */ - locsymdata =3D file->symtabdata; - /* String section data. */ - locdata =3D elf_rawdata (file->scninfo[symrunp->scndx].scn, - NULL); - assert (locdata !=3D NULL); - - /* While we are at it, remember the output - section. If we don't access the string data - section the section won't be in the output - file. So it is sufficient to do the work - here. */ - file->scninfo[symrunp->scndx].outscnndx =3D head->scnidx; - } - - /* Get the symbol information. This provides us the - offset into the string data section. */ - XElf_Sym_vardef (sym); - xelf_getsym (locsymdata, symrunp->symidx, sym); - assert (sym !=3D NULL); - - /* Get the data from the file. Using the raw - section data here is possible since we don't - interpret the string themselves except for - looking for the wide NUL character. The NUL - character has fortunately the same representation - regardless of the byte order. */ - symrunp->merge.handle - =3D ebl_wstrtabadd (mergestrtab, - (wchar_t *) ((char *) locdata->d_buf - + sym->st_value), 0); - } - while ((symrunp =3D symrunp->next_in_scn) !=3D runp->symbols); - - /* All strings have been added. Create the final table. */ - ebl_wstrtabfinalize (mergestrtab, outdata); - - /* Compute the final offsets in the section. */ - symrunp =3D runp->symbols; - do - { - symrunp->merge.value - =3D ebl_wstrtaboffset (symrunp->merge.handle); - symrunp->merged =3D 1; - } - while ((symrunp =3D symrunp->next_in_scn) !=3D runp->symbols); - - /* We don't need the string table anymore. */ - ebl_wstrtabfree (mergestrtab); - } - else - { - /* Non-standard merging. */ - struct Ebl_GStrtab *mergestrtab; - struct symbol *symrunp; - Elf_Data *locsymdata =3D NULL; - Elf_Data *locdata =3D NULL; - /* If this is no string section the length of each "string" - is always one. */ - unsigned int len =3D (head->flags & SHF_STRINGS) ? 0 : 1; - - /* This is the generic string table functionality. Much - slower than the specialized code. */ - mergestrtab - =3D ebl_gstrtabinit (SCNINFO_SHDR (head->last->shdr).sh_entsize, - false); - - symrunp =3D runp->symbols; - file =3D NULL; - do - { - /* Accelarate the loop. We cache the file - information since it might very well be the case - that the previous entry was from the same - file. */ - if (symrunp->file !=3D file) - { - /* Remember the file. */ - file =3D symrunp->file; - /* Symbol table data from that file. */ - locsymdata =3D file->symtabdata; - /* String section data. */ - locdata =3D elf_rawdata (file->scninfo[symrunp->scndx].scn, - NULL); - assert (locdata !=3D NULL); - - /* While we are at it, remember the output - section. If we don't access the string data - section the section won't be in the output - file. So it is sufficient to do the work - here. */ - file->scninfo[symrunp->scndx].outscnndx =3D head->scnidx; - } - - /* Get the symbol information. This provides us the - offset into the string data section. */ - XElf_Sym_vardef (sym); - xelf_getsym (locsymdata, symrunp->symidx, sym); - assert (sym !=3D NULL); - - /* Get the data from the file. Using the raw - section data here is possible since we don't - interpret the string themselves except for - looking for the wide NUL character. The NUL - character has fortunately the same representation - regardless of the byte order. */ - symrunp->merge.handle - =3D ebl_gstrtabadd (mergestrtab, - (char *) locdata->d_buf + sym->st_value, - len); - } - while ((symrunp =3D symrunp->next_in_scn) !=3D runp->symbols); - - /* Create the final table. */ - ebl_gstrtabfinalize (mergestrtab, outdata); - - /* Compute the final offsets in the section. */ - symrunp =3D runp->symbols; - do - { - symrunp->merge.value - =3D ebl_gstrtaboffset (symrunp->merge.handle); - symrunp->merged =3D 1; - } - while ((symrunp =3D symrunp->next_in_scn) !=3D runp->symbols); - - /* We don't need the string table anymore. */ - ebl_gstrtabfree (mergestrtab); - } - } - else - { - no_merge: - assert (head->scnidx =3D=3D elf_ndxscn (scn)); - - /* It is important to start with the first list entry (and - not just any one) to add the sections in the correct - order. */ - runp =3D head->last->next; - offset =3D 0; - do - { - Elf_Data *outdata =3D elf_newdata (scn); - if (outdata =3D=3D NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create section for output file: %s"), - elf_errmsg (-1)); - - /* Exceptional case: if we synthesize a data block SCN - is NULL and the sectio header info must be for a - SHT_NOBITS block and the size and alignment are - filled in. */ - if (likely (runp->scn !=3D NULL)) - { - data =3D elf_getdata (runp->scn, NULL); - assert (data !=3D NULL); - - /* We reuse the data buffer in the input file. */ - *outdata =3D *data; - - /* Given that we read the input file from disk we know there - cannot be another data part. */ - assert (elf_getdata (runp->scn, data) =3D=3D NULL); - } - else - { - /* Must be a NOBITS section. */ - assert (SCNINFO_SHDR (runp->shdr).sh_type =3D=3D SHT_NOBITS); - - outdata->d_buf =3D NULL; /* Not needed. */ - outdata->d_type =3D ELF_T_BYTE; - outdata->d_version =3D EV_CURRENT; - outdata->d_size =3D SCNINFO_SHDR (runp->shdr).sh_size; - outdata->d_align =3D SCNINFO_SHDR (runp->shdr).sh_addralign; - } - - XElf_Off align =3D MAX (1, outdata->d_align); - assert (powerof2 (align)); - offset =3D ((offset + align - 1) & ~(align - 1)); - - runp->offset =3D offset; - runp->outscnndx =3D head->scnidx; - runp->allsectionsidx =3D cnt; - - outdata->d_off =3D offset; - - offset +=3D outdata->d_size; - } - while ((runp =3D runp->next) !=3D head->last->next); - - /* If necessary add the additional line to the .comment section. */ - if (ld_state.add_ld_comment - && head->flags =3D=3D 0 - && head->type =3D=3D SHT_PROGBITS - && strcmp (head->name, ".comment") =3D=3D 0 - && head->entsize =3D=3D 0) - { - Elf_Data *outdata =3D elf_newdata (scn); - - if (outdata =3D=3D NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create section for output file: %s"), - elf_errmsg (-1)); - - outdata->d_buf =3D (void *) "\0ld (" PACKAGE_NAME ") " PACKAGE_VERS= ION; - outdata->d_size =3D strlen ((char *) outdata->d_buf + 1) + 2; - outdata->d_off =3D offset; - outdata->d_type =3D ELF_T_BYTE; - outdata->d_align =3D 1; - } - /* XXX We should create a .comment section if none exists. - This requires that we early on detect that no such - section exists. This should probably be implemented - together with some merging of the section contents. - Currently identical entries are not merged. */ - } - } - - /* The table we collect the strings in. */ - strtab =3D ebl_strtabinit (true); - if (strtab =3D=3D NULL) - error (EXIT_FAILURE, errno, gettext ("cannot create string table")); - - -#ifndef NDEBUG - /* Keep track of the use of the XINDEX. */ - need_xndx =3D false; -#endif - - /* We we generate a normal symbol table for an executable and the - --export-dynamic option is not given, we need an extra table - which keeps track of the symbol entry belonging to the symbol - table entry. Note that EXPORT_ALL_DYNAMIC is always set if we - generate a DSO so we do not have to test this separately. */ - ndxtosym =3D (struct symbol **) xcalloc (nsym_allocated, - sizeof (struct symbol)); - - /* Create the special symbol for the GOT section. */ - if (ld_state.got_symbol !=3D NULL) - { - assert (nsym < nsym_allocated); - // XXX Fix so that it works even if no PLT is needed. - fillin_special_symbol (ld_state.got_symbol, ld_state.gotpltscnidx, - nsym++, symdata, strtab); - } - - /* Similarly for the dynamic section symbol. */ - if (ld_state.dyn_symbol !=3D NULL) - { - assert (nsym < nsym_allocated); - fillin_special_symbol (ld_state.dyn_symbol, ld_state.dynamicscnidx, - nsym++, symdata, strtab); - } - - /* Create symbol table entries for the symbols defined in the linker - script. */ - if (ld_state.lscript_syms !=3D NULL) - { - struct symbol *rsym =3D ld_state.lscript_syms; - do - { - assert (nsym < nsym_allocated); - fillin_special_symbol (rsym, SHN_ABS, nsym++, symdata, strtab); - } - while ((rsym =3D rsym->next) !=3D NULL); - } - - /* Iterate over all input files to collect the symbols. */ - file =3D ld_state.relfiles->next; - symdata =3D elf_getdata (elf_getscn (ld_state.outelf, ld_state.symscnidx= ), - NULL); - - do - { - size_t maxcnt; - Elf_Data *insymdata; - Elf_Data *inxndxdata; - - /* There must be no dynamic symbol table when creating - relocatable files. */ - assert (ld_state.file_type !=3D relocatable_file_type - || file->dynsymtabdata =3D=3D NULL); - - insymdata =3D file->symtabdata; - assert (insymdata !=3D NULL); - inxndxdata =3D file->xndxdata; - - maxcnt =3D file->nsymtab; - - file->symindirect =3D (Elf32_Word *) xcalloc (maxcnt, sizeof (Elf32_= Word)); - - /* The dynamic symbol table does not contain local symbols. So - we skip those entries. */ - for (cnt =3D ld_state.need_symtab ? 1 : file->nlocalsymbols; cnt < m= axcnt; - ++cnt) - { - XElf_Sym_vardef (sym); - Elf32_Word xndx; - struct symbol *defp =3D NULL; - - xelf_getsymshndx (insymdata, inxndxdata, cnt, sym, xndx); - assert (sym !=3D NULL); - - if (unlikely (XELF_ST_TYPE (sym->st_info) =3D=3D STT_SECTION)) - { - /* Section symbols should always be local but who knows... */ - if (ld_state.need_symtab) - { - /* Determine the real section index in the source file. - Use the XINDEX section content if necessary. We don't - add this information to the dynamic symbol table. */ - if (sym->st_shndx !=3D SHN_XINDEX) - xndx =3D sym->st_shndx; - - assert (file->scninfo[xndx].allsectionsidx - < ld_state.nallsections); - file->symindirect[cnt] =3D ld_state.allsections[file->scninfo[xndx].al= lsectionsidx]->scnsymidx; - /* Note that the resulting index can be zero here. There is - no guarantee that the output file will contain all the - sections the input file did. */ - } - continue; - } - - if ((ld_state.strip >=3D strip_all || !ld_state.need_symtab) - /* XXX Do we need these entries? */ - && XELF_ST_TYPE (sym->st_info) =3D=3D STT_FILE) - continue; - -#if NATIVE_ELF !=3D 0 - /* Copy old data. We create a temporary copy because the - symbol might still be discarded. */ - XElf_Sym sym_mem; - sym_mem =3D *sym; - sym =3D &sym_mem; -#endif - - if (sym->st_shndx !=3D SHN_UNDEF - && (sym->st_shndx < SHN_LORESERVE - || sym->st_shndx =3D=3D SHN_XINDEX)) - { - /* If we are creating an executable with no normal - symbol table and we do not export all symbols and - this symbol is not defined in a DSO as well, ignore - it. */ - if (!ld_state.export_all_dynamic && !ld_state.need_symtab) - { - assert (cnt >=3D file->nlocalsymbols); - defp =3D file->symref[cnt]; - assert (defp !=3D NULL); - - if (!defp->in_dso) - /* Ignore it. */ - continue; - } - - /* Determine the real section index in the source file. Use - the XINDEX section content if necessary. */ - if (sym->st_shndx !=3D SHN_XINDEX) - xndx =3D sym->st_shndx; - - sym->st_value +=3D file->scninfo[xndx].offset; - - assert (file->scninfo[xndx].outscnndx < SHN_LORESERVE - || file->scninfo[xndx].outscnndx > SHN_HIRESERVE); - if (unlikely (file->scninfo[xndx].outscnndx > SHN_LORESERVE)) - { - /* It is not possible to have an extended section index - table for the dynamic symbol table. */ - if (!ld_state.need_symtab) - error (EXIT_FAILURE, 0, gettext ("\ -section index too large in dynamic symbol table")); - - assert (xndxdata !=3D NULL); - sym->st_shndx =3D SHN_XINDEX; - xndx =3D file->scninfo[xndx].outscnndx; -#ifndef NDEBUG - need_xndx =3D true; -#endif - } - else - { - sym->st_shndx =3D file->scninfo[xndx].outscnndx; - xndx =3D 0; - } - } - else if (sym->st_shndx =3D=3D SHN_COMMON || sym->st_shndx =3D=3D SHN_UN= DEF) - { - /* Check whether we have a (real) definition for this - symbol. If this is the case we skip this symbol - table entry. */ - assert (cnt >=3D file->nlocalsymbols); - defp =3D file->symref[cnt]; - assert (defp !=3D NULL); - - assert (sym->st_shndx !=3D SHN_COMMON || defp->defined); - - if ((sym->st_shndx =3D=3D SHN_COMMON && !defp->common) - || (sym->st_shndx =3D=3D SHN_UNDEF && defp->defined) - || defp->added) - /* Ignore this symbol table entry, there is a - "better" one or we already added it. */ - continue; - - /* Remember that we already added this symbol. */ - defp->added =3D 1; - - /* Adjust the section number for common symbols. */ - if (sym->st_shndx =3D=3D SHN_COMMON) - { - sym->st_value =3D (ld_state.common_section->offset - + file->symref[cnt]->merge.value); - assert (ld_state.common_section->outscnndx < SHN_LORESERVE); - sym->st_shndx =3D ld_state.common_section->outscnndx; - xndx =3D 0; - } - } - else if (unlikely (sym->st_shndx !=3D SHN_ABS)) - { - if (SPECIAL_SECTION_NUMBER_P (&ld_state, sym->st_shndx)) - /* XXX Add code to handle machine specific special - sections. */ - abort (); - } - - /* Add the symbol name to the string table. If the user - chooses the highest level of stripping avoid adding names - for local symbols in the string table. */ - if (sym->st_name !=3D 0 - && (ld_state.strip < strip_everything - || XELF_ST_BIND (sym->st_info) !=3D STB_LOCAL)) - symstrent[nsym] =3D ebl_strtabadd (strtab, - elf_strptr (file->elf, - file->symstridx, - sym->st_name), 0); - - /* Once we know the name this field will get the correct - offset. For now set it to zero which means no name - associated. */ - GElf_Word st_name =3D sym->st_name; - sym->st_name =3D 0; - - /* If we had to merge sections we have a completely new - offset for the symbol. */ - if (file->has_merge_sections && file->symref[cnt] !=3D NULL - && file->symref[cnt]->merged) - sym->st_value =3D file->symref[cnt]->merge.value; - - /* Create the record in the output sections. */ - assert (nsym < nsym_allocated); - xelf_update_symshndx (symdata, xndxdata, nsym, sym, xndx, 1); - - /* Add the reference to the symbol record in case we need it. - Find the symbol if this has not happened yet. We do - not need the information for local symbols. */ - if (defp =3D=3D NULL && cnt >=3D file->nlocalsymbols) - { - defp =3D file->symref[cnt]; - - if (defp =3D=3D NULL) - { - /* This is a symbol in a discarded COMDAT section. - Find the definition we actually use. */ - // XXX The question is: do we have to do this here - // XXX or can we do it earlier when we discard the - // XXX section. - struct symbol search; - search.name =3D elf_strptr (file->elf, file->symstridx, - st_name); - struct symbol *realp - =3D ld_symbol_tab_find (&ld_state.symbol_tab, - elf_hash (search.name), &search); - if (realp =3D=3D NULL) - // XXX What to do here? - error (EXIT_FAILURE, 0, - "couldn't find symbol from COMDAT section"); - - file->symref[cnt] =3D realp; - - continue; - } - } - - /* Store the reference to the symbol record. The sorting - code will have to keep this array in the correct order, too. */ - ndxtosym[nsym] =3D defp; - - /* One more entry finished. */ - if (cnt >=3D file->nlocalsymbols) - { - assert (file->symref[cnt]->outsymidx =3D=3D 0); - file->symref[cnt]->outsymidx =3D nsym; - } - file->symindirect[cnt] =3D nsym++; - } - } - while ((file =3D file->next) !=3D ld_state.relfiles->next); - /* Make sure we didn't create the extended section index table for - nothing. */ - assert (xndxdata =3D=3D NULL || need_xndx); - - /* Create the version related sections. */ - if (ld_state.verneedscnidx !=3D 0) - { - /* We know the number of input files and total number of - referenced versions. This allows us to allocate the memory - and then we iterate over the DSOs to get the version - information. */ - struct usedfiles *runp; - - runp =3D ld_state.dsofiles->next; - do - allocate_version_names (runp, dynstrtab); - while ((runp =3D runp->next) !=3D ld_state.dsofiles->next); - - if (ld_state.needed !=3D NULL) - { - runp =3D ld_state.needed->next; - do - allocate_version_names (runp, dynstrtab); - while ((runp =3D runp->next) !=3D ld_state.needed->next); - } - } - - /* At this point we should hide symbols and so on. */ - if (ld_state.default_bind_local || ld_state.version_str_tab.filled > 0) - /* XXX Add one more test when handling of wildcard symbol names - is supported. */ - { - /* Check all non-local symbols whether they are on the export list. */ - bool any_reduced =3D false; - - for (cnt =3D 1; cnt < nsym; ++cnt) - { - XElf_Sym_vardef (sym); - - /* Note that we don't have to use 'xelf_getsymshndx' since we - only need the binding and the symbol name. */ - xelf_getsym (symdata, cnt, sym); - assert (sym !=3D NULL); - - if (reduce_symbol_p (sym, symstrent[cnt])) - { - // XXX Check whether this is correct... - assert (ndxtosym[cnt]->outdynsymidx !=3D 0); - ndxtosym[cnt]->outdynsymidx =3D 0; - - sym->st_info =3D XELF_ST_INFO (STB_LOCAL, - XELF_ST_TYPE (sym->st_info)); - (void) xelf_update_sym (symdata, cnt, sym); - - /* Show that we don't need this string anymore. */ - if (ld_state.strip =3D=3D strip_everything) - { - symstrent[cnt] =3D NULL; - any_reduced =3D true; - } - } - } - - if (unlikely (any_reduced)) - { - /* Since we will not write names of local symbols in the - output file and we have reduced the binding of some - symbols the string table previously constructed contains - too many string. Correct it. */ - struct Ebl_Strtab *newp =3D ebl_strtabinit (true); - - for (cnt =3D 1; cnt < nsym; ++cnt) - if (symstrent[cnt] !=3D NULL) - symstrent[cnt] =3D ebl_strtabadd (newp, - ebl_string (symstrent[cnt]), 0); - - ebl_strtabfree (strtab); - strtab =3D newp; - } - } - - /* Add the references to DSOs. We can add these entries this late - (after sorting out versioning) because references to DSOs are not - effected. */ - if (ld_state.from_dso !=3D NULL) - { - struct symbol *runp; - size_t plt_base =3D nsym + ld_state.nfrom_dso - ld_state.nplt; - size_t plt_idx =3D 0; - size_t obj_idx =3D 0; - - assert (ld_state.nfrom_dso >=3D ld_state.nplt); - runp =3D ld_state.from_dso; - do - { - // XXX What about functions which are only referenced via - // pointers and not PLT entries? Can we distinguish such uses? - size_t idx; - if (runp->type =3D=3D STT_FUNC) - { - /* Store the PLT entry number. */ - runp->merge.value =3D plt_idx + 1; - idx =3D plt_base + plt_idx++; - } - else - idx =3D nsym + obj_idx++; - - XElf_Sym_vardef (sym); - xelf_getsym_ptr (symdata, idx, sym); - - sym->st_value =3D 0; - sym->st_size =3D runp->size; - sym->st_info =3D XELF_ST_INFO (runp->weak ? STB_WEAK : STB_GLOBAL, - runp->type); - sym->st_other =3D STV_DEFAULT; - sym->st_shndx =3D SHN_UNDEF; - - /* Create the record in the output sections. */ - xelf_update_symshndx (symdata, xndxdata, idx, sym, 0, 0); - - const char *name =3D runp->name; - size_t namelen =3D 0; - - if (runp->file->verdefdata !=3D NULL) - { - // XXX Is it useful to add the versym value to struct symbol? - XElf_Versym versym; - - (void) xelf_getversym_copy (runp->file->versymdata, runp->symidx, - versym); - - /* One can only link with the default version. */ - assert ((versym & 0x8000) =3D=3D 0); - - const char *versname - =3D ebl_string (runp->file->verdefent[versym]); - - size_t versname_len =3D strlen (versname) + 1; - namelen =3D strlen (name) + versname_len + 2; - char *newp =3D (char *) obstack_alloc (&ld_state.smem, namelen); - memcpy (stpcpy (stpcpy (newp, name), "@@"), - versname, versname_len); - name =3D newp; - } - - symstrent[idx] =3D ebl_strtabadd (strtab, name, namelen); - - /* Record the initial index in the symbol table. */ - runp->outsymidx =3D idx; - - /* Remember the symbol record this ELF symbol came from. */ - ndxtosym[idx] =3D runp; - } - while ((runp =3D runp->next) !=3D ld_state.from_dso); - - assert (nsym + obj_idx =3D=3D plt_base); - assert (plt_idx =3D=3D ld_state.nplt); - nsym =3D plt_base + plt_idx; - } - - /* Now we know how many symbols will be in the output file. Adjust - the count in the section data. */ - symdata->d_size =3D xelf_fsize (ld_state.outelf, ELF_T_SYM, nsym); - if (unlikely (xndxdata !=3D NULL)) - xndxdata->d_size =3D xelf_fsize (ld_state.outelf, ELF_T_WORD, nsym); - - /* Create the symbol string table section. */ - strscn =3D elf_newscn (ld_state.outelf); - ld_state.strscnidx =3D elf_ndxscn (strscn); - data =3D elf_newdata (strscn); - xelf_getshdr (strscn, shdr); - if (data =3D=3D NULL || shdr =3D=3D NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create section for output file: %s"), - elf_errmsg (-1)); - - /* Create a compact string table, allocate the memory for it, and - fill in the section data information. */ - ebl_strtabfinalize (strtab, data); - - shdr->sh_type =3D SHT_STRTAB; - assert (shdr->sh_entsize =3D=3D 0); - - if (unlikely (xelf_update_shdr (strscn, shdr) =3D=3D 0)) - error (EXIT_FAILURE, 0, - gettext ("cannot create section for output file: %s"), - elf_errmsg (-1)); - - /* Fill in the offsets of the symbol names. */ - for (cnt =3D 1; cnt < nsym; ++cnt) - if (symstrent[cnt] !=3D NULL) - { - XElf_Sym_vardef (sym); - - /* Note that we don't have to use 'xelf_getsymshndx' since we don't - modify the section index. */ - xelf_getsym (symdata, cnt, sym); - /* This better worked, we did it before. */ - assert (sym !=3D NULL); - sym->st_name =3D ebl_strtaboffset (symstrent[cnt]); - (void) xelf_update_sym (symdata, cnt, sym); - } - - /* Since we are going to reorder the symbol table but still have to - be able to find the new position based on the old one (since the - latter is stored in 'symindirect' information of the input file - data structure) we have to create yet another indirection - table. */ - ld_state.dblindirect =3D dblindirect - =3D (Elf32_Word *) xmalloc (nsym * sizeof (Elf32_Word)); - - /* Sort the symbol table so that the local symbols come first. */ - /* XXX We don't use stable sorting here. It seems not necessary and - would be more expensive. If it turns out to be necessary this can - be fixed easily. */ - nsym_local =3D 1; - cnt =3D nsym - 1; - while (nsym_local < cnt) - { - XElf_Sym_vardef (locsym); - Elf32_Word locxndx; - XElf_Sym_vardef (globsym); - Elf32_Word globxndx; - - do - { - xelf_getsymshndx (symdata, xndxdata, nsym_local, locsym, locxndx); - /* This better works. */ - assert (locsym !=3D NULL); - - if (XELF_ST_BIND (locsym->st_info) !=3D STB_LOCAL - && (ld_state.need_symtab || ld_state.export_all_dynamic)) - { - do - { - xelf_getsymshndx (symdata, xndxdata, cnt, globsym, globxndx); - /* This better works. */ - assert (globsym !=3D NULL); - - if (unlikely (XELF_ST_BIND (globsym->st_info) =3D=3D STB_LOCAL)) - { - /* We swap the two entries. */ -#if NATIVE_ELF !=3D 0 - /* Since we directly modify the data in the ELF - data structure we have to make a copy of one - of the entries. */ - XElf_Sym locsym_copy =3D *locsym; - locsym =3D &locsym_copy; -#endif - xelf_update_symshndx (symdata, xndxdata, nsym_local, - globsym, globxndx, 1); - xelf_update_symshndx (symdata, xndxdata, cnt, - locsym, locxndx, 1); - - /* Also swap the cross references. */ - dblindirect[nsym_local] =3D cnt; - dblindirect[cnt] =3D nsym_local; - - /* And the entries for the symbol names. */ - struct Ebl_Strent *strtmp =3D symstrent[nsym_local]; - symstrent[nsym_local] =3D symstrent[cnt]; - symstrent[cnt] =3D strtmp; - - /* And the mapping from symbol table entry to - struct symbol record. */ - struct symbol *symtmp =3D ndxtosym[nsym_local]; - ndxtosym[nsym_local] =3D ndxtosym[cnt]; - ndxtosym[cnt] =3D symtmp; - - /* Go to the next entry. */ - ++nsym_local; - --cnt; - - break; - } - - dblindirect[cnt] =3D cnt; - } - while (nsym_local < --cnt); - - break; - } - - dblindirect[nsym_local] =3D nsym_local; - } - while (++nsym_local < cnt); - } - - /* The symbol 'nsym_local' is currently pointing to might be local, - too. Check and increment the variable if this is the case. */ - if (likely (nsym_local < nsym)) - { - XElf_Sym_vardef (locsym); - - /* This entry isn't moved. */ - dblindirect[nsym_local] =3D nsym_local; - - /* Note that it is OK to not use 'xelf_getsymshndx' here. */ - xelf_getsym (symdata, nsym_local, locsym); - /* This better works. */ - assert (locsym !=3D NULL); - - if (XELF_ST_BIND (locsym->st_info) =3D=3D STB_LOCAL) - ++nsym_local; - } - - - /* We need the versym array right away to keep track of the version - symbols. */ - if (ld_state.versymscnidx !=3D 0) - { - /* We allocate more memory than we need since the array is morroring - the dynamic symbol table and not the normal symbol table. I.e., - no local symbols are present. */ - versymscn =3D elf_getscn (ld_state.outelf, ld_state.versymscnidx); - versymdata =3D elf_newdata (versymscn); - if (versymdata =3D=3D NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create versioning section: %s"), - elf_errmsg (-1)); - - versymdata->d_size =3D xelf_fsize (ld_state.outelf, ELF_T_HALF, - nsym - nsym_local + 1); - versymdata->d_buf =3D xcalloc (1, versymdata->d_size); - versymdata->d_align =3D xelf_fsize (ld_state.outelf, ELF_T_HALF, 1); - versymdata->d_off =3D 0; - versymdata->d_type =3D ELF_T_HALF; - } - - - /* If we have to construct the dynamic symbol table we must not include - the local symbols. If the normal symbol has to be emitted as well - we haven't done anything else yet and we can construct it from - scratch now. */ - if (unlikely (!ld_state.need_symtab)) - { - /* Note that the following code works even if there is no entry - to remove since the zeroth entry is always local. */ - size_t reduce =3D xelf_fsize (ld_state.outelf, ELF_T_SYM, nsym_local= - 1); - - XElf_Sym_vardef (nullsym); - xelf_getsym_ptr (symdata, nsym_local - 1, nullsym); - - /* Note that we don't have to use 'xelf_update_symshndx' since - this is the dynamic symbol table we write. */ - (void) xelf_update_sym (symdata, nsym_local - 1, - memset (nullsym, '\0', sizeof (*nullsym))); - - /* Update the buffer pointer and size in the output data. */ - symdata->d_buf =3D (char *) symdata->d_buf + reduce; - symdata->d_size -=3D reduce; - - /* Add the version symbol information. */ - if (versymdata !=3D NULL) - { - nsym_dyn =3D 1; - for (cnt =3D nsym_local; cnt < nsym; ++cnt, ++nsym_dyn) - { - struct symbol *symp =3D ndxtosym[cnt]; - - if (symp->file->versymdata !=3D NULL) - { - GElf_Versym versym; - - gelf_getversym (symp->file->versymdata, symp->symidx, - &versym); - - (void) gelf_update_versym (versymdata, symp->outdynsymidx, - &symp->file->verdefused[versym]); - } - } - } - - /* Since we only created the dynamic symbol table the number of - dynamic symbols is the total number of symbols. */ - nsym_dyn =3D nsym - nsym_local + 1; - - /* XXX TBI. Create whatever data structure is missing. */ - abort (); - } - else if (ld_state.need_dynsym) - { - /* Create the dynamic symbol table section data along with the - string table. We look at all non-local symbols we found for - the normal symbol table and add those. */ - dynsymscn =3D elf_getscn (ld_state.outelf, ld_state.dynsymscnidx); - dynsymdata =3D elf_newdata (dynsymscn); - - dynstrdata =3D elf_newdata (elf_getscn (ld_state.outelf, - ld_state.dynstrscnidx)); - if (dynsymdata =3D=3D NULL || dynstrdata =3D=3D NULL) - error (EXIT_FAILURE, 0, gettext ("\ -cannot create dynamic symbol table for output file: %s"), - elf_errmsg (-1)); - - nsym_dyn_allocated =3D nsym - nsym_local + 1; - dynsymdata->d_size =3D xelf_fsize (ld_state.outelf, ELF_T_SYM, - nsym_dyn_allocated); - dynsymdata->d_buf =3D memset (xmalloc (dynsymdata->d_size), '\0', - xelf_fsize (ld_state.outelf, ELF_T_SYM, 1)); - dynsymdata->d_type =3D ELF_T_SYM; - dynsymdata->d_off =3D 0; - dynsymdata->d_align =3D xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1); - - /* We need one more array which contains the hash codes of the - symbol names. */ - hashcodes =3D (Elf32_Word *) xcalloc (__builtin_popcount ((int) ld_s= tate.hash_style) - * nsym_dyn_allocated, - sizeof (Elf32_Word)); - gnuhashcodes =3D hashcodes; - if (GENERATE_SYSV_HASH) - gnuhashcodes +=3D nsym_dyn_allocated; - - /* We have and empty entry at the beginning. */ - nsym_dyn =3D 1; - - /* Populate the table. */ - for (cnt =3D nsym_local; cnt < nsym; ++cnt) - { - XElf_Sym_vardef (sym); - - xelf_getsym (symdata, cnt, sym); - assert (sym !=3D NULL); - - if (sym->st_shndx =3D=3D SHN_XINDEX) - error (EXIT_FAILURE, 0, gettext ("\ -section index too large in dynamic symbol table")); - - /* We do not add the symbol to the dynamic symbol table if - - - the symbol is for a file - - it is not externally visible (internal, hidden) - - export_all_dynamic is not set and the symbol is only defined - in the executable (i.e., it is defined, but not (also) in DSO) - - Set symstrent[cnt] to NULL in case an entry is ignored. */ - if (XELF_ST_TYPE (sym->st_info) =3D=3D STT_FILE - || XELF_ST_VISIBILITY (sym->st_other) =3D=3D STV_INTERNAL - || XELF_ST_VISIBILITY (sym->st_other) =3D=3D STV_HIDDEN - || (!ld_state.export_all_dynamic - && !ndxtosym[cnt]->in_dso && ndxtosym[cnt]->defined)) - { - symstrent[cnt] =3D NULL; - continue; - } - - /* Store the index of the symbol in the dynamic symbol - table. This is a preliminary value in case we use the - GNU-style hash table. */ - ndxtosym[cnt]->outdynsymidx =3D nsym_dyn; - - /* Create a new string table entry. */ - const char *str =3D ndxtosym[cnt]->name; - symstrent[cnt] =3D ebl_strtabadd (dynstrtab, str, 0); - if (GENERATE_SYSV_HASH) - hashcodes[nsym_dyn] =3D elf_hash (str); - if (GENERATE_GNU_HASH) - gnuhashcodes[nsym_dyn] =3D elf_gnu_hash (str); - ++nsym_dyn; - } - - if (ld_state.file_type !=3D relocatable_file_type) - { - /* Finalize the dynamic string table. */ - ebl_strtabfinalize (dynstrtab, dynstrdata); - - assert (ld_state.hashscnidx !=3D 0 || ld_state.gnuhashscnidx !=3D 0); - - /* Create the GNU-style hash table. */ - if (GENERATE_GNU_HASH) - create_gnu_hash (nsym_local, nsym, nsym_dyn, gnuhashcodes); - - /* Create the SysV-style hash table. This has to happen - after the GNU-style table is created since - CREATE-GNU-HASH might reorder the dynamic symbol table. */ - if (GENERATE_SYSV_HASH) - create_hash (nsym_local, nsym, nsym_dyn, hashcodes); - } - - /* Add the version information. */ - if (versymdata !=3D NULL) - for (cnt =3D nsym_local; cnt < nsym; ++cnt) - if (symstrent[cnt] !=3D NULL) - { - struct symbol *symp =3D ndxtosym[cnt]; - - /* Synthetic symbols (i.e., those with no file attached) - have no version information. */ - if (symp->file !=3D NULL && symp->file->verdefdata !=3D NULL) - { - GElf_Versym versym; - - gelf_getversym (symp->file->versymdata, symp->symidx, - &versym); - - (void) gelf_update_versym (versymdata, symp->outdynsymidx, - &symp->file->verdefused[versym]); - } - else - { - /* XXX Add support for version definitions. */ - GElf_Versym global =3D VER_NDX_GLOBAL; - (void) gelf_update_versym (versymdata, nsym_dyn, &global); - } - } - - /* Update the information about the symbol section. */ - if (versymdata !=3D NULL) - { - /* Correct the size now that we know how many entries the - dynamic symbol table has. */ - versymdata->d_size =3D xelf_fsize (ld_state.outelf, ELF_T_HALF, - nsym_dyn); - - /* Add the reference to the symbol table. */ - xelf_getshdr (versymscn, shdr); - assert (shdr !=3D NULL); - - shdr->sh_link =3D ld_state.dynsymscnidx; - - (void) xelf_update_shdr (versymscn, shdr); - } - } - - if (ld_state.file_type !=3D relocatable_file_type) - { - /* Now put the names in. */ - for (cnt =3D nsym_local; cnt < nsym; ++cnt) - if (symstrent[cnt] !=3D NULL) - { - XElf_Sym_vardef (sym); - size_t dynidx =3D ndxtosym[cnt]->outdynsymidx; - -#if NATIVE_ELF !=3D 0 - XElf_Sym *osym; - memcpy (xelf_getsym (dynsymdata, dynidx, sym), - xelf_getsym (symdata, cnt, osym), - sizeof (XElf_Sym)); -#else - xelf_getsym (symdata, cnt, sym); - assert (sym !=3D NULL); -#endif - - sym->st_name =3D ebl_strtaboffset (symstrent[cnt]); - - (void) xelf_update_sym (dynsymdata, dynidx, sym); - } - - free (hashcodes); - - /* Create the required version section. */ - if (ld_state.verneedscnidx !=3D 0) - { - Elf_Scn *verneedscn; - Elf_Data *verneeddata; - struct usedfiles *runp; - size_t verneed_size =3D xelf_fsize (ld_state.outelf, ELF_T_VNEED, 1); - size_t vernaux_size =3D xelf_fsize (ld_state.outelf, ELF_T_VNAUX, 1); - size_t offset; - int ntotal; - - verneedscn =3D elf_getscn (ld_state.outelf, ld_state.verneedscnidx); - xelf_getshdr (verneedscn, shdr); - verneeddata =3D elf_newdata (verneedscn); - if (shdr =3D=3D NULL || verneeddata =3D=3D NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create versioning data: %s"), - elf_errmsg (-1)); - - verneeddata->d_size =3D (ld_state.nverdeffile * verneed_size - + ld_state.nverdefused * vernaux_size); - verneeddata->d_buf =3D xmalloc (verneeddata->d_size); - verneeddata->d_type =3D ELF_T_VNEED; - verneeddata->d_align =3D xelf_fsize (ld_state.outelf, ELF_T_WORD, 1); - verneeddata->d_off =3D 0; - - offset =3D 0; - ntotal =3D ld_state.nverdeffile; - runp =3D ld_state.dsofiles->next; - do - { - offset =3D create_verneed_data (offset, verneeddata, runp, - &ntotal); - runp =3D runp->next; - } - while (ntotal > 0 && runp !=3D ld_state.dsofiles->next); - - if (ntotal > 0) - { - runp =3D ld_state.needed->next; - do - { - offset =3D create_verneed_data (offset, verneeddata, runp, - &ntotal); - runp =3D runp->next; - } - while (ntotal > 0 && runp !=3D ld_state.needed->next); - } - - assert (offset =3D=3D verneeddata->d_size); - - /* Add the needed information to the section header. */ - shdr->sh_link =3D ld_state.dynstrscnidx; - shdr->sh_info =3D ld_state.nverdeffile; - (void) xelf_update_shdr (verneedscn, shdr); - } - - /* Adjust the section size. */ - dynsymdata->d_size =3D xelf_fsize (ld_state.outelf, ELF_T_SYM, nsym_= dyn); - if (versymdata !=3D NULL) - versymdata->d_size =3D xelf_fsize (ld_state.outelf, ELF_T_HALF, - nsym_dyn); - - /* Add the remaining information to the section header. */ - xelf_getshdr (dynsymscn, shdr); - /* There is always exactly one local symbol. */ - shdr->sh_info =3D 1; - /* Reference the string table. */ - shdr->sh_link =3D ld_state.dynstrscnidx; - /* Write the updated info back. */ - (void) xelf_update_shdr (dynsymscn, shdr); - } - - /* We don't need the string table anymore. */ - free (symstrent); - - /* Remember the total number of symbols in the dynamic symbol table. */ - ld_state.ndynsym =3D nsym_dyn; - - /* Fill in the section header information. */ - symscn =3D elf_getscn (ld_state.outelf, ld_state.symscnidx); - xelf_getshdr (symscn, shdr); - if (shdr =3D=3D NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create symbol table for output file: %s"), - elf_errmsg (-1)); - - shdr->sh_type =3D SHT_SYMTAB; - shdr->sh_link =3D ld_state.strscnidx; - shdr->sh_info =3D nsym_local; - shdr->sh_entsize =3D xelf_fsize (ld_state.outelf, ELF_T_SYM, 1); - - (void) xelf_update_shdr (symscn, shdr); - - - /* Add names for the generated sections. */ - if (ld_state.symscnidx !=3D 0) - symtab_ent =3D ebl_strtabadd (ld_state.shstrtab, ".symtab", 8); - if (ld_state.xndxscnidx !=3D 0) - xndx_ent =3D ebl_strtabadd (ld_state.shstrtab, ".symtab_shndx", 14); - if (ld_state.strscnidx !=3D 0) - strtab_ent =3D ebl_strtabadd (ld_state.shstrtab, ".strtab", 8); - /* At this point we would have to test for failures in the - allocation. But we skip this. First, the problem will be caught - later when doing more allocations for the section header table. - Even if this would not be the case all that would happen is that - the section names are empty. The binary would still be usable if - it is an executable or a DSO. Not adding the test here saves - quite a bit of code. */ - - - /* Finally create the section for the section header string table. */ - shstrtab_scn =3D elf_newscn (ld_state.outelf); - shstrtab_ndx =3D elf_ndxscn (shstrtab_scn); - if (unlikely (shstrtab_ndx =3D=3D SHN_UNDEF)) - error (EXIT_FAILURE, 0, - gettext ("cannot create section header string section: %s"), - elf_errmsg (-1)); - - /* Add the name of the section to the string table. */ - shstrtab_ent =3D ebl_strtabadd (ld_state.shstrtab, ".shstrtab", 10); - if (unlikely (shstrtab_ent =3D=3D NULL)) - error (EXIT_FAILURE, errno, - gettext ("cannot create section header string section")); - - /* Finalize the section header string table. */ - data =3D elf_newdata (shstrtab_scn); - if (data =3D=3D NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create section header string section: %s"), - elf_errmsg (-1)); - ebl_strtabfinalize (ld_state.shstrtab, data); - - /* Now we know the string offsets for all section names. */ - for (cnt =3D 0; cnt < ld_state.nallsections; ++cnt) - if (ld_state.allsections[cnt]->scnidx !=3D 0) - { - Elf_Scn *scn; - - scn =3D elf_getscn (ld_state.outelf, ld_state.allsections[cnt]->scnidx); - - xelf_getshdr (scn, shdr); - assert (shdr !=3D NULL); - - shdr->sh_name =3D ebl_strtaboffset (ld_state.allsections[cnt]->nameent); - - if (xelf_update_shdr (scn, shdr) =3D=3D 0) - assert (0); - } - - /* Add the names for the generated sections to the respective - section headers. */ - if (symtab_ent !=3D NULL) - { - Elf_Scn *scn =3D elf_getscn (ld_state.outelf, ld_state.symscnidx); - - xelf_getshdr (scn, shdr); - /* This cannot fail, we already accessed the header before. */ - assert (shdr !=3D NULL); - - shdr->sh_name =3D ebl_strtaboffset (symtab_ent); - - (void) xelf_update_shdr (scn, shdr); - } - if (xndx_ent !=3D NULL) - { - Elf_Scn *scn =3D elf_getscn (ld_state.outelf, ld_state.xndxscnidx); - - xelf_getshdr (scn, shdr); - /* This cannot fail, we already accessed the header before. */ - assert (shdr !=3D NULL); - - shdr->sh_name =3D ebl_strtaboffset (xndx_ent); - - (void) xelf_update_shdr (scn, shdr); - } - if (strtab_ent !=3D NULL) - { - Elf_Scn *scn =3D elf_getscn (ld_state.outelf, ld_state.strscnidx); - - xelf_getshdr (scn, shdr); - /* This cannot fail, we already accessed the header before. */ - assert (shdr !=3D NULL); - - shdr->sh_name =3D ebl_strtaboffset (strtab_ent); - - (void) xelf_update_shdr (scn, shdr); - } - - /* And the section header table section itself. */ - xelf_getshdr (shstrtab_scn, shdr); - if (shdr =3D=3D NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create section header string section: %s"), - elf_errmsg (-1)); - - shdr->sh_name =3D ebl_strtaboffset (shstrtab_ent); - shdr->sh_type =3D SHT_STRTAB; - - if (unlikely (xelf_update_shdr (shstrtab_scn, shdr) =3D=3D 0)) - error (EXIT_FAILURE, 0, - gettext ("cannot create section header string section: %s"), - elf_errmsg (-1)); - - - /* Add the correct section header info to the section group sections. */ - groups =3D ld_state.groups; - while (groups !=3D NULL) - { - Elf_Scn *scn =3D elf_getscn (ld_state.outelf, groups->outscnidx); - xelf_getshdr (scn, shdr); - assert (shdr !=3D NULL); - - shdr->sh_name =3D ebl_strtaboffset (groups->nameent); - shdr->sh_type =3D SHT_GROUP; - shdr->sh_flags =3D 0; - shdr->sh_link =3D ld_state.symscnidx; - shdr->sh_entsize =3D sizeof (Elf32_Word); - - /* Determine the index for the signature symbol. */ - Elf32_Word si - =3D groups->symbol->file->symindirect[groups->symbol->symidx]; - if (si =3D=3D 0) - { - assert (groups->symbol->file->symref[groups->symbol->symidx] - !=3D NULL); - si =3D groups->symbol->file->symref[groups->symbol->symidx]->outsymidx; - assert (si !=3D 0); - } - shdr->sh_info =3D ld_state.dblindirect[si]; - - (void) xelf_update_shdr (scn, shdr); - - struct scngroup *oldp =3D groups; - groups =3D groups->next; - free (oldp); - } - - - if (ld_state.file_type !=3D relocatable_file_type) - { - /* Every executable needs a program header. The number of entries - varies. One exists for each segment. Each SHT_NOTE section gets - one, too. For dynamically linked executables we have to create - one for the program header, the interpreter, and the dynamic - section. First count the number of segments. - - XXX Determine whether the segment is non-empty. */ - size_t nphdr =3D 0; - - /* We always add a PT_GNU_stack entry. */ - ++nphdr; - - struct output_segment *segment =3D ld_state.output_segments; - while (segment !=3D NULL) - { - ++nphdr; - segment =3D segment->next; - } - - /* Add the number of SHT_NOTE sections. We counted them earlier. */ - nphdr +=3D ld_state.nnotesections; - - /* If we create a DSO or the file is linked against DSOs we have - at least one more entry: DYNAMIC. If an interpreter is - specified we add PHDR and INTERP, too. */ - if (dynamically_linked_p ()) - { - ++nphdr; - - if (ld_state.interp !=3D NULL || ld_state.file_type !=3D dso_file_type) - nphdr +=3D 2; - } - - /* If we need a TLS segment we need an entry for that. */ - if (ld_state.need_tls) - ++nphdr; - - /* Create the program header structure. */ - XElf_Phdr_vardef (phdr); - if (xelf_newphdr (ld_state.outelf, nphdr) =3D=3D 0) - error (EXIT_FAILURE, 0, gettext ("cannot create program header: %s"), - elf_errmsg (-1)); - - - /* Determine the section sizes and offsets. We have to do this - to be able to determine the memory layout (which normally - differs from the file layout). */ - if (elf_update (ld_state.outelf, ELF_C_NULL) =3D=3D -1) - error (EXIT_FAILURE, 0, gettext ("while determining file layout: %s"), - elf_errmsg (-1)); - - - /* Now determine the memory addresses of all the sections and - segments. */ - Elf32_Word nsec =3D 0; - Elf_Scn *scn =3D elf_getscn (ld_state.outelf, - ld_state.allsections[nsec]->scnidx); - xelf_getshdr (scn, shdr); - assert (shdr !=3D NULL); - - /* The address we start with is the offset of the first (not - zeroth) section. */ - XElf_Addr addr =3D shdr->sh_offset; - XElf_Addr tls_offset =3D 0; - XElf_Addr tls_start =3D ~((XElf_Addr) 0); - XElf_Addr tls_end =3D 0; - XElf_Off tls_filesize =3D 0; - XElf_Addr tls_align =3D 0; - - /* The index of the first loadable segment. */ - nphdr =3D 0; - if (dynamically_linked_p ()) - { - ++nphdr; - if (ld_state.interp !=3D NULL - || ld_state.file_type !=3D dso_file_type) - nphdr +=3D 2; - } - - segment =3D ld_state.output_segments; - while (segment !=3D NULL) - { - struct output_rule *orule; - bool first_section =3D true; - XElf_Off nobits_size =3D 0; - XElf_Off memsize =3D 0; - - /* The minimum alignment is a page size. */ - segment->align =3D ld_state.pagesize; - - for (orule =3D segment->output_rules; orule !=3D NULL; - orule =3D orule->next) - if (orule->tag =3D=3D output_section) - { - /* See whether this output rule corresponds to the next - section. Yes, this is a pointer comparison. */ - if (ld_state.allsections[nsec]->name - !=3D orule->val.section.name) - /* No, ignore this output rule. */ - continue; - - /* We assign addresses only in segments which are actually - loaded. */ - if (segment->mode !=3D 0) - { - /* Adjust the offset of the input sections. */ - struct scninfo *isect; - struct scninfo *first; - - isect =3D first =3D ld_state.allsections[nsec]->last; - if (isect !=3D NULL) - do - isect->offset +=3D addr; - while ((isect =3D isect->next) !=3D first); - - /* Set the address of current section. */ - shdr->sh_addr =3D addr; - - /* Write the result back. */ - (void) xelf_update_shdr (scn, shdr); - - /* Remember the address. */ - ld_state.allsections[nsec]->addr =3D addr; - - /* Handle TLS sections. */ - if (unlikely (shdr->sh_flags & SHF_TLS)) - { - if (tls_start > addr) - { - tls_start =3D addr; - tls_offset =3D shdr->sh_offset; - } - if (tls_end < addr + shdr->sh_size) - tls_end =3D addr + shdr->sh_size; - if (shdr->sh_type !=3D SHT_NOBITS) - tls_filesize +=3D shdr->sh_size; - if (shdr->sh_addralign > tls_align) - tls_align =3D shdr->sh_addralign; - } - } - - if (first_section) - { - /* The first segment starts at offset zero. */ - if (segment =3D=3D ld_state.output_segments) - { - segment->offset =3D 0; - segment->addr =3D addr - shdr->sh_offset; - } - else - { - segment->offset =3D shdr->sh_offset; - segment->addr =3D addr; - } - - /* Determine the maximum alignment requirement. */ - segment->align =3D MAX (segment->align, shdr->sh_addralign); - - first_section =3D false; - } - - /* NOBITS TLS sections are not laid out in address space - along with the other sections. */ - if (shdr->sh_type !=3D SHT_NOBITS - || (shdr->sh_flags & SHF_TLS) =3D=3D 0) - { - memsize =3D (shdr->sh_offset - segment->offset - + shdr->sh_size); - if (nobits_size !=3D 0 && shdr->sh_type !=3D SHT_NOTE) - error (EXIT_FAILURE, 0, gettext ("\ -internal error: non-nobits section follows nobits section")); - if (shdr->sh_type =3D=3D SHT_NOBITS) - nobits_size +=3D shdr->sh_size; - } - - /* Determine the new address which is computed using - the difference of the offsets on the sections. Note - that this assumes that the sections following each - other in the section header table are also - consecutive in the file. This is true here because - libelf constructs files this way. */ - XElf_Off oldoff =3D shdr->sh_offset; - - if (++nsec >=3D ld_state.nallsections) - break; - - scn =3D elf_getscn (ld_state.outelf, - ld_state.allsections[nsec]->scnidx); - xelf_getshdr (scn, shdr); - assert (shdr !=3D NULL); - - /* This is the new address resulting from the offsets - in the file. */ - assert (oldoff <=3D shdr->sh_offset); - addr +=3D shdr->sh_offset - oldoff; - } - else - { - assert (orule->tag =3D=3D output_assignment); - - if (strcmp (orule->val.assignment->variable, ".") =3D=3D 0) - /* This is a change of the address. */ - addr =3D eval_expression (orule->val.assignment->expression, - addr); - else if (orule->val.assignment->sym !=3D NULL) - { - /* This symbol is used. Update the symbol table - entry. */ - XElf_Sym_vardef (sym); - size_t idx; - - /* Note that we do not have to use - xelf_getsymshndx since we only update the - symbol address, not the section - information. */ - idx =3D dblindirect[orule->val.assignment->sym->outsymidx]; - xelf_getsym (symdata, idx, sym); - sym->st_value =3D addr; - (void) xelf_update_sym (symdata, idx, sym); - - idx =3D orule->val.assignment->sym->outdynsymidx; - if (idx !=3D 0) - { - assert (dynsymdata !=3D NULL); - xelf_getsym (dynsymdata, idx, sym); - sym->st_value =3D addr; - (void) xelf_update_sym (dynsymdata, idx, sym); - } - } - } - - /* Store the segment parameter for loadable segments. */ - if (segment->mode !=3D 0) - { - xelf_getphdr_ptr (ld_state.outelf, nphdr, phdr); - - phdr->p_type =3D PT_LOAD; - phdr->p_offset =3D segment->offset; - phdr->p_vaddr =3D segment->addr; - phdr->p_paddr =3D phdr->p_vaddr; - phdr->p_filesz =3D memsize - nobits_size; - phdr->p_memsz =3D memsize; - phdr->p_flags =3D segment->mode; - phdr->p_align =3D segment->align; - - (void) xelf_update_phdr (ld_state.outelf, nphdr, phdr); - ++nphdr; - } - - segment =3D segment->next; - } - - /* Create the other program header entries. */ - xelf_getehdr (ld_state.outelf, ehdr); - assert (ehdr !=3D NULL); - - /* Add the TLS information. */ - if (ld_state.need_tls) - { - xelf_getphdr_ptr (ld_state.outelf, nphdr, phdr); - phdr->p_type =3D PT_TLS; - phdr->p_offset =3D tls_offset; - phdr->p_vaddr =3D tls_start; - phdr->p_paddr =3D tls_start; - phdr->p_filesz =3D tls_filesize; - phdr->p_memsz =3D tls_end - tls_start; - phdr->p_flags =3D PF_R; - phdr->p_align =3D tls_align; - ld_state.tls_tcb =3D tls_end; - ld_state.tls_start =3D tls_start; - - (void) xelf_update_phdr (ld_state.outelf, nphdr, phdr); - ++nphdr; - } - - /* Add the stack information. */ - xelf_getphdr_ptr (ld_state.outelf, nphdr, phdr); - phdr->p_type =3D PT_GNU_STACK; - phdr->p_offset =3D 0; - phdr->p_vaddr =3D 0; - phdr->p_paddr =3D 0; - phdr->p_filesz =3D 0; - phdr->p_memsz =3D 0; - phdr->p_flags =3D (PF_R | PF_W - | (ld_state.execstack =3D=3D execstack_true ? PF_X : 0)); - phdr->p_align =3D xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1); - - (void) xelf_update_phdr (ld_state.outelf, nphdr, phdr); - ++nphdr; - - - /* Adjust the addresses in the address fields of the symbol - records according to the load addresses of the sections. */ - if (ld_state.need_symtab) - for (cnt =3D 1; cnt < nsym; ++cnt) - { - XElf_Sym_vardef (sym); - Elf32_Word shndx; - - xelf_getsymshndx (symdata, xndxdata, cnt, sym, shndx); - assert (sym !=3D NULL); - - if (sym->st_shndx !=3D SHN_XINDEX) - shndx =3D sym->st_shndx; - - if ((shndx > SHN_UNDEF && shndx < SHN_LORESERVE) - || shndx > SHN_HIRESERVE) - { - /* Note we subtract 1 from the section index since ALLSECTIONS - does not store the dummy section with offset zero. */ - sym->st_value +=3D ld_state.allsections[shndx - 1]->addr; - - /* We don't have to use 'xelf_update_symshndx' since the - section number doesn't change. */ - (void) xelf_update_sym (symdata, cnt, sym); - } - } - - if (ld_state.need_dynsym) - for (cnt =3D 1; cnt < nsym_dyn; ++cnt) - { - XElf_Sym_vardef (sym); - - xelf_getsym (dynsymdata, cnt, sym); - assert (sym !=3D NULL); - - if (sym->st_shndx > SHN_UNDEF && sym->st_shndx < SHN_LORESERVE) - { - /* Note we subtract 1 from the section index since ALLSECTIONS - does not store the dummy section with offset zero. */ - sym->st_value +=3D ld_state.allsections[sym->st_shndx - 1]->addr; - - /* We don't have to use 'xelf_update_symshndx' since the - section number doesn't change. */ - (void) xelf_update_sym (dynsymdata, cnt, sym); - } - } - - /* Now is a good time to determine the values of all the symbols - we encountered. */ - // XXX This loop is very inefficient. The hash tab iterator also - // returns all symbols in DSOs. - struct symbol *se; - void *p =3D NULL; - while ((se =3D ld_symbol_tab_iterate (&ld_state.symbol_tab, &p)) != =3D NULL) - if (! se->in_dso) - { - XElf_Sym_vardef (sym); - - addr =3D 0; - - if (se->outdynsymidx !=3D 0) - { - xelf_getsym (dynsymdata, se->outdynsymidx, sym); - assert (sym !=3D NULL); - addr =3D sym->st_value; - } - else if (se->outsymidx !=3D 0) - { - assert (dblindirect[se->outsymidx] !=3D 0); - xelf_getsym (symdata, dblindirect[se->outsymidx], sym); - assert (sym !=3D NULL); - addr =3D sym->st_value; - } - else - abort (); - - se->merge.value =3D addr; - } - - /* Complete the header of the .rel.dyn/.rela.dyn section. Point - to the symbol table. The sh_info field is left zero since - there is no specific section the contained relocations are - for. */ - if (ld_state.reldynscnidx !=3D 0) - { - assert (ld_state.dynsymscnidx !=3D 0); - scn =3D elf_getscn (ld_state.outelf, ld_state.reldynscnidx); - xelf_getshdr (scn, shdr); - assert (shdr !=3D NULL); - - shdr->sh_link =3D ld_state.dynsymscnidx; - - (void) xelf_update_shdr (scn, shdr); - } - - /* Fill in the dynamic segment/section. */ - if (dynamically_linked_p ()) - { - Elf_Scn *outscn; - - int idx =3D 0; - if (ld_state.interp !=3D NULL || ld_state.file_type !=3D dso_file_type) - { - assert (ld_state.interpscnidx !=3D 0); - xelf_getshdr (elf_getscn (ld_state.outelf, - ld_state.interpscnidx), shdr); - assert (shdr !=3D NULL); - - xelf_getphdr_ptr (ld_state.outelf, idx, phdr); - phdr->p_type =3D PT_PHDR; - phdr->p_offset =3D ehdr->e_phoff; - phdr->p_vaddr =3D ld_state.output_segments->addr + phdr->p_offset; - phdr->p_paddr =3D phdr->p_vaddr; - phdr->p_filesz =3D ehdr->e_phnum * ehdr->e_phentsize; - phdr->p_memsz =3D phdr->p_filesz; - phdr->p_flags =3D 0; /* No need to set PF_R or so. */ - phdr->p_align =3D xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1); - - (void) xelf_update_phdr (ld_state.outelf, idx, phdr); - ++idx; - - /* The interpreter string. */ - xelf_getphdr_ptr (ld_state.outelf, idx, phdr); - phdr->p_type =3D PT_INTERP; - phdr->p_offset =3D shdr->sh_offset; - phdr->p_vaddr =3D shdr->sh_addr; - phdr->p_paddr =3D phdr->p_vaddr; - phdr->p_filesz =3D shdr->sh_size; - phdr->p_memsz =3D phdr->p_filesz; - phdr->p_flags =3D 0; /* No need to set PF_R or so. */ - phdr->p_align =3D 1; /* It's a string. */ - - (void) xelf_update_phdr (ld_state.outelf, idx, phdr); - ++idx; - } - - /* The pointer to the dynamic section. We this we need to - get the information for the dynamic section first. */ - assert (ld_state.dynamicscnidx); - outscn =3D elf_getscn (ld_state.outelf, ld_state.dynamicscnidx); - xelf_getshdr (outscn, shdr); - assert (shdr !=3D NULL); - - xelf_getphdr_ptr (ld_state.outelf, idx, phdr); - phdr->p_type =3D PT_DYNAMIC; - phdr->p_offset =3D shdr->sh_offset; - phdr->p_vaddr =3D shdr->sh_addr; - phdr->p_paddr =3D phdr->p_vaddr; - phdr->p_filesz =3D shdr->sh_size; - phdr->p_memsz =3D phdr->p_filesz; - phdr->p_flags =3D 0; /* No need to set PF_R or so. */ - phdr->p_align =3D shdr->sh_addralign; - - (void) xelf_update_phdr (ld_state.outelf, idx, phdr); - - /* Fill in the reference to the .dynstr section. */ - assert (ld_state.dynstrscnidx !=3D 0); - shdr->sh_link =3D ld_state.dynstrscnidx; - (void) xelf_update_shdr (outscn, shdr); - - /* And fill the remaining entries. */ - Elf_Data *dyndata =3D elf_getdata (outscn, NULL); - assert (dyndata !=3D NULL); - - /* Add the DT_NEEDED entries. */ - if (ld_state.ndsofiles > 0) - { - struct usedfiles *runp =3D ld_state.dsofiles->next; - - do - if (runp->used || !runp->as_needed) - { - /* Add the position-dependent flag if necessary. */ - if (runp->lazyload) - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, - DT_POSFLAG_1, DF_P1_LAZYLOAD); - - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, - DT_NEEDED, - ebl_strtaboffset (runp->sonameent)); - } - while ((runp =3D runp->next) !=3D ld_state.dsofiles->next); - } - - /* We can finish the DT_RUNPATH/DT_RPATH entries now. */ - if (ld_state.rxxpath_strent !=3D NULL) - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, - ld_state.rxxpath_tag, - ebl_strtaboffset (ld_state.rxxpath_strent)); - - /* Reference to initialization and finalization functions. */ - // XXX This code depends on symbol table being relocated. - if (ld_state.init_symbol !=3D NULL) - { - XElf_Sym_vardef (sym); - - if (ld_state.need_symtab) - xelf_getsym (symdata, - dblindirect[ld_state.init_symbol->outsymidx], - sym); - else - xelf_getsym (dynsymdata, ld_state.init_symbol->outdynsymidx, - sym); - assert (sym !=3D NULL); - - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, - DT_INIT, sym->st_value); - } - if (ld_state.fini_symbol !=3D NULL) - { - XElf_Sym_vardef (sym); - - if (ld_state.need_symtab) - xelf_getsym (symdata, - dblindirect[ld_state.fini_symbol->outsymidx], - sym); - else - xelf_getsym (dynsymdata, ld_state.fini_symbol->outdynsymidx, - sym); - assert (sym !=3D NULL); - - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, - DT_FINI, sym->st_value); - } - // XXX Support init,fini,preinit arrays - - /* The hash table which comes with dynamic symbol table. */ - xelf_getshdr (elf_getscn (ld_state.outelf, ld_state.hashscnidx), - shdr); - assert (shdr !=3D NULL); - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_HASH, - shdr->sh_addr); - - /* Reference to the symbol table section. */ - assert (ld_state.dynsymscnidx !=3D 0); - xelf_getshdr (elf_getscn (ld_state.outelf, ld_state.dynsymscnidx), - shdr); - assert (shdr !=3D NULL); - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_SYMTAB, - shdr->sh_addr); - - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_SYMENT, - xelf_fsize (ld_state.outelf, ELF_T_SYM, 1)); - - /* And the string table which comes with it. */ - xelf_getshdr (elf_getscn (ld_state.outelf, ld_state.dynstrscnidx), - shdr); - assert (shdr !=3D NULL); - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_STRTAB, - shdr->sh_addr); - - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_STRSZ, - shdr->sh_size); - - /* Add the entries related to the .plt. */ - if (ld_state.nplt > 0) - { - // XXX Make this work if there is no PLT - xelf_getshdr (elf_getscn (ld_state.outelf, - ld_state.gotpltscnidx), shdr); - assert (shdr !=3D NULL); - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, - // XXX This should probably be machine - // dependent. - DT_PLTGOT, shdr->sh_addr); - - xelf_getshdr (elf_getscn (ld_state.outelf, - ld_state.pltrelscnidx), shdr); - assert (shdr !=3D NULL); - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, - DT_PLTRELSZ, shdr->sh_size); - - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, - DT_JMPREL, shdr->sh_addr); - - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, - DT_PLTREL, REL_TYPE (statep)); - } - - if (ld_state.relsize_total > 0) - { - int rel =3D REL_TYPE (statep); - xelf_getshdr (elf_getscn (ld_state.outelf, - ld_state.reldynscnidx), shdr); - assert (shdr !=3D NULL); - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, - rel, shdr->sh_addr); - - /* Trick ahead. Use arithmetic to get the right tag. - We check the validity of this assumption in the asserts. */ - assert (DT_RELASZ - DT_RELA =3D=3D 1); - assert (DT_RELSZ - DT_REL =3D=3D 1); - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, - rel + 1, shdr->sh_size); - - /* Similar for the entry size tag. */ - assert (DT_RELAENT - DT_RELA =3D=3D 2); - assert (DT_RELENT - DT_REL =3D=3D 2); - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, - rel + 2, - rel =3D=3D DT_REL - ? xelf_fsize (ld_state.outelf, ELF_T_REL, 1) - : xelf_fsize (ld_state.outelf, ELF_T_RELA, - 1)); - } - - if (ld_state.verneedscnidx !=3D 0) - { - xelf_getshdr (elf_getscn (ld_state.outelf, - ld_state.verneedscnidx), shdr); - assert (shdr !=3D NULL); - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, - DT_VERNEED, shdr->sh_addr); - - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, - DT_VERNEEDNUM, ld_state.nverdeffile); - } - - if (ld_state.versymscnidx !=3D 0) - { - xelf_getshdr (elf_getscn (ld_state.outelf, - ld_state.versymscnidx), shdr); - assert (shdr !=3D NULL); - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, - DT_VERSYM, shdr->sh_addr); - } - - /* We always create the DT_DEBUG entry. */ - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_DEBUG, 0); - assert (ld_state.ndynamic_filled < ld_state.ndynamic); - - /* Add the flag words if necessary. */ - if (ld_state.dt_flags !=3D 0) - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_FLAGS, - ld_state.dt_flags); - - /* Create entry for the DT_FLAGS_1 flag. */ - if (ld_state.dt_flags_1 !=3D 0) - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, - DT_FLAGS_1, ld_state.dt_flags_1); - - /* Create entry for the DT_FEATURE_1 flag. */ - if (ld_state.dt_feature_1 !=3D 0) - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, - DT_FEATURE_1, ld_state.dt_feature_1); - - assert (ld_state.ndynamic_filled <=3D ld_state.ndynamic); - } - } - - - // XXX The following code isn't nice. We use two different - // mechanisms to handle relocations, one for relocatable files, one - // for executables and DSOs. Maybe this is the best method but also - // maybe it can be somewhat unified. - - /* Now that we created the symbol table we can add the reference to - it in the sh_link field of the section headers of the relocation - sections. */ - while (rellist !=3D NULL) - { - assert (ld_state.file_type =3D=3D relocatable_file_type); - Elf_Scn *outscn; - - outscn =3D elf_getscn (ld_state.outelf, rellist->scnidx); - xelf_getshdr (outscn, shdr); - /* This must not fail since we did it before. */ - assert (shdr !=3D NULL); - - /* Remember the symbol table which belongs to the relocation section= . */ - shdr->sh_link =3D ld_state.symscnidx; - - /* And the reference to the section which is relocated by this - relocation section. We use the info from the first input - section but all records should have the same information. */ - shdr->sh_info =3D - rellist->scninfo->fileinfo->scninfo[SCNINFO_SHDR (rellist->scninfo->shdr)= .sh_info].outscnndx; - - - /* Perform the actual relocations. We only have to adjust - offsets and symbol indices. */ - RELOCATE_SECTION (statep, outscn, rellist->scninfo, dblindirect); - - /* Store the changes. */ - (void) xelf_update_shdr (outscn, shdr); - - /* Up to the next relocation section. */ - rellist =3D rellist->next; - } - - if (ld_state.rellist !=3D NULL) - { - assert (ld_state.file_type !=3D relocatable_file_type); - /* Create the relocations for the output file. */ - CREATE_RELOCATIONS (statep, dblindirect); - } - - - /* We need the ELF header once more. */ - xelf_getehdr (ld_state.outelf, ehdr); - assert (ehdr !=3D NULL); - - /* Set the section header string table index. */ - if (likely (shstrtab_ndx < SHN_HIRESERVE) - && likely (shstrtab_ndx !=3D SHN_XINDEX)) - ehdr->e_shstrndx =3D shstrtab_ndx; - else - { - /* We have to put the section index in the sh_link field of the - zeroth section header. */ - Elf_Scn *scn =3D elf_getscn (ld_state.outelf, 0); - - xelf_getshdr (scn, shdr); - if (unlikely (shdr =3D=3D NULL)) - error (EXIT_FAILURE, 0, - gettext ("cannot get header of 0th section: %s"), - elf_errmsg (-1)); - - shdr->sh_link =3D shstrtab_ndx; - - (void) xelf_update_shdr (scn, shdr); - - ehdr->e_shstrndx =3D SHN_XINDEX; - } - - if (ld_state.file_type !=3D relocatable_file_type) - /* DSOs and executables have to define the entry point symbol. */ - ehdr->e_entry =3D find_entry_point (); - - if (unlikely (xelf_update_ehdr (ld_state.outelf, ehdr) =3D=3D 0)) - error (EXIT_FAILURE, 0, - gettext ("cannot update ELF header: %s"), - elf_errmsg (-1)); - - - /* Free the data which we don't need anymore. */ - free (ld_state.dblindirect); - - - /* Finalize the .plt section and what else belongs to it. */ - FINALIZE_PLT (statep, nsym, nsym_local, ndxtosym); - - - /* Finally, if we have to compute the build ID. */ - if (ld_state.build_id !=3D NULL) - compute_build_id (); - - - /* We don't need the map from the symbol table index to the symbol - structure anymore. */ - free (ndxtosym); - - return 0; -} - - -/* This is a function which must be specified in all backends. */ -static void -ld_generic_relocate_section (struct ld_state *statep, Elf_Scn *outscn, - struct scninfo *firstp, - const Elf32_Word *dblindirect) -{ - error (EXIT_FAILURE, 0, gettext ("\ -linker backend didn't specify function to relocate section")); - /* NOTREACHED */ -} - - -/* Finalize the output file. */ -static int -ld_generic_finalize (struct ld_state *statep) -{ - /* Write out the ELF file data. */ - if (elf_update (ld_state.outelf, ELF_C_WRITE) =3D=3D -1) - error (EXIT_FAILURE, 0, gettext ("while writing output file: %s"), - elf_errmsg (-1)); - - /* Free the resources. */ - if (elf_end (ld_state.outelf) !=3D 0) - error (EXIT_FAILURE, 0, gettext ("while finishing output file: %s"), - elf_errmsg (-1)); - - /* Get the file status of the temporary file. */ - struct stat temp_st; - if (fstat (ld_state.outfd, &temp_st) !=3D 0) - error (EXIT_FAILURE, errno, gettext ("cannot stat output file")); - - /* Now it's time to rename the file. Remove an old existing file - first. */ - if (rename (ld_state.tempfname, ld_state.outfname) !=3D 0) - /* Something went wrong. */ - error (EXIT_FAILURE, errno, gettext ("cannot rename output file")); - - /* Make sure the output file is really the one we created. */ - struct stat new_st; - if (stat (ld_state.outfname, &new_st) !=3D 0 - || new_st.st_ino !=3D temp_st.st_ino - || new_st.st_dev !=3D temp_st.st_dev) - { - /* Wow, somebody overwrote the output file, probably some intruder. = */ - unlink (ld_state.outfname); - error (EXIT_FAILURE, 0, gettext ("\ -WARNING: temporary output file overwritten before linking finished")); - } - - /* Close the file descriptor. */ - (void) close (ld_state.outfd); - - /* Signal the cleanup handler that the file is correctly created. */ - ld_state.tempfname =3D NULL; - - return 0; -} - - -static bool -ld_generic_special_section_number_p (struct ld_state *statep, size_t numbe= r) -{ - /* There are no special section numbers in the gABI. */ - return false; -} - - -static bool -ld_generic_section_type_p (struct ld_state *statep, GElf_Word type) -{ - if (type < SHT_NUM - /* XXX Enable the following two when implemented. */ - // || type =3D=3D SHT_GNU_LIBLIST - // || type =3D=3D SHT_CHECKSUM - /* XXX Eventually include SHT_SUNW_move, SHT_SUNW_COMDAT, and - SHT_SUNW_syminfo. */ - || (type >=3D SHT_GNU_verdef && type <=3D SHT_GNU_versym)) - return true; - - return false; -} - - -static XElf_Xword -ld_generic_dynamic_section_flags (struct ld_state *statep) -{ - /* By default the .dynamic section is writable (and is of course - loaded). Few architecture differ from this. */ - return SHF_ALLOC | SHF_WRITE; -} - - -static void -ld_generic_initialize_plt (struct ld_state *statep, Elf_Scn *scn) -{ - /* This cannot be implemented generally. There should have been a - machine dependent implementation and we should never have arrived - here. */ - error (EXIT_FAILURE, 0, gettext ("no machine specific '%s' implementatio= n"), - "initialize_plt"); -} - - -static void -ld_generic_initialize_pltrel (struct ld_state *statep, Elf_Scn *scn) -{ - /* This cannot be implemented generally. There should have been a - machine dependent implementation and we should never have arrived - here. */ - error (EXIT_FAILURE, 0, gettext ("no machine specific '%s' implementatio= n"), - "initialize_pltrel"); -} - - -static void -ld_generic_initialize_got (struct ld_state *statep, Elf_Scn *scn) -{ - /* This cannot be implemented generally. There should have been a - machine dependent implementation and we should never have arrived - here. */ - error (EXIT_FAILURE, 0, gettext ("no machine specific '%s' implementatio= n"), - "initialize_got"); -} - - -static void -ld_generic_initialize_gotplt (struct ld_state *statep, Elf_Scn *scn) -{ - /* This cannot be implemented generally. There should have been a - machine dependent implementation and we should never have arrived - here. */ - error (EXIT_FAILURE, 0, gettext ("no machine specific '%s' implementatio= n"), - "initialize_gotplt"); -} - - -static void -ld_generic_finalize_plt (struct ld_state *statep, size_t nsym, size_t nsym= _dyn, - struct symbol **ndxtosymp) -{ - /* By default we assume that nothing has to be done. */ -} - - -static int -ld_generic_rel_type (struct ld_state *statep) -{ - /* This cannot be implemented generally. There should have been a - machine dependent implementation and we should never have arrived - here. */ - error (EXIT_FAILURE, 0, gettext ("no machine specific '%s' implementatio= n"), - "rel_type"); - /* Just to keep the compiler calm. */ - return 0; -} - - -static void -ld_generic_count_relocations (struct ld_state *statep, struct scninfo *scn= info) -{ - /* This cannot be implemented generally. There should have been a - machine dependent implementation and we should never have arrived - here. */ - error (EXIT_FAILURE, 0, gettext ("no machine specific '%s' implementatio= n"), - "count_relocations"); -} - - -static void -ld_generic_create_relocations (struct ld_state *statep, - const Elf32_Word *dblindirect) -{ - /* This cannot be implemented generally. There should have been a - machine dependent implementation and we should never have arrived - here. */ - error (EXIT_FAILURE, 0, gettext ("no machine specific '%s' implementatio= n"), - "create_relocations"); -} diff --git a/src/ldlex.l b/src/ldlex.l deleted file mode 100644 index 835c2dc..0000000 --- a/src/ldlex.l +++ /dev/null @@ -1,353 +0,0 @@ -%{ -/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2008 Red Hat, Inc. - This file is part of elfutils. - Written by Ulrich Drepper , 2001. - - This file 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. - - elfutils 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, see . = */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "ldscript.h" - -/* We sure use no threads to read the stream, so use the _unlocked - variants of the functions. */ -#undef getc -#define getc(s) getc_unlocked (s) -#undef ferror -#define ferror(s) ferror_unlocked (s) -#undef fread -#define fread(b, m, n, s) fread_unlocked (b, m, n, s) -#undef fwrite -#define fwrite(b, m, n, s) fwrite_unlocked (b, m, n, s) - -/* ECHO must be redefined since the default implementation ignores - the return value of fwrite_unlocked. */ -#define ECHO do { size_t n__ __attribute__ ((unused)) \ - =3D fwrite (yytext, yyleng, 1, yyout); } while (0) - -/* Defined in ld.c. */ -extern int ld_scan_version_script; - -#define MAX_PREPDEPTH 20 -static enum prepstate -{ - prep_normal, - skip_if, - skip_to_endif -} prepstate[MAX_PREPDEPTH]; -static int prepdepth; - -static void eat_comment (void); -static void eat_to_eol (bool empty); -static int attrib_convert (int c); -static void push_state (enum prepstate); -static int pop_state (void); -static int handle_ifdef (void); -static void invalid_char (int ch); -%} - -ID [a-zA-Z0-9_.*?][a-zA-Z0-9_.*?-]* -FILENAMECHAR1 [a-zA-Z0-9_/.\\~] -FILENAMECHAR [^][{}[:space:]():;]+ -HEX 0[xX][0-9a-fA-F]+[kKmM]? -OCT 0[0-7]*[kKmM]? -DEC [0-9]+[kKmM]? -WHITE [[:space:]]+ - -%option yylineno -%option never-interactive -%option noyywrap - -%x IGNORE - -%% - if (unlikely (ld_scan_version_script)) - { - ld_scan_version_script =3D -1; - return kVERSION_SCRIPT; - } - -^"#"ifdef/[[:space:]] { BEGIN (handle_ifdef ()); } -^"#"else/[[:space:]\n] { eat_to_eol (true); - push_state (skip_to_endif); - BEGIN (IGNORE); } -^"#"elifdef/[[:space:]] { eat_to_eol (false); - push_state (skip_to_endif); - BEGIN (IGNORE); } -^"#"endif/[[:space:]\n] { eat_to_eol (true) ; } - -^"#"ifdef/[[:space:]\n] { eat_to_eol (false); - push_state (skip_to_endif); } -^"#"else/[[:space:]\n] { eat_to_eol (true); - assert (prepdepth > 0); - if (prepstate[prepdepth - 1] =3D=3D skip_if) - { - /* Back to normal processing. */ - assert (prepdepth =3D=3D 1); - BEGIN (pop_state ()); - } - } -^"#"elifdef/[[:space:]] { assert (prepdepth > 0); - if (prepstate[prepdepth - 1] =3D=3D skip_if) - { - /* Maybe this symbol is defined. */ - pop_state (); - BEGIN (handle_ifdef ()); - } - } -^"#"endif/[[:space:]\n] { eat_to_eol (true); - BEGIN (pop_state ()); } -.|\n { /* nothing */ } - - -"/*" { eat_comment (); } - -ALIGN { return kALIGN; } -AS_NEEDED { return kAS_NEEDED; } -ENTRY { return kENTRY; } -EXCLUDE_FILE { return kEXCLUDE_FILE; } -"global:" { return kGLOBAL; } -GROUP { return kGROUP; } -INPUT { return kINPUT; } -INTERP { return kINTERP; } -KEEP { return kKEEP; } -"local:" { return kLOCAL; } -OUTPUT_FORMAT { return kOUTPUT_FORMAT; } -PAGESIZE { return kPAGESIZE; } -PROVIDE { return kPROVIDE; } -SEARCH_DIR { return kSEARCH_DIR; } -SEGMENT { return kSEGMENT; } -SIZEOF_HEADERS { return kSIZEOF_HEADERS; } -SORT { return kSORT; } -VERSION { return kVERSION; } - -"["([RWX]){0,3}"]" { unsigned int cnt =3D 1 ; - ldlval.num =3D 0; - while (cnt < yyleng - 1) - ldlval.num |=3D attrib_convert (yytext[cnt++]); - return kMODE; } - -"{" { return '{'; } -"}" { return '}'; } -"(" { return '('; } -")" { return ')'; } -":" { return ':'; } -";" { return ';'; } -"=3D" { return '=3D'; } -"+" { ldlval.op =3D exp_plus; return kADD_OP; } -"-" { ldlval.op =3D exp_minus; return kADD_OP; } -"*" { return '*'; } -"/" { ldlval.op =3D exp_div; return kMUL_OP; } -"%" { ldlval.op =3D exp_mod; return kMUL_OP; } -"&" { return '&'; } -"|" { return '|'; } - -"," { return ','; } - -{HEX}|{OCT}|{DEC} { char *endp; - ldlval.num =3D strtoumax (yytext, &endp, 0); - if (*endp !=3D '\0') - { - if (tolower (*endp) =3D=3D 'k') - ldlval.num *=3D 1024; - else - { - assert (tolower (*endp) =3D=3D 'm'); - ldlval.num *=3D 1024 * 1024; - } - } - return kNUM; } - -{ID} { ldlval.str =3D obstack_strndup (&ld_state.smem, - yytext, yyleng); - return kID; } - -{FILENAMECHAR1}{FILENAMECHAR} { ldlval.str =3D obstack_strndup (&ld_state.= smem, - yytext, yyleng); - return kFILENAME; } - -{WHITE} { /* IGNORE */ } - -. { invalid_char (*yytext); } - -%% - -static void -eat_comment (void) -{ - while (1) - { - int c =3D input (); - - while (c !=3D '*' && c !=3D EOF) - c =3D input (); - - if (c =3D=3D '*') - { - c =3D input (); - while (c =3D=3D '*') - c =3D input (); - if (c =3D=3D '/') - break; - } - - if (c =3D=3D EOF) - { - /* XXX Use the setjmp buffer and signal EOF in comment */ - error (0, 0, gettext ("EOF in comment")); - break; - } - } -} - - -static void -eat_to_eol (bool empty) -{ - bool warned =3D false; - - while (1) - { - int c =3D input (); - - if (c =3D=3D EOF) - break; - if (c =3D=3D '\n') - { - ++yylineno; - break; - } - - if (empty && ! isspace (c) && ! warned) - { - error (0, 0, gettext ("%d: garbage at end of line"), yylineno); - warned =3D true; - } - } -} - - -static int -attrib_convert (int c) -{ - if (c =3D=3D 'X') - return PF_X; - if (c =3D=3D 'W') - return PF_W; - assert (c =3D=3D 'R'); - return PF_R; -} - - -static void -push_state (enum prepstate state) -{ - if (prepdepth >=3D MAX_PREPDEPTH) - error (EXIT_FAILURE, 0, gettext ("%d: conditionals nested too deep"), - yylineno); - - prepstate[prepdepth++] =3D state; -} - - -static int -pop_state (void) -{ - if (prepdepth =3D=3D 0) - error (0, 0, gettext ("%d: unexpected #endif"), yylineno); - else - --prepdepth; - - return prepdepth =3D=3D 0 ? INITIAL : IGNORE; -} - - -static int -handle_ifdef (void) -{ - char idbuf[50]; - char *id =3D idbuf; - size_t idlen =3D 0; - size_t idmax =3D sizeof (idbuf); - bool ignore_ws =3D true; - bool defined =3D false; - int result; - - while (1) - { - int c =3D input (); - - if (isspace (c) && ignore_ws) - continue; - - if (c !=3D '_' && (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') - && (idlen =3D=3D 0 || c < '0' || c > '9')) - { - unput (c); - break; - } - - if (idlen =3D=3D idmax) - { - char *newp =3D (char *) alloca (idmax *=3D 2); - id =3D memcpy (newp, id, idlen); - } - - id[idlen++] =3D c; - ignore_ws =3D false; - } - - /* XXX Compare in a better way. */ - if (idlen =3D=3D 6 && strncmp (id, "SHARED", 6) =3D=3D 0) - defined =3D ld_state.file_type =3D=3D dso_file_type; - - if (defined) - result =3D INITIAL; - else - { - push_state (skip_if); - result =3D IGNORE; - } - - return result; -} - - -static void -invalid_char (int ch) -{ - error (0, 0, (isascii (ch) - ? gettext ("invalid character '%c' at line %d; ignored") - : gettext ("invalid character '\\%o' at line %d; ignored")), - ch, yylineno); -} - - -// Local Variables: -// mode: C -// End: diff --git a/src/ldscript.y b/src/ldscript.y deleted file mode 100644 index 3502ce1..0000000 --- a/src/ldscript.y +++ /dev/null @@ -1,803 +0,0 @@ -%{ -/* Parser for linker scripts. - Copyright (C) 2001-2011 Red Hat, Inc. - This file is part of elfutils. - Written by Ulrich Drepper , 2001. - - This file 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. - - elfutils 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, see . = */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* The error handler. */ -static void yyerror (const char *s); - -/* Some helper functions we need to construct the data structures - describing information from the file. */ -static struct expression *new_expr (int tag); -static struct input_section_name *new_input_section_name (const char *name, - bool sort_flag); -static struct input_rule *new_input_rule (int tag); -static struct output_rule *new_output_rule (int tag); -static struct assignment *new_assignment (const char *variable, - struct expression *expression, - bool provide_flag); -static void new_segment (int mode, struct output_rule *output_rule); -static struct filename_list *new_filename_listelem (const char *string); -static void add_inputfiles (struct filename_list *fnames); -static struct id_list *new_id_listelem (const char *str); - static struct filename_list *mark_as_needed (struct filename_list *listp); -static struct version *new_version (struct id_list *local, - struct id_list *global); -static struct version *merge_versions (struct version *one, - struct version *two); -static void add_versions (struct version *versions); - -extern int yylex (void); -%} - -%union { - uintmax_t num; - enum expression_tag op; - char *str; - struct expression *expr; - struct input_section_name *sectionname; - struct filemask_section_name *filemask_section_name; - struct input_rule *input_rule; - struct output_rule *output_rule; - struct assignment *assignment; - struct filename_list *filename_list; - struct version *version; - struct id_list *id_list; -} - -%token kADD_OP -%token kALIGN -%token kAS_NEEDED -%token kENTRY -%token kEXCLUDE_FILE -%token kFILENAME -%token kGLOBAL -%token kGROUP -%token kID -%token kINPUT -%token kINTERP -%token kKEEP -%token kLOCAL -%token kMODE -%token kMUL_OP -%token kNUM -%token kOUTPUT_FORMAT -%token kPAGESIZE -%token kPROVIDE -%token kSEARCH_DIR -%token kSEGMENT -%token kSIZEOF_HEADERS -%token kSORT -%token kVERSION -%token kVERSION_SCRIPT - -%left '|' -%left '&' -%left ADD_OP -%left MUL_OP '*' - -%type kADD_OP -%type kMUL_OP -%type filename_id -%type filename_id_star -%type exclude_opt -%type expr -%type sort_opt_name -%type sectionname -%type inputsection -%type inputsections -%type outputsection -%type outputsections -%type assignment -%type filename_id_list -%type filename_id_listelem -%type versionlist -%type version -%type version_stmt_list -%type version_stmt -%type filename_id_star_list - -%expect 16 - -%% - -script_or_version: - file - | kVERSION_SCRIPT versionlist - { add_versions ($2); } - ; - -file: file content - | content - ; - -content: kENTRY '(' kID ')' ';' - { - if (likely (ld_state.entry =3D=3D NULL)) - ld_state.entry =3D $3; - } - | kSEARCH_DIR '(' filename_id ')' ';' - { - ld_new_searchdir ($3); - } - | kPAGESIZE '(' kNUM ')' ';' - { - if (likely (ld_state.pagesize =3D=3D 0)) - ld_state.pagesize =3D $3; - } - | kINTERP '(' filename_id ')' ';' - { - if (likely (ld_state.interp =3D=3D NULL) - && ld_state.file_type !=3D dso_file_type) - ld_state.interp =3D $3; - } - | kSEGMENT kMODE '{' outputsections '}' - { - new_segment ($2, $4); - } - | kSEGMENT error '{' outputsections '}' - { - fputs_unlocked (gettext ("mode for segment invalid\n"), - stderr); - new_segment (0, $4); - } - | kGROUP '(' filename_id_list ')' - { - /* First little optimization. If there is only one - file in the group don't do anything. */ - if ($3 !=3D $3->next) - { - $3->next->group_start =3D 1; - $3->group_end =3D 1; - } - add_inputfiles ($3); - } - | kINPUT '(' filename_id_list ')' - { add_inputfiles ($3); } - | kAS_NEEDED '(' filename_id_list ')' - { add_inputfiles (mark_as_needed ($3)); } - | kVERSION '{' versionlist '}' - { add_versions ($3); } - | kOUTPUT_FORMAT '(' filename_id ')' - { /* XXX TODO */ } - ; - -outputsections: outputsections outputsection - { - $2->next =3D $1->next; - $$ =3D $1->next =3D $2; - } - | outputsection - { $$ =3D $1; } - ; - -outputsection: assignment ';' - { - $$ =3D new_output_rule (output_assignment); - $$->val.assignment =3D $1; - } - | kID '{' inputsections '}' - { - $$ =3D new_output_rule (output_section); - $$->val.section.name =3D $1; - $$->val.section.input =3D $3->next; - if (ld_state.strip =3D=3D strip_debug - && ebl_debugscn_p (ld_state.ebl, $1)) - $$->val.section.ignored =3D true; - else - $$->val.section.ignored =3D false; - $3->next =3D NULL; - } - | kID ';' - { - /* This is a short cut for "ID { *(ID) }". */ - $$ =3D new_output_rule (output_section); - $$->val.section.name =3D $1; - $$->val.section.input =3D new_input_rule (input_section); - $$->val.section.input->next =3D NULL; - $$->val.section.input->val.section =3D - (struct filemask_section_name *) - obstack_alloc (&ld_state.smem, - sizeof (struct filemask_section_name)); - $$->val.section.input->val.section->filemask =3D NULL; - $$->val.section.input->val.section->excludemask =3D NULL; - $$->val.section.input->val.section->section_name =3D - new_input_section_name ($1, false); - $$->val.section.input->val.section->keep_flag =3D false; - if (ld_state.strip =3D=3D strip_debug - && ebl_debugscn_p (ld_state.ebl, $1)) - $$->val.section.ignored =3D true; - else - $$->val.section.ignored =3D false; - } - ; - -assignment: kID '=3D' expr - { $$ =3D new_assignment ($1, $3, false); } - | kPROVIDE '(' kID '=3D' expr ')' - { $$ =3D new_assignment ($3, $5, true); } - ; - -inputsections: inputsections inputsection - { - $2->next =3D $1->next; - $$ =3D $1->next =3D $2; - } - | inputsection - { $$ =3D $1; } - ; - -inputsection: sectionname - { - $$ =3D new_input_rule (input_section); - $$->val.section =3D $1; - } - | kKEEP '(' sectionname ')' - { - $3->keep_flag =3D true; - - $$ =3D new_input_rule (input_section); - $$->val.section =3D $3; - } - | assignment ';' - { - $$ =3D new_input_rule (input_assignment); - $$->val.assignment =3D $1; - } - ; - -sectionname: filename_id_star '(' exclude_opt sort_opt_name ')' - { - $$ =3D (struct filemask_section_name *) - obstack_alloc (&ld_state.smem, sizeof (*$$)); - $$->filemask =3D $1; - $$->excludemask =3D $3; - $$->section_name =3D $4; - $$->keep_flag =3D false; - } - ; - -sort_opt_name: kID - { $$ =3D new_input_section_name ($1, false); } - | kSORT '(' kID ')' - { $$ =3D new_input_section_name ($3, true); } - ; - -exclude_opt: kEXCLUDE_FILE '(' filename_id ')' - { $$ =3D $3; } - | - { $$ =3D NULL; } - ; - -expr: kALIGN '(' expr ')' - { - $$ =3D new_expr (exp_align); - $$->val.child =3D $3; - } - | '(' expr ')' - { $$ =3D $2; } - | expr '*' expr - { - $$ =3D new_expr (exp_mult); - $$->val.binary.left =3D $1; - $$->val.binary.right =3D $3; - } - | expr kMUL_OP expr - { - $$ =3D new_expr ($2); - $$->val.binary.left =3D $1; - $$->val.binary.right =3D $3; - } - | expr kADD_OP expr - { - $$ =3D new_expr ($2); - $$->val.binary.left =3D $1; - $$->val.binary.right =3D $3; - } - | expr '&' expr - { - $$ =3D new_expr (exp_and); - $$->val.binary.left =3D $1; - $$->val.binary.right =3D $3; - } - | expr '|' expr - { - $$ =3D new_expr (exp_or); - $$->val.binary.left =3D $1; - $$->val.binary.right =3D $3; - } - | kNUM - { - $$ =3D new_expr (exp_num); - $$->val.num =3D $1; - } - | kID - { - $$ =3D new_expr (exp_id); - $$->val.str =3D $1; - } - | kSIZEOF_HEADERS - { $$ =3D new_expr (exp_sizeof_headers); } - | kPAGESIZE - { $$ =3D new_expr (exp_pagesize); } - ; - -filename_id_list: filename_id_list comma_opt filename_id_listelem - { - $3->next =3D $1->next; - $$ =3D $1->next =3D $3; - } - | filename_id_listelem - { $$ =3D $1; } - ; - -comma_opt: ',' - | - ; - -filename_id_listelem: kGROUP '(' filename_id_list ')' - { - /* First little optimization. If there is only one - file in the group don't do anything. */ - if ($3 !=3D $3->next) - { - $3->next->group_start =3D 1; - $3->group_end =3D 1; - } - $$ =3D $3; - } - | kAS_NEEDED '(' filename_id_list ')' - { $$ =3D mark_as_needed ($3); } - | filename_id - { $$ =3D new_filename_listelem ($1); } - ; - - -versionlist: versionlist version - { - $2->next =3D $1->next; - $$ =3D $1->next =3D $2; - } - | version - { $$ =3D $1; } - ; - -version: '{' version_stmt_list '}' ';' - { - $2->versionname =3D ""; - $2->parentname =3D NULL; - $$ =3D $2; - } - | filename_id '{' version_stmt_list '}' ';' - { - $3->versionname =3D $1; - $3->parentname =3D NULL; - $$ =3D $3; - } - | filename_id '{' version_stmt_list '}' filename_id ';' - { - $3->versionname =3D $1; - $3->parentname =3D $5; - $$ =3D $3; - } - ; - -version_stmt_list: - version_stmt_list version_stmt - { $$ =3D merge_versions ($1, $2); } - | version_stmt - { $$ =3D $1; } - ; - -version_stmt: kGLOBAL filename_id_star_list - { $$ =3D new_version (NULL, $2); } - | kLOCAL filename_id_star_list - { $$ =3D new_version ($2, NULL); } - ; - -filename_id_star_list: - filename_id_star_list filename_id_star ';' - { - struct id_list *newp =3D new_id_listelem ($2); - newp->next =3D $1->next; - $$ =3D $1->next =3D newp; - } - | filename_id_star ';' - { $$ =3D new_id_listelem ($1); } - ; - -filename_id: kFILENAME - { $$ =3D $1; } - | kID - { $$ =3D $1; } - ; - -filename_id_star: filename_id - { $$ =3D $1; } - | '*' - { $$ =3D NULL; } - ; - -%% - -static void -yyerror (const char *s) -{ - error (0, 0, (ld_scan_version_script - ? gettext ("while reading version script '%s': %s at line %d") - : gettext ("while reading linker script '%s': %s at line %d")), - ldin_fname, gettext (s), ldlineno); -} - - -static struct expression * -new_expr (int tag) -{ - struct expression *newp =3D (struct expression *) - obstack_alloc (&ld_state.smem, sizeof (*newp)); - - newp->tag =3D tag; - return newp; -} - - -static struct input_section_name * -new_input_section_name (const char *name, bool sort_flag) -{ - struct input_section_name *newp =3D (struct input_section_name *) - obstack_alloc (&ld_state.smem, sizeof (*newp)); - - newp->name =3D name; - newp->sort_flag =3D sort_flag; - return newp; -} - - -static struct input_rule * -new_input_rule (int tag) -{ - struct input_rule *newp =3D (struct input_rule *) - obstack_alloc (&ld_state.smem, sizeof (*newp)); - - newp->tag =3D tag; - newp->next =3D newp; - return newp; -} - - -static struct output_rule * -new_output_rule (int tag) -{ - struct output_rule *newp =3D (struct output_rule *) - memset (obstack_alloc (&ld_state.smem, sizeof (*newp)), - '\0', sizeof (*newp)); - - newp->tag =3D tag; - newp->next =3D newp; - return newp; -} - - -static struct assignment * -new_assignment (const char *variable, struct expression *expression, - bool provide_flag) -{ - struct assignment *newp =3D (struct assignment *) - obstack_alloc (&ld_state.smem, sizeof (*newp)); - - newp->variable =3D variable; - newp->expression =3D expression; - newp->sym =3D NULL; - newp->provide_flag =3D provide_flag; - - /* Insert the symbol into a hash table. We will later have to matc*/ - return newp; -} - - -static void -new_segment (int mode, struct output_rule *output_rule) -{ - struct output_segment *newp; - - newp - =3D (struct output_segment *) obstack_alloc (&ld_state.smem, sizeof (*= newp)); - newp->mode =3D mode; - newp->next =3D newp; - - newp->output_rules =3D output_rule->next; - output_rule->next =3D NULL; - - /* Enqueue the output segment description. */ - if (ld_state.output_segments =3D=3D NULL) - ld_state.output_segments =3D newp; - else - { - newp->next =3D ld_state.output_segments->next; - ld_state.output_segments =3D ld_state.output_segments->next =3D newp; - } - - /* If the output file should be stripped of all symbol set the flag - in the structures of all output sections. */ - if (mode =3D=3D 0 && ld_state.strip =3D=3D strip_all) - { - struct output_rule *runp; - - for (runp =3D newp->output_rules; runp !=3D NULL; runp =3D runp->nex= t) - if (runp->tag =3D=3D output_section) - runp->val.section.ignored =3D true; - } -} - - -static struct filename_list * -new_filename_listelem (const char *string) -{ - struct filename_list *newp; - - /* We use calloc and not the obstack since this object can be freed soon= . */ - newp =3D (struct filename_list *) xcalloc (1, sizeof (*newp)); - newp->name =3D string; - newp->next =3D newp; - return newp; -} - - -static struct filename_list * -mark_as_needed (struct filename_list *listp) -{ - struct filename_list *runp =3D listp; - do - { - runp->as_needed =3D true; - runp =3D runp->next; - } - while (runp !=3D listp); - - return listp; -} - - -static void -add_inputfiles (struct filename_list *fnames) -{ - assert (fnames !=3D NULL); - - if (ld_state.srcfiles =3D=3D NULL) - ld_state.srcfiles =3D fnames; - else - { - struct filename_list *first =3D ld_state.srcfiles->next; - - ld_state.srcfiles->next =3D fnames->next; - fnames->next =3D first; - ld_state.srcfiles->next =3D fnames; - } -} - - -static _Bool -special_char_p (const char *str) -{ - while (*str !=3D '\0') - { - if (__builtin_expect (*str =3D=3D '*', 0) - || __builtin_expect (*str =3D=3D '?', 0) - || __builtin_expect (*str =3D=3D '[', 0)) - return true; - - ++str; - } - - return false; -} - - -static struct id_list * -new_id_listelem (const char *str) -{ - struct id_list *newp; - - newp =3D (struct id_list *) obstack_alloc (&ld_state.smem, sizeof (*newp= )); - if (str =3D=3D NULL) - newp->u.id_type =3D id_all; - else if (__builtin_expect (special_char_p (str), false)) - newp->u.id_type =3D id_wild; - else - newp->u.id_type =3D id_str; - newp->id =3D str; - newp->next =3D newp; - - return newp; -} - - -static struct version * -new_version (struct id_list *local, struct id_list *global) -{ - struct version *newp; - - newp =3D (struct version *) obstack_alloc (&ld_state.smem, sizeof (*newp= )); - newp->next =3D newp; - newp->local_names =3D local; - newp->global_names =3D global; - newp->versionname =3D NULL; - newp->parentname =3D NULL; - - return newp; -} - - -static struct version * -merge_versions (struct version *one, struct version *two) -{ - assert (two->local_names =3D=3D NULL || two->global_names =3D=3D NULL); - - if (two->local_names !=3D NULL) - { - if (one->local_names =3D=3D NULL) - one->local_names =3D two->local_names; - else - { - two->local_names->next =3D one->local_names->next; - one->local_names =3D one->local_names->next =3D two->local_names; - } - } - else - { - if (one->global_names =3D=3D NULL) - one->global_names =3D two->global_names; - else - { - two->global_names->next =3D one->global_names->next; - one->global_names =3D one->global_names->next =3D two->global_names; - } - } - - return one; -} - - -static void -add_id_list (const char *versionname, struct id_list *runp, _Bool local) -{ - struct id_list *lastp =3D runp; - - if (runp =3D=3D NULL) - /* Nothing to do. */ - return; - - /* Convert into a simple single-linked list. */ - runp =3D runp->next; - assert (runp !=3D NULL); - lastp->next =3D NULL; - - do - if (runp->u.id_type =3D=3D id_str) - { - struct id_list *curp; - struct id_list *defp; - unsigned long int hval =3D elf_hash (runp->id); - - curp =3D runp; - runp =3D runp->next; - - defp =3D ld_version_str_tab_find (&ld_state.version_str_tab, hval, curp); - if (defp !=3D NULL) - { - /* There is already a version definition for this symbol. */ - while (strcmp (defp->u.s.versionname, versionname) !=3D 0) - { - if (defp->next =3D=3D NULL) - { - /* No version like this so far. */ - defp->next =3D curp; - curp->u.s.local =3D local; - curp->u.s.versionname =3D versionname; - curp->next =3D NULL; - defp =3D NULL; - break; - } - - defp =3D defp->next; - } - - if (defp !=3D NULL && defp->u.s.local !=3D local) - error (EXIT_FAILURE, 0, versionname[0] =3D=3D '\0' - ? gettext ("\ -symbol '%s' is declared both local and global for unnamed version '%s'") - : gettext ("\ -symbol '%s' is declared both local and global for version '%s'"), - runp->id, versionname); - } - else - { - /* This is the first version definition for this symbol. */ - ld_version_str_tab_insert (&ld_state.version_str_tab, hval, curp); - - curp->u.s.local =3D local; - curp->u.s.versionname =3D versionname; - curp->next =3D NULL; - } - } - else if (runp->u.id_type =3D=3D id_all) - { - if (local) - { - if (ld_state.default_bind_global) - error (EXIT_FAILURE, 0, - gettext ("default visibility set as local and global")); - ld_state.default_bind_local =3D true; - } - else - { - if (ld_state.default_bind_local) - error (EXIT_FAILURE, 0, - gettext ("default visibility set as local and global")); - ld_state.default_bind_global =3D true; - } - - runp =3D runp->next; - } - else - { - assert (runp->u.id_type =3D=3D id_wild); - /* XXX TBI */ - abort (); - } - while (runp !=3D NULL); -} - - -static void -add_versions (struct version *versions) -{ - struct version *lastp =3D versions; - - if (versions =3D=3D NULL) - return; - - /* Convert into a simple single-linked list. */ - versions =3D versions->next; - assert (versions !=3D NULL); - lastp->next =3D NULL; - - do - { - add_id_list (versions->versionname, versions->local_names, true); - add_id_list (versions->versionname, versions->global_names, false); - - versions =3D versions->next; - } - while (versions !=3D NULL); -} diff --git a/src/libld_elf_i386.map b/src/libld_elf_i386.map deleted file mode 100644 index 703af6d..0000000 --- a/src/libld_elf_i386.map +++ /dev/null @@ -1,7 +0,0 @@ -ELFUTILS_1.0 { - global: - elf_i386_ld_init; - - local: - *; -}; diff --git a/src/none_ld.c b/src/none_ld.c deleted file mode 100644 index fb0f0fb..0000000 --- a/src/none_ld.c +++ /dev/null @@ -1 +0,0 @@ -/* Nothing here. This is just a testimony of automake inflexibility. */ diff --git a/src/sectionhash.c b/src/sectionhash.c deleted file mode 100644 index 83a7cca..0000000 --- a/src/sectionhash.c +++ /dev/null @@ -1,73 +0,0 @@ -/* Section hash table implementation. - Copyright (C) 2001, 2002, 2005 Red Hat, Inc. - This file is part of elfutils. - Written by Ulrich Drepper , 2001. - - This file 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. - - elfutils 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, see . = */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -#include -#include - - -/* Comparison function for sections. */ -static int -scnhead_compare (struct scnhead *one, struct scnhead *two) -{ - int result =3D strcmp (one->name, two->name); - - if (result =3D=3D 0) - { - result =3D one->type - two->type; - - if (result =3D=3D 0) - { - GElf_Sxword diff =3D (SH_FLAGS_IMPORTANT (one->flags) - - SH_FLAGS_IMPORTANT (two->flags)); - result =3D diff < 0 ? -1 : diff =3D=3D 0 ? 0 : 1; - - if (result =3D=3D 0) - { - result =3D one->entsize - two->entsize; - - if (result =3D=3D 0) - { - result =3D (one->grp_signature =3D=3D NULL - ? (two->grp_signature =3D=3D NULL ? 0 : -1) - : (two->grp_signature =3D=3D NULL - ? 1 : strcmp (one->grp_signature, - two->grp_signature))); - - if (result =3D=3D 0) - result =3D one->kind - two->kind; - } - } - } - } - - return result; -} - -/* Definitions for the section hash table. */ -#define TYPE struct scnhead * -#define NAME ld_section_tab -#define ITERATE 1 -#define COMPARE(a, b) scnhead_compare (a, b) - -#include "../lib/dynamicsizehash.c" diff --git a/src/sectionhash.h b/src/sectionhash.h deleted file mode 100644 index 96da336..0000000 --- a/src/sectionhash.h +++ /dev/null @@ -1,27 +0,0 @@ -/* Copyright (C) 2001, 2002 Red Hat, Inc. - This file is part of elfutils. - Written by Ulrich Drepper , 2001. - - This file 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. - - elfutils 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, see . = */ - -#ifndef SECTIONHASH_H -#define SECTIONHASH_H 1 - -/* Definitions for the section hash table. */ -#define TYPE struct scnhead * -#define NAME ld_section_tab -#define ITERATE 1 -#include - -#endif /* sectionhash.h */ diff --git a/src/symbolhash.c b/src/symbolhash.c deleted file mode 100644 index 3fd9649..0000000 --- a/src/symbolhash.c +++ /dev/null @@ -1,33 +0,0 @@ -/* Symbol hash table implementation. - Copyright (C) 2001, 2002 Red Hat, Inc. - This file is part of elfutils. - Written by Ulrich Drepper , 2001. - - This file 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. - - elfutils 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, see . = */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -#include - -/* Definitions for the symbol hash table. */ -#define TYPE struct symbol * -#define NAME ld_symbol_tab -#define ITERATE 1 -#define COMPARE(a, b) strcmp ((a)->name, (b)->name) - -#include "../lib/dynamicsizehash.c" diff --git a/src/symbolhash.h b/src/symbolhash.h deleted file mode 100644 index 062dade..0000000 --- a/src/symbolhash.h +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright (C) 2001, 2002 Red Hat, Inc. - This file is part of elfutils. - Written by Ulrich Drepper , 2001. - - This file 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. - - elfutils 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, see . = */ - -#ifndef SYMBOLHASH_H -#define SYMBOLHASH_H 1 - -/* Definitions for the symbol hash table. */ -#define TYPE struct symbol * -#define NAME ld_symbol_tab -#define ITERATE 1 -#define COMPARE(a, b) strcmp ((a)->name, (b)->name) -#include - -#endif /* symbolhash.h */ diff --git a/src/unaligned.h b/src/unaligned.h deleted file mode 100644 index 2916653..0000000 --- a/src/unaligned.h +++ /dev/null @@ -1,102 +0,0 @@ -/* Unaligned memory access functionality. - Copyright (C) 2000, 2001, 2002, 2003, 2008 Red Hat, Inc. - This file is part of elfutils. - Written by Ulrich Drepper , 2001. - - This file 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. - - elfutils 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, see . = */ - -#ifndef _UNALIGNED_H -#define _UNALIGNED_H 1 - -#include -#include - - -#ifndef UNALIGNED_ACCESS_CLASS -# error "UNALIGNED_ACCESS_CLASS must be defined" -#endif - - -/* Macros to convert from the host byte order to that of the object file. = */ -#if UNALIGNED_ACCESS_CLASS =3D=3D BYTE_ORDER -# define target_bswap_16(n) (n) -# define target_bswap_32(n) (n) -# define target_bswap_64(n) (n) -#else -# define target_bswap_16(n) bswap_16 (n) -# define target_bswap_32(n) bswap_32 (n) -# define target_bswap_64(n) bswap_64 (n) -#endif - - -union u_2ubyte_unaligned -{ - uint16_t u; - char c[2]; -} __attribute__((packed)); - -union u_4ubyte_unaligned -{ - uint32_t u; - char c[4]; -} __attribute__((packed)); - -union u_8ubyte_unaligned -{ - uint64_t u; - char c[8]; -} __attribute__((packed)); - - -/* Macros to store value at unaligned address. */ -#define store_2ubyte_unaligned(ptr, value) \ - (void) (((union u_2ubyte_unaligned *) (ptr))->u =3D target_bswap_16 (val= ue)) -#define store_4ubyte_unaligned(ptr, value) \ - (void) (((union u_4ubyte_unaligned *) (ptr))->u =3D target_bswap_32 (val= ue)) -#define store_8ubyte_unaligned(ptr, value) \ - (void) (((union u_8ubyte_unaligned *) (ptr))->u =3D target_bswap_64 (val= ue)) - - -/* Macros to add value to unaligned address. This is a bit more - complicated since the value must be read from memory and eventually - converted twice. */ -#if UNALIGNED_ACCESS_CLASS =3D=3D BYTE_ORDER -# define add_2ubyte_unaligned(ptr, value) \ - (void) (((union u_2ubyte_unaligned *) (ptr))->u +=3D value) -# define add_4ubyte_unaligned(ptr, value) \ - (void) (((union u_4ubyte_unaligned *) (ptr))->u +=3D value) -# define add_8ubyte_unaligned(ptr, value) \ - (void) (((union u_8ubyte_unaligned *) (ptr))->u +=3D value) -#else -# define add_2ubyte_unaligned(ptr, value) \ - do { \ - union u_2ubyte_unaligned *_ptr =3D (void *) (ptr); \ - uint16_t _val =3D bswap_16 (_ptr->u) + (value); \ - _ptr->u =3D bswap_16 (_val); \ - } while (0) -# define add_4ubyte_unaligned(ptr, value) \ - do { \ - union u_4ubyte_unaligned *_ptr =3D (void *) (ptr); \ - uint32_t _val =3D bswap_32 (_ptr->u) + (value); \ - _ptr->u =3D bswap_32 (_val); \ - } while (0) -# define add_8ubyte_unaligned(ptr, value) \ - do { \ - union u_8ubyte_unaligned *_ptr =3D (void *) (ptr); \ - uint64_t _val =3D bswap_64 (_ptr->u) + (value); \ - _ptr->u =3D bswap_64 (_val); \ - } while (0) -#endif - -#endif /* unaligned.h */ diff --git a/src/versionhash.c b/src/versionhash.c deleted file mode 100644 index cc4d283..0000000 --- a/src/versionhash.c +++ /dev/null @@ -1,32 +0,0 @@ -/* Version symbol hash table implementation. - Copyright (C) 2001, 2002 Red Hat, Inc. - This file is part of elfutils. - Written by Ulrich Drepper , 2001. - - This file 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. - - elfutils 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, see . = */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -#include - -/* Definitions for the symbol hash table. */ -#define TYPE struct id_list * -#define NAME ld_version_str_tab -#define COMPARE(a, b) strcmp ((a)->id, (b)->id) - -#include "../lib/dynamicsizehash.c" diff --git a/src/versionhash.h b/src/versionhash.h deleted file mode 100644 index 4434e05..0000000 --- a/src/versionhash.h +++ /dev/null @@ -1,26 +0,0 @@ -/* Copyright (C) 2001, 2002 Red Hat, Inc. - This file is part of elfutils. - Written by Ulrich Drepper , 2001. - - This file 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. - - elfutils 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, see . = */ - -#ifndef VERSIONHASH_H -#define VERSIONHASH_H 1 - -/* Definitions for the symbol hash table. */ -#define TYPE struct id_list * -#define NAME ld_version_str_tab -#include - -#endif /* versionhash.h */ diff --git a/src/xelf.h b/src/xelf.h deleted file mode 100644 index f292327..0000000 --- a/src/xelf.h +++ /dev/null @@ -1,391 +0,0 @@ -/* Macros to enable writing native and generic ELF access code. - Copyright (C) 2003 Red Hat, Inc. - This file is part of elfutils. - Written by Ulrich Drepper , 2003. - - This file 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. - - elfutils 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, see . = */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - - -/* By default the linker is handling all architectures. But it can - be configured to be a native-only linker. */ -#if NATIVE_ELF =3D=3D 32 -/* 32-bit only. */ -# define XElf_Ehdr Elf32_Ehdr -# define XElf_Shdr Elf32_Shdr -# define XElf_Off Elf32_Off -# define XElf_Addr Elf32_Addr -# define XElf_Half Elf32_Half -# define XElf_Word Elf32_Word -# define XElf_Xword Elf32_Word -# define XElf_Sxword Elf32_Sword -# define XElf_Versym Elf32_Versym -# define XElf_Sym Elf32_Sym -# define XElf_Rel Elf32_Rel -# define XElf_Rela Elf32_Rela - -# define XElf_Ehdr_vardef(name) Elf32_Ehdr *name -# define xelf_getehdr(elf, name) name =3D elf32_getehdr (elf) -# define xelf_getehdr_copy(elf, name, copy) \ - (copy) =3D *(name =3D elf32_getehdr (elf)) -# define xelf_newehdr(elf, klass) elf32_newehdr (elf) -# define xelf_update_ehdr(elf, ehdr) \ - /* nothing */ ((void) (elf), (void) (ehdr), 1) - -# define xelf_getclass(elf) ELFCLASS32 - -# define XElf_Phdr_vardef(name) Elf32_Phdr *name -# define xelf_newphdr(elf, n) elf32_newphdr (elf, n) -# define xelf_getphdr(elf, idx, name) name =3D elf32_getphdr (elf) + idx -# define xelf_getphdr_ptr(elf, idx, name) name =3D elf32_getphdr (elf) + i= dx -# define xelf_update_phdr(elf, idx, phdr) \ - /* nothing */ ((void) (elf), (void) (idx), (void) (phdr), 1) - -# define XElf_Shdr_vardef(name) Elf32_Shdr *name -# define xelf_getshdr(scn, name) name =3D elf32_getshdr (scn) -# define xelf_getshdr_copy(scn, name, copy) \ - (copy) =3D *(name =3D elf32_getshdr (scn)) -# define xelf_update_shdr(scn, shdr) \ - /* nothing */ ((void) (scn), (void) (shdr), 1) - -# define XElf_Sym_vardef(name) Elf32_Sym *name -# define xelf_getsym(data, idx, name) \ - name =3D &((Elf32_Sym *) (data)->d_buf)[idx] -# define xelf_getsym_ptr(data, idx, name) \ - name =3D &((Elf32_Sym *) (data)->d_buf)[idx] -# define xelf_getsymshndx(data, ndxdata, idx, name1, name2) \ - (name1 =3D &((Elf32_Sym *) ((data)->d_buf))[idx]); \ - name2 =3D (unlikely ((ndxdata) !=3D NULL) \ - ? ((Elf32_Word *) ((ndxdata)->d_buf))[idx] : 0) -# define xelf_update_sym(data, idx, sym) \ - /* nothing */ ((void) (data), (void) (idx), (void) (sym), 1) -# define xelf_update_symshndx(data, ndxdata, idx, name1, name2, datachange= d) \ - if (datachanged) \ - ((Elf32_Sym *) ((data)->d_buf))[idx] =3D *name1; \ - if (unlikely (ndxdata !=3D NULL)) \ - ((Elf32_Word *) ((ndxdata)->d_buf))[idx] =3D name2 - -# define XElf_Versym_vardef(name) Elf32_Versym name -# define xelf_getversym_copy(data, idx, name) \ - (name =3D ((Elf32_Versym *) ((data)->d_buf))[idx], &name) - -# define XElf_Dyn_vardef(name) Elf32_Dyn *name -# define xelf_getdyn(data, idx, name) \ - name =3D &((Elf32_Dyn *) ((data)->d_buf))[idx] -# define xelf_getdyn_ptr(data, idx, name) \ - name =3D &((Elf32_Dyn *) ((data)->d_buf))[idx] -# define xelf_update_dyn(data, idx, name) \ - /* nothing */ ((void) (data), (void) (idx), (void) (name), 1) - -# define XElf_Rel_vardef(name) Elf32_Rel *name -# define xelf_getrel(data, idx, name) \ - name =3D &((Elf32_Rel *) ((data)->d_buf))[idx] -# define xelf_getrel_ptr(data, idx, name) \ - name =3D &((Elf32_Rel *) ((data)->d_buf))[idx] -# define xelf_update_rel(data, idx, name) \ - /* nothing */ ((void) (data), (void) (idx), (void) (name), 1) - -# define XElf_Rela_vardef(name) Elf32_Rela *name -# define xelf_getrela(data, idx, name) \ - name =3D &((Elf32_Rela *) ((data)->d_buf))[idx] -# define xelf_getrela_ptr(data, idx, name) \ - name =3D &((Elf32_Rela *) ((data)->d_buf))[idx] -# define xelf_update_rela(data, idx, name) \ - /* nothing */ ((void) (data), (void) (idx), (void) (name), 1) - -# define XElf_Verdef_vardef(name) Elf32_Verdef *name -# define xelf_getverdef(data, offset, name) \ - name =3D ((Elf32_Verdef *) ((char *) ((data)->d_buf) + (offset))) - -# define XElf_Verdaux_vardef(name) Elf32_Verdaux *name -# define xelf_getverdaux(data, offset, name) \ - name =3D ((Elf32_Verdaux *) ((char *) ((data)->d_buf) + (offset))) - -# define XELF_ST_TYPE(info) ELF32_ST_TYPE (info) -# define XELF_ST_BIND(info) ELF32_ST_BIND (info) -# define XELF_ST_INFO(bind, type) ELF32_ST_INFO (bind, type) -# define XELF_ST_VISIBILITY(info) ELF32_ST_VISIBILITY (info) - -# define XELF_R_SYM(info) ELF32_R_SYM (info) -# define XELF_R_TYPE(info) ELF32_R_TYPE (info) -# define XELF_R_INFO(sym, type) ELF32_R_INFO (sym, type) - -# define xelf_fsize(elf, type, cnt) \ - (__builtin_constant_p (type) \ - ? ({ size_t fsize; \ - switch (type) \ - { \ - case ELF_T_BYTE: fsize =3D 1; break; \ - case ELF_T_ADDR: fsize =3D sizeof (Elf32_Addr); break; \ - case ELF_T_DYN: fsize =3D sizeof (Elf32_Dyn); break; \ - case ELF_T_EHDR: fsize =3D sizeof (Elf32_Ehdr); break; \ - case ELF_T_HALF: fsize =3D sizeof (Elf32_Half); break; \ - case ELF_T_OFF: fsize =3D sizeof (Elf32_Off); break; \ - case ELF_T_PHDR: fsize =3D sizeof (Elf32_Phdr); break; \ - case ELF_T_RELA: fsize =3D sizeof (Elf32_Rela); break; \ - case ELF_T_REL: fsize =3D sizeof (Elf32_Rel); break; \ - case ELF_T_SHDR: fsize =3D sizeof (Elf32_Shdr); break; \ - case ELF_T_SWORD: fsize =3D sizeof (Elf32_Sword); break; \ - case ELF_T_SYM: fsize =3D sizeof (Elf32_Sym); break; \ - case ELF_T_WORD: fsize =3D sizeof (Elf32_Word); break; \ - case ELF_T_XWORD: fsize =3D sizeof (Elf32_Xword); break; \ - case ELF_T_SXWORD: fsize =3D sizeof (Elf32_Sxword); break; \ - case ELF_T_VDEF: fsize =3D sizeof (Elf32_Verdef); break; \ - case ELF_T_VDAUX: fsize =3D sizeof (Elf32_Verdaux); break; \ - case ELF_T_VNEED: fsize =3D sizeof (Elf32_Verneed); break; \ - case ELF_T_VNAUX: fsize =3D sizeof (Elf32_Vernaux); break; \ - case ELF_T_NHDR: fsize =3D sizeof (Elf32_Nhdr); break; \ - case ELF_T_SYMINFO: fsize =3D sizeof (Elf32_Syminfo); break; \ - case ELF_T_MOVE: fsize =3D sizeof (Elf32_Move); break; \ - default: fsize =3D 0; break; \ - } \ - fsize * (cnt); }) \ - : gelf_fsize (elf, type, cnt, EV_CURRENT)) -#elif NATIVE_ELF =3D=3D 64 -/* 64-bit only. */ -# define XElf_Ehdr Elf64_Ehdr -# define XElf_Shdr Elf64_Shdr -# define XElf_Addr Elf64_Addr -# define XElf_Half Elf64_Half -# define XElf_Off Elf64_Off -# define XElf_Word Elf64_Word -# define XElf_Xword Elf64_Xword -# define XElf_Sxword Elf64_Sxword -# define XElf_Versym Elf64_Versym -# define XElf_Sym Elf64_Sym -# define XElf_Rel Elf64_Rel -# define XElf_Rela Elf64_Rela - -# define XElf_Ehdr_vardef(name) Elf64_Ehdr *name -# define xelf_getehdr(elf, name) name =3D elf64_getehdr (elf) -# define xelf_getehdr_copy(elf, name, copy) \ - (copy) =3D *(name =3D elf64_getehdr (elf)) -# define xelf_newehdr(elf, klass) elf64_newehdr (elf) -# define xelf_update_ehdr(elf, ehdr) \ - /* nothing */ ((void) (elf), (void) (ehdr), 1) - -# define xelf_getclass(elf) ELFCLASS32 - -# define XElf_Phdr_vardef(name) Elf64_Phdr *name -# define xelf_newphdr(elf, n) elf64_newphdr (elf, n) -# define xelf_getphdr(elf, idx, name) name =3D elf64_getphdr (elf) + idx -# define xelf_getphdr_ptr(elf, idx, name) name =3D elf64_getphdr (elf) + i= dx -# define xelf_update_phdr(elf, idx, phdr) \ - /* nothing */ ((void) (elf), (void) (idx), (void) (phdr), 1) - -# define XElf_Shdr_vardef(name) Elf64_Shdr *name -# define xelf_getshdr(scn, name) name =3D elf64_getshdr (scn) -# define xelf_getshdr_copy(scn, name, copy) \ - (copy) =3D *(name =3D elf64_getshdr (scn)) -# define xelf_update_shdr(scn, shdr) \ - /* nothing */ ((void) (scn), (void) (shdr), 1) - -# define XElf_Sym_vardef(name) Elf64_Sym *name -# define xelf_getsym(data, idx, name) \ - name =3D &((Elf64_Sym *) (data)->d_buf)[idx] -# define xelf_getsym_ptr(data, idx, name) \ - name =3D &((Elf64_Sym *) (data)->d_buf)[idx] -# define xelf_getsymshndx(data, ndxdata, idx, name1, name2) \ - (name1 =3D &((Elf64_Sym *) ((data)->d_buf))[idx]); \ - name2 =3D (unlikely ((ndxdata) !=3D NULL) \ - ? ((Elf32_Word *) ((ndxdata)->d_buf))[idx] : 0) -# define xelf_update_sym(data, idx, sym) \ - /* nothing */ ((void) (data), (void) (idx), (void) (sym), 1) -# define xelf_update_symshndx(data, ndxdata, idx, name1, name2, datachange= d) \ - if (datachanged) \ - ((Elf64_Sym *) ((data)->d_buf))[idx] =3D *name1; \ - if (ndxdata !=3D NULL) \ - (((Elf32_Word *) ((ndxdata)->d_buf))[idx] =3D name2) - -# define XElf_Versym_vardef(name) Elf64_Versym name -# define xelf_getversym_copy(data, idx, name) \ - (name =3D ((Elf64_Versym *) ((data)->d_buf))[idx], (&name)) - -# define XElf_Dyn_vardef(name) Elf64_Dyn *name -# define xelf_getdyn(data, idx, name) \ - name =3D &((Elf64_Dyn *) ((data)->d_buf))[idx] -# define xelf_getdyn_ptr(data, idx, name) \ - name =3D &((Elf64_Dyn *) ((data)->d_buf))[idx] -# define xelf_update_dyn(data, idx, name) \ - /* nothing */ ((void) (data), (void) (idx), (void) (name), 1) - -# define XElf_Rel_vardef(name) Elf64_Rel *name -# define xelf_getrel(data, idx, name) \ - name =3D &((Elf64_Rel *) ((data)->d_buf))[idx] -# define xelf_getrel_ptr(data, idx, name) \ - name =3D &((Elf64_Rel *) ((data)->d_buf))[idx] -# define xelf_update_rel(data, idx, name) \ - /* nothing */ ((void) (data), (void) (idx), (void) (name), 1) - -# define XElf_Rela_vardef(name) Elf64_Rela *name -# define xelf_getrela(data, idx, name) \ - name =3D &((Elf64_Rela *) ((data)->d_buf))[idx] -# define xelf_getrela_ptr(data, idx, name) \ - name =3D &((Elf64_Rela *) ((data)->d_buf))[idx] -# define xelf_update_rela(data, idx, name) \ - /* nothing */ ((void) (data), (void) (idx), (void) (name), 1) - -# define XElf_Verdef_vardef(name) Elf64_Verdef *name -# define xelf_getverdef(data, offset, name) \ - name =3D ((Elf64_Verdef *) ((char *) ((data)->d_buf) + (offset))) - -# define XElf_Verdaux_vardef(name) Elf64_Verdaux *name -# define xelf_getverdaux(data, offset, name) \ - name =3D ((Elf64_Verdaux *) ((char *) ((data)->d_buf) + (offset))) - -# define XELF_ST_TYPE(info) ELF64_ST_TYPE (info) -# define XELF_ST_BIND(info) ELF64_ST_BIND (info) -# define XELF_ST_INFO(bind, type) ELF64_ST_INFO (bind, type) -# define XELF_ST_VISIBILITY(info) ELF64_ST_VISIBILITY (info) - -# define XELF_R_SYM(info) ELF64_R_SYM (info) -# define XELF_R_TYPE(info) ELF64_R_TYPE (info) -# define XELF_R_INFO(sym, type) ELF64_R_INFO (sym, type) - -# define xelf_fsize(elf, type, cnt) \ - (__builtin_constant_p (type) \ - ? ({ size_t fsize; \ - switch (type) \ - { \ - case ELF_T_BYTE: fsize =3D 1; break; \ - case ELF_T_ADDR: fsize =3D sizeof (Elf64_Addr); break; \ - case ELF_T_DYN: fsize =3D sizeof (Elf64_Dyn); break; \ - case ELF_T_EHDR: fsize =3D sizeof (Elf64_Ehdr); break; \ - case ELF_T_HALF: fsize =3D sizeof (Elf64_Half); break; \ - case ELF_T_OFF: fsize =3D sizeof (Elf64_Off); break; \ - case ELF_T_PHDR: fsize =3D sizeof (Elf64_Phdr); break; \ - case ELF_T_RELA: fsize =3D sizeof (Elf64_Rela); break; \ - case ELF_T_REL: fsize =3D sizeof (Elf64_Rel); break; \ - case ELF_T_SHDR: fsize =3D sizeof (Elf64_Shdr); break; \ - case ELF_T_SWORD: fsize =3D sizeof (Elf64_Sword); break; \ - case ELF_T_SYM: fsize =3D sizeof (Elf64_Sym); break; \ - case ELF_T_WORD: fsize =3D sizeof (Elf64_Word); break; \ - case ELF_T_XWORD: fsize =3D sizeof (Elf64_Xword); break; \ - case ELF_T_SXWORD: fsize =3D sizeof (Elf64_Sxword); break; \ - case ELF_T_VDEF: fsize =3D sizeof (Elf64_Verdef); break; \ - case ELF_T_VDAUX: fsize =3D sizeof (Elf64_Verdaux); break; \ - case ELF_T_VNEED: fsize =3D sizeof (Elf64_Verneed); break; \ - case ELF_T_VNAUX: fsize =3D sizeof (Elf64_Vernaux); break; \ - case ELF_T_NHDR: fsize =3D sizeof (Elf64_Nhdr); break; \ - case ELF_T_SYMINFO: fsize =3D sizeof (Elf64_Syminfo); break; \ - case ELF_T_MOVE: fsize =3D sizeof (Elf64_Move); break; \ - default: fsize =3D 0; break; \ - } \ - fsize * (cnt); }) \ - : gelf_fsize (elf, type, cnt, EV_CURRENT)) -#else -# include - -/* Generic linker. */ -# define XElf_Ehdr GElf_Ehdr -# define XElf_Shdr GElf_Shdr -# define XElf_Addr GElf_Addr -# define XElf_Half GElf_Half -# define XElf_Off GElf_Off -# define XElf_Word GElf_Word -# define XElf_Xword GElf_Xword -# define XElf_Sxword GElf_Sxword -# define XElf_Versym GElf_Versym -# define XElf_Sym GElf_Sym -# define XElf_Rel GElf_Rel -# define XElf_Rela GElf_Rela - -# define XElf_Ehdr_vardef(name) GElf_Ehdr name##_mem; GElf_Ehdr *name -# define xelf_getehdr(elf, name) name =3D gelf_getehdr (elf, &name##_mem) -# define xelf_getehdr_copy(elf, name, copy) \ - name =3D gelf_getehdr (elf, &(copy)) -# define xelf_newehdr(elf, klass) gelf_newehdr (elf, klass) -# define xelf_update_ehdr(elf, ehdr) gelf_update_ehdr (elf, ehdr) - -# define xelf_getclass(elf) gelf_getclass (elf) - -# define XElf_Phdr_vardef(name) GElf_Phdr name##_mem; GElf_Phdr *name -# define xelf_newphdr(elf, n) gelf_newphdr (elf, n) -# define xelf_getphdr(elf, idx, name) \ - name =3D gelf_getphdr (elf, idx, &name##_mem) -# define xelf_getphdr_ptr(elf, idx, name) \ - name =3D &name##_mem -# define xelf_update_phdr(elf, idx, phdr) \ - gelf_update_phdr (elf, idx, phdr) - -# define XElf_Shdr_vardef(name) GElf_Shdr name##_mem; GElf_Shdr *name -# define xelf_getshdr(scn, name) name =3D gelf_getshdr (scn, &name##_mem) -# define xelf_getshdr_copy(scn, name, copy) \ - name =3D gelf_getshdr (scn, &(copy)) -# define xelf_update_shdr(scn, shdr) gelf_update_shdr (scn, shdr) - -# define XElf_Sym_vardef(name) GElf_Sym name##_mem; GElf_Sym *name -# define xelf_getsym(data, idx, name) \ - name =3D gelf_getsym (data, idx, &name##_mem) -# define xelf_getsym_ptr(data, idx, name) \ - name =3D &name##_mem -# define xelf_getsymshndx(data, ndxdata, idx, name1, name2) \ - name1 =3D gelf_getsymshndx (data, ndxdata, idx, &name1##_mem, &(name2)) -# define xelf_update_sym(data, idx, sym) gelf_update_sym (data, idx, sym) -# define xelf_update_symshndx(data, ndxdata, idx, name1, name2, datachange= d) \ - gelf_update_symshndx (data, ndxdata, idx, name1, name2) - -# define XElf_Versym_vardef(name) GElf_Versym name -# define xelf_getversym_copy(data, idx, name) \ - gelf_getversym (data, idx, &name) - -# define XElf_Dyn_vardef(name) GElf_Dyn name##_mem; GElf_Dyn *name -# define xelf_getdyn(data, idx, name) \ - name =3D gelf_getdyn (data, idx, &name##_mem) -# define xelf_getdyn_ptr(data, idx, name) \ - name =3D &name##_mem -# define xelf_update_dyn(data, idx, name) \ - gelf_update_dyn (data, idx, name) - -# define XElf_Rel_vardef(name) GElf_Rel name##_mem; GElf_Rel *name -# define xelf_getrel(data, idx, name) \ - name =3D gelf_getrel (data, idx, &name##_mem) -# define xelf_getrel_ptr(data, idx, name) \ - name =3D &name##_mem -# define xelf_update_rel(data, idx, name) \ - gelf_update_rel (data, idx, name) - -# define XElf_Rela_vardef(name) GElf_Rela name##_mem; GElf_Rela *name -# define xelf_getrela(data, idx, name) \ - name =3D gelf_getrela (data, idx, &name##_mem) -# define xelf_getrela_ptr(data, idx, name) \ - name =3D &name##_mem -# define xelf_update_rela(data, idx, name) \ - gelf_update_rela (data, idx, name) - -# define XElf_Verdef_vardef(name) GElf_Verdef name##_mem; GElf_Verdef *name -# define xelf_getverdef(data, offset, name) \ - name =3D gelf_getverdef (data, offset, &name##_mem) - -# define XElf_Verdaux_vardef(name) GElf_Verdaux name##_mem; GElf_Verdaux *= name -# define xelf_getverdaux(data, offset, name) \ - name =3D gelf_getverdaux (data, offset, &name##_mem) - -# define XELF_ST_TYPE(info) GELF_ST_TYPE (info) -# define XELF_ST_BIND(info) GELF_ST_BIND (info) -# define XELF_ST_INFO(bind, type) GELF_ST_INFO (bind, type) -# define XELF_ST_VISIBILITY(info) GELF_ST_VISIBILITY (info) - -# define XELF_R_SYM(info) GELF_R_SYM (info) -# define XELF_R_TYPE(info) GELF_R_TYPE (info) -# define XELF_R_INFO(sym, type) GELF_R_INFO (sym, type) - -# define xelf_fsize(elf, type, cnt) \ - gelf_fsize (elf, type, cnt, EV_CURRENT) -#endif -- = 2.7.4 --===============0334493565604174374==--