diff options
| author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:22 -0800 |
|---|---|---|
| committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:22 -0800 |
| commit | 7a80622f69812ca3262d2027c07a4ed0c0242945 (patch) | |
| tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /src | |
| parent | ee6008996aa701ad2a50d5d6b1529c9e2c2724c1 (diff) | |
| download | platform_external_elfutils-7a80622f69812ca3262d2027c07a4ed0c0242945.tar.gz platform_external_elfutils-7a80622f69812ca3262d2027c07a4ed0c0242945.tar.bz2 platform_external_elfutils-7a80622f69812ca3262d2027c07a4ed0c0242945.zip | |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 188 | ||||
| -rw-r--r-- | src/Makefile | 638 | ||||
| -rw-r--r-- | src/Makefile.am | 130 | ||||
| -rw-r--r-- | src/Makefile.in | 638 | ||||
| -rw-r--r-- | src/elf32-i386.script | 215 | ||||
| -rw-r--r-- | src/elflint.c | 2578 | ||||
| -rw-r--r-- | src/i386_ld.c | 891 | ||||
| -rw-r--r-- | src/ld.c | 1520 | ||||
| -rw-r--r-- | src/ld.h | 1073 | ||||
| -rw-r--r-- | src/ldgeneric.c | 6376 | ||||
| -rw-r--r-- | src/ldlex.c | 2663 | ||||
| -rw-r--r-- | src/ldlex.l | 343 | ||||
| -rw-r--r-- | src/ldscript.c | 2220 | ||||
| -rw-r--r-- | src/ldscript.h | 116 | ||||
| -rw-r--r-- | src/ldscript.y | 764 | ||||
| -rw-r--r-- | src/libld_elf_i386.map | 7 | ||||
| -rw-r--r-- | src/nm.c | 1302 | ||||
| -rw-r--r-- | src/none_ld.c | 1 | ||||
| -rw-r--r-- | src/readelf.c | 4541 | ||||
| -rw-r--r-- | src/sectionhash.c | 69 | ||||
| -rw-r--r-- | src/sectionhash.h | 23 | ||||
| -rw-r--r-- | src/size.c | 698 | ||||
| -rw-r--r-- | src/strip.c | 1769 | ||||
| -rw-r--r-- | src/symbolhash.c | 29 | ||||
| -rw-r--r-- | src/symbolhash.h | 24 | ||||
| -rw-r--r-- | src/unaligned.h | 98 | ||||
| -rw-r--r-- | src/versionhash.c | 28 | ||||
| -rw-r--r-- | src/versionhash.h | 22 | ||||
| -rw-r--r-- | src/xelf.h | 387 | ||||
| -rw-r--r-- | src/ylwrap | 154 |
30 files changed, 0 insertions, 29505 deletions
diff --git a/src/ChangeLog b/src/ChangeLog deleted file mode 100644 index e5b44049..00000000 --- a/src/ChangeLog +++ /dev/null @@ -1,188 +0,0 @@ -2004-09-25 Ulrich Drepper <drepper@redhat.com> - - * readelf.c: Make compile with gcc 4.0. - * strip.c: Likewise. - -2004-08-16 Ulrich Drepper <drepper@redhat.com> - - * strip.c (handle_elf): Rewrite dynamic memory handling to use of - allocate to work around gcc 3.4 bug. - -2004-01-25 Ulrich Drepper <drepper@redhat.com> - - * ldlex.l (invalid_char): Better error message. - -2004-01-23 Ulrich Drepper <drepper@redhat.com> - - * readelf.c: Print SHT_GNU_LIBLIST sections. - - * none_ld.c: New file. - -2004-01-21 Ulrich Drepper <drepper@redhat.com> - - * Makefile.am: Enable building of machine specific linker. - -2004-01-20 Ulrich Drepper <drepper@redhat.com> - - * Makefile.am: Support building with mudflap. - - * i386_ld.c: Fix warnings gcc 3.4 spits out. - * ldgeneric.c: Likewise. - * ldscript.y: Likewise. - * readelf.c: Likewise. - * strip.c: Likewise. - - * readelf.c (print_debug_line_section): Determine address size - correctly. - -2004-01-19 Ulrich Drepper <drepper@redhat.com> - - * readelf.c (print_phdr): Show which sections are covered by the - PT_GNU_RELRO entry. - - * elflint.c (check_program_header): Check PT_GNU_RELRO entry. - - * readelf.c (print_debug_macinfo_section): Implement. - -2004-01-18 Ulrich Drepper <drepper@redhat.com> - - * readelf.c (print_debug_line_section): Implement. - -2004-01-17 Ulrich Drepper <drepper@redhat.com> - - * src/elflint.c: Use PACKAGE_NAME instead of PACKAGE. - * src/ld.c: Likewise. - * src/nm.c: Likewise. - * src/readelf.c: Likewise. - * src/size.c: Likewise. - * src/strip.c: Likewise. - - * strip.c: Add a few more unlikely. Reduce scope of some variables. - - * Makefile.am: Support building with mudflap. - -2004-01-16 Ulrich Drepper <drepper@redhat.com> - - * readelf.c (print_debug_info_section): Free dies memory. - - * readelf.c: Print .debug_info section content. - -2004-01-13 Ulrich Drepper <drepper@redhat.com> - - * readelf.c (print_shdr): Add support for SHF_ORDERED and SHF_EXCLUDE. - -2004-01-12 Ulrich Drepper <drepper@redhat.com> - - * readelf.c (print_debug_aranges): Implement using libdw. - -2004-01-11 Ulrich Drepper <drepper@redhat.com> - - * nm.c: Adjust for Dwarf_Files type and dwarf_lineno interface change. - - * readelf.c: Use libdw instead of libdwarf. Not all of the old - behavior is available yet. - * Makefile.am: Link readelf with libdw. Remove libdwarf include path. - -2004-01-09 Ulrich Drepper <drepper@redhat.com> - - * nm.c (get_local_names): Adjust call to dwarf_nextcu. - - * nm.c: Implement getting information about local variables. - -2004-01-07 Ulrich Drepper <drepper@redhat.com> - - * nm.c: Read also debug information for local symbols. - -2004-01-05 Ulrich Drepper <drepper@redhat.com> - - * nm.c: Shuffle dwarf handling code around so the maximum column - width can be computed ahead of printing. Avoid collection symbols - which are not printed anyway. - - * nm.c: Rewrite dwarf handling to use libdw. - * Makefile.am (AM_CFLAGS): Add -std parameter. - (INCLUDES): Find header in libdw subdir. - (nm_LDADD): Replace libdwarf with libdw. - - * elflint.c: Update copyright year. - * readelf.c: Likewise. - * size.c: Likewise. - * strip.c: Likewise. - * nm.c: Likewise. - -2003-12-31 Ulrich Drepper <drepper@redhat.com> - - * strip.c (process_file): Close file before returning. - -2003-11-19 Ulrich Drepper <drepper@redhat.com> - - * readelf.c (handle_dynamic): Make column for tag name wider. - -2003-09-29 Ulrich Drepper <drepper@redhat.com> - - * readelf.c (handle_dynamic): Always terminate tag name with a space. - -2003-09-25 Ulrich Drepper <drepper@redhat.com> - - * strip.c (process_file): Don't mmap the input file, we modify the - data structures and don't want the change end up on disk. - -2003-09-23 Jakub Jelinek <jakub@redhat.com> - - * unaligned.h (union u_2ubyte_unaligned, - union u_4ubyte_unaligned, union u_8ubyte_unaligned): Add - packed attribute. - (add_2ubyte_unaligned, add_4ubyte_unaligned, - add_8ubyte_unaligned): Avoid nesting bswap_NN macros. - Read/store value through _ptr->u instead of *_ptr. - -2003-09-22 Ulrich Drepper <drepper@redhat.com> - - * size.c (show_sysv): Change type of maxlen to int. - - * strip.c (handle_elf): Handle the 64-bit archs which is 64-bit - buckets. - - * i386_ld.c: Many many fixes and extensions. - * ld.c: Likewise. - * ldgeneric.c: Likewise. - -2003-08-16 Ulrich Drepper <drepper@redhat.com> - - * ldgeneric.c (check_definition): Don't add symbol on dso_list if - the reference is from another DSO. - -2003-08-15 Ulrich Drepper <drepper@redhat.com> - - * ldgeneric.c (find_entry_point): It is no fatal error if no entry - point is found when creating a DSO. - -2003-08-14 Ulrich Drepper <drepper@redhat.com> - - * ld.c (main): Always call FLAG_UNRESOLVED. - * ldgeneric.c (ld_generic_flag_unresolved): Only complain about - undefined symbols if not creating DSO or ld_state.nodefs is not set. - -2003-08-13 Ulrich Drepper <drepper@redhat.com> - - * Makefile.in: Depend on libebl.a, not libebl.so. - - * ld.c (main): Mark stream for linker script as locked by caller. - (read_version_script): Likewise. - * ldlex.c: Define fread and fwrite to _unlocked variant. - - * i386_ld.c (elf_i386_finalize_plt): Replace #ifdefs with uses of - target_bswap_32. - * unaligned.h: Define target_bswap_16, target_bswap_32, and - target_bswap_64. - (store_2ubyte_unaligned, store_4ubyte_unaligned, - store_8ubyte_unaligned): Define using new macros. - -2003-08-12 Ulrich Drepper <drepper@redhat.com> - - * i386_ld.c (elf_i386_finalize_plt): Use packed structs to access - possibly unaligned memory. Support use of big endian machines. - -2003-08-11 Ulrich Drepper <drepper@redhat.com> - - * Moved to CVS archive. diff --git a/src/Makefile b/src/Makefile deleted file mode 100644 index f147eee2..00000000 --- a/src/Makefile +++ /dev/null @@ -1,638 +0,0 @@ -# Makefile.in generated by automake 1.9.2 from Makefile.am. -# src/Makefile. Generated from Makefile.in by configure. - -# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004 Free Software Foundation, Inc. -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - - - - - -SOURCES = $(libld_elf_a_SOURCES) $(libld_elf_i386_pic_a_SOURCES) elflint.c $(ld_SOURCES) $(libld_elf_i386_so_SOURCES) nm.c readelf.c size.c strip.c - -srcdir = . -top_srcdir = .. - -pkgdatadir = $(datadir)/elfutils -pkglibdir = $(libdir)/elfutils -pkgincludedir = $(includedir)/elfutils -top_builddir = .. -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -INSTALL = /usr/bin/install -c -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = i686-pc-linux-gnu -host_triplet = i686-pc-linux-gnu -bin_PROGRAMS = readelf$(EXEEXT) nm$(EXEEXT) size$(EXEEXT) \ - strip$(EXEEXT) ld$(EXEEXT) elflint$(EXEEXT) -noinst_PROGRAMS = $(am__EXEEXT_1) -#am__append_1 = libld_elf.a -subdir = src -DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ - $(srcdir)/Makefile.in ChangeLog ldlex.c ldscript.c ylwrap -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ - $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = -LIBRARIES = $(noinst_LIBRARIES) -AR = ar -ARFLAGS = cru -libld_elf_a_AR = $(AR) $(ARFLAGS) -libld_elf_a_LIBADD = -am_libld_elf_a_OBJECTS = $(base_cpu)_ld.$(OBJEXT) -libld_elf_a_OBJECTS = $(am_libld_elf_a_OBJECTS) -libld_elf_i386_pic_a_AR = $(AR) $(ARFLAGS) -libld_elf_i386_pic_a_LIBADD = -libld_elf_i386_pic_a_OBJECTS = $(am_libld_elf_i386_pic_a_OBJECTS) -am__installdirs = "$(DESTDIR)$(bindir)" -binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) -am__EXEEXT_1 = libld_elf_i386.so$(EXEEXT) -PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) -elflint_SOURCES = elflint.c -elflint_OBJECTS = elflint.$(OBJEXT) -am__DEPENDENCIES_1 = ../libebl/libebl.a -am__DEPENDENCIES_2 = ../libelf/libelf.so -#am__DEPENDENCIES_2 = ../libelf/libelf.a -am__DEPENDENCIES_3 = ../lib/libeu.a -elflint_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \ - $(am__DEPENDENCIES_3) -am_ld_OBJECTS = ld.$(OBJEXT) ldgeneric.$(OBJEXT) ldlex.$(OBJEXT) \ - ldscript.$(OBJEXT) symbolhash.$(OBJEXT) sectionhash.$(OBJEXT) \ - versionhash.$(OBJEXT) -ld_OBJECTS = $(am_ld_OBJECTS) -#am__DEPENDENCIES_4 = libld_elf.a -ld_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \ - $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_4) -am_libld_elf_i386_so_OBJECTS = -libld_elf_i386_so_OBJECTS = $(am_libld_elf_i386_so_OBJECTS) -libld_elf_i386_so_LDADD = $(LDADD) -nm_SOURCES = nm.c -nm_OBJECTS = nm.$(OBJEXT) -am__DEPENDENCIES_5 = ../libdw/libdw.so -#am__DEPENDENCIES_5 = ../libdw/libdw.a -nm_DEPENDENCIES = $(am__DEPENDENCIES_5) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_3) -readelf_SOURCES = readelf.c -readelf_OBJECTS = readelf.$(OBJEXT) -readelf_DEPENDENCIES = $(am__DEPENDENCIES_5) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_3) -size_SOURCES = size.c -size_OBJECTS = size.$(OBJEXT) -size_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_3) -strip_SOURCES = strip.c -strip_OBJECTS = strip.$(OBJEXT) -strip_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \ - $(am__DEPENDENCIES_3) -DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -depcomp = $(SHELL) $(top_srcdir)/config/depcomp -am__depfiles_maybe = depfiles -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -CCLD = $(CC) -LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ -LEXCOMPILE = $(LEX) $(LFLAGS) $(AM_LFLAGS) -YACCCOMPILE = $(YACC) $(YFLAGS) $(AM_YFLAGS) -SOURCES = $(libld_elf_a_SOURCES) $(libld_elf_i386_pic_a_SOURCES) \ - elflint.c $(ld_SOURCES) $(libld_elf_i386_so_SOURCES) nm.c \ - readelf.c size.c strip.c -DIST_SOURCES = $(libld_elf_a_SOURCES) $(libld_elf_i386_pic_a_SOURCES) \ - elflint.c $(ld_SOURCES) $(libld_elf_i386_so_SOURCES) nm.c \ - readelf.c size.c strip.c -HEADERS = $(noinst_HEADERS) -ETAGS = etags -CTAGS = ctags -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = ${SHELL} /work/elfutils/stock/elfutils-0.97/config/missing --run aclocal-1.9 -AMDEP_FALSE = # -AMDEP_TRUE = -AMTAR = ${SHELL} /work/elfutils/stock/elfutils-0.97/config/missing --run tar -AUTOCONF = ${SHELL} /work/elfutils/stock/elfutils-0.97/config/missing --run autoconf -AUTOHEADER = ${SHELL} /work/elfutils/stock/elfutils-0.97/config/missing --run autoheader -AUTOMAKE = ${SHELL} /work/elfutils/stock/elfutils-0.97/config/missing --run automake-1.9 -AWK = gawk -CC = gcc -CCDEPMODE = depmode=gcc3 -CFLAGS = -g -O2 -CPP = gcc -E -CPPFLAGS = -CYGPATH_W = echo -DATADIRNAME = ${prefix}/share -DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H $(YYDEBUG) \ - -DSRCDIR=\"$(shell cd $(srcdir);pwd)\" -DOBJDIR=\"$(shell pwd)\" - -DEPDIR = .deps -ECHO_C = -ECHO_N = -n -ECHO_T = -EGREP = grep -E -EXEEXT = -GMSGFMT = /usr/bin/msgfmt -INSTALL_DATA = ${INSTALL} -m 644 -INSTALL_PROGRAM = ${INSTALL} -INSTALL_SCRIPT = ${INSTALL} -INSTALL_STRIP_PROGRAM = ${SHELL} $(install_sh) -c -s -INTLLIBS = -LDFLAGS = -LEX = flex -LEXLIB = -lfl -LEX_OUTPUT_ROOT = lex.yy -LIBICONV = -liconv -LIBINTL = -LIBOBJS = -LIBS = -LOCALEDIR = ${prefix}/share -LTLIBICONV = -liconv -LTLIBINTL = -LTLIBOBJS = -MAKEINFO = ${SHELL} /work/elfutils/stock/elfutils-0.97/config/missing --run makeinfo -MKINSTALLDIRS = config/mkinstalldirs -MSGFMT = /usr/bin/msgfmt -MSGMERGE = /usr/bin/msgmerge -MUDFLAP_FALSE = -MUDFLAP_TRUE = # -NATIVE_LD_FALSE = -NATIVE_LD_TRUE = # -OBJEXT = o -PACKAGE = elfutils -PACKAGE_BUGREPORT = http://bugzilla.redhat.com/bugzilla/ -PACKAGE_NAME = Red Hat elfutils -PACKAGE_STRING = Red Hat elfutils 0.97 -PACKAGE_TARNAME = elfutils -PACKAGE_VERSION = 0.97 -PATH_SEPARATOR = : -POSUB = po -RANLIB = ranlib -SET_MAKE = -SHELL = /bin/sh -STRIP = -USE_NLS = yes -VERSION = 0.97 -XGETTEXT = /usr/bin/xgettext -YACC = bison -y -d -ac_ct_CC = gcc -ac_ct_RANLIB = ranlib -ac_ct_STRIP = -am__fastdepCC_FALSE = # -am__fastdepCC_TRUE = -am__include = include -am__leading_dot = . -am__quote = -am__tar = ${AMTAR} chof - "$$tardir" -am__untar = ${AMTAR} xf - -base_cpu = none -bindir = ${exec_prefix}/bin -build = i686-pc-linux-gnu -build_alias = -build_cpu = i686 -build_os = linux-gnu -build_vendor = pc -datadir = ${prefix}/share -exec_prefix = ${prefix} -host = i686-pc-linux-gnu -host_alias = -host_cpu = i686 -host_os = linux-gnu -host_vendor = pc -includedir = ${prefix}/include -infodir = ${prefix}/info -install_sh = /work/elfutils/stock/elfutils-0.97/config/install-sh -libdir = ${exec_prefix}/lib -libexecdir = ${exec_prefix}/libexec -localstatedir = ${prefix}/var -mandir = ${prefix}/man -mkdir_p = mkdir -p -- -oldincludedir = /usr/include -prefix = /work/elfutils/google/linux-install-elfutils-0.97/ -program_transform_name = s,x,x, -sbindir = ${exec_prefix}/sbin -sharedstatedir = ${prefix}/com -sysconfdir = ${prefix}/etc -target_alias = -AM_CFLAGS = -Wall -Wshadow -std=gnu99 \ - $(if $($(*F)_no_Werror),,-Werror) $(native_ld_cflags) - -#AM_CFLAGS = -Wall -Wshadow -std=gnu99 \ -# $(native_ld_cflags) - -#AM_LDFLAGS = -fmudflap -INCLUDES = -I$(srcdir) -I$(srcdir)/../libelf -I$(srcdir)/../libebl -I$(srcdir)/../lib -I$(srcdir)/../libdw -I.. -AM_YFLAGS = -pld -AM_LFLAGS = -Pld -olex.yy.c -native_ld = @native_ld@ -ld_dsos = libld_elf_i386_pic.a -noinst_LIBRARIES = libld_elf.a $(ld_dsos) -#noinst_LIBRARIES = libld_elf.a -#native_ld_cflags = -DBASE_ELF_NAME=elf_$(base_cpu) -ld_SOURCES = ld.c ldgeneric.c ldlex.l ldscript.y symbolhash.c sectionhash.c \ - versionhash.c - -noinst_HEADERS = ld.h symbolhash.h sectionhash.h versionhash.h \ - ldscript.h xelf.h unaligned.h - -EXTRA_DIST = elf32-i386.script libld_elf_i386.map $(ld_modules) -ld_modules = i386_ld.c -libdw = ../libdw/libdw.so -#libdw = ../libdw/libdw.a -libelf = ../libelf/libelf.so -#libelf = ../libelf/libelf.a -libebl = ../libebl/libebl.a -libeu = ../lib/libeu.a -readelf_LDADD = $(libdw) $(libebl) $(libelf) $(libeu) -ldl -nm_LDADD = $(libdw) $(libebl) $(libelf) $(libeu) -ldl -size_LDADD = $(libelf) $(libeu) -strip_LDADD = $(libebl) $(libelf) $(libeu) -ldl -ld_LDADD = $(libebl) $(libelf) $(libeu) -ldl $(am__append_1) -ld_LDFLAGS = -rdynamic -elflint_LDADD = $(libebl) $(libelf) $(libeu) -ldl -ldlex_no_Werror = yes - -# Machine-specific linker code. -libld_elf_a_SOURCES = $(base_cpu)_ld.c -libld_elf_i386_pic_a_SOURCES = -am_libld_elf_i386_pic_a_OBJECTS = i386_ld.os -libld_elf_i386_so_SOURCES = -CLEANFILES = none_ld.os $(ld_modules:.c=.os) -all: all-am - -.SUFFIXES: -.SUFFIXES: .c .l .o .obj .y -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ - && exit 0; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits src/Makefile'; \ - cd $(top_srcdir) && \ - $(AUTOMAKE) --gnits src/Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -clean-noinstLIBRARIES: - -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) -libld_elf.a: $(libld_elf_a_OBJECTS) $(libld_elf_a_DEPENDENCIES) - -rm -f libld_elf.a - $(libld_elf_a_AR) libld_elf.a $(libld_elf_a_OBJECTS) $(libld_elf_a_LIBADD) - $(RANLIB) libld_elf.a -libld_elf_i386_pic.a: $(libld_elf_i386_pic_a_OBJECTS) $(libld_elf_i386_pic_a_DEPENDENCIES) - -rm -f libld_elf_i386_pic.a - $(libld_elf_i386_pic_a_AR) libld_elf_i386_pic.a $(libld_elf_i386_pic_a_OBJECTS) $(libld_elf_i386_pic_a_LIBADD) - $(RANLIB) libld_elf_i386_pic.a -install-binPROGRAMS: $(bin_PROGRAMS) - @$(NORMAL_INSTALL) - test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)" - @list='$(bin_PROGRAMS)'; for p in $$list; do \ - p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ - if test -f $$p \ - ; then \ - f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ - echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ - $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ - else :; fi; \ - done - -uninstall-binPROGRAMS: - @$(NORMAL_UNINSTALL) - @list='$(bin_PROGRAMS)'; for p in $$list; do \ - f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ - echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ - rm -f "$(DESTDIR)$(bindir)/$$f"; \ - done - -clean-binPROGRAMS: - -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) - -clean-noinstPROGRAMS: - -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) -elflint$(EXEEXT): $(elflint_OBJECTS) $(elflint_DEPENDENCIES) - @rm -f elflint$(EXEEXT) - $(LINK) $(elflint_LDFLAGS) $(elflint_OBJECTS) $(elflint_LDADD) $(LIBS) -ld$(EXEEXT): $(ld_OBJECTS) $(ld_DEPENDENCIES) - @rm -f ld$(EXEEXT) - $(LINK) $(ld_LDFLAGS) $(ld_OBJECTS) $(ld_LDADD) $(LIBS) -nm$(EXEEXT): $(nm_OBJECTS) $(nm_DEPENDENCIES) - @rm -f nm$(EXEEXT) - $(LINK) $(nm_LDFLAGS) $(nm_OBJECTS) $(nm_LDADD) $(LIBS) -readelf$(EXEEXT): $(readelf_OBJECTS) $(readelf_DEPENDENCIES) - @rm -f readelf$(EXEEXT) - $(LINK) $(readelf_LDFLAGS) $(readelf_OBJECTS) $(readelf_LDADD) $(LIBS) -size$(EXEEXT): $(size_OBJECTS) $(size_DEPENDENCIES) - @rm -f size$(EXEEXT) - $(LINK) $(size_LDFLAGS) $(size_OBJECTS) $(size_LDADD) $(LIBS) -strip$(EXEEXT): $(strip_OBJECTS) $(strip_DEPENDENCIES) - @rm -f strip$(EXEEXT) - $(LINK) $(strip_LDFLAGS) $(strip_OBJECTS) $(strip_LDADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -include ./$(DEPDIR)/$(base_cpu)_ld.Po -include ./$(DEPDIR)/elflint.Po -include ./$(DEPDIR)/ld.Po -include ./$(DEPDIR)/ldgeneric.Po -include ./$(DEPDIR)/ldlex.Po -include ./$(DEPDIR)/ldscript.Po -include ./$(DEPDIR)/nm.Po -include ./$(DEPDIR)/readelf.Po -include ./$(DEPDIR)/sectionhash.Po -include ./$(DEPDIR)/size.Po -include ./$(DEPDIR)/strip.Po -include ./$(DEPDIR)/symbolhash.Po -include ./$(DEPDIR)/versionhash.Po - -.c.o: - if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ - then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi -# source='$<' object='$@' libtool=no \ -# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ -# $(COMPILE) -c $< - -.c.obj: - if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ - then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi -# source='$<' object='$@' libtool=no \ -# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ -# $(COMPILE) -c `$(CYGPATH_W) '$<'` - -.l.c: - $(LEXCOMPILE) $< - sed '/^#/ s|$(LEX_OUTPUT_ROOT)\.c|$@|' $(LEX_OUTPUT_ROOT).c >$@ - rm -f $(LEX_OUTPUT_ROOT).c - -.y.c: - $(YACCCOMPILE) $< - if test -f y.tab.h; then \ - to=`echo "$*_H" | sed \ - -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \ - -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'`; \ - sed -e "/^#/!b" -e "s/Y_TAB_H/$$to/g" -e "s|y\.tab\.h|$*.h|" \ - y.tab.h >$*.ht; \ - rm -f y.tab.h; \ - if cmp -s $*.ht $*.h; then \ - rm -f $*.ht ;\ - else \ - mv $*.ht $*.h; \ - fi; \ - fi - if test -f y.output; then \ - mv y.output $*.output; \ - fi - sed '/^#/ s|y\.tab\.c|$@|' y.tab.c >$@t && mv $@t $@ - rm -f y.tab.c -uninstall-info-am: - -ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - mkid -fID $$unique -tags: TAGS - -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - tags=; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$tags $$unique; \ - fi -ctags: CTAGS -CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - tags=; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - test -z "$(CTAGS_ARGS)$$tags$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$tags $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && cd $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) $$here - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ - list='$(DISTFILES)'; for file in $$list; do \ - case $$file in \ - $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ - $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ - esac; \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test "$$dir" != "$$file" && test "$$dir" != "."; then \ - dir="/$$dir"; \ - $(mkdir_p) "$(distdir)$$dir"; \ - else \ - dir=''; \ - fi; \ - if test -d $$d/$$file; then \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ - fi; \ - cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ - else \ - test -f $(distdir)/$$file \ - || cp -p $$d/$$file $(distdir)/$$file \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-am -all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(HEADERS) -installdirs: - for dir in "$(DESTDIR)$(bindir)"; do \ - test -z "$$dir" || $(mkdir_p) "$$dir"; \ - done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - `test -z '$(STRIP)' || \ - echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install -mostlyclean-generic: - -clean-generic: - -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." - -rm -f ldlex.c - -rm -f ldscript.c -clean: clean-am - -clean-am: clean-binPROGRAMS clean-generic clean-noinstLIBRARIES \ - clean-noinstPROGRAMS mostlyclean-am - -distclean: distclean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -info: info-am - -info-am: - -install-data-am: - -install-exec-am: install-binPROGRAMS - -install-info: install-info-am - -install-man: - -installcheck-am: installcheck-binPROGRAMS - -maintainer-clean: maintainer-clean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-compile mostlyclean-generic - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-binPROGRAMS uninstall-info-am - -.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ - clean-generic clean-noinstLIBRARIES clean-noinstPROGRAMS ctags \ - distclean distclean-compile distclean-generic distclean-tags \ - distdir dvi dvi-am html html-am info info-am install \ - install-am install-binPROGRAMS install-data install-data-am \ - install-exec install-exec-am install-info install-info-am \ - install-man install-strip installcheck installcheck-am \ - installcheck-binPROGRAMS installdirs maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-compile \ - mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ - uninstall-am uninstall-binPROGRAMS uninstall-info-am - - -ldlex.o: ldscript.c -ldscript.h: ldscript.c -libld_elf_i386.so: libld_elf_i386_pic.a libld_elf_i386.map - $(CC) -shared -o $@ -Wl,--whole-archive,$<,--no-whole-archive \ - $(libelf) $(libeu) \ - -Wl,--version-script,$(srcdir)/libld_elf_i386.map - -%.os: %.c %.o - if $(filter-out -fmudflap,$(COMPILE)) -c -o $@ -fpic -DPIC -DSHARED \ - -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ - `test -f '$<' || echo '$(srcdir)/'`$<; \ - then cat "$(DEPDIR)/$*.Tpo" >> "$(DEPDIR)/$*.Po"; \ - rm -f "$(DEPDIR)/$*.Tpo"; \ - else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ - fi - -# 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=0; pid=$$$$; list="$(bin_PROGRAMS)"; for p in $$list; do \ - case ' $(AM_INSTALLCHECK_STD_OPTIONS_EXEMPT) ' in \ - *" $$p "* | *" $(srcdir)/$$p "*) continue;; \ - esac; \ - f=`echo "$$p" | \ - sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ - for opt in --help --version; do \ - if LD_LIBRARY_PATH=$(DESTDIR)$(libdir) \ - $(DESTDIR)$(bindir)/$$f $$opt > c$${pid}_.out 2> c$${pid}_.err \ - && test -n "`cat c$${pid}_.out`" \ - && test -z "`cat c$${pid}_.err`"; then :; \ - else echo "$$f does not support $$opt" 1>&2; bad=1; fi; \ - done; \ - done; rm -f c$${pid}_.???; exit $$bad -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/src/Makefile.am b/src/Makefile.am deleted file mode 100644 index 7b957eb5..00000000 --- a/src/Makefile.am +++ /dev/null @@ -1,130 +0,0 @@ -## Process this file with automake to create Makefile.in -## Configure input file for elfutils. -## -## Copyright (C) 1996-2002, 2003, 2004 Red Hat, Inc. -## -## This program is Open Source software; you can redistribute it and/or -## modify it under the terms of the Open Software License version 1.0 as -## published by the Open Source Initiative. -## -## You should have received a copy of the Open Software License along -## with this program; if not, you may obtain a copy of the Open Software -## License version 1.0 from http://www.opensource.org/licenses/osl.php or -## by writing the Open Source Initiative c/o Lawrence Rosen, Esq., -## 3001 King Ranch Road, Ukiah, CA 95482. -## -DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H $(YYDEBUG) \ - -DSRCDIR=\"$(shell cd $(srcdir);pwd)\" -DOBJDIR=\"$(shell pwd)\" -if MUDFLAP -AM_CFLAGS = -Wall -Wshadow -std=gnu99 \ - $(native_ld_cflags) -else -AM_CFLAGS = -Wall -Wshadow -std=gnu99 \ - $(if $($(*F)_no_Werror),,-Werror) $(native_ld_cflags) -endif -if MUDFLAP -AM_LDFLAGS = -fmudflap -endif -INCLUDES = -I$(srcdir) -I$(srcdir)/../libelf -I$(srcdir)/../libebl -I$(srcdir)/../lib -I$(srcdir)/../libdw -I.. - -YACC = @YACC@ -d -AM_YFLAGS = -pld -AM_LFLAGS = -Pld -olex.yy.c -## Uncomment to enable debugging of linker script parser -##YYDEBUG = -DYYDEBUG=1 - -native_ld = @native_ld@ -base_cpu = @base_cpu@ - -bin_PROGRAMS = readelf nm size strip ld elflint - - -ld_dsos = libld_elf_i386_pic.a -if NATIVE_LD -noinst_LIBRARIES = libld_elf.a -native_ld_cflags = -DBASE_ELF_NAME=elf_$(base_cpu) -else -noinst_LIBRARIES = libld_elf.a $(ld_dsos) -noinst_PROGRAMS = $(ld_dsos:_pic.a=.so) -endif - - -ld_SOURCES = ld.c ldgeneric.c ldlex.l ldscript.y symbolhash.c sectionhash.c \ - versionhash.c - -noinst_HEADERS = ld.h symbolhash.h sectionhash.h versionhash.h \ - ldscript.h xelf.h unaligned.h - -EXTRA_DIST = elf32-i386.script libld_elf_i386.map $(ld_modules) -ld_modules = i386_ld.c - -if MUDFLAP -libdw = ../libdw/libdw.a -libelf = ../libelf/libelf.a -else -libdw = ../libdw/libdw.so -libelf = ../libelf/libelf.so -endif -libebl = ../libebl/libebl.a -libeu = ../lib/libeu.a - -readelf_LDADD = $(libdw) $(libebl) $(libelf) $(libeu) -ldl -nm_LDADD = $(libdw) $(libebl) $(libelf) $(libeu) -ldl -size_LDADD = $(libelf) $(libeu) -strip_LDADD = $(libebl) $(libelf) $(libeu) -ldl -ld_LDADD = $(libebl) $(libelf) $(libeu) -ldl -if NATIVE_LD -ld_LDADD += libld_elf.a -endif -ld_LDFLAGS = -rdynamic -elflint_LDADD = $(libebl) $(libelf) $(libeu) -ldl - -ldlex.o: ldscript.c -ldlex_no_Werror = yes -ldscript.h: ldscript.c - -# Machine-specific linker code. -libld_elf_a_SOURCES = $(base_cpu)_ld.c - -libld_elf_i386_pic_a_SOURCES = -am_libld_elf_i386_pic_a_OBJECTS = i386_ld.os - -libld_elf_i386_so_SOURCES = -libld_elf_i386.so: libld_elf_i386_pic.a libld_elf_i386.map - $(CC) -shared -o $@ -Wl,--whole-archive,$<,--no-whole-archive \ - $(libelf) $(libeu) \ - -Wl,--version-script,$(srcdir)/libld_elf_i386.map - - -%.os: %.c %.o - if $(filter-out -fmudflap,$(COMPILE)) -c -o $@ -fpic -DPIC -DSHARED \ - -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ - `test -f '$<' || echo '$(srcdir)/'`$<; \ - then cat "$(DEPDIR)/$*.Tpo" >> "$(DEPDIR)/$*.Po"; \ - rm -f "$(DEPDIR)/$*.Tpo"; \ - else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ - fi - -# 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=0; pid=$$$$; list="$(bin_PROGRAMS)"; for p in $$list; do \ - case ' $(AM_INSTALLCHECK_STD_OPTIONS_EXEMPT) ' in \ - *" $$p "* | *" $(srcdir)/$$p "*) continue;; \ - esac; \ - f=`echo "$$p" | \ - sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ - for opt in --help --version; do \ - if LD_LIBRARY_PATH=$(DESTDIR)$(libdir) \ - $(DESTDIR)$(bindir)/$$f $$opt > c$${pid}_.out 2> c$${pid}_.err \ - && test -n "`cat c$${pid}_.out`" \ - && test -z "`cat c$${pid}_.err`"; then :; \ - else echo "$$f does not support $$opt" 1>&2; bad=1; fi; \ - done; \ - done; rm -f c$${pid}_.???; exit $$bad - -CLEANFILES = none_ld.os $(ld_modules:.c=.os) diff --git a/src/Makefile.in b/src/Makefile.in deleted file mode 100644 index 0eb72237..00000000 --- a/src/Makefile.in +++ /dev/null @@ -1,638 +0,0 @@ -# Makefile.in generated by automake 1.9.2 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004 Free Software Foundation, Inc. -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - - - -SOURCES = $(libld_elf_a_SOURCES) $(libld_elf_i386_pic_a_SOURCES) elflint.c $(ld_SOURCES) $(libld_elf_i386_so_SOURCES) nm.c readelf.c size.c strip.c - -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ -VPATH = @srcdir@ -pkgdatadir = $(datadir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -top_builddir = .. -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -INSTALL = @INSTALL@ -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -bin_PROGRAMS = readelf$(EXEEXT) nm$(EXEEXT) size$(EXEEXT) \ - strip$(EXEEXT) ld$(EXEEXT) elflint$(EXEEXT) -@NATIVE_LD_FALSE@noinst_PROGRAMS = $(am__EXEEXT_1) -@NATIVE_LD_TRUE@am__append_1 = libld_elf.a -subdir = src -DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ - $(srcdir)/Makefile.in ChangeLog ldlex.c ldscript.c ylwrap -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ - $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = -LIBRARIES = $(noinst_LIBRARIES) -AR = ar -ARFLAGS = cru -libld_elf_a_AR = $(AR) $(ARFLAGS) -libld_elf_a_LIBADD = -am_libld_elf_a_OBJECTS = $(base_cpu)_ld.$(OBJEXT) -libld_elf_a_OBJECTS = $(am_libld_elf_a_OBJECTS) -libld_elf_i386_pic_a_AR = $(AR) $(ARFLAGS) -libld_elf_i386_pic_a_LIBADD = -libld_elf_i386_pic_a_OBJECTS = $(am_libld_elf_i386_pic_a_OBJECTS) -am__installdirs = "$(DESTDIR)$(bindir)" -binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) -am__EXEEXT_1 = libld_elf_i386.so$(EXEEXT) -PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) -elflint_SOURCES = elflint.c -elflint_OBJECTS = elflint.$(OBJEXT) -am__DEPENDENCIES_1 = ../libebl/libebl.a -@MUDFLAP_FALSE@am__DEPENDENCIES_2 = ../libelf/libelf.so -@MUDFLAP_TRUE@am__DEPENDENCIES_2 = ../libelf/libelf.a -am__DEPENDENCIES_3 = ../lib/libeu.a -elflint_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \ - $(am__DEPENDENCIES_3) -am_ld_OBJECTS = ld.$(OBJEXT) ldgeneric.$(OBJEXT) ldlex.$(OBJEXT) \ - ldscript.$(OBJEXT) symbolhash.$(OBJEXT) sectionhash.$(OBJEXT) \ - versionhash.$(OBJEXT) -ld_OBJECTS = $(am_ld_OBJECTS) -@NATIVE_LD_TRUE@am__DEPENDENCIES_4 = libld_elf.a -ld_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \ - $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_4) -am_libld_elf_i386_so_OBJECTS = -libld_elf_i386_so_OBJECTS = $(am_libld_elf_i386_so_OBJECTS) -libld_elf_i386_so_LDADD = $(LDADD) -nm_SOURCES = nm.c -nm_OBJECTS = nm.$(OBJEXT) -@MUDFLAP_FALSE@am__DEPENDENCIES_5 = ../libdw/libdw.so -@MUDFLAP_TRUE@am__DEPENDENCIES_5 = ../libdw/libdw.a -nm_DEPENDENCIES = $(am__DEPENDENCIES_5) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_3) -readelf_SOURCES = readelf.c -readelf_OBJECTS = readelf.$(OBJEXT) -readelf_DEPENDENCIES = $(am__DEPENDENCIES_5) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_3) -size_SOURCES = size.c -size_OBJECTS = size.$(OBJEXT) -size_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_3) -strip_SOURCES = strip.c -strip_OBJECTS = strip.$(OBJEXT) -strip_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \ - $(am__DEPENDENCIES_3) -DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -depcomp = $(SHELL) $(top_srcdir)/config/depcomp -am__depfiles_maybe = depfiles -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -CCLD = $(CC) -LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ -LEXCOMPILE = $(LEX) $(LFLAGS) $(AM_LFLAGS) -YACCCOMPILE = $(YACC) $(YFLAGS) $(AM_YFLAGS) -SOURCES = $(libld_elf_a_SOURCES) $(libld_elf_i386_pic_a_SOURCES) \ - elflint.c $(ld_SOURCES) $(libld_elf_i386_so_SOURCES) nm.c \ - readelf.c size.c strip.c -DIST_SOURCES = $(libld_elf_a_SOURCES) $(libld_elf_i386_pic_a_SOURCES) \ - elflint.c $(ld_SOURCES) $(libld_elf_i386_so_SOURCES) nm.c \ - readelf.c size.c strip.c -HEADERS = $(noinst_HEADERS) -ETAGS = etags -CTAGS = ctags -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -AMDEP_FALSE = @AMDEP_FALSE@ -AMDEP_TRUE = @AMDEP_TRUE@ -AMTAR = @AMTAR@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -CC = @CC@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DATADIRNAME = @DATADIRNAME@ -DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H $(YYDEBUG) \ - -DSRCDIR=\"$(shell cd $(srcdir);pwd)\" -DOBJDIR=\"$(shell pwd)\" - -DEPDIR = @DEPDIR@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -EXEEXT = @EXEEXT@ -GMSGFMT = @GMSGFMT@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -INTLLIBS = @INTLLIBS@ -LDFLAGS = @LDFLAGS@ -LEX = @LEX@ -LEXLIB = @LEXLIB@ -LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ -LIBICONV = @LIBICONV@ -LIBINTL = @LIBINTL@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LOCALEDIR = @LOCALEDIR@ -LTLIBICONV = @LTLIBICONV@ -LTLIBINTL = @LTLIBINTL@ -LTLIBOBJS = @LTLIBOBJS@ -MAKEINFO = @MAKEINFO@ -MKINSTALLDIRS = @MKINSTALLDIRS@ -MSGFMT = @MSGFMT@ -MSGMERGE = @MSGMERGE@ -MUDFLAP_FALSE = @MUDFLAP_FALSE@ -MUDFLAP_TRUE = @MUDFLAP_TRUE@ -NATIVE_LD_FALSE = @NATIVE_LD_FALSE@ -NATIVE_LD_TRUE = @NATIVE_LD_TRUE@ -OBJEXT = @OBJEXT@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -POSUB = @POSUB@ -RANLIB = @RANLIB@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -STRIP = @STRIP@ -USE_NLS = @USE_NLS@ -VERSION = @VERSION@ -XGETTEXT = @XGETTEXT@ -YACC = @YACC@ -d -ac_ct_CC = @ac_ct_CC@ -ac_ct_RANLIB = @ac_ct_RANLIB@ -ac_ct_STRIP = @ac_ct_STRIP@ -am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ -am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -base_cpu = @base_cpu@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -datadir = @datadir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -oldincludedir = @oldincludedir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -sysconfdir = @sysconfdir@ -target_alias = @target_alias@ -@MUDFLAP_FALSE@AM_CFLAGS = -Wall -Wshadow -std=gnu99 \ -@MUDFLAP_FALSE@ $(if $($(*F)_no_Werror),,-Werror) $(native_ld_cflags) - -@MUDFLAP_TRUE@AM_CFLAGS = -Wall -Wshadow -std=gnu99 \ -@MUDFLAP_TRUE@ $(native_ld_cflags) - -@MUDFLAP_TRUE@AM_LDFLAGS = -fmudflap -INCLUDES = -I$(srcdir) -I$(srcdir)/../libelf -I$(srcdir)/../libebl -I$(srcdir)/../lib -I$(srcdir)/../libdw -I.. -AM_YFLAGS = -pld -AM_LFLAGS = -Pld -olex.yy.c -native_ld = @native_ld@ -ld_dsos = libld_elf_i386_pic.a -@NATIVE_LD_FALSE@noinst_LIBRARIES = libld_elf.a $(ld_dsos) -@NATIVE_LD_TRUE@noinst_LIBRARIES = libld_elf.a -@NATIVE_LD_TRUE@native_ld_cflags = -DBASE_ELF_NAME=elf_$(base_cpu) -ld_SOURCES = ld.c ldgeneric.c ldlex.l ldscript.y symbolhash.c sectionhash.c \ - versionhash.c - -noinst_HEADERS = ld.h symbolhash.h sectionhash.h versionhash.h \ - ldscript.h xelf.h unaligned.h - -EXTRA_DIST = elf32-i386.script libld_elf_i386.map $(ld_modules) -ld_modules = i386_ld.c -@MUDFLAP_FALSE@libdw = ../libdw/libdw.so -@MUDFLAP_TRUE@libdw = ../libdw/libdw.a -@MUDFLAP_FALSE@libelf = ../libelf/libelf.so -@MUDFLAP_TRUE@libelf = ../libelf/libelf.a -libebl = ../libebl/libebl.a -libeu = ../lib/libeu.a -readelf_LDADD = $(libdw) $(libebl) $(libelf) $(libeu) -ldl -nm_LDADD = $(libdw) $(libebl) $(libelf) $(libeu) -ldl -size_LDADD = $(libelf) $(libeu) -strip_LDADD = $(libebl) $(libelf) $(libeu) -ldl -ld_LDADD = $(libebl) $(libelf) $(libeu) -ldl $(am__append_1) -ld_LDFLAGS = -rdynamic -elflint_LDADD = $(libebl) $(libelf) $(libeu) -ldl -ldlex_no_Werror = yes - -# Machine-specific linker code. -libld_elf_a_SOURCES = $(base_cpu)_ld.c -libld_elf_i386_pic_a_SOURCES = -am_libld_elf_i386_pic_a_OBJECTS = i386_ld.os -libld_elf_i386_so_SOURCES = -CLEANFILES = none_ld.os $(ld_modules:.c=.os) -all: all-am - -.SUFFIXES: -.SUFFIXES: .c .l .o .obj .y -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ - && exit 0; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits src/Makefile'; \ - cd $(top_srcdir) && \ - $(AUTOMAKE) --gnits src/Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -clean-noinstLIBRARIES: - -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) -libld_elf.a: $(libld_elf_a_OBJECTS) $(libld_elf_a_DEPENDENCIES) - -rm -f libld_elf.a - $(libld_elf_a_AR) libld_elf.a $(libld_elf_a_OBJECTS) $(libld_elf_a_LIBADD) - $(RANLIB) libld_elf.a -libld_elf_i386_pic.a: $(libld_elf_i386_pic_a_OBJECTS) $(libld_elf_i386_pic_a_DEPENDENCIES) - -rm -f libld_elf_i386_pic.a - $(libld_elf_i386_pic_a_AR) libld_elf_i386_pic.a $(libld_elf_i386_pic_a_OBJECTS) $(libld_elf_i386_pic_a_LIBADD) - $(RANLIB) libld_elf_i386_pic.a -install-binPROGRAMS: $(bin_PROGRAMS) - @$(NORMAL_INSTALL) - test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)" - @list='$(bin_PROGRAMS)'; for p in $$list; do \ - p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ - if test -f $$p \ - ; then \ - f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ - echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ - $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ - else :; fi; \ - done - -uninstall-binPROGRAMS: - @$(NORMAL_UNINSTALL) - @list='$(bin_PROGRAMS)'; for p in $$list; do \ - f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ - echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ - rm -f "$(DESTDIR)$(bindir)/$$f"; \ - done - -clean-binPROGRAMS: - -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) - -clean-noinstPROGRAMS: - -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) -elflint$(EXEEXT): $(elflint_OBJECTS) $(elflint_DEPENDENCIES) - @rm -f elflint$(EXEEXT) - $(LINK) $(elflint_LDFLAGS) $(elflint_OBJECTS) $(elflint_LDADD) $(LIBS) -ld$(EXEEXT): $(ld_OBJECTS) $(ld_DEPENDENCIES) - @rm -f ld$(EXEEXT) - $(LINK) $(ld_LDFLAGS) $(ld_OBJECTS) $(ld_LDADD) $(LIBS) -nm$(EXEEXT): $(nm_OBJECTS) $(nm_DEPENDENCIES) - @rm -f nm$(EXEEXT) - $(LINK) $(nm_LDFLAGS) $(nm_OBJECTS) $(nm_LDADD) $(LIBS) -readelf$(EXEEXT): $(readelf_OBJECTS) $(readelf_DEPENDENCIES) - @rm -f readelf$(EXEEXT) - $(LINK) $(readelf_LDFLAGS) $(readelf_OBJECTS) $(readelf_LDADD) $(LIBS) -size$(EXEEXT): $(size_OBJECTS) $(size_DEPENDENCIES) - @rm -f size$(EXEEXT) - $(LINK) $(size_LDFLAGS) $(size_OBJECTS) $(size_LDADD) $(LIBS) -strip$(EXEEXT): $(strip_OBJECTS) $(strip_DEPENDENCIES) - @rm -f strip$(EXEEXT) - $(LINK) $(strip_LDFLAGS) $(strip_OBJECTS) $(strip_LDADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/$(base_cpu)_ld.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elflint.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ld.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldgeneric.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldlex.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldscript.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readelf.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sectionhash.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/size.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strip.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/symbolhash.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/versionhash.Po@am__quote@ - -.c.o: -@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c $< - -.c.obj: -@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` - -.l.c: - $(LEXCOMPILE) $< - sed '/^#/ s|$(LEX_OUTPUT_ROOT)\.c|$@|' $(LEX_OUTPUT_ROOT).c >$@ - rm -f $(LEX_OUTPUT_ROOT).c - -.y.c: - $(YACCCOMPILE) $< - if test -f y.tab.h; then \ - to=`echo "$*_H" | sed \ - -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \ - -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'`; \ - sed -e "/^#/!b" -e "s/Y_TAB_H/$$to/g" -e "s|y\.tab\.h|$*.h|" \ - y.tab.h >$*.ht; \ - rm -f y.tab.h; \ - if cmp -s $*.ht $*.h; then \ - rm -f $*.ht ;\ - else \ - mv $*.ht $*.h; \ - fi; \ - fi - if test -f y.output; then \ - mv y.output $*.output; \ - fi - sed '/^#/ s|y\.tab\.c|$@|' y.tab.c >$@t && mv $@t $@ - rm -f y.tab.c -uninstall-info-am: - -ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - mkid -fID $$unique -tags: TAGS - -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - tags=; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$tags $$unique; \ - fi -ctags: CTAGS -CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - tags=; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - test -z "$(CTAGS_ARGS)$$tags$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$tags $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && cd $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) $$here - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ - list='$(DISTFILES)'; for file in $$list; do \ - case $$file in \ - $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ - $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ - esac; \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test "$$dir" != "$$file" && test "$$dir" != "."; then \ - dir="/$$dir"; \ - $(mkdir_p) "$(distdir)$$dir"; \ - else \ - dir=''; \ - fi; \ - if test -d $$d/$$file; then \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ - fi; \ - cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ - else \ - test -f $(distdir)/$$file \ - || cp -p $$d/$$file $(distdir)/$$file \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-am -all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(HEADERS) -installdirs: - for dir in "$(DESTDIR)$(bindir)"; do \ - test -z "$$dir" || $(mkdir_p) "$$dir"; \ - done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - `test -z '$(STRIP)' || \ - echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install -mostlyclean-generic: - -clean-generic: - -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." - -rm -f ldlex.c - -rm -f ldscript.c -clean: clean-am - -clean-am: clean-binPROGRAMS clean-generic clean-noinstLIBRARIES \ - clean-noinstPROGRAMS mostlyclean-am - -distclean: distclean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -info: info-am - -info-am: - -install-data-am: - -install-exec-am: install-binPROGRAMS - -install-info: install-info-am - -install-man: - -installcheck-am: installcheck-binPROGRAMS - -maintainer-clean: maintainer-clean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-compile mostlyclean-generic - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-binPROGRAMS uninstall-info-am - -.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ - clean-generic clean-noinstLIBRARIES clean-noinstPROGRAMS ctags \ - distclean distclean-compile distclean-generic distclean-tags \ - distdir dvi dvi-am html html-am info info-am install \ - install-am install-binPROGRAMS install-data install-data-am \ - install-exec install-exec-am install-info install-info-am \ - install-man install-strip installcheck installcheck-am \ - installcheck-binPROGRAMS installdirs maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-compile \ - mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ - uninstall-am uninstall-binPROGRAMS uninstall-info-am - - -ldlex.o: ldscript.c -ldscript.h: ldscript.c -libld_elf_i386.so: libld_elf_i386_pic.a libld_elf_i386.map - $(CC) -shared -o $@ -Wl,--whole-archive,$<,--no-whole-archive \ - $(libelf) $(libeu) \ - -Wl,--version-script,$(srcdir)/libld_elf_i386.map - -%.os: %.c %.o - if $(filter-out -fmudflap,$(COMPILE)) -c -o $@ -fpic -DPIC -DSHARED \ - -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ - `test -f '$<' || echo '$(srcdir)/'`$<; \ - then cat "$(DEPDIR)/$*.Tpo" >> "$(DEPDIR)/$*.Po"; \ - rm -f "$(DEPDIR)/$*.Tpo"; \ - else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ - fi - -# 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=0; pid=$$$$; list="$(bin_PROGRAMS)"; for p in $$list; do \ - case ' $(AM_INSTALLCHECK_STD_OPTIONS_EXEMPT) ' in \ - *" $$p "* | *" $(srcdir)/$$p "*) continue;; \ - esac; \ - f=`echo "$$p" | \ - sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ - for opt in --help --version; do \ - if LD_LIBRARY_PATH=$(DESTDIR)$(libdir) \ - $(DESTDIR)$(bindir)/$$f $$opt > c$${pid}_.out 2> c$${pid}_.err \ - && test -n "`cat c$${pid}_.out`" \ - && test -z "`cat c$${pid}_.err`"; then :; \ - else echo "$$f does not support $$opt" 1>&2; bad=1; fi; \ - done; \ - done; rm -f c$${pid}_.???; exit $$bad -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/src/elf32-i386.script b/src/elf32-i386.script deleted file mode 100644 index d62333ac..00000000 --- a/src/elf32-i386.script +++ /dev/null @@ -1,215 +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 - . = SIZEOF_HEADERS; -#else - . = 0x08048000 + SIZEOF_HEADERS; -#endif - - .interp; - .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 = .); - PROVIDE (_etext = .); - PROVIDE (etext = .); - .rodata - { - *(.rodata) - *(.rodata.*) - *(.gnu.linkonce.r.*) - } - .rodata1; - . = ALIGN(32 / 8); - PROVIDE (__preinit_array_start = .); - .preinit_array - { - *(.preinit_array) - } - PROVIDE (__preinit_array_end = .); - PROVIDE (__init_array_start = .); - .init_array - { - *(.init_array) - } - PROVIDE (__init_array_end = .); - PROVIDE (__fini_array_start = .); - .fini_array - { - *(.fini_array) - } - PROVIDE (__fini_array_end = .); -} - -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. */ - . = ALIGN(PAGESIZE) + (. & (PAGESIZE - 1)); - .data - { - *(.data) - *(.data.*) - *(.gnu.linkonce.d.*) - } - .data1; - .eh_frame - { - KEEP (*(.eh_frame)) - } - .gcc_except_table; - .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 - 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; - .got - { - *(.got.plt) - *(.got) - } - .dynamic; - /* We want the small data sections together, so single-instruction offsets - can access them all, and initialized data all before uninitialized, so - we can shorten the on-disk segment size. */ - .sdata - { - *(.sdata) - *(.sdata.*) - *(.gnu.linkonce.s.*) - } - _edata = .; - PROVIDE (edata = .); - __bss_start = .; - .sbss - { - PROVIDE (__sbss_start = .); - PROVIDE (___sbss_start = .); - *(.dynsbss) - *(.sbss) - *(.sbss.*) - *(.gnu.linkonce.sb.*) - *(.scommon) - PROVIDE (__sbss_end = .); - PROVIDE (___sbss_end = .); - } - .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. */ - . = ALIGN(32 / 8); - } - . = ALIGN(32 / 8); - _end = .; - PROVIDE (end = .); -} - -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/elflint.c b/src/elflint.c deleted file mode 100644 index d66cdd13..00000000 --- a/src/elflint.c +++ /dev/null @@ -1,2578 +0,0 @@ -/* Pedantic checking of ELF files compliance with gABI/psABI spec. - Copyright (C) 2001, 2002, 2003, 2004 Red Hat, Inc. - Written by Ulrich Drepper <drepper@redhat.com>, 2001. - - This program is Open Source software; you can redistribute it and/or - modify it under the terms of the Open Software License version 1.0 as - published by the Open Source Initiative. - - You should have received a copy of the Open Software License along - with this program; if not, you may obtain a copy of the Open Software - License version 1.0 from http://www.opensource.org/licenses/osl.php or - by writing the Open Source Initiative c/o Lawrence Rosen, Esq., - 3001 King Ranch Road, Ukiah, CA 95482. */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <argp.h> -#include <assert.h> -#include <byteswap.h> -#include <endian.h> -#include <error.h> -#include <fcntl.h> -#include <gelf.h> -#include <inttypes.h> -#include <libebl.h> -#include <libintl.h> -#include <locale.h> -#include <stdbool.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <sys/param.h> - -#include <elf-knowledge.h> -#include <system.h> - - -/* Name and version of program. */ -static void print_version (FILE *stream, struct argp_state *state); -void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; - - -#define ARGP_strict 300 -#define ARGP_gnuld 301 - -/* Definitions of arguments for argp functions. */ -static const struct argp_option options[] = -{ - - { "strict", ARGP_strict, NULL, 0, - N_("Be extremely strict, flag level 2 features.") }, - { "quiet", 'q', NULL, 0, N_("Do not print anything if successful") }, - { "gnu-ld", ARGP_gnuld, NULL, 0, - N_("Binary has been created with GNU ld and is therefore known to be \ -broken in certain ways") }, - { NULL, 0, NULL, 0, NULL } -}; - -/* Short description of program. */ -static const char doc[] = N_("\ -Pedantic checking of ELF files compliance with gABI/psABI spec."); - -/* Strings for arguments in help texts. */ -static const char args_doc[] = N_("FILE..."); - -/* Prototype for option handler. */ -static error_t parse_opt (int key, char *arg, struct argp_state *state); - -/* Function to print some extra text in the help message. */ -static char *more_help (int key, const char *text, void *input); - -/* Data structure to communicate with argp functions. */ -static struct argp argp = -{ - options, parse_opt, args_doc, doc, NULL, more_help -}; - - -/* Declarations of local functions. */ -static void process_file (int fd, Elf *elf, const char *prefix, - const char *suffix, const char *fname, size_t size, - bool only_one); -static void process_elf_file (Elf *elf, const char *prefix, const char *suffix, - const char *fname, size_t size, bool only_one); - -/* Report an error. */ -#define ERROR(str, args...) \ - do { \ - printf (str, ##args); \ - ++error_count; \ - } while (0) -static int error_count; - -/* True if we should perform very strict testing. */ -static bool be_strict; - -/* True if no message is to be printed if the run is succesful. */ -static bool be_quiet; - -/* True if binary is assumed to be generated with GNU ld. */ -static bool gnuld; - -/* Index of section header string table. */ -static uint32_t shstrndx; - -/* Array to count references in section groups. */ -static int *scnref; - - -int -main (int argc, char *argv[]) -{ - int remaining; - bool only_one; - - /* Set locale. */ - setlocale (LC_ALL, ""); - - /* Initialize the message catalog. */ - textdomain (PACKAGE); - - /* Parse and process arguments. */ - argp_parse (&argp, argc, argv, 0, &remaining, NULL); - - /* If no ELF file is given punt. */ - if (remaining >= argc) - { - argp_help (&argp, stdout, ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR, - program_invocation_short_name); - exit (1); - } - - /* Before we start tell the ELF library which version we are using. */ - elf_version (EV_CURRENT); - - /* Now process all the files given at the command line. */ - only_one = remaining + 1 == argc; - do - { - int fd; - Elf *elf; - - /* Open the file. */ - fd = open (argv[remaining], O_RDONLY); - if (fd == -1) - { - error (0, errno, gettext ("cannot open input file")); - continue; - } - - /* Create an `Elf' descriptor. */ - elf = elf_begin (fd, ELF_C_READ_MMAP, NULL); - if (elf == NULL) - ERROR (gettext ("cannot generate Elf descriptor: %s\n"), - elf_errmsg (-1)); - else - { - unsigned int prev_error_count = error_count; - struct stat64 st; - - if (fstat64 (fd, &st) != 0) - { - printf ("cannot stat '%s': %m\n", argv[remaining]); - close (fd); - continue; - } - - process_file (fd, elf, NULL, NULL, argv[remaining], st.st_size, - only_one); - - /* Now we can close the descriptor. */ - if (elf_end (elf) != 0) - ERROR (gettext ("error while closing Elf descriptor: %s\n"), - elf_errmsg (-1)); - - if (prev_error_count == error_count && !be_quiet) - puts (gettext ("No errors")); - } - - close (fd); - } - while (++remaining < argc); - - return error_count != 0; -} - - -/* Handle program arguments. */ -static error_t -parse_opt (int key, char *arg, struct argp_state *state) -{ - switch (key) - { - case ARGP_strict: - be_strict = true; - break; - - case 'q': - be_quiet = true; - break; - - case ARGP_gnuld: - gnuld = true; - break; - - default: - return ARGP_ERR_UNKNOWN; - } - return 0; -} - - -static char * -more_help (int key, const char *text, void *input) -{ - char *buf; - - switch (key) - { - case ARGP_KEY_HELP_EXTRA: - /* We print some extra information. */ - if (asprintf (&buf, gettext ("Please report bugs to %s.\n"), - PACKAGE_BUGREPORT) < 0) - buf = NULL; - return buf; - - default: - break; - } - return (char *) text; -} - - -/* Print the version information. */ -static void -print_version (FILE *stream, struct argp_state *state) -{ - fprintf (stream, "elflint (%s) %s\n", PACKAGE_NAME, 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\ -"), "2004"); - fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); -} - - -/* Process one file. */ -static void -process_file (int fd, Elf *elf, const char *prefix, const char *suffix, - const char *fname, size_t size, bool only_one) -{ - /* We can handle two types of files: ELF files and archives. */ - Elf_Kind kind = elf_kind (elf); - - switch (kind) - { - case ELF_K_ELF: - /* Yes! It's an ELF file. */ - process_elf_file (elf, prefix, suffix, fname, size, only_one); - break; - - case ELF_K_AR: - { - Elf *subelf; - Elf_Cmd cmd = ELF_C_READ_MMAP; - size_t prefix_len = prefix == NULL ? 0 : strlen (prefix); - size_t fname_len = strlen (fname) + 1; - char new_prefix[prefix_len + 1 + fname_len]; - char new_suffix[(suffix == NULL ? 0 : strlen (suffix)) + 2]; - char *cp = new_prefix; - - /* Create the full name of the file. */ - if (prefix != NULL) - { - cp = mempcpy (cp, prefix, prefix_len); - *cp++ = '('; - strcpy (stpcpy (new_suffix, suffix), ")"); - } - else - new_suffix[0] = '\0'; - memcpy (cp, fname, fname_len); - - /* It's an archive. We process each file in it. */ - while ((subelf = elf_begin (fd, cmd, elf)) != NULL) - { - kind = elf_kind (subelf); - - /* Call this function recursively. */ - if (kind == ELF_K_ELF || kind == ELF_K_AR) - { - Elf_Arhdr *arhdr = elf_getarhdr (subelf); - assert (arhdr != NULL); - - process_file (fd, subelf, new_prefix, new_suffix, - arhdr->ar_name, arhdr->ar_size, false); - } - - /* Get next archive element. */ - cmd = elf_next (subelf); - if (elf_end (subelf) != 0) - ERROR (gettext (" error while freeing sub-ELF descriptor: %s\n"), - elf_errmsg (-1)); - } - } - break; - - default: - /* We cannot do anything. */ - ERROR (gettext ("\ -Not an ELF file - it has the wrong magic bytes at the start")); - break; - } -} - - -static const char * -section_name (Ebl *ebl, GElf_Ehdr *ehdr, int idx) -{ - GElf_Shdr shdr_mem; - GElf_Shdr *shdr; - - shdr = gelf_getshdr (elf_getscn (ebl->elf, idx), &shdr_mem); - - return elf_strptr (ebl->elf, shstrndx, shdr->sh_name); -} - - -static const int valid_e_machine[] = - { - EM_M32, EM_SPARC, EM_386, EM_68K, EM_88K, EM_860, EM_MIPS, EM_S370, - EM_MIPS_RS3_LE, EM_PARISC, EM_VPP500, EM_SPARC32PLUS, EM_960, EM_PPC, - EM_PPC64, EM_S390, EM_V800, EM_FR20, EM_RH32, EM_RCE, EM_ARM, - EM_FAKE_ALPHA, EM_SH, EM_SPARCV9, EM_TRICORE, EM_ARC, EM_H8_300, - EM_H8_300H, EM_H8S, EM_H8_500, EM_IA_64, EM_MIPS_X, EM_COLDFIRE, - EM_68HC12, EM_MMA, EM_PCP, EM_NCPU, EM_NDR1, EM_STARCORE, EM_ME16, - EM_ST100, EM_TINYJ, EM_X86_64, EM_PDSP, EM_FX66, EM_ST9PLUS, EM_ST7, - EM_68HC16, EM_68HC11, EM_68HC08, EM_68HC05, EM_SVX, EM_ST19, EM_VAX, - EM_CRIS, EM_JAVELIN, EM_FIREPATH, EM_ZSP, EM_MMIX, EM_HUANY, EM_PRISM, - EM_AVR, EM_FR30, EM_D10V, EM_D30V, EM_V850, EM_M32R, EM_MN10300, - EM_MN10200, EM_PJ, EM_OPENRISC, EM_ARC_A5, EM_XTENSA - }; -#define nvalid_e_machine \ - (sizeof (valid_e_machine) / sizeof (valid_e_machine[0])) - - -/* Number of sections. */ -static unsigned int shnum; - - -static void -check_elf_header (Ebl *ebl, GElf_Ehdr *ehdr, size_t size) -{ - char buf[512]; - size_t cnt; - - /* Check e_ident field. */ - if (ehdr->e_ident[EI_MAG0] != ELFMAG0) - ERROR ("e_ident[%d] != '%c'\n", EI_MAG0, ELFMAG0); - if (ehdr->e_ident[EI_MAG1] != ELFMAG1) - ERROR ("e_ident[%d] != '%c'\n", EI_MAG1, ELFMAG1); - if (ehdr->e_ident[EI_MAG2] != ELFMAG2) - ERROR ("e_ident[%d] != '%c'\n", EI_MAG2, ELFMAG2); - if (ehdr->e_ident[EI_MAG3] != ELFMAG3) - ERROR ("e_ident[%d] != '%c'\n", EI_MAG3, ELFMAG3); - - if (ehdr->e_ident[EI_CLASS] != ELFCLASS32 - && ehdr->e_ident[EI_CLASS] != ELFCLASS64) - ERROR (gettext ("e_ident[%d] == %d is no known class\n"), - EI_CLASS, ehdr->e_ident[EI_CLASS]); - - if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB - && ehdr->e_ident[EI_DATA] != ELFDATA2MSB) - ERROR (gettext ("e_ident[%d] == %d is no known data encoding\n"), - EI_DATA, ehdr->e_ident[EI_DATA]); - - if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) - ERROR (gettext ("unknown ELF header version number e_ident[%d] == %d\n"), - EI_VERSION, ehdr->e_ident[EI_VERSION]); - - /* We currently don't handle any OS ABIs. */ - if (ehdr->e_ident[EI_OSABI] != ELFOSABI_NONE) - ERROR (gettext ("unsupported OS ABI e_ident[%d] == \"%s\"\n"), - EI_OSABI, - ebl_osabi_name (ebl, ehdr->e_ident[EI_OSABI], buf, sizeof (buf))); - - /* No ABI versions other than zero supported either. */ - if (ehdr->e_ident[EI_ABIVERSION] != 0) - ERROR (gettext ("unsupport ABI version e_ident[%d] == %d\n"), - EI_ABIVERSION, ehdr->e_ident[EI_ABIVERSION]); - - for (cnt = EI_PAD; cnt < EI_NIDENT; ++cnt) - if (ehdr->e_ident[cnt] != 0) - ERROR (gettext ("e_ident[%zu] is not zero\n"), cnt); - - /* Check the e_type field. */ - if (ehdr->e_type != ET_REL && ehdr->e_type != ET_EXEC - && ehdr->e_type != ET_DYN && ehdr->e_type != ET_CORE) - ERROR (gettext ("unknown object file type %d\n"), ehdr->e_type); - - /* Check the e_machine field. */ - for (cnt = 0; cnt < nvalid_e_machine; ++cnt) - if (valid_e_machine[cnt] == ehdr->e_machine) - break; - if (cnt == nvalid_e_machine) - ERROR (gettext ("unknown machine type %d\n"), ehdr->e_machine); - - /* Check the e_version field. */ - if (ehdr->e_version != EV_CURRENT) - ERROR (gettext ("unknown object file version\n")); - - /* Check the e_phoff and e_phnum fields. */ - if (ehdr->e_phoff == 0) - { - if (ehdr->e_phnum != 0) - ERROR (gettext ("invalid program header offset\n")); - else if (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN) - ERROR (gettext ("\ -executables and DSOs cannot have zero program header offset\n")); - } - else if (ehdr->e_phnum == 0) - ERROR (gettext ("invalid number of program header entries\n")); - - /* Check the e_shoff field. */ - shnum = ehdr->e_shnum; - shstrndx = ehdr->e_shstrndx; - if (ehdr->e_shoff == 0) - { - if (ehdr->e_shnum != 0) - ERROR (gettext ("invalid section header table offset\n")); - else if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN - && ehdr->e_type != ET_CORE) - ERROR (gettext ("section header table must be present\n")); - } - else - { - if (ehdr->e_shnum == 0) - { - /* Get the header of the zeroth section. The sh_size field - might contain the section number. */ - GElf_Shdr shdr_mem; - GElf_Shdr *shdr; - - shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem); - if (shdr != NULL) - { - /* The error will be reported later. */ - if (shdr->sh_size == 0) - ERROR (gettext ("\ -invalid number of section header table entries\n")); - else - shnum = shdr->sh_size; - } - } - - if (ehdr->e_shstrndx == SHN_XINDEX) - { - /* Get the header of the zeroth section. The sh_size field - might contain the section number. */ - GElf_Shdr shdr_mem; - GElf_Shdr *shdr; - - shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem); - if (shdr != NULL) - { - /* The error will be reported later. */ - if (shdr->sh_link >= shnum) - ERROR (gettext ("invalid section header index\n")); - else - shstrndx = shdr->sh_link; - } - } - else if (shstrndx >= shnum) - ERROR (gettext ("invalid section header index\n")); - } - - /* Check the e_flags field. */ - if (!ebl_machine_flag_check (ebl, ehdr->e_flags)) - ERROR (gettext ("invalid machine flags: %s\n"), - ebl_machine_flag_name (ebl, ehdr->e_flags, buf, sizeof (buf))); - - /* Check e_ehsize, e_phentsize, and e_shentsize fields. */ - if (gelf_getclass (ebl->elf) == ELFCLASS32) - { - if (ehdr->e_ehsize != 0 && ehdr->e_ehsize != sizeof (Elf32_Ehdr)) - ERROR (gettext ("invalid ELF header size: %hd\n"), ehdr->e_ehsize); - - if (ehdr->e_phentsize != 0 && ehdr->e_phentsize != sizeof (Elf32_Phdr)) - ERROR (gettext ("invalid program header size: %hd\n"), - ehdr->e_phentsize); - else if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > size) - ERROR (gettext ("invalid program header position or size\n")); - - if (ehdr->e_shentsize != 0 && ehdr->e_shentsize != sizeof (Elf32_Shdr)) - ERROR (gettext ("invalid section header size: %hd\n"), - ehdr->e_shentsize); - else if (ehdr->e_shoff + ehdr->e_shnum * ehdr->e_shentsize > size) - ERROR (gettext ("invalid section header position or size\n")); - } - else if (gelf_getclass (ebl->elf) == ELFCLASS64) - { - if (ehdr->e_ehsize != 0 && ehdr->e_ehsize != sizeof (Elf64_Ehdr)) - ERROR (gettext ("invalid ELF header size: %hd\n"), ehdr->e_ehsize); - - if (ehdr->e_phentsize != 0 && ehdr->e_phentsize != sizeof (Elf64_Phdr)) - ERROR (gettext ("invalid program header size: %hd\n"), - ehdr->e_phentsize); - else if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > size) - ERROR (gettext ("invalid program header position or size\n")); - - if (ehdr->e_shentsize != 0 && ehdr->e_shentsize != sizeof (Elf64_Shdr)) - ERROR (gettext ("invalid section header size: %hd\n"), - ehdr->e_shentsize); - else if (ehdr->e_shoff + ehdr->e_shnum * ehdr->e_shentsize > size) - ERROR (gettext ("invalid section header position or size\n")); - } -} - - -/* Check that there is a section group section with index < IDX which - contains section IDX and that there is exactly one. */ -static void -check_scn_group (Ebl *ebl, GElf_Ehdr *ehdr, int idx) -{ - if (scnref[idx] == 0) - { - /* No reference so far. Search following sections, maybe the - order is wrong. */ - size_t cnt; - - for (cnt = idx + 1; cnt < shnum; ++cnt) - { - Elf_Scn *scn; - GElf_Shdr shdr_mem; - GElf_Shdr *shdr; - Elf_Data *data; - Elf32_Word *grpdata; - size_t inner; - - scn = elf_getscn (ebl->elf, cnt); - shdr = gelf_getshdr (scn, &shdr_mem); - if (shdr == NULL) - /* We cannot get the section header so we cannot check it. - The error to get the section header will be shown - somewhere else. */ - continue; - - if (shdr->sh_type != SHT_GROUP) - continue; - - data = elf_getdata (scn, NULL); - if (data == NULL || data->d_size < sizeof (Elf32_Word)) - /* Cannot check the section. */ - continue; - - grpdata = (Elf32_Word *) data->d_buf; - for (inner = 1; inner < data->d_size / sizeof (Elf32_Word); ++inner) - if (grpdata[inner] == (Elf32_Word) idx) - goto out; - } - - out: - if (cnt == shnum) - ERROR (gettext ("\ -section [%2d] '%s': section with SHF_GROUP flag set not part of a section group\n"), - idx, section_name (ebl, ehdr, idx)); - else - ERROR (gettext ("\ -section [%2d] '%s': section group [%2zu] '%s' does not preceed group member\n"), - idx, section_name (ebl, ehdr, idx), - cnt, section_name (ebl, ehdr, cnt)); - } -} - - -static void -check_symtab (Ebl *ebl, GElf_Ehdr *ehdr, int idx) -{ - bool no_xndx_warned = false; - int no_pt_tls = 0; - - Elf_Scn *scn = elf_getscn (ebl->elf, idx); - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - GElf_Shdr strshdr_mem; - GElf_Shdr *strshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), - &strshdr_mem); - if (shdr == NULL || strshdr == NULL) - return; - Elf_Data *data = elf_getdata (scn, NULL); - if (data == NULL) - { - ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), - idx, section_name (ebl, ehdr, idx)); - return; - } - - if (strshdr->sh_type != SHT_STRTAB) - ERROR (gettext ("section [%2d] '%s': referenced as string table for section [%2d] '%s' but type is not SHT_STRTAB\n"), - shdr->sh_link, section_name (ebl, ehdr, shdr->sh_link), - idx, section_name (ebl, ehdr, idx)); - - /* Search for an extended section index table section. */ - size_t cnt; - GElf_Shdr xndxshdr_mem; - GElf_Shdr *xndxshdr = NULL; - Elf_Data *xndxdata = NULL; - Elf32_Word xndxscnidx = 0; - for (cnt = 1; cnt < shnum; ++cnt) - if (cnt != (size_t) idx) - { - Elf_Scn *xndxscn = elf_getscn (ebl->elf, cnt); - xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem); - xndxdata = elf_getdata (xndxscn, NULL); - xndxscnidx = elf_ndxscn (xndxscn); - - if (xndxshdr == NULL || xndxdata == NULL) - continue; - - if (xndxshdr->sh_type == SHT_SYMTAB_SHNDX - && xndxshdr->sh_link == (GElf_Word) idx) - break; - } - if (cnt == shnum) - { - xndxshdr = NULL; - xndxdata = NULL; - } - - if (shdr->sh_entsize != gelf_fsize (ebl->elf, ELF_T_SYM, 1, EV_CURRENT)) - ERROR (gettext ("\ -section [%2zu] '%s': entry size is does not match ElfXX_Sym\n"), - cnt, section_name (ebl, ehdr, cnt)); - - /* Test the zeroth entry. */ - GElf_Sym sym_mem; - Elf32_Word xndx; - GElf_Sym *sym = gelf_getsymshndx (data, xndxdata, 0, &sym_mem, &xndx); - if (sym == NULL) - ERROR (gettext ("section [%2d] '%s': cannot get symbol %d: %s\n"), - idx, section_name (ebl, ehdr, idx), 0, elf_errmsg (-1)); - else - { - if (sym->st_name != 0) - ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"), - idx, section_name (ebl, ehdr, idx), "st_name"); - if (sym->st_value != 0) - ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"), - idx, section_name (ebl, ehdr, idx), "st_value"); - if (sym->st_size != 0) - ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"), - idx, section_name (ebl, ehdr, idx), "st_size"); - if (sym->st_info != 0) - ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"), - idx, section_name (ebl, ehdr, idx), "st_info"); - if (sym->st_other != 0) - ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"), - idx, section_name (ebl, ehdr, idx), "st_other"); - if (sym->st_shndx != 0) - ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"), - idx, section_name (ebl, ehdr, idx), "st_shndx"); - if (xndxdata != NULL && xndx != 0) - ERROR (gettext ("\ -section [%2d] '%s': XINDEX for zeroth entry not zero\n"), - xndxscnidx, section_name (ebl, ehdr, xndxscnidx)); - } - - for (cnt = 1; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt) - { - sym = gelf_getsymshndx (data, xndxdata, cnt, &sym_mem, &xndx); - if (sym == NULL) - { - ERROR (gettext ("section [%2d] '%s': cannot get symbol %zu: %s\n"), - idx, section_name (ebl, ehdr, idx), cnt, elf_errmsg (-1)); - continue; - } - - const char *name = NULL; - if (sym->st_name >= strshdr->sh_size) - ERROR (gettext ("\ -section [%2d] '%s': symbol %zu: invalid name value\n"), - idx, section_name (ebl, ehdr, idx), cnt); - else - { - name = elf_strptr (ebl->elf, shdr->sh_link, sym->st_name); - assert (name != NULL); - } - - if (sym->st_shndx == SHN_XINDEX) - { - if (xndxdata == NULL) - { - ERROR (gettext ("\ -section [%2d] '%s': symbol %zu: too large section index but no extended section index section\n"), - idx, section_name (ebl, ehdr, idx), cnt); - no_xndx_warned = true; - } - else if (xndx < SHN_LORESERVE) - ERROR (gettext ("\ -section [%2d] '%s': symbol %zu: XINDEX used for index which would fit in st_shndx (%" PRIu32 ")\n"), - xndxscnidx, section_name (ebl, ehdr, xndxscnidx), cnt, - xndx); - } - else if ((sym->st_shndx >= SHN_LORESERVE - // && sym->st_shndx <= SHN_HIRESERVE always true - && sym->st_shndx != SHN_ABS - && sym->st_shndx != SHN_COMMON) - || (sym->st_shndx >= shnum - && (sym->st_shndx < SHN_LORESERVE - /* || sym->st_shndx > SHN_HIRESERVE always false */))) - ERROR (gettext ("\ -section [%2d] '%s': symbol %zu: invalid section index\n"), - idx, section_name (ebl, ehdr, idx), cnt); - else - xndx = sym->st_shndx; - - if (GELF_ST_TYPE (sym->st_info) >= STT_NUM) - ERROR (gettext ("section [%2d] '%s': symbol %zu: unknown type\n"), - idx, section_name (ebl, ehdr, idx), cnt); - - if (GELF_ST_BIND (sym->st_info) >= STB_NUM) - ERROR (gettext ("\ -section [%2d] '%s': symbol %zu: unknown symbol binding\n"), - idx, section_name (ebl, ehdr, idx), cnt); - - if (xndx == SHN_COMMON) - { - /* Common symbols can only appear in relocatable files. */ - if (ehdr->e_type != ET_REL) - ERROR (gettext ("\ -section [%2d] '%s': symbol %zu: COMMON only allowed in relocatable files\n"), - idx, section_name (ebl, ehdr, idx), cnt); - if (cnt < shdr->sh_info) - ERROR (gettext ("\ -section [%2d] '%s': symbol %zu: local COMMON symbols are nonsense\n"), - idx, section_name (ebl, ehdr, idx), cnt); - if (GELF_R_TYPE (sym->st_info) == STT_FUNC) - ERROR (gettext ("\ -section [%2d] '%s': symbol %zu: function in COMMON section is nonsense\n"), - idx, section_name (ebl, ehdr, idx), cnt); - } - else if (xndx > 0 && xndx < shnum) - { - GElf_Shdr destshdr_mem; - GElf_Shdr *destshdr; - - destshdr = gelf_getshdr (elf_getscn (ebl->elf, xndx), &destshdr_mem); - if (destshdr != NULL) - { - if (GELF_ST_TYPE (sym->st_info) != STT_TLS) - { - if ((sym->st_value - destshdr->sh_addr) > destshdr->sh_size) - ERROR (gettext ("\ -section [%2d] '%s': symbol %zu: st_value out of bounds\n"), - idx, section_name (ebl, ehdr, idx), cnt); - else if ((sym->st_value - destshdr->sh_addr + sym->st_size) - > destshdr->sh_size) - ERROR (gettext ("\ -section [%2d] '%s': symbol %zu does not fit completely in referenced section [%2d] '%s'\n"), - idx, section_name (ebl, ehdr, idx), cnt, - (int) xndx, section_name (ebl, ehdr, xndx)); - } - else - { - if ((destshdr->sh_flags & SHF_TLS) == 0) - ERROR (gettext ("\ -section [%2d] '%s': symbol %zu: referenced section [%2d] '%s' does not have SHF_TLS flag set\n"), - idx, section_name (ebl, ehdr, idx), cnt, - (int) xndx, section_name (ebl, ehdr, xndx)); - - if (ehdr->e_type == ET_REL) - { - /* For object files the symbol value must fall - into the section. */ - if (sym->st_value > destshdr->sh_size) - ERROR (gettext ("\ -section [%2d] '%s': symbol %zu: st_value out of bounds of referenced section [%2d] '%s'\n"), - idx, section_name (ebl, ehdr, idx), cnt, - (int) xndx, section_name (ebl, ehdr, xndx)); - else if (sym->st_value + sym->st_size - > destshdr->sh_size) - ERROR (gettext ("\ -section [%2d] '%s': symbol %zu does not fit completely in referenced section [%2d] '%s'\n"), - idx, section_name (ebl, ehdr, idx), cnt, - (int) xndx, section_name (ebl, ehdr, xndx)); - } - else - { - GElf_Phdr phdr_mem; - GElf_Phdr *phdr = NULL; - int pcnt; - - for (pcnt = 0; pcnt < ehdr->e_phnum; ++pcnt) - { - phdr = gelf_getphdr (ebl->elf, pcnt, &phdr_mem); - if (phdr != NULL && phdr->p_type == PT_TLS) - break; - } - - if (pcnt == ehdr->e_phnum) - { - if (no_pt_tls++ == 0) - ERROR (gettext ("\ -section [%2d] '%s': symbol %zu: TLS symbol but no TLS program header entry\n"), - idx, section_name (ebl, ehdr, idx), cnt); - } - else - { - if (sym->st_value - < destshdr->sh_offset - phdr->p_offset) - ERROR (gettext ("\ -section [%2d] '%s': symbol %zu: st_value short of referenced section [%2d] '%s'\n"), - idx, section_name (ebl, ehdr, idx), cnt, - (int) xndx, section_name (ebl, ehdr, xndx)); - else if (sym->st_value - > (destshdr->sh_offset - phdr->p_offset - + destshdr->sh_size)) - ERROR (gettext ("\ -section [%2d] '%s': symbol %zu: st_value out of bounds of referenced section [%2d] '%s'\n"), - idx, section_name (ebl, ehdr, idx), cnt, - (int) xndx, section_name (ebl, ehdr, xndx)); - else if (sym->st_value + sym->st_size - > (destshdr->sh_offset - phdr->p_offset - + destshdr->sh_size)) - ERROR (gettext ("\ -section [%2d] '%s': symbol %zu does not fit completely in referenced section [%2d] '%s'\n"), - idx, section_name (ebl, ehdr, idx), cnt, - (int) xndx, section_name (ebl, ehdr, xndx)); - } - } - } - } - } - - if (GELF_ST_BIND (sym->st_info) == STB_LOCAL) - { - if (cnt >= shdr->sh_info) - ERROR (gettext ("\ -section [%2d] '%s': symbol %zu: local symbol outside range described in sh_info\n"), - idx, section_name (ebl, ehdr, idx), cnt); - } - else - { - if (cnt < shdr->sh_info) - ERROR (gettext ("\ -section [%2d] '%s': symbol %zu: non-local symbol outside range described in sh_info\n"), - idx, section_name (ebl, ehdr, idx), cnt); - } - - if (GELF_ST_TYPE (sym->st_info) == STT_SECTION - && GELF_ST_BIND (sym->st_info) != STB_LOCAL) - ERROR (gettext ("\ -section [%2d] '%s': symbol %zu: non-local section symbol\n"), - idx, section_name (ebl, ehdr, idx), cnt); - - if (name != NULL) - { - if (strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0) - { - /* Check that address and size match the global offset - table. We have to locate the GOT by searching for a - section named ".got". */ - Elf_Scn *gscn = NULL; - - while ((gscn = elf_nextscn (ebl->elf, gscn)) != NULL) - { - GElf_Shdr gshdr_mem; - GElf_Shdr *gshdr = gelf_getshdr (gscn, &gshdr_mem); - assert (gshdr != NULL); - - const char *sname = elf_strptr (ebl->elf, ehdr->e_shstrndx, - gshdr->sh_name); - if (sname != NULL && strcmp (sname, ".got") == 0) - { - /* Found it. */ - if (sym->st_value != gshdr->sh_addr) - /* This test is more strict than the psABIs - which usually allow the symbol to be in the - middle of the .got section, allowing - negative offsets. */ - ERROR (gettext ("\ -section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol value %#" PRIx64 " does not match .got section address %#" PRIx64 "\n"), - idx, section_name (ebl, ehdr, idx), - (uint64_t) sym->st_value, - (uint64_t) gshdr->sh_addr); - - if (sym->st_size != gshdr->sh_size) - ERROR (gettext ("\ -section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol size %" PRIu64 " does not match .got section size %" PRIu64 "\n"), - idx, section_name (ebl, ehdr, idx), - (uint64_t) sym->st_size, - (uint64_t) gshdr->sh_size); - - break; - } - } - - if (gscn == NULL) - ERROR (gettext ("\ -section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol present, but no .got section\n"), - idx, section_name (ebl, ehdr, idx)); - } - else if (strcmp (name, "_DYNAMIC") == 0) - { - /* Check that address and size match the dynamic - section. We locate the dynamic section via the - program header entry. */ - int pcnt; - - for (pcnt = 0; pcnt < ehdr->e_phnum; ++pcnt) - { - GElf_Phdr phdr_mem; - GElf_Phdr *phdr = gelf_getphdr (ebl->elf, pcnt, &phdr_mem); - - if (phdr != NULL && phdr->p_type == PT_DYNAMIC) - { - if (sym->st_value != phdr->p_vaddr) - ERROR (gettext ("\ -section [%2d] '%s': _DYNAMIC_ symbol value %#" PRIx64 " does not match dynamic segment address %#" PRIx64 "\n"), - idx, section_name (ebl, ehdr, idx), - (uint64_t) sym->st_value, - (uint64_t) phdr->p_vaddr); - - if (sym->st_size != phdr->p_memsz) - ERROR (gettext ("\ -section [%2d] '%s': _DYNAMIC symbol size %" PRIu64 " does not match dynamic segment size %" PRIu64 "\n"), - idx, section_name (ebl, ehdr, idx), - (uint64_t) sym->st_size, - (uint64_t) phdr->p_memsz); - - break; - } - } - } - } - } -} - - -static bool -is_rel_dyn (Ebl *ebl, GElf_Ehdr *ehdr, int idx, GElf_Shdr *shdr, bool rela) -{ - /* If this is no executable or DSO it cannot be a .rel.dyn section. */ - if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) - return false; - - /* Check the section name. Unfortunately necessary. */ - if (strcmp (section_name (ebl, ehdr, idx), rela ? ".rela.dyn" : ".rel.dyn")) - return false; - - /* When a .rel.dyn section is used a DT_RELCOUNT dynamic section - entry can be present as well. */ - Elf_Scn *scn = NULL; - while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) - { - GElf_Shdr rcshdr_mem; - const GElf_Shdr *rcshdr = gelf_getshdr (scn, &rcshdr_mem); - assert (rcshdr != NULL); - - if (rcshdr->sh_type == SHT_DYNAMIC) - { - /* Found the dynamic section. Look through it. */ - Elf_Data *d = elf_getdata (scn, NULL); - int cnt; - - for (cnt = 1; cnt < rcshdr->sh_size / rcshdr->sh_entsize; ++cnt) - { - GElf_Dyn dyn_mem; - GElf_Dyn *dyn = gelf_getdyn (d, cnt, &dyn_mem); - assert (dyn != NULL); - - if (dyn->d_tag == DT_RELCOUNT) - { - /* Found it. One last check: does the number - specified number of relative relocations exceed - the total number of relocations? */ - if (dyn->d_un.d_val > shdr->sh_size / shdr->sh_entsize) - ERROR (gettext ("\ -section [%2d] '%s': DT_RELCOUNT value %d too high for this section\n"), - idx, section_name (ebl, ehdr, idx), - (int) dyn->d_un.d_val); - } - } - - break; - } - } - - return true; -} - - -static void -check_rela (Ebl *ebl, GElf_Ehdr *ehdr, int idx) -{ - Elf_Scn *scn; - GElf_Shdr shdr_mem; - GElf_Shdr *shdr; - Elf_Data *data; - GElf_Shdr destshdr_mem; - GElf_Shdr *destshdr = NULL; - size_t cnt; - bool reldyn = false; - bool known_broken = gnuld; - - scn = elf_getscn (ebl->elf, idx); - shdr = gelf_getshdr (scn, &shdr_mem); - if (shdr == NULL) - return; - data = elf_getdata (scn, NULL); - if (data == NULL) - { - ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), - idx, section_name (ebl, ehdr, idx)); - return; - } - - /* Check whether the link to the section we relocate is reasonable. */ - if (shdr->sh_info >= shnum) - ERROR (gettext ("section [%2d] '%s': invalid destination section index\n"), - idx, section_name (ebl, ehdr, idx)); - else - { - destshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_info), - &destshdr_mem); - if (destshdr != NULL) - { - if(destshdr->sh_type != SHT_PROGBITS - && destshdr->sh_type != SHT_NOBITS) - { - reldyn = is_rel_dyn (ebl, ehdr, idx, shdr, true); - if (!reldyn) - ERROR (gettext ("\ -section [%2d] '%s': invalid destination section type\n"), - idx, section_name (ebl, ehdr, idx)); - else - { - /* There is no standard, but we require that .rela.dyn - sections have a sh_info value of zero. */ - if (shdr->sh_info != 0) - ERROR (gettext ("\ -section [%2d] '%s': sh_info should be zero\n"), - idx, section_name (ebl, ehdr, idx)); - } - } - - if ((destshdr->sh_flags & (SHF_MERGE | SHF_STRINGS)) != 0) - ERROR (gettext ("\ -section [%2d] '%s': no relocations for merge-able sections possible\n"), - idx, section_name (ebl, ehdr, idx)); - } - } - - if (shdr->sh_entsize != gelf_fsize (ebl->elf, ELF_T_RELA, 1, EV_CURRENT)) - ERROR (gettext ("\ -section [%2d] '%s': section entry size does not match ElfXX_Rela\n"), - idx, section_name (ebl, ehdr, idx)); - - Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link); - GElf_Shdr symshdr_mem; - GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem); - Elf_Data *symdata = elf_getdata (symscn, NULL); - - for (cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt) - { - GElf_Rela rela_mem; - GElf_Rela *rela; - - rela = gelf_getrela (data, cnt, &rela_mem); - if (rela == NULL) - { - ERROR (gettext ("\ -section [%2d] '%s': cannot get relocation %zu: %s\n"), - idx, section_name (ebl, ehdr, idx), cnt, elf_errmsg (-1)); - continue; - } - - if (!ebl_reloc_type_check (ebl, GELF_R_TYPE (rela->r_info))) - ERROR (gettext ("section [%2d] '%s': relocation %zu: invalid type\n"), - idx, section_name (ebl, ehdr, idx), cnt); - else if (!ebl_reloc_valid_use (ebl, GELF_R_TYPE (rela->r_info))) - ERROR (gettext ("\ -section [%2d] '%s': relocation %zu: relocation type invalid for the file type\n"), - idx, section_name (ebl, ehdr, idx), cnt); - - if (symshdr != NULL - && ((GELF_R_SYM (rela->r_info) + 1) - * gelf_fsize (ebl->elf, ELF_T_SYM, 1, EV_CURRENT) - > symshdr->sh_size)) - ERROR (gettext ("\ -section [%2d] '%s': relocation %zu: invalid symbol index\n"), - idx, section_name (ebl, ehdr, idx), cnt); - - if (ebl_gotpc_reloc_check (ebl, GELF_R_TYPE (rela->r_info))) - { - const char *name; - char buf[64]; - GElf_Sym sym_mem; - GElf_Sym *sym = gelf_getsym (symdata, GELF_R_SYM (rela->r_info), - &sym_mem); - if (sym != NULL - /* Get the name for the symbol. */ - && (name = elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name)) - && strcmp (name, "_GLOBAL_OFFSET_TABLE_") !=0 ) - ERROR (gettext ("\ -section [%2d] '%s': relocation %zu: only symbol '_GLOBAL_OFFSET_TABLE_' can be used with %s\n"), - idx, section_name (ebl, ehdr, idx), cnt, - ebl_reloc_type_name (ebl, GELF_R_SYM (rela->r_info), - buf, sizeof (buf))); - } - - if (reldyn) - { - // XXX TODO Check .rel.dyn section addresses. - } - else if (!known_broken) - { - if (destshdr != NULL - && (rela->r_offset - destshdr->sh_addr) >= destshdr->sh_size) - ERROR (gettext ("\ -section [%2d] '%s': relocation %zu: offset out of bounds\n"), - idx, section_name (ebl, ehdr, idx), cnt); - } - } -} - - -static void -check_rel (Ebl *ebl, GElf_Ehdr *ehdr, int idx) -{ - Elf_Scn *scn; - GElf_Shdr shdr_mem; - GElf_Shdr *shdr; - Elf_Data *data; - GElf_Shdr destshdr_mem; - GElf_Shdr *destshdr = NULL; - size_t cnt; - bool reldyn = false; - bool known_broken = gnuld; - - scn = elf_getscn (ebl->elf, idx); - shdr = gelf_getshdr (scn, &shdr_mem); - if (shdr == NULL) - return; - data = elf_getdata (scn, NULL); - if (data == NULL) - { - ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), - idx, section_name (ebl, ehdr, idx)); - return; - } - - /* Check whether the link to the section we relocate is reasonable. */ - if (shdr->sh_info >= shnum) - ERROR (gettext ("section [%2d] '%s': invalid destination section index\n"), - idx, section_name (ebl, ehdr, idx)); - else - { - destshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_info), - &destshdr_mem); - if (destshdr != NULL) - { - if (destshdr->sh_type != SHT_PROGBITS - && destshdr->sh_type != SHT_NOBITS) - { - reldyn = is_rel_dyn (ebl, ehdr, idx, shdr, false); - if (!reldyn) - ERROR (gettext ("\ -section [%2d] '%s': invalid destination section type\n"), - idx, section_name (ebl, ehdr, idx)); - else - { - /* There is no standard, but we require that .rela.dyn - sections have a sh_info value of zero. */ - if (shdr->sh_info != 0) - ERROR (gettext ("\ -section [%2d] '%s': sh_info should be zero\n"), - idx, section_name (ebl, ehdr, idx)); - } - } - - if ((destshdr->sh_flags & (SHF_MERGE | SHF_STRINGS)) != 0) - ERROR (gettext ("\ -section [%2d] '%s': no relocations for merge-able sections possible\n"), - idx, section_name (ebl, ehdr, idx)); - } - } - - if (shdr->sh_entsize != gelf_fsize (ebl->elf, ELF_T_REL, 1, EV_CURRENT)) - ERROR (gettext ("\ -section [%2d] '%s': section entry size does not match ElfXX_Rel\n"), - idx, section_name (ebl, ehdr, idx)); - - Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link); - GElf_Shdr symshdr_mem; - GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem); - Elf_Data *symdata = elf_getdata (symscn, NULL); - - for (cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt) - { - GElf_Rel rel_mem; - GElf_Rel *rel; - - rel = gelf_getrel (data, cnt, &rel_mem); - if (rel == NULL) - { - ERROR (gettext ("\ -section [%2d] '%s': cannot get relocation %zu: %s\n"), - idx, section_name (ebl, ehdr, idx), cnt, elf_errmsg (-1)); - continue; - } - - if (!ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))) - ERROR (gettext ("section [%2d] '%s': relocation %zu: invalid type\n"), - idx, section_name (ebl, ehdr, idx), cnt); - else if (!ebl_reloc_valid_use (ebl, GELF_R_TYPE (rel->r_info))) - ERROR (gettext ("\ -section [%2d] '%s': relocation %zu: relocation type invalid for the file type\n"), - idx, section_name (ebl, ehdr, idx), cnt); - - if (symshdr != NULL - && ((GELF_R_SYM (rel->r_info) + 1) - * gelf_fsize (ebl->elf, ELF_T_SYM, 1, EV_CURRENT) - > symshdr->sh_size)) - ERROR (gettext ("\ -section [%2d] '%s': relocation %zu: invalid symbol index\n"), - idx, section_name (ebl, ehdr, idx), cnt); - - if (ebl_gotpc_reloc_check (ebl, GELF_R_TYPE (rel->r_info))) - { - const char *name; - char buf[64]; - GElf_Sym sym_mem; - GElf_Sym *sym = gelf_getsym (symdata, GELF_R_SYM (rel->r_info), - &sym_mem); - if (sym != NULL - /* Get the name for the symbol. */ - && (name = elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name)) - && strcmp (name, "_GLOBAL_OFFSET_TABLE_") !=0 ) - ERROR (gettext ("\ -section [%2d] '%s': relocation %zu: only symbol '_GLOBAL_OFFSET_TABLE_' can be used with %s\n"), - idx, section_name (ebl, ehdr, idx), cnt, - ebl_reloc_type_name (ebl, GELF_R_SYM (rel->r_info), - buf, sizeof (buf))); - } - - if (reldyn) - { - // XXX TODO Check .rel.dyn section addresses. - } - else if (!known_broken) - { - if (destshdr != NULL - && GELF_R_TYPE (rel->r_info) != 0 - && (rel->r_offset - destshdr->sh_addr) >= destshdr->sh_size) - ERROR (gettext ("\ -section [%2d] '%s': relocation %zu: offset out of bounds\n"), - idx, section_name (ebl, ehdr, idx), cnt); - } - } -} - - -/* Number of dynamic sections. */ -static int ndynamic; - - -static void -check_dynamic (Ebl *ebl, GElf_Ehdr *ehdr, int idx) -{ - Elf_Scn *scn; - GElf_Shdr shdr_mem; - GElf_Shdr *shdr; - Elf_Data *data; - GElf_Shdr strshdr_mem; - GElf_Shdr *strshdr; - size_t cnt; - static const bool dependencies[DT_NUM][DT_NUM] = - { - [DT_NEEDED] = { [DT_STRTAB] = true }, - [DT_PLTRELSZ] = { [DT_JMPREL] = true }, - [DT_HASH] = { [DT_SYMTAB] = true }, - [DT_STRTAB] = { [DT_STRSZ] = true }, - [DT_SYMTAB] = { [DT_STRTAB] = true, [DT_HASH] = true, - [DT_SYMENT] = true }, - [DT_RELA] = { [DT_RELASZ] = true, [DT_RELAENT] = true }, - [DT_RELASZ] = { [DT_RELA] = true }, - [DT_RELAENT] = { [DT_RELA] = true }, - [DT_STRSZ] = { [DT_STRTAB] = true }, - [DT_SYMENT] = { [DT_SYMTAB] = true }, - [DT_SONAME] = { [DT_STRTAB] = true }, - [DT_RPATH] = { [DT_STRTAB] = true }, - [DT_REL] = { [DT_RELSZ] = true, [DT_RELENT] = true }, - [DT_RELSZ] = { [DT_REL] = true }, - [DT_RELENT] = { [DT_REL] = true }, - [DT_JMPREL] = { [DT_PLTRELSZ] = true, [DT_PLTREL] = true }, - [DT_RUNPATH] = { [DT_STRTAB] = true }, - [DT_PLTREL] = { [DT_JMPREL] = true }, - [DT_PLTRELSZ] = { [DT_JMPREL] = true } - }; - bool has_dt[DT_NUM]; - static const bool level2[DT_NUM] = - { - [DT_RPATH] = true, - [DT_SYMBOLIC] = true, - [DT_TEXTREL] = true, - [DT_BIND_NOW] = true - }; - static const bool mandatory[DT_NUM] = - { - [DT_NULL] = true, - [DT_HASH] = true, - [DT_STRTAB] = true, - [DT_SYMTAB] = true, - [DT_STRSZ] = true, - [DT_SYMENT] = true - }; - GElf_Addr reladdr = 0; - GElf_Word relsz = 0; - GElf_Addr pltreladdr = 0; - GElf_Word pltrelsz = 0; - - memset (has_dt, '\0', sizeof (has_dt)); - - if (++ndynamic == 2) - ERROR (gettext ("more than one dynamic section present\n")); - - scn = elf_getscn (ebl->elf, idx); - shdr = gelf_getshdr (scn, &shdr_mem); - if (shdr == NULL) - return; - data = elf_getdata (scn, NULL); - if (data == NULL) - { - ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), - idx, section_name (ebl, ehdr, idx)); - return; - } - - strshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), &strshdr_mem); - if (strshdr != NULL && strshdr->sh_type != SHT_STRTAB) - ERROR (gettext ("\ -section [%2d] '%s': referenced as string table for section [%2d] '%s' but type is not SHT_STRTAB\n"), - shdr->sh_link, section_name (ebl, ehdr, shdr->sh_link), - idx, section_name (ebl, ehdr, idx)); - - if (shdr->sh_entsize != gelf_fsize (ebl->elf, ELF_T_DYN, 1, EV_CURRENT)) - ERROR (gettext ("\ -section [%2d] '%s': section entry size does not match ElfXX_Dyn\n"), - idx, section_name (ebl, ehdr, idx)); - - if (shdr->sh_info != 0) - ERROR (gettext ("section [%2d] '%s': sh_info not zero\n"), - idx, section_name (ebl, ehdr, idx)); - - bool non_null_warned = false; - for (cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt) - { - GElf_Dyn dyn_mem; - GElf_Dyn *dyn; - - dyn = gelf_getdyn (data, cnt, &dyn_mem); - if (dyn == NULL) - { - ERROR (gettext ("\ -section [%2d] '%s': cannot get dynamic section entry %zu: %s\n"), - idx, section_name (ebl, ehdr, idx), cnt, elf_errmsg (-1)); - continue; - } - - if (has_dt[DT_NULL] && dyn->d_tag != DT_NULL && ! non_null_warned) - { - ERROR (gettext ("\ -section [%2d] '%s': non-DT_NULL entries follow DT_NULL entry\n"), - idx, section_name (ebl, ehdr, idx)); - non_null_warned = true; - } - - if (!ebl_dynamic_tag_check (ebl, dyn->d_tag)) - ERROR (gettext ("section [%2d] '%s': entry %zu: unknown tag\n"), - idx, section_name (ebl, ehdr, idx), cnt); - - if (dyn->d_tag < DT_NUM) - { - if (has_dt[dyn->d_tag] - && dyn->d_tag != DT_NEEDED - && dyn->d_tag != DT_NULL - && dyn->d_tag != DT_POSFLAG_1) - { - char buf[50]; - ERROR (gettext ("\ -section [%2d] '%s': entry %zu: more than one entry with tag %s\n"), - idx, section_name (ebl, ehdr, idx), cnt, - ebl_dynamic_tag_name (ebl, dyn->d_tag, - buf, sizeof (buf))); - } - - if (be_strict && level2[dyn->d_tag]) - { - char buf[50]; - ERROR (gettext ("\ -section [%2d] '%s': entry %zu: level 2 tag %s used\n"), - idx, section_name (ebl, ehdr, idx), cnt, - ebl_dynamic_tag_name (ebl, dyn->d_tag, - buf, sizeof (buf))); - } - - has_dt[dyn->d_tag] = true; - } - - if (dyn->d_tag == DT_PLTREL && dyn->d_un.d_val != DT_REL - && dyn->d_un.d_val != DT_RELA) - ERROR (gettext ("\ -section [%2d] '%s': entry %zu: DT_PLTREL value must be DT_REL or DT_RELA\n"), - idx, section_name (ebl, ehdr, idx), cnt); - - if (dyn->d_tag == DT_REL) - reladdr = dyn->d_un.d_ptr; - if (dyn->d_tag == DT_RELSZ) - relsz = dyn->d_un.d_val; - if (dyn->d_tag == DT_JMPREL) - pltreladdr = dyn->d_un.d_ptr; - if (dyn->d_tag == DT_PLTRELSZ) - pltrelsz = dyn->d_un.d_val; - } - - for (cnt = 1; cnt < DT_NUM; ++cnt) - if (has_dt[cnt]) - { - int inner; - - for (inner = 0; inner < DT_NUM; ++inner) - if (dependencies[cnt][inner] && ! has_dt[inner]) - { - char buf1[50]; - char buf2[50]; - - ERROR (gettext ("\ -section [%2d] '%s': contains %s entry but not %s\n"), - idx, section_name (ebl, ehdr, idx), - ebl_dynamic_tag_name (ebl, cnt, buf1, sizeof (buf1)), - ebl_dynamic_tag_name (ebl, inner, buf2, sizeof (buf2))); - } - } - else - { - if (mandatory[cnt]) - { - char buf[50]; - ERROR (gettext ("\ -section [%2d] '%s': mandatory tag %s not present\n"), - idx, section_name (ebl, ehdr, idx), - ebl_dynamic_tag_name (ebl, cnt, buf, sizeof (buf))); - } - } - - /* Check the rel/rela tags. At least one group must be available. */ - if ((has_dt[DT_RELA] || has_dt[DT_RELASZ] || has_dt[DT_RELAENT]) - && (!has_dt[DT_RELA] || !has_dt[DT_RELASZ] || !has_dt[DT_RELAENT])) - ERROR (gettext ("\ -section [%2d] '%s': not all of %s, %s, and %s are present\n"), - idx, section_name (ebl, ehdr, idx), - "DT_RELA", "DT_RELASZ", "DT_RELAENT"); - - if ((has_dt[DT_REL] || has_dt[DT_RELSZ] || has_dt[DT_RELENT]) - && (!has_dt[DT_REL] || !has_dt[DT_RELSZ] || !has_dt[DT_RELENT])) - ERROR (gettext ("\ -section [%2d] '%s': not all of %s, %s, and %s are present\n"), - idx, section_name (ebl, ehdr, idx), - "DT_REL", "DT_RELSZ", "DT_RELENT"); -} - - -static void -check_symtab_shndx (Ebl *ebl, GElf_Ehdr *ehdr, int idx) -{ - Elf_Scn *scn; - GElf_Shdr shdr_mem; - GElf_Shdr *shdr; - GElf_Shdr symshdr_mem; - GElf_Shdr *symshdr; - Elf_Scn *symscn; - size_t cnt; - Elf_Data *data; - Elf_Data *symdata; - - scn = elf_getscn (ebl->elf, idx); - shdr = gelf_getshdr (scn, &shdr_mem); - if (shdr == NULL) - return; - - symscn = elf_getscn (ebl->elf, shdr->sh_link); - symshdr = gelf_getshdr (symscn, &symshdr_mem); - if (symshdr != NULL && symshdr->sh_type != SHT_SYMTAB) - ERROR (gettext ("\ -section [%2d] '%s': extended section index section not for symbol table\n"), - idx, section_name (ebl, ehdr, idx)); - symdata = elf_getdata (symscn, NULL); - if (symdata == NULL) - ERROR (gettext ("cannot get data for symbol section\n")); - - if (shdr->sh_entsize != sizeof (Elf32_Word)) - ERROR (gettext ("\ -section [%2d] '%s': entry size does not match Elf32_Word\n"), - idx, section_name (ebl, ehdr, idx)); - - if (symshdr != NULL - && (shdr->sh_size / shdr->sh_entsize - < symshdr->sh_size / symshdr->sh_entsize)) - ERROR (gettext ("\ -section [%2d] '%s': extended index table too small for symbol table\n"), - idx, section_name (ebl, ehdr, idx)); - - if (shdr->sh_info != 0) - ERROR (gettext ("section [%2d] '%s': sh_info not zero\n"), - idx, section_name (ebl, ehdr, idx)); - - for (cnt = idx + 1; cnt < shnum; ++cnt) - { - GElf_Shdr rshdr_mem; - GElf_Shdr *rshdr; - - rshdr = gelf_getshdr (elf_getscn (ebl->elf, cnt), &rshdr_mem); - if (rshdr != NULL && rshdr->sh_type == SHT_SYMTAB_SHNDX - && rshdr->sh_link == shdr->sh_link) - { - ERROR (gettext ("\ -section [%2d] '%s': extended section index in section [%2zu] '%s' refers to same symbol table\n"), - idx, section_name (ebl, ehdr, idx), - cnt, section_name (ebl, ehdr, cnt)); - break; - } - } - - data = elf_getdata (scn, NULL); - - if (*((Elf32_Word *) data->d_buf) != 0) - ERROR (gettext ("symbol 0 should have zero extended section index\n")); - - for (cnt = 1; cnt < data->d_size / sizeof (Elf32_Word); ++cnt) - { - Elf32_Word xndx = ((Elf32_Word *) data->d_buf)[cnt]; - - if (xndx != 0) - { - GElf_Sym sym_data; - GElf_Sym *sym = gelf_getsym (symdata, cnt, &sym_data); - if (sym == NULL) - { - ERROR (gettext ("cannot get data for symbol %zu\n"), cnt); - continue; - } - - if (sym->st_shndx != SHN_XINDEX) - ERROR (gettext ("\ -extended section index is %" PRIu32 " but symbol index is not XINDEX\n"), - (uint32_t) xndx); - } - } -} - - -static void -check_hash (Ebl *ebl, GElf_Ehdr *ehdr, int idx) -{ - Elf_Scn *scn; - GElf_Shdr shdr_mem; - GElf_Shdr *shdr; - Elf_Data *data; - Elf32_Word nbucket; - Elf32_Word nchain; - GElf_Shdr symshdr_mem; - GElf_Shdr *symshdr; - - scn = elf_getscn (ebl->elf, idx); - shdr = gelf_getshdr (scn, &shdr_mem); - if (shdr == NULL) - return; - data = elf_getdata (scn, NULL); - if (data == NULL) - { - ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), - idx, section_name (ebl, ehdr, idx)); - return; - } - - symshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), &symshdr_mem); - if (symshdr != NULL && symshdr->sh_type != SHT_DYNSYM) - ERROR (gettext ("\ -section [%2d] '%s': hash table not for dynamic symbol table\n"), - idx, section_name (ebl, ehdr, idx)); - - if (shdr->sh_entsize != sizeof (Elf32_Word)) - ERROR (gettext ("\ -section [%2d] '%s': entry size does not match Elf32_Word\n"), - idx, section_name (ebl, ehdr, idx)); - - if ((shdr->sh_flags & SHF_ALLOC) == 0) - ERROR (gettext ("section [%2d] '%s': not marked to be allocated\n"), - idx, section_name (ebl, ehdr, idx)); - - if (shdr->sh_size < 2 * shdr->sh_entsize) - { - ERROR (gettext ("\ -section [%2d] '%s': hash table has not even room for nbucket and nchain\n"), - idx, section_name (ebl, ehdr, idx)); - return; - } - - nbucket = ((Elf32_Word *) data->d_buf)[0]; - nchain = ((Elf32_Word *) data->d_buf)[1]; - - if (shdr->sh_size < (2 + nbucket + nchain) * shdr->sh_entsize) - ERROR (gettext ("\ -section [%2d] '%s': hash table section is too small (is %ld, expected %ld)\n"), - idx, section_name (ebl, ehdr, idx), (long int) shdr->sh_size, - (long int) ((2 + nbucket + nchain) * shdr->sh_entsize)); - - if (symshdr != NULL) - { - size_t symsize = symshdr->sh_size / symshdr->sh_entsize; - size_t cnt; - - if (nchain < symshdr->sh_size / symshdr->sh_entsize) - ERROR (gettext ("section [%2d] '%s': chain array not large enough\n"), - idx, section_name (ebl, ehdr, idx)); - - for (cnt = 2; cnt < 2 + nbucket; ++cnt) - if (((Elf32_Word *) data->d_buf)[cnt] >= symsize) - ERROR (gettext ("\ -section [%2d] '%s': hash bucket reference %zu out of bounds\n"), - idx, section_name (ebl, ehdr, idx), cnt - 2); - - for (; cnt < 2 + nbucket + nchain; ++cnt) - if (((Elf32_Word *) data->d_buf)[cnt] >= symsize) - ERROR (gettext ("\ -section [%2d] '%s': hash chain reference %zu out of bounds\n"), - idx, section_name (ebl, ehdr, idx), cnt - 2 - nbucket); - } -} - - -static void -check_null (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) -{ -#define TEST(name, extra) \ - if (extra && shdr->sh_##name != 0) \ - ERROR (gettext ("section [%2d] '%s': nonzero sh_%s for NULL section\n"), \ - idx, section_name (ebl, ehdr, idx), #name) - - TEST (name, 1); - TEST (flags, 1); - TEST (addr, 1); - TEST (offset, 1); - TEST (size, idx != 0); - TEST (link, idx != 0); - TEST (info, 1); - TEST (addralign, 1); - TEST (entsize, 1); -} - - -static void -check_group (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) -{ - if (ehdr->e_type != ET_REL) - { - ERROR (gettext ("\ -section [%2d] '%s': section groups only allowed in relocatable object files\n"), - idx, section_name (ebl, ehdr, idx)); - return; - } - - /* Check that sh_link is an index of a symbol table. */ - GElf_Shdr symshdr_mem; - GElf_Shdr *symshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), - &symshdr_mem); - if (symshdr == NULL) - ERROR (gettext ("section [%2d] '%s': cannot get symbol table: %s\n"), - idx, section_name (ebl, ehdr, idx), elf_errmsg (-1)); - else - { - if (symshdr->sh_type != SHT_SYMTAB) - ERROR (gettext ("\ -section [%2d] '%s': section reference in sh_link is no symbol table\n"), - idx, section_name (ebl, ehdr, idx)); - - if (shdr->sh_info >= symshdr->sh_size / gelf_fsize (ebl->elf, ELF_T_SYM, - 1, EV_CURRENT)) - ERROR (gettext ("\ -section [%2d] '%s': invalid symbol index in sh_info\n"), - idx, section_name (ebl, ehdr, idx)); - - if (shdr->sh_flags != 0) - ERROR (gettext ("section [%2d] '%s': sh_flags not zero\n"), - idx, section_name (ebl, ehdr, idx)); - - if (be_strict - && shdr->sh_entsize != elf32_fsize (ELF_T_WORD, 1, EV_CURRENT)) - ERROR (gettext ("section [%2d] '%s': sh_flags not set correctly\n"), - idx, section_name (ebl, ehdr, idx)); - } - - Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL); - if (data == NULL) - ERROR (gettext ("section [%2d] '%s': cannot get data: %s\n"), - idx, section_name (ebl, ehdr, idx), elf_errmsg (-1)); - else - { - size_t elsize = elf32_fsize (ELF_T_WORD, 1, EV_CURRENT); - size_t cnt; - Elf32_Word val; - - if (data->d_size % elsize != 0) - ERROR (gettext ("\ -section [%2d] '%s': section size not multiple of sizeof(Elf32_Word)\n"), - idx, section_name (ebl, ehdr, idx)); - - if (data->d_size < elsize) - ERROR (gettext ("\ -section [%2d] '%s': section group without flags word\n"), - idx, section_name (ebl, ehdr, idx)); - else if (be_strict) - { - if (data->d_size < 2 * elsize) - ERROR (gettext ("\ -section [%2d] '%s': section group without member\n"), - idx, section_name (ebl, ehdr, idx)); - else if (data->d_size < 3 * elsize) - ERROR (gettext ("\ -section [%2d] '%s': section group with only one member\n"), - idx, section_name (ebl, ehdr, idx)); - } - -#if ALLOW_UNALIGNED - val = *((Elf32_Word *) data->d_buf); -#else - memcpy (&val, data->d_buf, elsize); -#endif - if ((val & ~GRP_COMDAT) != 0) - ERROR (gettext ("section [%2d] '%s': unknown section group flags\n"), - idx, section_name (ebl, ehdr, idx)); - - for (cnt = elsize; cnt < data->d_size; cnt += elsize) - { -#if ALLOW_UNALIGNED - val = *((Elf32_Word *) ((char *) data->d_buf + cnt)); -#else - memcpy (&val, (char *) data->d_buf + cnt, elsize); -#endif - - if (val > shnum) - ERROR (gettext ("\ -section [%2d] '%s': section index %Zu out of range\n"), - idx, section_name (ebl, ehdr, idx), cnt / elsize); - else - { - GElf_Shdr refshdr_mem; - GElf_Shdr *refshdr; - - refshdr = gelf_getshdr (elf_getscn (ebl->elf, val), - &refshdr_mem); - if (refshdr == NULL) - ERROR (gettext ("\ -section [%2d] '%s': cannot get section header for element %zu: %s\n"), - idx, section_name (ebl, ehdr, idx), cnt / elsize, - elf_errmsg (-1)); - else - { - if (refshdr->sh_type == SHT_GROUP) - ERROR (gettext ("\ -section [%2d] '%s': section group contains another group [%2d] '%s'\n"), - idx, section_name (ebl, ehdr, idx), - val, section_name (ebl, ehdr, val)); - - if ((refshdr->sh_flags & SHF_GROUP) == 0) - ERROR (gettext ("\ -section [%2d] '%s': element %Zu references section [%2d] '%s' without SHF_GROUP flag set\n"), - idx, section_name (ebl, ehdr, idx), cnt / elsize, - val, section_name (ebl, ehdr, val)); - } - - if (++scnref[val] == 2) - ERROR (gettext ("\ -section [%2d] '%s' is contained in more than one section group\n"), - val, section_name (ebl, ehdr, val)); - } - } - } -} - - -static bool has_loadable_segment; -static bool has_interp_segment; - -static const struct -{ - const char *name; - size_t namelen; - GElf_Word type; - enum { unused, exact, atleast } attrflag; - GElf_Word attr; - GElf_Word attr2; -} special_sections[] = - { - /* See figure 4-14 in the gABI. */ - { ".bss", 5, SHT_NOBITS, exact, SHF_ALLOC | SHF_WRITE, 0 }, - { ".comment", 8, SHT_PROGBITS, exact, 0, 0 }, - { ".data", 6, SHT_PROGBITS, exact, SHF_ALLOC | SHF_WRITE, 0 }, - { ".data1", 7, SHT_PROGBITS, exact, SHF_ALLOC | SHF_WRITE, 0 }, - { ".debug", 7, SHT_PROGBITS, exact, 0, 0 }, - { ".dynamic", 9, SHT_DYNAMIC, atleast, SHF_ALLOC, SHF_WRITE }, - { ".dynstr", 8, SHT_STRTAB, exact, SHF_ALLOC, 0 }, - { ".dynsym", 8, SHT_DYNSYM, exact, SHF_ALLOC, 0 }, - { ".fini", 6, SHT_PROGBITS, exact, SHF_ALLOC | SHF_EXECINSTR, 0 }, - { ".fini_array", 12, SHT_FINI_ARRAY, exact, SHF_ALLOC | SHF_WRITE, 0 }, - { ".got", 5, SHT_PROGBITS, unused, 0, 0 }, // XXX more info? - { ".hash", 6, SHT_HASH, exact, SHF_ALLOC, 0 }, - { ".init", 6, SHT_PROGBITS, exact, SHF_ALLOC | SHF_EXECINSTR, 0 }, - { ".init_array", 12, SHT_INIT_ARRAY, exact, SHF_ALLOC | SHF_WRITE, 0 }, - { ".interp", 8, SHT_PROGBITS, atleast, 0, SHF_ALLOC }, // XXX more tests? - { ".line", 6, SHT_PROGBITS, exact, 0, 0 }, - { ".note", 6, SHT_NOTE, exact, 0, 0 }, - { ".plt", 5, SHT_PROGBITS, unused, 0, 0 }, // XXX more tests - { ".preinit_array", 15, SHT_PREINIT_ARRAY, exact, SHF_ALLOC | SHF_WRITE, 0 }, - { ".rela", 5, SHT_RELA, atleast, 0, SHF_ALLOC }, // XXX more tests - { ".rel", 4, SHT_REL, atleast, 0, SHF_ALLOC }, // XXX more tests - { ".rodata", 8, SHT_PROGBITS, exact, SHF_ALLOC, 0 }, - { ".rodata1", 9, SHT_PROGBITS, exact, SHF_ALLOC, 0 }, - { ".shstrtab", 10, SHT_STRTAB, exact, 0, 0 }, - { ".strtab", 8, SHT_STRTAB, atleast, 0, SHF_ALLOC }, // XXX more tests - { ".symtab", 8, SHT_SYMTAB, atleast, 0, SHF_ALLOC }, // XXX more tests - { ".symtab_shndx", 14, SHT_SYMTAB_SHNDX, atleast, 0, SHF_ALLOC }, // XXX more tests - { ".tbss", 6, SHT_NOBITS, exact, SHF_ALLOC | SHF_WRITE | SHF_TLS, 0 }, - { ".tdata", 7, SHT_PROGBITS, exact, SHF_ALLOC | SHF_WRITE | SHF_TLS, 0 }, - { ".tdata1", 8, SHT_PROGBITS, exact, SHF_ALLOC | SHF_WRITE | SHF_TLS, 0 }, - { ".text", 6, SHT_PROGBITS, exact, SHF_ALLOC | SHF_EXECINSTR, 0 } - }; -#define nspecial_sections \ - (sizeof (special_sections) / sizeof (special_sections[0])) - - -static const char * -section_flags_string (GElf_Word flags, char *buf, size_t len) -{ - static const struct - { - GElf_Word flag; - const char *name; - } known_flags[] = - { -#define NEWFLAG(name) { SHF_##name, #name } - NEWFLAG (WRITE), - NEWFLAG (ALLOC), - NEWFLAG (EXECINSTR), - NEWFLAG (MERGE), - NEWFLAG (STRINGS), - NEWFLAG (INFO_LINK), - NEWFLAG (LINK_ORDER), - NEWFLAG (OS_NONCONFORMING), - NEWFLAG (GROUP), - NEWFLAG (TLS) - }; -#undef NEWFLAG - const size_t nknown_flags = sizeof (known_flags) / sizeof (known_flags[0]); - - char *cp = buf; - size_t cnt; - - for (cnt = 0; cnt < nknown_flags; ++cnt) - if (flags & known_flags[cnt].flag) - { - if (cp != buf && len > 1) - { - *cp++ = '|'; - --len; - } - - size_t ncopy = MIN (len - 1, strlen (known_flags[cnt].name)); - cp = mempcpy (cp, known_flags[cnt].name, ncopy); - len -= ncopy; - - flags ^= known_flags[cnt].flag; - } - - if (flags != 0 || cp == buf) - snprintf (cp, len - 1, "%" PRIx64, (uint64_t) flags); - - *cp = '\0'; - - return buf; -} - - -static void -check_versym (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) -{ - /* The number of elements in the version symbol table must be the - same as the number of symbols. */ - GElf_Shdr symshdr_mem; - GElf_Shdr *symshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), - &symshdr_mem); - if (symshdr == NULL) - /* The error has already been reported. */ - return; - - if (symshdr->sh_type != SHT_DYNSYM) - { - ERROR (gettext ("\ -section [%2d] '%s' refers in sh_link to section [%2d] '%s' which is no dynamic symbol table\n"), - idx, section_name (ebl, ehdr, idx), - shdr->sh_link, section_name (ebl, ehdr, shdr->sh_link)); - return; - } - - if (shdr->sh_size / shdr->sh_entsize - != symshdr->sh_size / symshdr->sh_entsize) - ERROR (gettext ("\ -section [%2d] '%s' has different number of entries than symbol table [%2d] '%s'\n"), - idx, section_name (ebl, ehdr, idx), - shdr->sh_link, section_name (ebl, ehdr, shdr->sh_link)); - - // XXX TODO A lot more tests - // check value of the fields. local symbols must have zero entries. - // nonlocal symbols refer to valid version. Check that version index - // in bound. -} - - -static void -check_sections (Ebl *ebl, GElf_Ehdr *ehdr) -{ - GElf_Shdr shdr_mem; - GElf_Shdr *shdr; - size_t cnt; - bool dot_interp_section = false; - - if (ehdr->e_shoff == 0) - /* No section header. */ - return; - - /* Allocate array to count references in section groups. */ - scnref = (int *) xcalloc (shnum, sizeof (int)); - - /* Check the zeroth section first. It must not have any contents - and the section header must contain nonzero value at most in the - sh_size and sh_link fields. */ - shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem); - if (shdr == NULL) - ERROR (gettext ("cannot get section header of zeroth section\n")); - else - { - if (shdr->sh_name != 0) - ERROR (gettext ("zeroth section has nonzero name\n")); - if (shdr->sh_type != 0) - ERROR (gettext ("zeroth section has nonzero type\n")); - if (shdr->sh_flags != 0) - ERROR (gettext ("zeroth section has nonzero flags\n")); - if (shdr->sh_addr != 0) - ERROR (gettext ("zeroth section has nonzero address\n")); - if (shdr->sh_offset != 0) - ERROR (gettext ("zeroth section has nonzero offset\n")); - if (shdr->sh_info != 0) - ERROR (gettext ("zeroth section has nonzero info field\n")); - if (shdr->sh_addralign != 0) - ERROR (gettext ("zeroth section has nonzero align value\n")); - if (shdr->sh_entsize != 0) - ERROR (gettext ("zeroth section has nonzero entry size value\n")); - - if (shdr->sh_size != 0 && ehdr->e_shnum != 0) - ERROR (gettext ("\ -zeroth section has nonzero size value while ELF header has nonzero shnum value\n")); - - if (shdr->sh_link != 0 && ehdr->e_shstrndx != SHN_XINDEX) - ERROR (gettext ("\ -zeroth section has nonzero link value while ELF header does not signal overflow in shstrndx\n")); - } - - for (cnt = 1; cnt < shnum; ++cnt) - { - Elf_Scn *scn; - - scn = elf_getscn (ebl->elf, cnt); - shdr = gelf_getshdr (scn, &shdr_mem); - if (shdr == NULL) - { - ERROR (gettext ("\ -cannot get section header for section [%2zu] '%s': %s\n"), - cnt, section_name (ebl, ehdr, cnt), elf_errmsg (-1)); - continue; - } - - const char *scnname = elf_strptr (ebl->elf, shstrndx, shdr->sh_name); - - if (scnname == NULL) - ERROR (gettext ("section [%2zu]: invalid name\n"), cnt); - else - { - /* Check whether it is one of the special sections defined in - the gABI. */ - size_t s; - for (s = 0; s < nspecial_sections; ++s) - if (strncmp (scnname, special_sections[s].name, - special_sections[s].namelen) == 0) - { - char stbuf1[100]; - char stbuf2[100]; - char stbuf3[100]; - - if (shdr->sh_type != special_sections[s].type) - ERROR (gettext ("\ -section [%2d] '%s' has wrong type: expected %s, is %s\n"), - (int) cnt, scnname, - ebl_section_type_name (ebl, special_sections[s].type, - stbuf1, sizeof (stbuf1)), - ebl_section_type_name (ebl, shdr->sh_type, - stbuf2, sizeof (stbuf2))); - - if (special_sections[s].attrflag == exact) - { - /* Except for the link order and group bit all the - other bits should match exactly. */ - if ((shdr->sh_flags & ~(SHF_LINK_ORDER | SHF_GROUP)) - != special_sections[s].attr) - ERROR (gettext ("\ -section [%2zu] '%s' has wrong flags: expected %s, is %s\n"), - cnt, scnname, - section_flags_string (special_sections[s].attr, - stbuf1, sizeof (stbuf1)), - section_flags_string (shdr->sh_flags - & ~SHF_LINK_ORDER, - stbuf2, sizeof (stbuf2))); - } - else if (special_sections[s].attrflag == atleast) - { - if ((shdr->sh_flags & special_sections[s].attr) - != special_sections[s].attr - || ((shdr->sh_flags & ~(SHF_LINK_ORDER | SHF_GROUP - | special_sections[s].attr - | special_sections[s].attr2)) - != 0)) - ERROR (gettext ("\ -section [%2zu] '%s' has wrong flags: expected %s and possibly %s, is %s\n"), - cnt, scnname, - section_flags_string (special_sections[s].attr, - stbuf1, sizeof (stbuf1)), - section_flags_string (special_sections[s].attr2, - stbuf2, sizeof (stbuf2)), - section_flags_string (shdr->sh_flags - & ~(SHF_LINK_ORDER - | SHF_GROUP), - stbuf3, sizeof (stbuf3))); - } - - if (strcmp (scnname, ".interp") == 0) - { - dot_interp_section = true; - - if (ehdr->e_type == ET_REL) - ERROR (gettext ("\ -section [%2zu] '%s' present in object file\n"), - cnt, scnname); - - if ((shdr->sh_flags & SHF_ALLOC) != 0 - && !has_loadable_segment) - ERROR (gettext ("\ -section [%2zu] '%s' has SHF_ALLOC flag set but there is no loadable segment\n"), - cnt, scnname); - else if ((shdr->sh_flags & SHF_ALLOC) == 0 - && has_loadable_segment) - ERROR (gettext ("\ -section [%2zu] '%s' has SHF_ALLOC flag not set but there are loadable segments\n"), - cnt, scnname); - } - else - { - if (strcmp (scnname, ".symtab_shndx") == 0 - && ehdr->e_type != ET_REL) - ERROR (gettext ("\ -section [%2zu] '%s' is extension section index table in non-object file\n"), - cnt, scnname); - - /* These sections must have the SHF_ALLOC flag set iff - a loadable segment is available. - - .relxxx - .strtab - .symtab - .symtab_shndx - - Check that if there is a reference from the - loaded section these sections also have the - ALLOC flag set. */ -#if 0 - // XXX TODO - if ((shdr->sh_flags & SHF_ALLOC) != 0 - && !has_loadable_segment) - ERROR (gettext ("\ -section [%2zu] '%s' has SHF_ALLOC flag set but there is no loadable segment\n"), - cnt, scnname); - else if ((shdr->sh_flags & SHF_ALLOC) == 0 - && has_loadable_segment) - ERROR (gettext ("\ -section [%2zu] '%s' has SHF_ALLOC flag not set but there are loadable segments\n"), - cnt, scnname); -#endif - } - - break; - } - } - - if (shdr->sh_entsize != 0 && shdr->sh_size % shdr->sh_entsize) - ERROR (gettext ("\ -section [%2zu] '%s': size not multiple of entry size\n"), - cnt, section_name (ebl, ehdr, cnt)); - - if (elf_strptr (ebl->elf, shstrndx, shdr->sh_name) == NULL) - ERROR (gettext ("cannot get section header\n")); - - if (shdr->sh_type >= SHT_NUM - && shdr->sh_type != SHT_GNU_LIBLIST - && shdr->sh_type != SHT_CHECKSUM - && shdr->sh_type != SHT_GNU_verdef - && shdr->sh_type != SHT_GNU_verneed - && shdr->sh_type != SHT_GNU_versym) - ERROR (gettext ("unsupported section type %d\n"), (int) shdr->sh_type); - -#define ALL_SH_FLAGS (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR | SHF_MERGE \ - | SHF_STRINGS | SHF_INFO_LINK | SHF_LINK_ORDER \ - | SHF_OS_NONCONFORMING | SHF_GROUP | SHF_TLS) - if (shdr->sh_flags & ~ALL_SH_FLAGS) - ERROR (gettext ("section [%2zu] '%s' contain unknown flag(s) %d\n"), - cnt, section_name (ebl, ehdr, cnt), - (int) shdr->sh_flags & ~ALL_SH_FLAGS); - else if (shdr->sh_flags & SHF_TLS) - { - // XXX Correct? - if (shdr->sh_addr != 0 && !gnuld) - ERROR (gettext ("\ -section [%2zu] '%s': thread-local data sections address not zero\n"), - cnt, section_name (ebl, ehdr, cnt)); - - // XXX TODO more tests!? - } - - if (shdr->sh_link >= shnum) - ERROR (gettext ("\ -section [%2zu] '%s': invalid section reference in link value\n"), - cnt, section_name (ebl, ehdr, cnt)); - - if (SH_INFO_LINK_P (shdr) && shdr->sh_info >= shnum) - ERROR (gettext ("\ -section [%2zu] '%s': invalid section reference in info value\n"), - cnt, section_name (ebl, ehdr, cnt)); - - if ((shdr->sh_flags & SHF_MERGE) == 0 - && (shdr->sh_flags & SHF_STRINGS) != 0 - && be_strict) - ERROR (gettext ("\ -section [%2zu] '%s': strings flag set without merge flag\n"), - cnt, section_name (ebl, ehdr, cnt)); - - if ((shdr->sh_flags & SHF_MERGE) != 0 && shdr->sh_entsize == 0) - ERROR (gettext ("\ -section [%2zu] '%s': merge flag set but entry size is zero\n"), - cnt, section_name (ebl, ehdr, cnt)); - - if (shdr->sh_flags & SHF_GROUP) - check_scn_group (ebl, ehdr, cnt); - - if (ehdr->e_type != ET_REL && (shdr->sh_flags & SHF_ALLOC) != 0) - { - /* Make sure the section is contained in a loaded segment - and that the initialization part matches NOBITS sections. */ - int pcnt; - GElf_Phdr phdr_mem; - GElf_Phdr *phdr; - - for (pcnt = 0; pcnt < ehdr->e_phnum; ++pcnt) - if ((phdr = gelf_getphdr (ebl->elf, pcnt, &phdr_mem)) != NULL - && ((phdr->p_type == PT_LOAD - && (shdr->sh_flags & SHF_TLS) == 0) - || (phdr->p_type == PT_TLS - && (shdr->sh_flags & SHF_TLS) != 0)) - && phdr->p_offset <= shdr->sh_offset - && phdr->p_offset + phdr->p_memsz > shdr->sh_offset) - { - /* Found the segment. */ - if (phdr->p_offset + phdr->p_memsz - < shdr->sh_offset + shdr->sh_size) - ERROR (gettext ("\ -section [%2zu] '%s' not fully contained in segment of program header entry %d\n"), - cnt, section_name (ebl, ehdr, cnt), pcnt); - - if (shdr->sh_type == SHT_NOBITS) - { - if (shdr->sh_offset < phdr->p_offset + phdr->p_filesz) - ERROR (gettext ("\ -section [%2zu] '%s' has type NOBITS but is read from the file in segment of program header entry %d\n"), - cnt, section_name (ebl, ehdr, cnt), pcnt); - } - else - { - if (shdr->sh_offset >= phdr->p_offset + phdr->p_filesz) - ERROR (gettext ("\ -section [%2zu] '%s' has not type NOBITS but is not read from the file in segment of program header entry %d\n"), - cnt, section_name (ebl, ehdr, cnt), pcnt); - } - - break; - } - - if (pcnt == ehdr->e_phnum) - ERROR (gettext ("\ -section [%2zu] '%s': alloc flag set but section not in any loaded segment\n"), - cnt, section_name (ebl, ehdr, cnt)); - } - - if (cnt == shstrndx && shdr->sh_type != SHT_STRTAB) - ERROR (gettext ("\ -section [%2zu] '%s': ELF header says this is the section header string table but type is not SHT_TYPE\n"), - cnt, section_name (ebl, ehdr, cnt)); - - switch (shdr->sh_type) - { - case SHT_SYMTAB: - case SHT_DYNSYM: - check_symtab (ebl, ehdr, cnt); - break; - - case SHT_RELA: - check_rela (ebl, ehdr, cnt); - break; - - case SHT_REL: - check_rel (ebl, ehdr, cnt); - break; - - case SHT_DYNAMIC: - check_dynamic (ebl, ehdr, cnt); - break; - - case SHT_SYMTAB_SHNDX: - check_symtab_shndx (ebl, ehdr, cnt); - break; - - case SHT_HASH: - check_hash (ebl, ehdr, cnt); - break; - - case SHT_NULL: - check_null (ebl, ehdr, shdr, cnt); - break; - - case SHT_GROUP: - check_group (ebl, ehdr, shdr, cnt); - break; - - case SHT_GNU_versym: - check_versym (ebl, ehdr, shdr, cnt); - break; - - default: - /* Nothing. */ - break; - } - } - - if (has_interp_segment && !dot_interp_section) - ERROR (gettext ("INTERP program header entry but no .interp section\n")); - - free (scnref); -} - - -static void -check_note (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Phdr *phdr, int cnt) -{ - if (ehdr->e_type != ET_CORE && ehdr->e_type != ET_REL - && ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) - ERROR (gettext ("\ -phdr[%d]: no note entries defined for the type of file\n"), - cnt); - - char *notemem = gelf_rawchunk (ebl->elf, phdr->p_offset, phdr->p_filesz); - - /* ELF64 files often use note section entries in the 32-bit format. - The p_align field is set to 8 in case the 64-bit format is used. - In case the p_align value is 0 or 4 the 32-bit format is - used. */ - GElf_Xword align = phdr->p_align == 0 || phdr->p_align == 4 ? 4 : 8; -#define ALIGNED_LEN(len) (((len) + align - 1) & ~(align - 1)) - - GElf_Xword idx = 0; - while (idx < phdr->p_filesz) - { - uint64_t namesz; - uint64_t descsz; - uint64_t type; - uint32_t namesz32; - uint32_t descsz32; - - if (align == 4) - { - uint32_t *ptr = (uint32_t *) (notemem + idx); - - if ((__BYTE_ORDER == __LITTLE_ENDIAN - && ehdr->e_ident[EI_DATA] == ELFDATA2MSB) - || (__BYTE_ORDER == __BIG_ENDIAN - && ehdr->e_ident[EI_DATA] == ELFDATA2LSB)) - { - namesz32 = namesz = bswap_32 (*ptr); - ++ptr; - descsz32 = descsz = bswap_32 (*ptr); - ++ptr; - type = bswap_32 (*ptr); - } - else - { - namesz32 = namesz = *ptr++; - descsz32 = descsz = *ptr++; - type = *ptr; - } - } - else - { - uint64_t *ptr = (uint64_t *) (notemem + idx); - uint32_t *ptr32 = (uint32_t *) (notemem + idx); - - if ((__BYTE_ORDER == __LITTLE_ENDIAN - && ehdr->e_ident[EI_DATA] == ELFDATA2MSB) - || (__BYTE_ORDER == __BIG_ENDIAN - && ehdr->e_ident[EI_DATA] == ELFDATA2LSB)) - { - namesz = bswap_64 (*ptr); - ++ptr; - descsz = bswap_64 (*ptr); - ++ptr; - type = bswap_64 (*ptr); - - namesz32 = bswap_32 (*ptr32); - ++ptr32; - descsz32 = bswap_32 (*ptr32); - } - else - { - namesz = *ptr++; - descsz = *ptr++; - type = *ptr; - - namesz32 = *ptr32++; - descsz32 = *ptr32; - } - } - - if (idx + 3 * align > phdr->p_filesz - || (idx + 3 * align + ALIGNED_LEN (namesz) + ALIGNED_LEN (descsz) - > phdr->p_filesz)) - { - if (ehdr->e_ident[EI_CLASS] == ELFCLASS64 - && idx + 3 * 4 <= phdr->p_filesz - && (idx + 3 * 4 + ALIGNED_LEN (namesz32) + ALIGNED_LEN (descsz32) - <= phdr->p_filesz)) - ERROR (gettext ("\ -phdr[%d]: note entries probably in form of a 32-bit ELF file\n"), cnt); - else - ERROR (gettext ("phdr[%d]: extra %zu bytes after last note\n"), - cnt, (size_t) (phdr->p_filesz - idx)); - break; - } - - /* Make sure it is one of the note types we know about. */ - if (ehdr->e_type == ET_CORE) - { - switch (type) - { - case NT_PRSTATUS: - case NT_FPREGSET: - case NT_PRPSINFO: - case NT_TASKSTRUCT: /* NT_PRXREG on Solaris. */ - case NT_PLATFORM: - case NT_AUXV: - case NT_GWINDOWS: - case NT_ASRS: - case NT_PSTATUS: - case NT_PSINFO: - case NT_PRCRED: - case NT_UTSNAME: - case NT_LWPSTATUS: - case NT_LWPSINFO: - case NT_PRFPXREG: - /* Known type. */ - break; - - default: - ERROR (gettext ("\ -phdr[%d]: unknown core file note type %" PRIu64 " at offset %" PRIu64 "\n"), - cnt, type, idx); - } - } - else - { - if (type != NT_VERSION) - ERROR (gettext ("\ -phdr[%d]: unknown object file note type %" PRIu64 " at offset %" PRIu64 "\n"), - cnt, type, idx); - } - - /* Move to the next entry. */ - idx += 3 * align + ALIGNED_LEN (namesz) + ALIGNED_LEN (descsz); - - } - - gelf_freechunk (ebl->elf, notemem); -} - - -static void -check_program_header (Ebl *ebl, GElf_Ehdr *ehdr) -{ - if (ehdr->e_phoff == 0) - return; - - if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN - && ehdr->e_type != ET_CORE) - ERROR (gettext ("\ -only executables, shared objects, and core files can have program headers\n")); - - int num_pt_interp = 0; - int num_pt_tls = 0; - int num_pt_relro = 0; - - for (int cnt = 0; cnt < ehdr->e_phnum; ++cnt) - { - GElf_Phdr phdr_mem; - GElf_Phdr *phdr; - - phdr = gelf_getphdr (ebl->elf, cnt, &phdr_mem); - if (phdr == NULL) - { - ERROR (gettext ("cannot get program header entry %d: %s\n"), - cnt, elf_errmsg (-1)); - continue; - } - - if (phdr->p_type >= PT_NUM && phdr->p_type != PT_GNU_EH_FRAME - && phdr->p_type != PT_GNU_STACK) - ERROR (gettext ("\ -program header entry %d: unknown program header entry type\n"), - cnt); - - if (phdr->p_type == PT_LOAD) - has_loadable_segment = true; - else if (phdr->p_type == PT_INTERP) - { - if (++num_pt_interp != 1) - { - if (num_pt_interp == 2) - ERROR (gettext ("\ -more than one INTERP entry in program header\n")); - } - has_interp_segment = true; - } - else if (phdr->p_type == PT_TLS) - { - if (++num_pt_tls == 2) - ERROR (gettext ("more than one TLS entry in program header\n")); - } - else if (phdr->p_type == PT_NOTE) - check_note (ebl, ehdr, phdr, cnt); - else if (phdr->p_type == PT_DYNAMIC - && ehdr->e_type == ET_EXEC && ! has_interp_segment) - ERROR (gettext ("static executable cannot have dynamic sections\n")); - else if (phdr->p_type == PT_GNU_RELRO) - { - if (++num_pt_relro == 2) - ERROR (gettext ("\ -more than one GNU_RELRO entry in program header\n")); - else - { - /* Check that the region is in a writable segment. */ - int inner; - for (inner = 0; inner < ehdr->e_phnum; ++inner) - { - GElf_Phdr phdr2_mem; - GElf_Phdr *phdr2; - - phdr2 = gelf_getphdr (ebl->elf, cnt, &phdr2_mem); - if (phdr2 == NULL) - continue; - - if (phdr2->p_type == PT_LOAD - && phdr->p_vaddr >= phdr2->p_vaddr - && (phdr->p_vaddr + phdr->p_memsz - <= phdr2->p_vaddr + phdr2->p_memsz)) - { - if ((phdr2->p_flags & PF_W) == 0) - ERROR (gettext ("\ -loadable segment GNU_RELRO applies to is not writable\n")); - if ((phdr2->p_flags & PF_X) != 0) - ERROR (gettext ("\ -loadable segment GNU_RELRO applies to is executable\n")); - break; - } - } - - if (inner >= ehdr->e_phnum) - ERROR (gettext ("\ -GNU_RELRO segment not contained in a loaded segment\n")); - } - } - - if (phdr->p_filesz > phdr->p_memsz) - ERROR (gettext ("\ -program header entry %d: file size greater than memory size\n"), - cnt); - - if (phdr->p_align > 1) - { - if (!powerof2 (phdr->p_align)) - ERROR (gettext ("\ -program header entry %d: alignment not a power of 2\n"), cnt); - else if ((phdr->p_vaddr - phdr->p_offset) % phdr->p_align != 0) - ERROR (gettext ("\ -program header entry %d: file offset and virtual address not module of alignment\n"), cnt); - } - } -} - - -/* Process one file. */ -static void -process_elf_file (Elf *elf, const char *prefix, const char *suffix, - const char *fname, size_t size, bool only_one) -{ - /* Reset variables. */ - ndynamic = 0; - - GElf_Ehdr ehdr_mem; - GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); - Ebl *ebl; - - /* Print the file name. */ - if (!only_one) - { - if (prefix != NULL) - printf ("\n%s(%s)%s:\n", prefix, fname, suffix); - else - printf ("\n%s:\n", fname); - } - - if (ehdr == NULL) - { - ERROR (gettext ("cannot read ELF header: %s\n"), elf_errmsg (-1)); - return; - } - - ebl = ebl_openbackend (elf); - /* If there is no appropriate backend library we cannot test - architecture and OS specific features. Any encountered extension - is an error. */ - - /* Go straight by the gABI, check all the parts in turn. */ - check_elf_header (ebl, ehdr, size); - - /* Check the program header. */ - check_program_header (ebl, ehdr); - - /* Next the section headers. It is OK if there are no section - headers at all. */ - check_sections (ebl, ehdr); - - /* Free the resources. */ - ebl_closebackend (ebl); -} diff --git a/src/i386_ld.c b/src/i386_ld.c deleted file mode 100644 index 28304ca0..00000000 --- a/src/i386_ld.c +++ /dev/null @@ -1,891 +0,0 @@ -/* Copyright (C) 2001, 2002, 2003, 2004 Red Hat, Inc. - Written by Ulrich Drepper <drepper@redhat.com>, 2001. - - This program is Open Source software; you can redistribute it and/or - modify it under the terms of the Open Software License version 1.0 as - published by the Open Source Initiative. - - You should have received a copy of the Open Software License along - with this program; if not, you may obtain a copy of the Open Software - License version 1.0 from http://www.opensource.org/licenses/osl.php or - by writing the Open Source Initiative c/o Lawrence Rosen, Esq., - 3001 King Ranch Road, Ukiah, CA 95482. */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <assert.h> -#include <error.h> -#include <libintl.h> -#include <stdlib.h> -#include <string.h> - -// XXX For debugging -#include <stdio.h> - -#include <system.h> -#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, int klass, - int data) -{ - /* 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, 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. I get them iteratively, too. */ - runp = firstp; - data = NULL; - do - { - Elf_Data *reltgtdata; - Elf_Data *insymdata; - Elf_Data *inxndxdata = NULL; - size_t maxcnt; - size_t cnt; - const Elf32_Word *symindirect; - struct symbol **symref; - struct usedfiles *file = runp->fileinfo; - XElf_Shdr *shdr = &SCNINFO_SHDR (runp->shdr); - - /* Get the output section data buffer for this input section. */ - data = elf_getdata (outscn, data); - assert (data != 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 = elf_getdata (file->scninfo[shdr->sh_info].scn, NULL); - - /* Get the data for the input section symbol table for this - relocation section. */ - insymdata = elf_getdata (file->scninfo[shdr->sh_link].scn, NULL); - assert (insymdata != NULL); - - /* And the extended section index table. */ - inxndxdata = runp->fileinfo->xndxdata; - - /* Number of relocations. */ - maxcnt = shdr->sh_size / shdr->sh_entsize; - - /* Array directing local symbol table offsets to output symbol - table offsets. */ - symindirect = file->symindirect; - - /* References to the symbol records. */ - symref = file->symref; - - /* Iterate over all the relocations in the section. */ - for (cnt = 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 != NULL); - - /* Compute the symbol index in the output file. */ - si = symindirect[XELF_R_SYM (rel->r_info)]; - if (si == 0) - { - /* This happens if the symbol is locally undefined or - superceded by some other definition. */ - assert (symref[XELF_R_SYM (rel->r_info)] != NULL); - si = symref[XELF_R_SYM (rel->r_info)]->outsymidx; - } - /* Take reordering performed to sort the symbol table into - account. */ - si = dblindirect[si]; - - /* Get the symbol table entry. */ - xelf_getsymshndx (insymdata, inxndxdata, XELF_R_SYM (rel->r_info), - sym, xndx); - if (sym->st_shndx != SHN_XINDEX) - xndx = 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 is a - relocation referred 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) == STT_SECTION) - { - Elf32_Word toadd; - - /* We expect here on R_386_32 relocations. */ - assert (XELF_R_TYPE (rel->r_info) == 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. */ - toadd = file->scninfo[xndx].offset; - if (toadd != 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 += file->scninfo[shdr->sh_info].offset; - - /* And finally adjust the index of the symbol in the output - symbol table. */ - rel->r_info = XELF_R_INFO (si, XELF_R_TYPE (rel->r_info)); - - /* Store the result. */ - (void) xelf_update_rel (data, cnt, rel); - } - - runp = runp->next; - } - while (runp != 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 != NULL); - shdr->sh_entsize = PLT_ENTRY_SIZE; - (void) xelf_update_shdr (scn, shdr); - - data = elf_newdata (scn); - if (data == 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 = (1 + statep->nplt) * PLT_ENTRY_SIZE; - data->d_buf = xcalloc (1, data->d_size); - data->d_align = 8; - data->d_off = 0; - - statep->nplt_used = 1; -} - - -static void -elf_i386_initialize_pltrel (struct ld_state *statep, Elf_Scn *scn) -{ - Elf_Data *data; - - data = elf_newdata (scn); - if (data == NULL) - error (EXIT_FAILURE, 0, gettext ("cannot allocate PLTREL section: %s"), - elf_errmsg (-1)); - - /* One relocation per PLT entry. */ - data->d_size = statep->nplt * sizeof (Elf32_Rel); - data->d_buf = xcalloc (1, data->d_size); - data->d_type = ELF_T_REL; - data->d_align = 4; - data->d_off = 0; -} - - -static void -elf_i386_initialize_got (struct ld_state *statep, Elf_Scn *scn) -{ - Elf_Data *data; - - /* If we have no .plt we don't need the special entries we normally - create for it. The other contents is created later. */ - if (statep->ngot + statep->nplt == 0) - return; - - data = elf_newdata (scn); - if (data == NULL) - error (EXIT_FAILURE, 0, gettext ("cannot allocate GOT section: %s"), - elf_errmsg (-1)); - - /* We construct the .got section in pieces. Here we only add the data - 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. */ - data->d_size = (3 + statep->ngot + statep->nplt) * sizeof (Elf32_Addr); - data->d_buf = xcalloc (1, data->d_size); - data->d_align = sizeof (Elf32_Addr); - data->d_off = 0; -} - - -/* 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] = -{ - 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. */ - 0, 0, 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] = -{ - 0xff, 0xb3, 4, 0, 0, 0, /* pushl 4(%ebx) */ - 0xff, 0xa3, 8, 0, 0, 0, /* jmp *8(%ebx) */ - 0, 0, 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] = -{ - 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] = -{ - 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_dyn) -{ - Elf_Scn *scn; - XElf_Shdr_vardef (shdr); - Elf_Data *data; - Elf_Data *symdata = NULL; - Elf_Data *dynsymdata; - size_t cnt; - const bool build_dso = statep->file_type == dso_file_type; - - if (unlikely (statep->nplt + statep->ngot == 0)) - /* Nothing to be done. */ - return; - - /* Get the address of the got section. */ - scn = elf_getscn (statep->outelf, statep->gotscnidx); - xelf_getshdr (scn, shdr); - data = elf_getdata (scn, NULL); - assert (shdr != NULL && data != NULL); - Elf32_Addr gotaddr = shdr->sh_addr; - - /* Now create the initial values for the .got section. The first - word contains the address of the .dynamic section. */ - xelf_getshdr (elf_getscn (statep->outelf, statep->dynamicscnidx), shdr); - assert (shdr != NULL); - ((Elf32_Word *) data->d_buf)[0] = shdr->sh_addr; - - /* 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. Since the first PLT entry is special the first used one - has the index 1. */ - scn = elf_getscn (statep->outelf, statep->pltscnidx); - xelf_getshdr (scn, shdr); - assert (shdr != NULL); - - dynsymdata = elf_getdata (elf_getscn (statep->outelf, statep->dynsymscnidx), - NULL); - assert (dynsymdata != NULL); - - if (statep->symscnidx != 0) - { - symdata = elf_getdata (elf_getscn (statep->outelf, statep->symscnidx), - NULL); - assert (symdata != NULL); - } - - for (cnt = 0; cnt < statep->nplt; ++cnt) - { - assert ((4 + cnt) * sizeof (Elf32_Word) <= data->d_size); - - /* Address in the PLT. */ - Elf32_Addr pltentryaddr = shdr->sh_addr + (1 + cnt) * PLT_ENTRY_SIZE; - - /* Point the GOT entry at the PLT entry, after the initial jmp. */ - ((Elf32_Word *) data->d_buf)[3 + cnt] = pltentryaddr + 6; - - /* 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)[1 + cnt].st_value = pltentryaddr; - - if (symdata != NULL) - ((Elf32_Sym *) symdata->d_buf)[nsym - statep->nplt + cnt].st_value - = pltentryaddr; - } - - /* Create the .plt section. */ - scn = elf_getscn (statep->outelf, statep->pltscnidx); - data = elf_getdata (scn, NULL); - assert (data != NULL); - - /* Create the first entry. */ - assert (data->d_size >= PLT_ENTRY_SIZE); - if (build_dso) - /* Copy the entry. It's complete, no relocation needed. */ - memcpy (data->d_buf, elf_i386_pic_plt0_entry, PLT_ENTRY_SIZE); - else - { - /* Copy the skeleton. */ - memcpy (data->d_buf, elf_i386_plt0_entry, PLT_ENTRY_SIZE); - - /* And fill in the addresses. */ - struct plt0_entry *addr = (struct plt0_entry *) data->d_buf; - addr->gotp4_addr = target_bswap_32 (gotaddr + 4); - addr->gotp8_addr = target_bswap_32 (gotaddr + 8); - } - - /* For DSOs we need GOT offsets, otherwise the GOT address. */ - Elf32_Addr gotaddr_off = build_dso ? 0 : gotaddr; - - /* Create the remaining entries. */ - const unsigned char *plt_template - = build_dso ? elf_i386_pic_plt_entry : elf_i386_plt_entry; - - for (cnt = 0; cnt < statep->nplt; ++cnt) - { - struct plt_entry *addr; - - /* Copy the template. */ - assert (data->d_size >= (2 + cnt) * PLT_ENTRY_SIZE); - addr = (struct plt_entry *) ((char *) data->d_buf - + (1 + cnt) * 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 = target_bswap_32 (gotaddr_off - + (3 + cnt) * sizeof (Elf32_Addr)); - /* Offset into relocation table. */ - addr->push_imm = target_bswap_32 (cnt * sizeof (Elf32_Rel)); - /* Offset to start of .plt. */ - addr->plt0_offset = target_bswap_32 (-(2 + cnt) * PLT_ENTRY_SIZE); - } - - /* Create the .rel.plt section data. It simply means relocations - addressing the corresponding entry in the .got section. The - section name is misleading. */ - scn = elf_getscn (statep->outelf, statep->pltrelscnidx); - xelf_getshdr (scn, shdr); - data = elf_getdata (scn, NULL); - assert (shdr != NULL && data != NULL); - - /* Update the sh_link to point to the section being modified. We - point it here (correctly) to the .got 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 = statep->dynsymscnidx; - shdr->sh_info = statep->gotscnidx; - (void) xelf_update_shdr (scn, shdr); - - for (cnt = 0; cnt < statep->nplt; ++cnt) - { - XElf_Rel_vardef (rel); - - assert ((1 + cnt) * sizeof (Elf32_Rel) <= data->d_size); - xelf_getrel_ptr (data, cnt, rel); - rel->r_offset = gotaddr + (3 + cnt) * sizeof (Elf32_Addr); - /* The symbol table entries for the functions from DSOs are at - the end of the symbol table. */ - rel->r_info = XELF_R_INFO (1 + cnt, R_386_JMP_SLOT); - (void) xelf_update_rel (data, cnt, 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 *scninfo) -{ - /* 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 = elf_getdata (scninfo->scn, NULL); - XElf_Shdr *shdr = &SCNINFO_SHDR (scninfo->shdr); - size_t maxcnt = shdr->sh_size / shdr->sh_entsize; - size_t relsize = 0; - size_t cnt; - struct symbol *sym; - - assert (shdr->sh_type == SHT_REL); - - for (cnt = 0; cnt < maxcnt; ++cnt) - { - XElf_Rel_vardef (rel); - - xelf_getrel (data, cnt, rel); - /* XXX Should we complain about failing accesses? */ - if (rel != NULL) - { - int r_sym = XELF_R_SYM (rel->r_info); - - switch (XELF_R_TYPE (rel->r_info)) - { - case R_386_GOT32: - if (! scninfo->fileinfo->symref[r_sym]->defined) - relsize += sizeof (Elf32_Rel); - - /* This relocation is not emitted in the output file but - requires a GOT entry. */ - ++statep->ngot; - ++statep->nrel_got; - - /* FALLTHROUGH */ - - case R_386_GOTOFF: - case R_386_GOTPC: - statep->need_got = 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 == dso_file_type) - { - relsize += sizeof (Elf32_Rel); - statep->dt_flags |= DF_TEXTREL; - } - else - { - /* Non-function objects from a DSO need to get a - copy relocation. */ - sym = scninfo->fileinfo->symref[r_sym]; - - /* Only do this if we have not requested a copy - relocation already. */ - if (unlikely (sym->type != STT_FUNC) && ! sym->need_copy) - { - sym->need_copy = 1; - ++statep->ncopy; - relsize += sizeof (Elf32_Rel); - } - } - } - else if (statep->file_type == dso_file_type - && r_sym >= SCNINFO_SHDR (scninfo->fileinfo->scninfo[shdr->sh_link].shdr).sh_info - && scninfo->fileinfo->symref[r_sym]->outdynsymidx != 0 - && XELF_R_TYPE (rel->r_info) == R_386_32) - relsize += 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) - { - assert (!statep->statically); - - sym = scninfo->fileinfo->symref[r_sym]; - sym->type = STT_FUNC; - sym->in_dso = 1; - sym->defined = 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_GD: - 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_LDO_32: - 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 = relsize; -} - - -static void -elf_i386_create_relocations (struct ld_state *statep, - const Elf32_Word *dblindirect) -{ - /* Get the address of the got section. */ - Elf_Scn *pltscn = elf_getscn (statep->outelf, statep->pltscnidx); - Elf32_Shdr *shdr = elf32_getshdr (pltscn); - assert (shdr != NULL); - Elf32_Addr pltaddr = shdr->sh_addr; - - Elf_Scn *gotscn = elf_getscn (statep->outelf, statep->gotscnidx); - shdr = elf32_getshdr (gotscn); - assert (shdr != NULL); - Elf32_Addr gotaddr = shdr->sh_addr; - - Elf_Scn *reldynscn = elf_getscn (statep->outelf, statep->reldynscnidx); - Elf_Data *reldyndata = elf_getdata (reldynscn, NULL); - - size_t nreldyn = 0; -#define ngot_used (3 + statep->nplt + nreldyn) - - struct scninfo *first = statep->rellist->next; - struct scninfo *runp = first; - do - { - XElf_Shdr *rshdr = &SCNINFO_SHDR (runp->shdr); - Elf_Data *reldata = elf_getdata (runp->scn, NULL); - int nrels = rshdr->sh_size / rshdr->sh_entsize; - - /* We will need the following vlaues a couple of times. Help - the compiler and improve readability. */ - struct symbol **symref = runp->fileinfo->symref; - struct scninfo *scninfo = runp->fileinfo->scninfo; - - /* This is the offset of the input section we are looking at in - the output file. */ - XElf_Addr inscnoffset = scninfo[rshdr->sh_info].offset; - - /* The target section. We use the data from the input file. */ - Elf_Data *data = 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) == 0); - - /* Cache the access to the symbol table data. */ - Elf_Data *symdata = elf_getdata (scninfo[rshdr->sh_link].scn, NULL); - - int cnt; - for (cnt = 0; cnt < nrels; ++cnt) - { - XElf_Rel_vardef (rel); - XElf_Rel *rel2; - xelf_getrel (reldata, cnt, rel); - assert (rel != NULL); - XElf_Addr reladdr = inscnoffset + rel->r_offset; - XElf_Addr value; - - size_t idx = XELF_R_SYM (rel->r_info); - if (idx < runp->fileinfo->nlocalsymbols) - { - XElf_Sym_vardef (sym); - xelf_getsym (symdata, idx, sym); - - /* The value just depends on the position of the referenced - section in the output file and the addend. */ - value = scninfo[sym->st_shndx].offset + sym->st_value; - } - else if (symref[idx]->in_dso) - { - /* MERGE.VALUE contains the PLT index. We have to add 1 since - there is this one special PLT entry at the beginning. */ - assert (symref[idx]->merge.value != 0 - || symref[idx]->type != STT_FUNC); - value = pltaddr + symref[idx]->merge.value * PLT_ENTRY_SIZE; - } - else - value = symref[idx]->merge.value; - - /* Address of the relocated memory in the data buffer. */ - void *relloc = (char *) data->d_buf + rel->r_offset; - - 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 -= reladdr; - /* FALLTHROUGH */ - - case R_386_32: - if (linked_from_dso_p (scninfo, idx) - && statep->file_type != dso_file_type - && symref[idx]->type != STT_FUNC) - { - value = (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 != 0); -#if NATIVE_ELF != 0 - xelf_getrel_ptr (reldyndata, nreldyn, rel2); -#else - rel2 = &rel_mem; -#endif - rel2->r_offset = value; - rel2->r_info - = XELF_R_INFO (symref[idx]->outdynsymidx, R_386_COPY); - (void) xelf_update_rel (reldyndata, nreldyn, rel2); - ++nreldyn; - - /* Update the symbol table record for the new - address. */ - Elf32_Word symidx = symref[idx]->outdynsymidx; - Elf_Scn *symscn = elf_getscn (statep->outelf, - statep->dynsymscnidx); - Elf_Data *outsymdata = elf_getdata (symscn, NULL); - assert (outsymdata != NULL); - XElf_Sym_vardef (sym); - xelf_getsym (outsymdata, symidx, sym); - sym->st_value = value; - sym->st_shndx = statep->copy_section->outscnndx; - (void) xelf_update_sym (outsymdata, symidx, sym); - - symidx = symref[idx]->outsymidx; - if (symidx != 0) - { - symidx = statep->dblindirect[symidx]; - symscn = elf_getscn (statep->outelf, - statep->symscnidx); - outsymdata = elf_getdata (symscn, NULL); - assert (outsymdata != NULL); - xelf_getsym (outsymdata, symidx, sym); - sym->st_value = value; - sym->st_shndx = statep->copy_section->outscnndx; - (void) xelf_update_sym (outsymdata, symidx, sym); - } - - /* Remember that we set up the copy relocation. */ - symref[idx]->need_copy = 0; - } - } - else if (statep->file_type == dso_file_type - && idx >= SCNINFO_SHDR (scninfo[rshdr->sh_link].shdr).sh_info - && symref[idx]->outdynsymidx != 0) - { -#if NATIVE_ELF != 0 - xelf_getrel_ptr (reldyndata, nreldyn, rel2); -#else - rel2 = &rel_mem; -#endif - rel2->r_offset = value; - rel2->r_info - = XELF_R_INFO (symref[idx]->outdynsymidx, R_386_32); - (void) xelf_update_rel (reldyndata, nreldyn, rel2); - ++nreldyn; - - value = 0; - } - add_4ubyte_unaligned (relloc, value); - break; - - case R_386_GOT32: - store_4ubyte_unaligned (relloc, ngot_used * sizeof (Elf32_Addr)); - - /* Add a relocation to initialize the GOT entry. */ -#if NATIVE_ELF != 0 - xelf_getrel_ptr (reldyndata, nreldyn, rel2); -#else - rel2 = &rel_mem; -#endif - rel2->r_offset = gotaddr + ngot_used * sizeof (Elf32_Addr); - rel2->r_info - = XELF_R_INFO (symref[idx]->outdynsymidx, R_386_GLOB_DAT); - (void) xelf_update_rel (reldyndata, nreldyn, rel2); - ++nreldyn; - break; - - case R_386_GOTOFF: - add_4ubyte_unaligned (relloc, value - gotaddr); - break; - - case R_386_32PLT: - case R_386_TLS_TPOFF: - case R_386_TLS_IE: - case R_386_TLS_GOTIE: - case R_386_TLS_LE: - case R_386_TLS_GD: - 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_LDO_32: - case R_386_TLS_IE_32: - case R_386_TLS_LE_32: - // XXX For now fall through - printf("ignored relocation %d\n", (int) XELF_R_TYPE (rel->r_info)); - 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 = runp->next) != first); -} - - -int -elf_i386_ld_init (struct ld_state *statep) -{ - /* We have a few callbacks available. */ - old_open_outfile = statep->callbacks.open_outfile; - statep->callbacks.open_outfile = elf_i386_open_outfile; - - statep->callbacks.relocate_section = elf_i386_relocate_section; - - statep->callbacks.initialize_plt = elf_i386_initialize_plt; - statep->callbacks.initialize_pltrel = elf_i386_initialize_pltrel; - - statep->callbacks.initialize_got = elf_i386_initialize_got; - - statep->callbacks.finalize_plt = elf_i386_finalize_plt; - - statep->callbacks.rel_type = elf_i386_rel_type; - - statep->callbacks.count_relocations = elf_i386_count_relocations; - - statep->callbacks.create_relocations = elf_i386_create_relocations; - - return 0; -} diff --git a/src/ld.c b/src/ld.c deleted file mode 100644 index a6b664f7..00000000 --- a/src/ld.c +++ /dev/null @@ -1,1520 +0,0 @@ -/* Copyright (C) 2001, 2002, 2003, 2004 Red Hat, Inc. - Written by Ulrich Drepper <drepper@redhat.com>, 2001. - - This program is Open Source software; you can redistribute it and/or - modify it under the terms of the Open Software License version 1.0 as - published by the Open Source Initiative. - - You should have received a copy of the Open Software License along - with this program; if not, you may obtain a copy of the Open Software - License version 1.0 from http://www.opensource.org/licenses/osl.php or - by writing the Open Source Initiative c/o Lawrence Rosen, Esq., - 3001 King Ranch Road, Ukiah, CA 95482. */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <argp.h> -#include <assert.h> -#include <error.h> -#include <fcntl.h> -#include <libelf.h> -#include <libintl.h> -#include <locale.h> -#include <mcheck.h> -#include <stdio.h> -#include <stdio_ext.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include <system.h> -#include "ld.h" -#include "list.h" - - -/* Name and version of program. */ -static void print_version (FILE *stream, struct argp_state *state); -void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; - - -/* Values for the various options. */ -enum - { - ARGP_whole_archive = 300, - ARGP_no_whole_archive, - ARGP_static, - ARGP_dynamic, - ARGP_pagesize, - ARGP_rpath, - ARGP_rpath_link, - ARGP_runpath, - ARGP_runpath_link, - ARGP_version_script, - ARGP_gc_sections, - ARGP_no_gc_sections, - ARGP_no_undefined, - ARGP_conserve, -#if YYDEBUG - ARGP_yydebug, -#endif - }; - - -/* Definitions of arguments for argp functions. */ -static const struct argp_option options[] = -{ - /* XXX This list will be reordered and section names will be added. - Just not right now. */ - { "whole-archive", ARGP_whole_archive, NULL, 0, - N_("Include whole archives in the output from now on.") }, - { "no-whole-archive", ARGP_no_whole_archive, NULL, 0, - N_("Stop including the whole arhives in the output.") }, - - { "output", 'o', N_("FILE"), 0, N_("Place output in FILE.") }, - - { NULL, 'O', N_("LEVEL"), OPTION_ARG_OPTIONAL, - N_("Set optimization level to LEVEL.") }, - - { "verbose", 'v', NULL, 0, N_("Verbose messages.") }, - { "trace", 't', NULL, 0, N_("Trace file opens.") }, - { "conserve-memory", ARGP_conserve, NULL, 0, - N_("Trade speed for less memory usage") }, - - { NULL, 'z', "KEYWORD", OPTION_HIDDEN, NULL }, - { "-z nodefaultlib", '\0', NULL, OPTION_DOC, - N_("Object is marked to not use default search path at runtime.") }, - { "-z allextract", '\0', NULL, OPTION_DOC, - N_("Same as --whole-archive.") }, - { "-z defaultextract", '\0', NULL, OPTION_DOC, N_("\ -Default rules of extracting from archive; weak references are not enough.") }, - { "-z weakextract", '\0', NULL, OPTION_DOC, - N_("Weak references cause extraction from archive.") }, - { "-z muldefs", '\0', NULL, OPTION_DOC, - N_("Allow multiple definitions; first is used.") }, - { "-z defs | nodefs", '\0', NULL, OPTION_DOC, - N_("Disallow/allow undefined symbols in DSOs.") }, - { "no-undefined", ARGP_no_undefined, NULL, OPTION_HIDDEN, NULL }, - { "-z origin", '\0', NULL, OPTION_DOC, - N_("Object requires immediate handling of $ORIGIN.") }, - { "-z now", '\0', NULL, OPTION_DOC, - N_("Relocation will not be processed lazily.") }, - { "-z nodelete", '\0', NULL, OPTION_DOC, - N_("Object cannot be unloaded at runtime.") }, - { "-z initfirst", '\0', NULL, OPTION_DOC, - N_("Mark object to be initialized first.") }, - { "-z lazyload | nolazyload", '\0', NULL, OPTION_DOC, - N_("Enable/disable lazy-loading flag for following dependencies.") }, - { "-z nodlopen", '\0', NULL, OPTION_DOC, - N_("Mark object as not loadable with 'dlopen'.") }, - { "-z ignore | record", '\0', NULL, OPTION_DOC, - N_("Ignore/record dependencies on unused DSOs.") }, - { "-z systemlibrary", '\0', NULL, OPTION_DOC, - N_("Generated DSO will be a system library.") }, - - { NULL, 'l', N_("FILE"), OPTION_HIDDEN, NULL }, - - { NULL, '(', NULL, 0, N_("Start a group.") }, - { NULL, ')', NULL, 0, N_("End a group.") }, - - { NULL, 'L', N_("PATH"), 0, - N_("Add PATH to list of directories files are searched in.") }, - - { NULL, 'c', N_("FILE"), 0, N_("Use linker script in FILE.") }, - - { "entry", 'e', N_("ADDRESS"), 0, N_("Set entry point address.") }, - - { "static", ARGP_static, NULL, OPTION_HIDDEN, NULL }, - { "-B static", ARGP_static, NULL, OPTION_DOC, - N_("Do not link against shared libraries.") }, - { "dynamic", ARGP_dynamic, NULL, OPTION_HIDDEN, NULL }, - { "-B dynamic", ARGP_dynamic, NULL, OPTION_DOC, - N_("Prefer linking against shared libraries.") }, - - { "export-dynamic", 'E', NULL, 0, N_("Export all dynamic symbols.") }, - - { "strip-all", 's', NULL, 0, N_("Strip all symbols.") }, - { "strip-debug", 'S', NULL, 0, N_("Strip debugging symbols.") }, - - { "pagesize", ARGP_pagesize, "SIZE", 0, - N_("Assume pagesize for the target system to be SIZE.") }, - - { "rpath", ARGP_rpath, "PATH", OPTION_HIDDEN, NULL }, - { "rpath-link", ARGP_rpath_link, "PATH", OPTION_HIDDEN, NULL }, - - { "runpath", ARGP_runpath, "PATH", 0, N_("Set runtime DSO search path.") }, - { "runpath-link", ARGP_runpath_link, "PATH", 0, - N_("Set link time DSO search path.") }, - - { NULL, 'i', NULL, 0, N_("Ignore LD_LIBRARY_PATH environment variable.") }, - - { "version-script", ARGP_version_script, "FILE", 0, - N_("Read version information from FILE.") }, - - { "emulation", 'm', "NAME", 0, N_("Set emulation to NAME.") }, - - { "shared", 'G', NULL, 0, N_("Generate dynamic shared object.") }, - { NULL, 'r', NULL, 0L, N_("Generate relocatable object.") }, - - { NULL, 'B', "KEYWORD", OPTION_HIDDEN, "" }, - { "-B local", 'B', NULL, OPTION_DOC, - N_("Causes symbol not assigned to a version be reduced to local.") }, - - { "gc-sections", ARGP_gc_sections, NULL, 0, N_("Remove unused sections.") }, - { "no-gc-sections", ARGP_no_gc_sections, NULL, 0, - N_("Don't remove unused sections.") }, - - { "soname", 'h', "NAME", 0, N_("Set soname of shared object.") }, - { "dynamic-linker", 'I', "NAME", 0, N_("Set the dynamic linker name.") }, - - { NULL, 'Q', "YN", OPTION_HIDDEN, NULL }, - { "-Q y | n", 'Q', NULL, OPTION_DOC, - N_("Add/suppress addition indentifying link-editor to .comment section") }, - -#if YYDEBUG - { "yydebug", ARGP_yydebug, NULL, 0, - N_("Select to get parser debug information") }, -#endif - - { NULL, 0, NULL, 0, NULL } -}; - -/* Short description of program. */ -static const char doc[] = N_("Combine object and archive files."); - -/* Strings for arguments in help texts. */ -static const char args_doc[] = N_("[FILE]..."); - -/* Prototype for option handler. */ -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); - -/* Function to print some extra text in the help message. */ -static char *more_help (int key, const char *text, void *input); - -/* Data structure to communicate with argp functions. */ -static struct argp argp_1st = -{ - options, parse_opt_1st, args_doc, doc, NULL, more_help -}; -static struct argp argp_2nd = -{ - options, parse_opt_2nd, args_doc, doc, NULL, more_help -}; - - -/* 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 = 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; - -#ifndef NDEBUG - /* Enable memory debugging. */ - mtrace (); -#endif - - /* Sanity check. We always want to use the LFS functionality. */ - if (sizeof (off_t) != sizeof (off64_t)) - 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, LOCALEDIR); - - /* Initialize the message catalog. */ - textdomain (PACKAGE); - - /* 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 = getenv ("LD_LIBRARY_PATH"); - - /* Initialize the memory handling. */ -#define obstack_chunk_alloc xmalloc -#define obstack_chunk_free free - obstack_init (&ld_state.smem); - - /* 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 == 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 (); - - /* Prepare state. */ - err = ld_prepare_state (emulation); - if (err != 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 = fopen (linker_script, "r"); - if (ldin == NULL) - error (EXIT_FAILURE, errno, gettext ("cannot open linker script \"%s\""), - linker_script); - /* No need for locking. */ - __fsetlocking (ldin, FSETLOCKING_BYCALLER); - - ld_state.srcfiles = NULL; - ldlineno = 1; - ld_scan_version_script = 0; - ldin_fname = linker_script; - if (ldparse () != 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 = ld_state.paths; - ld_state.paths = ld_state.tailpaths = 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 == argc); - - /* Process the last file. */ - while (last_file != NULL) - /* Try to open the file. */ - error_loading |= 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 != 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) != 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 != relocatable_file_type) - { - void *p ; - struct scnhead *h; - - p = NULL; - while ((h = ld_section_tab_iterate (&ld_state.section_tab, &p)) != NULL) - if (h->type == SHT_REL || h->type == SHT_RELA) - { - struct scninfo *runp = 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 += runp->relsize; - } - while ((runp = runp->next) != 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) != 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) != 0) - exit (1); - - /* Finalize the output file, write the data out. */ - err |= FINALIZE (&ld_state); - - /* Return with an non-zero exit status also if any error message has - been printed. */ - return err | (error_message_count != 0); -} - - -static char * -more_help (int key, const char *text, void *input) -{ - char *buf; - - switch (key) - { - case ARGP_KEY_HELP_EXTRA: - /* We print some extra information. */ - if (asprintf (&buf, gettext ("Please report bugs to %s.\n"), - PACKAGE_BUGREPORT) < 0) - buf = NULL; - return buf; - - default: - break; - } - return (char *) text; -} - - -/* 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) -{ - switch (key) - { - case 'B': - parse_B_option (arg); - break; - - case 'c': - linker_script = arg; - break; - - case 'E': - ld_state.export_all_dynamic = true; - break; - - case 'G': - if (ld_state.file_type != no_file_type) - error (EXIT_FAILURE, 0, - gettext ("only one option of -G and -r is allowed")); - ld_state.file_type = dso_file_type; - - /* If we generate a DSO we have to export all symbols. */ - ld_state.export_all_dynamic = true; - break; - - case 'h': - ld_state.soname = arg; - break; - - case 'i': - /* Discard the LD_LIBRARY_PATH value we found. */ - ld_library_path1 = NULL; - break; - - case 'I': - ld_state.interp = arg; - break; - - case 'm': - if (emulation != NULL) - error (EXIT_FAILURE, 0, gettext ("more than one '-m' parameter")); - emulation = arg; - break; - - case 'Q': - if (arg[1] == '\0' && (arg[0] == 'y' || arg[0] == 'Y')) - ld_state.add_ld_comment = true; - else if (arg[1] == '\0' && (arg[0] == 'n' || arg[0] == 'N')) - ld_state.add_ld_comment = true; - else - error (EXIT_FAILURE, 0, gettext ("unknown option `-%c %s'"), 'Q', arg); - break; - - case 'r': - if (ld_state.file_type != no_file_type) - error (EXIT_FAILURE, 0, - gettext ("only one option of -G and -r is allowed")); - ld_state.file_type = relocatable_file_type; - break; - - case 'S': - ld_state.strip = strip_debug; - break; - - case 't': - ld_state.trace_files = true; - break; - - case 'v': - verbose = 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 = strtoul (arg, &endp, 0); - if (*endp != '\0') - { - if (endp[1] == '\0' && tolower (*endp) == 'k') - ld_state.pagesize *= 1024; - else if (endp[1] == '\0' && tolower (*endp) == 'm') - ld_state.pagesize *= 1024 * 1024; - else - { - error (0, 0, - gettext ("invalid page size value \"%s\": ignored"), - arg); - ld_state.pagesize = 0; - } - } - } - break; - - case ARGP_rpath: - 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 = key == ARGP_gc_sections; - break; - - case 's': - if (arg == NULL) - { - if (ld_state.strip == strip_all) - ld_state.strip = strip_everything; - else - ld_state.strip = strip_all; - break; - } - /* FALLTHROUGH */ - - case 'e': - case 'o': - case 'O': - case ARGP_whole_archive: - case ARGP_no_whole_archive: - 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 = (struct file_list *) xmalloc (sizeof (struct file_list)); - newp->name = arg; -#ifndef NDEBUG - newp->next = NULL; -#endif - CSNGL_LIST_ADD_REAR (input_file_list, newp); - } - break; - -#if YYDEBUG - case ARGP_yydebug: - lddebug = 1; - break; -#endif - - case ARGP_no_undefined: - ld_state.nodefs = false; - break; - - case ARGP_conserve: - conserve_memory = 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) -{ - 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 = arg; - break; - - case 'o': - if (ld_state.outfname != 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 = arg; - break; - - case 'O': - if (arg == NULL) - ld_state.optlevel = 1; - else - { - char *endp; - unsigned long int level = strtoul (arg, &endp, 10); - if (*endp != '\0') - { - error (0, 0, gettext ("Invalid optimization level `%s'"), arg); - goto see_help; - } - ld_state.optlevel = level; - } - break; - - case ARGP_whole_archive: - ld_state.extract_rule = allextract; - break; - case ARGP_no_whole_archive: - ld_state.extract_rule = defaultextract; - break; - - case ARGP_static: - case ARGP_dynamic: - /* Enable/disable use for DSOs. */ - ld_state.statically = key == 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 = true; - group_end_requested = 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 == 0) - { - error (0, 0, gettext ("-) without matching -(")); - goto see_help; - } - } - else - last_file->group_end = true; - - if (group_level > 0) - --group_level; - break; - - case 'l': - case ARGP_KEY_ARG: - { - while (last_file != NULL) - /* Try to open the file. */ - error_loading |= FILE_PROCESS (-1, last_file, &ld_state, &last_file); - - last_file = ld_new_inputfile (arg, - key == 'l' - ? archive_file_type - : relocatable_file_type); - if (group_start_requested) - { - last_file->group_start = true; - - group_start_requested = false; - group_end_requested = 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 == NULL) - return; - - runp = first = ld_state.needed->next; - do - { - struct usedfiles *ignore; - struct usedfiles *next = runp->next; - int err; - - err = FILE_PROCESS (-1, runp, &ld_state, &ignore); - if (err != 0) - /* Something went wrong. */ - exit (err); - - runp = next; - } - while (runp != first); -} - - -/* Print the version information. */ -static void -print_version (FILE *stream, struct argp_state *state) -{ - fprintf (stream, "ld (%s) %s\n", PACKAGE_NAME, 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\ -"), "2004"); - 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") == 0 - /* This is only meaningful if we create a DSO. */ - && ld_state.file_type == dso_file_type) - ld_state.dt_flags_1 |= DF_1_NODEFLIB; - else if (strcmp (arg, "muldefs") == 0) - ld_state.muldefs = true; - else if (strcmp (arg, "nodefs") == 0) - ld_state.nodefs = true; - else if (strcmp (arg, "defs") == 0) - ld_state.nodefs = false; - else if (strcmp (arg, "now") == 0) - /* We could also set the DF_1_NOW flag in DT_FLAGS_1 but this isn't - necessary. */ - ld_state.dt_flags |= DF_BIND_NOW; - else if (strcmp (arg, "origin") == 0) - /* We could also set the DF_1_ORIGIN flag in DT_FLAGS_1 but this isn't - necessary. */ - ld_state.dt_flags |= DF_ORIGIN; - else if (strcmp (arg, "nodelete") == 0 - /* This is only meaningful if we create a DSO. */ - && ld_state.file_type == dso_file_type) - ld_state.dt_flags_1 |= DF_1_NODELETE; - else if (strcmp (arg, "initfirst") == 0) - ld_state.dt_flags_1 |= DF_1_INITFIRST; - else if (strcmp (arg, "nodlopen") == 0 - /* This is only meaningful if we create a DSO. */ - && ld_state.file_type == dso_file_type) - ld_state.dt_flags_1 |= DF_1_NOOPEN; - else if (strcmp (arg, "ignore") == 0) - ld_state.ignore_unused_dsos = true; - else if (strcmp (arg, "record") == 0) - ld_state.ignore_unused_dsos = false; - else if (strcmp (arg, "systemlibrary") == 0) - ld_state.is_system_library = true; - else if (strcmp (arg, "allextract") != 0 - && strcmp (arg, "defaultextract") != 0 - && strcmp (arg, "weakextract") != 0 - && strcmp (arg, "lazyload") != 0 - && strcmp (arg, "nolazyload") != 0) - error (0, 0, gettext ("unknown option `-%c %s'"), 'z', arg); -} - - -static void -parse_z_option_2 (const char *arg) -{ - if (strcmp (arg, "allextract") == 0) - ld_state.extract_rule = allextract; - else if (strcmp (arg, "defaultextract") == 0) - ld_state.extract_rule = defaultextract; - else if (strcmp (arg, "weakextract") == 0) - ld_state.extract_rule = weakextract; - else if (strcmp (arg, "lazyload") == 0) - ld_state.lazyload = true; - else if (strcmp (arg, "nolazyload") == 0) - ld_state.lazyload = false; -} - - -/* There are a lot of -B options, parse them here. */ -static void -parse_B_option (const char *arg) -{ - if (strcmp (arg, "local") == 0) - ld_state.default_bind_local = true; - else if (strcmp (arg, "symbolic") != 0 - && strcmp (arg, "static") != 0 - && strcmp (arg, "dynamic") != 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") == 0) - ld_state.statically = true; - else if (strcmp (arg, "dynamic") == 0) - ld_state.statically = false; - else if (strcmp (arg, "symbolic") == 0 - /* This is only meaningful if we create a DSO. */ - && ld_state.file_type == dso_file_type) - ld_state.dt_flags |= DF_SYMBOLIC; -} - - -static void -determine_output_format (void) -{ - /* First change the 'input_file_list' variable in a simple - single-linked list. */ - struct file_list *last = input_file_list; - input_file_list = input_file_list->next; - last->next = 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 != NULL) - { - ld_state.ebl = ebl_openbackend_emulation (emulation); - - assert (ld_state.ebl != NULL); - } - else - { - /* Find an ELF input file and let it determine the ELf backend. */ - struct file_list *runp = input_file_list; - - while (runp != NULL) - { - int fd = open (runp->name, O_RDONLY); - if (fd != -1) - { - int try (Elf *elf) - { - int result = 0; - - if (elf == NULL) - return 0; - - if (elf_kind (elf) == 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 != NULL) - ld_state.ebl = - ebl_openbackend_machine (ehdr->e_machine); - - result = 1; - } - else if (elf_kind (elf) == 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 = ELF_C_READ_MMAP; - - while ((subelf = elf_begin (fd, cmd, elf)) != NULL) - { - cmd = elf_next (subelf); - - if (try (subelf) != 0) - break; - } - } - - elf_end (elf); - - return result; - } - - if (try (elf_begin (fd, ELF_C_READ_MMAP, NULL)) != 0) - /* Found a file. */ - break; - } - - runp = runp->next; - } - - if (ld_state.ebl == 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 != NULL) - { - struct file_list *oldp = input_file_list; - input_file_list = 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 == no_file_type) - ld_state.file_type = 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 = (struct pathelement *) - obstack_calloc (&ld_state.smem, sizeof (struct pathelement)); - - newpath->pname = dir; - - /* Enqueue the file. */ - if (ld_state.tailpaths == NULL) - ld_state.paths = ld_state.tailpaths = newpath; - else - { - ld_state.tailpaths->next = newpath; - ld_state.tailpaths = newpath; - } -} - - -struct usedfiles * -ld_new_inputfile (const char *fname, enum file_type type) -{ - struct usedfiles *newfile = (struct usedfiles *) - obstack_calloc (&ld_state.smem, sizeof (struct usedfiles)); - - newfile->soname = newfile->fname = newfile->rfname = fname; - newfile->file_type = type; - newfile->extract_rule = ld_state.extract_rule; - newfile->lazyload = ld_state.lazyload; - newfile->status = 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 = 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 = - (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 = 0; - p = NULL; - while ((h = ld_section_tab_iterate (&ld_state.section_tab, &p)) != NULL) - { - struct scninfo *runp; - bool used = false; - - if (h->kind == scn_normal) - { - runp = h->last; - do - { - if (h->type == SHT_REL || h->type == 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 - = runp->fileinfo->scninfo[SCNINFO_SHDR (runp->shdr).sh_info].used; - } - - /* Accumulate the result. */ - used |= runp->used; - - /* Next input section. */ - runp = runp->next; - } - while (runp != h->last); - - h->used = used; - } - - ld_state.allsections[cnt++] = h; - } - ld_state.nusedsections = cnt; - - assert (cnt == 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 = (struct pathelement *) obstack_alloc (&ld_state.smem, sizeof (*newp)); - newp->pname = str; - newp->exist = 0; -#ifndef NDEBUG - newp->next = 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 = *pathp; - - do - { - const char *pname = (*pathp)->pname; - const char *colonp = strchrnul (pname, ':'); - - if (colonp != NULL) - { - struct pathelement *lastp = *pathp; - struct pathelement *newp; - - while (1) - { - if (colonp == pname) - lastp->pname = "."; - else - lastp->pname = obstack_strndup (&ld_state.smem, pname, - colonp - pname); - - if (*colonp == '\0') - break; - pname = colonp + 1; - - newp = (struct pathelement *) obstack_alloc (&ld_state.smem, - sizeof (*newp)); - newp->next = lastp->next; - newp->exist = 0; - lastp = lastp->next = newp; - - colonp = strchrnul (pname, ':'); - } - - pathp = &lastp->next; - } - else - pathp = &(*pathp)->next; - } - while (*pathp != 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 != NULL) - { - struct pathelement *endp = ld_state.rpath; - ld_state.rpath = ld_state.rpath->next; - endp->next = NULL; - } - if (ld_state.rpath_link != NULL) - { - struct pathelement *endp = ld_state.rpath_link; - ld_state.rpath_link = ld_state.rpath_link->next; - endp->next = NULL; - } - - if (ld_state.runpath != NULL) - { - struct pathelement *endp = ld_state.runpath; - ld_state.runpath = ld_state.runpath->next; - endp->next = NULL; - - /* If rpath information is also available discard it. - XXX Should there be a possibility to avoid this? */ - while (ld_state.rpath != NULL) - { - struct pathelement *old = ld_state.rpath; - ld_state.rpath = ld_state.rpath->next; - free (old); - } - } - if (ld_state.runpath_link != NULL) - { - struct pathelement *endp = ld_state.runpath_link; - ld_state.runpath_link = ld_state.runpath_link->next; - endp->next = NULL; - - /* If rpath information is also available discard it. - XXX Should there be a possibility to avoid this? */ - while (ld_state.rpath_link != NULL) - { - struct pathelement *old = ld_state.rpath_link; - ld_state.rpath_link = 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 != 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 != NULL) - { - ld_library_path2 = strchr (ld_library_path1, ';'); - if (ld_library_path2 == NULL) - { - /* If no semicolon is present the directories are looked at - after the -L parameters (-> ld_library_path2). */ - ld_library_path2 = ld_library_path1; - ld_library_path1 = NULL; - } - else - { - /* NUL terminate the first part. */ - *ld_library_path2++ = '\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 = fopen (fname, "r"); - if (ldin == 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 = 1; - - ldlineno = 1; - ldin_fname = fname; - if (ldparse () != 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 and those marked - with PROVIDE if there is a undefined reference. */ - if (ld_state.output_segments == NULL) - return; - - struct output_segment *segment = ld_state.output_segments->next; - do - { - struct output_rule *orule; - - for (orule = segment->output_rules; orule != NULL; orule = orule->next) - if (orule->tag == output_assignment - /* The assignments to "." (i.e., the PC) have to be - ignored here. */ - && strcmp (orule->val.assignment->variable, ".") != 0) - { - struct symbol *s = ld_state.unresolved; - - /* Check whether the symbol is needed. */ - if (likely (s != NULL)) - { - struct symbol *first = s; - const char *providename = 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) == 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 = s->next) != 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 = (struct symbol *) - obstack_calloc (&ld_state.smem, sizeof (struct symbol)); - - /* Initialize it. */ - s->name = orule->val.assignment->variable; - - /* Insert it into the symbol hash table. */ - unsigned long int hval = elf_hash (s->name); - if (unlikely (ld_symbol_tab_insert (&ld_state.symbol_tab, - hval, s) != 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 = ld_symbol_tab_find (&ld_state.symbol_tab, - hval, s); - assert (old != 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 = old; - } - - use_it: - /* The symbol is (now) defined. */ - s->defined = 1; - s->type = STT_NOTYPE; - - /* Add a reference to the symbol record. We will come - across it when creating the output file. */ - orule->val.assignment->sym = s; - - SNGL_LIST_PUSH (ld_state.lscript_syms, s); - ++ld_state.nlscript_syms; - - next_rule: - ; - } - - segment = segment->next; - } - while (segment != 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 == NULL) - { - /* No symbol defined found yet. Create one. */ - struct symbol *newsym = (struct symbol *) - obstack_calloc (&ld_state.smem, sizeof (*newsym)); - - newsym->name = 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) != 0)) - abort (); - - *symp = newsym; - } - else if ((*symp)->defined) - /* Cannot happen. We do use this symbol from any input file. */ - abort (); - - (*symp)->defined = 1; - (*symp)->type = STT_OBJECT; - - ++ld_state.nsymtab; -} diff --git a/src/ld.h b/src/ld.h deleted file mode 100644 index 760ff125..00000000 --- a/src/ld.h +++ /dev/null @@ -1,1073 +0,0 @@ -/* Copyright (C) 2001, 2002, 2003 Red Hat, Inc. - Written by Ulrich Drepper <drepper@redhat.com>, 2001. - - This program is Open Source software; you can redistribute it and/or - modify it under the terms of the Open Software License version 1.0 as - published by the Open Source Initiative. - - You should have received a copy of the Open Software License along - with this program; if not, you may obtain a copy of the Open Software - License version 1.0 from http://www.opensource.org/licenses/osl.php or - by writing the Open Source Initiative c/o Lawrence Rosen, Esq., - 3001 King Ranch Road, Ukiah, CA 95482. */ - -#ifndef LD_H -#define LD_H 1 - -#include <dlfcn.h> -#include <obstack.h> -#include <stdbool.h> -#include <stdio.h> -#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 = 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; - - /* 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 != 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_getshstrndx() 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 != 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; - /* 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). */ - 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) == ELF_K_ELF - && FILEINFO_EHDR (file->ehdr).e_type == ET_REL); -} - -static inline int -ld_file_dso_p (struct usedfiles *file) -{ - return (elf_kind (file->elf) == ELF_K_ELF - && FILEINFO_EHDR (file->ehdr).e_type == ET_DYN); -} - -static inline int -ld_file_ar_p (struct usedfiles *file) -{ - return elf_kind (file->elf) == 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, data)) - - /* 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); -#define FINALIZE_PLT(state, nsym, nsym_dyn) \ - DL_CALL_FCT ((state)->callbacks.finalize_plt, (state, nsym, nsym_dyn)) - - /* 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)) - - /* 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; - /* 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 <symbolhash.h> - -/* 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; -}; - - -/* 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_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_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. */ - } 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 <sectionhash.h> - -/* Define hash table for version symbols. */ -#include <versionhash.h> - - -/* 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; - - /* 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 table. */ - size_t hashscnidx; - - /* 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; - - /* 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; - - /* 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; - - /* 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 is DSOs which are not used in the linking process are not - recorded. */ - bool ignore_unused_dsos; - - - /* True if in executables all global symbols should be exported in - the dynamic symbol table. */ - bool export_all_dynamic; - - /* 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, int symidx); -extern inline bool -linked_from_dso_p (struct scninfo *scninfo, int symidx) -{ - struct usedfiles *file = 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 = 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 a33e9fcc..00000000 --- a/src/ldgeneric.c +++ /dev/null @@ -1,6376 +0,0 @@ -/* Copyright (C) 2001, 2002, 2003, 2004 Red Hat, Inc. - Written by Ulrich Drepper <drepper@redhat.com>, 2001. - - This program is Open Source software; you can redistribute it and/or - modify it under the terms of the Open Software License version 1.0 as - published by the Open Source Initiative. - - You should have received a copy of the Open Software License along - with this program; if not, you may obtain a copy of the Open Software - License version 1.0 from http://www.opensource.org/licenses/osl.php or - by writing the Open Source Initiative c/o Lawrence Rosen, Esq., - 3001 King Ranch Road, Ukiah, CA 95482. */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <assert.h> -#include <dlfcn.h> -#include <errno.h> -#include <error.h> -#include <fcntl.h> -#include <fnmatch.h> -#include <gelf.h> -#include <inttypes.h> -#include <libintl.h> -#include <stdbool.h> -#include <stdio_ext.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <sys/param.h> -#include <sys/stat.h> - -#include <system.h> -#include "ld.h" -#include "list.h" - - -/* 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 *statep); -static void ld_generic_initialize_plt (struct ld_state *statep, Elf_Scn *scn); -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 *scn); -static void ld_generic_finalize_plt (struct ld_state *statep, size_t nsym, - size_t nsym_dyn); -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)) - == sizeof (e_type) - && e_type == 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 = 0; - - if (fileinfo->archive_file != NULL) - { - npar = 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 == dso_file_type || ld_state.nplt > 0 - || ld_state.ngot > 0); -} - - -bool -linked_from_dso_p (struct scninfo *scninfo, int symidx) -{ - struct usedfiles *file = 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 = 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 = true; - - /* To be able to detect problems we add a .comment section entry by - default. */ - ld_state.add_ld_comment = true; - - /* XXX We probably should find a better place for this. The index - of the first user-defined version is 2. */ - ld_state.nextveridx = 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 = ebl_strtabinit (true); - if (ld_state.shstrtab == 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 = ld_generic_lib_extensions; - ld_state.callbacks.file_process = ld_generic_file_process; - ld_state.callbacks.file_close = ld_generic_file_close; - ld_state.callbacks.generate_sections = ld_generic_generate_sections; - ld_state.callbacks.create_sections = ld_generic_create_sections; - ld_state.callbacks.flag_unresolved = ld_generic_flag_unresolved; - ld_state.callbacks.open_outfile = ld_generic_open_outfile; - ld_state.callbacks.create_outfile = ld_generic_create_outfile; - ld_state.callbacks.relocate_section = ld_generic_relocate_section; - ld_state.callbacks.finalize = ld_generic_finalize; - ld_state.callbacks.special_section_number_p = - ld_generic_special_section_number_p; - ld_state.callbacks.section_type_p = ld_generic_section_type_p; - ld_state.callbacks.dynamic_section_flags = ld_generic_dynamic_section_flags; - ld_state.callbacks.initialize_plt = ld_generic_initialize_plt; - ld_state.callbacks.initialize_pltrel = ld_generic_initialize_pltrel; - ld_state.callbacks.initialize_got = ld_generic_initialize_got; - ld_state.callbacks.finalize_plt = ld_generic_finalize_plt; - ld_state.callbacks.rel_type = ld_generic_rel_type; - ld_state.callbacks.count_relocations = ld_generic_count_relocations; - ld_state.callbacks.create_relocations = 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 == NULL) - { - emulation = ebl_backend_name (ld_state.ebl); - assert (emulation != NULL); - } - size_t emulation_len = strlen (emulation); - - /* Construct the file name. */ - char *fname = (char *) alloca (sizeof "libld_" - 1 + emulation_len - + sizeof ".so"); - strcpy (mempcpy (stpcpy (fname, "libld_"), emulation, emulation_len), ".so"); - - /* Try loading. */ - void *h = dlopen (fname, RTLD_LAZY); - if (h == NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot load ld backend library '%s': %s"), - fname, dlerror ()); - - /* Find the initializer. It must be present. */ - char *initname = (char *) alloca (emulation_len + sizeof "_ld_init"); - strcpy (mempcpy (initname, emulation, emulation_len), "_ld_init"); - int (*initfct) (struct ld_state *) - = (int (*) (struct ld_state *)) dlsym (h, initname); - - if (initfct == NULL) - error (EXIT_FAILURE, 0, gettext ("\ -cannot find init function in ld backend library '%s': %s"), - fname, dlerror ()); - - /* Store the handle. */ - ld_state.ldlib = 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; - struct usedfiles *prevp; - - if (list == NULL) - return 0; - - prevp = list; - list = first = 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 == not_opened)) - break; - - if (unlikely (list->ino == newp->ino) - && unlikely (list->dev == newp->dev)) - { - close (newp->fd); - newp->fd = -1; - newp->status = closed; - if (newp->file_type == relocatable_file_type) - error (0, 0, gettext ("%s listed more than once as input"), - newp->rfname); - - return 1; - } - list = list->next; - } - while (likely (list != 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 = st.st_dev; - newp->ino = 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 = fileinfo->fname; - size_t fnamelen = strlen (fname); - int err = ENOENT; - struct pathelement *firstp = path; - - if (path == NULL) - /* Cannot find anything since we have no path. */ - return ENOENT; - - do - { - if (likely (path->exist >= 0)) - { - /* Create the file name. */ - char *rfname = NULL; - size_t dirlen = strlen (path->pname); - int fd = -1; - - if (fileinfo->file_type == archive_file_type) - { - const char **exts = (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 != NULL) - { - size_t extlen = strlen (*exts); - rfname = (char *) alloca (dirlen + 5 + fnamelen + extlen); - memcpy (mempcpy (stpcpy (mempcpy (rfname, path->pname, - dirlen), - "/lib"), - fname, fnamelen), - *exts, extlen + 1); - - fd = open (rfname, O_RDONLY); - if (likely (fd != -1) || errno != ENOENT) - { - err = fd == -1 ? errno : 0; - break; - } - - /* Next extension. */ - ++exts; - } - } - else - { - assert (fileinfo->file_type == dso_file_type - || fileinfo->file_type == dso_needed_file_type); - - rfname = (char *) alloca (dirlen + 1 + fnamelen + 1); - memcpy (stpcpy (mempcpy (rfname, path->pname, dirlen), "/"), - fname, fnamelen + 1); - - fd = open (rfname, O_RDONLY); - if (unlikely (fd == -1)) - err = errno; - } - - if (likely (fd != -1)) - { - /* We found the file. This also means the directory - exists. */ - fileinfo->fd = fd; - path->exist = 1; - - /* Check whether we have this file already loaded. */ - if (unlikely (check_for_duplicate (fileinfo) != 0)) - return EAGAIN; - - /* Make a copy of the name. */ - fileinfo->rfname = obstack_strdup (&ld_state.smem, rfname); - - if (unlikely (ld_state.trace_files)) - printf (fileinfo->file_type == 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 == 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] = '\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 = -1; - else - path->exist = 1; - } - } - - /* Next path element. */ - path = path->next; - } - while (likely (err == ENOENT && path != firstp)); - - return err; -} - - -static int -open_along_path (struct usedfiles *fileinfo) -{ - const char *fname = fileinfo->fname; - int err = ENOENT; - - if (fileinfo->file_type == relocatable_file_type) - { - /* Only libraries are searched along the path. */ - fileinfo->fd = open (fname, O_RDONLY); - - if (likely (fileinfo->fd != -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 = errno; - } - else - { - /* If the user specified two parts to the LD_LIBRARY_PATH variable - try the first part now. */ - err = open_along_path2 (fileinfo, ld_state.ld_library_path1); - - /* Try the user-specified path next. */ - if (err == ENOENT) - err = open_along_path2 (fileinfo, - fileinfo->file_type == archive_file_type - ? ld_state.paths : ld_state.rpath_link); - - /* Then the second part of the LD_LIBRARY_PATH value. */ - if (unlikely (err == ENOENT)) - { - err = open_along_path2 (fileinfo, ld_state.ld_library_path2); - - /* In case we look for a DSO handle now the RUNPATH. */ - if (err == ENOENT) - { - if (fileinfo->file_type == dso_file_type) - err = open_along_path2 (fileinfo, ld_state.runpath_link); - - /* Finally the path from the default linker script. */ - if (err == ENOENT) - err = open_along_path2 (fileinfo, ld_state.default_paths); - } - } - } - - if (unlikely (err != 0) - && (err != EAGAIN || fileinfo->file_type == relocatable_file_type)) - error (0, err, gettext ("cannot open %s"), fileinfo->fname); - - return err; -} - - -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) != STT_NOTYPE && oldp->type != STT_NOTYPE - && unlikely (oldp->type != 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) == STT_OBJECT - && oldp->size != 0 - && unlikely (oldp->size != 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 symidx, - struct usedfiles *fileinfo, struct symbol *oldp) -{ - int result = 0; - bool old_in_dso = FILEINFO_EHDR (oldp->file->ehdr).e_type == ET_DYN; - bool new_in_dso = FILEINFO_EHDR (fileinfo->ehdr).e_type == ET_DYN; - bool use_new_def = false; - - if (sym->st_shndx != SHN_UNDEF - && (! oldp->defined - || (sym->st_shndx != 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 = true; - } - else if (sym->st_shndx != SHN_UNDEF - && unlikely (! oldp->common) - && oldp->defined - && sym->st_shndx != 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 == 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 shndx; - size_t shnum; - - if (elf_getshnum (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 (sym->st_shndx < SHN_LORESERVE // || sym->st_shndx > SHN_HIRESERVE - && sym->st_shndx < shnum) - scnname = elf_strptr (fileinfo->elf, - fileinfo->shstrndx, - SCNINFO_SHDR (fileinfo->scninfo[sym->st_shndx].shdr).sh_name); - else - // XXX extended section - scnname = ebl_section_name (ld_state.ebl, sym->st_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 = oldp->file; - xelf_getsymshndx (oldfile->symtabdata, oldfile->xndxdata, oldp->symidx, - oldsym, xndx); - if (oldsym == NULL) - /* This should never happen since the same call - succeeded before. */ - abort (); - - shndx = oldsym->st_shndx; - if (unlikely (oldsym->st_shndx == SHN_XINDEX)) - shndx = xndx; - - /* XXX Use only ebl_section_name. */ - if (shndx < SHN_LORESERVE || shndx > SHN_HIRESERVE) - scnname = elf_strptr (oldfile->elf, - oldfile->shstrndx, - SCNINFO_SHDR (oldfile->scninfo[shndx].shdr).sh_name); - else - scnname = ebl_section_name (ld_state.ebl, oldsym->st_shndx, shndx, 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 = 1; - } - else if (old_in_dso && fileinfo->file_type == relocatable_file_type - && sym->st_shndx != 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 = 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 == STT_FUNC) - ++ld_state.nplt; - else - ++ld_state.ngot; - - oldp->on_dsolist = 1; - } - else if (oldp->common && sym->st_shndx == SHN_COMMON) - { - /* The symbol size is the largest of all common definitions. */ - oldp->size = MAX (oldp->size, sym->st_size); - /* Similarly for the alignment. */ - oldp->merge.value = 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 == relocatable_file_type) - { - CDBL_LIST_DEL (ld_state.from_dso, oldp); - --ld_state.nfrom_dso; - - if (likely (oldp->type == STT_FUNC)) - --ld_state.nplt; - else - --ld_state.ngot; - - oldp->on_dsolist = 0; - } - - /* Use the values of the definition from now on. */ - oldp->size = sym->st_size; - oldp->type = XELF_ST_TYPE (sym->st_info); - oldp->symidx = symidx; - oldp->scndx = sym->st_shndx; - //oldp->symscndx = THESYMSCNDX must be passed; - oldp->file = fileinfo; - oldp->defined = 1; - oldp->in_dso = new_in_dso; - oldp->common = sym->st_shndx == SHN_COMMON; - if (likely (fileinfo->file_type == 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 = XELF_ST_BIND (sym->st_info) == STB_WEAK; - - if (sym->st_shndx != SHN_COMMON) - { - struct scninfo *ignore; - mark_section_used (&fileinfo->scninfo[sym->st_shndx], - sym->st_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 == STT_FUNC) - ++ld_state.nplt; - else - ++ld_state.ngot; - - oldp->on_dsolist = 1; - } - else if (sym->st_shndx == SHN_COMMON) - { - /* Store the alignment. */ - oldp->merge.value = 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 = fileinfo->groups; runp != NULL; runp = runp->next) - if (!runp->used) - { - Elf32_Word *grpref; - size_t cnt; - Elf_Data *data; - - data = elf_getdata (runp->scn, NULL); - if (data == 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) == NULL); - - grpref = (Elf32_Word *) data->d_buf; - cnt = 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] == shndx) - { - *datap = 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 = find_section_group (fileinfo, shndx, &data); - *grpscnp = 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 sections - is therefore probably not what is wanted if stripping is required. */ - - /* Mark the section group as handled. */ - grpscn->used = true; - - grpref = (Elf32_Word *) data->d_buf; - cnt = data->d_size / sizeof (Elf32_Word); - while (cnt > 1) - { - Elf32_Word idx = grpref[--cnt]; - XElf_Shdr *shdr = &SCNINFO_SHDR (fileinfo->scninfo[idx].shdr); - - if (fileinfo->scninfo[idx].grpid != 0) - error (EXIT_FAILURE, 0, gettext ("\ -%s: section [%2d] '%s' is in more than one section group"), - fileinfo->fname, (int) idx, - elf_strptr (fileinfo->elf, fileinfo->shstrndx, shdr->sh_name)); - - fileinfo->scninfo[idx].grpid = grpscn->grpid; - - if (ld_state.strip == 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 != SHT_RELA && shdr->sh_type != 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 = true; - - /* Make sure the section header has been read from the file. */ - XElf_Shdr *shdr = &SCNINFO_SHDR (scninfo->shdr); -#if NATIVE_ELF - if (unlikely (scninfo->shdr == NULL)) -#else - if (unlikely (scninfo->shdr.sh_type == SHT_NULL)) -#endif - { -#if NATIVE_ELF != 0 - shdr = xelf_getshdr (scninfo->scn, scninfo->shdr); -#else - xelf_getshdr_copy (scninfo->scn, shdr, scninfo->shdr); -#endif - if (unlikely (shdr == 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 != 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 != 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 = &SCNINFO_SHDR (scninfo->shdr); - struct scninfo *grpscn = NULL; - Elf_Data *grpscndata = 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 == strip_none - || (shdr->sh_flags & SHF_ALLOC) != 0 - || shdr->sh_type == SHT_NOTE - || (shdr->sh_type == SHT_PROGBITS - && strcmp (elf_strptr (fileinfo->elf, - fileinfo->shstrndx, - shdr->sh_name), ".comment") == 0)) - && (fileinfo->status != 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 == NULL) - /* Determine the symbol which name constitutes the signature - for the section group. */ - grpscn = find_section_group (fileinfo, elf_ndxscn (scninfo->scn), - &grpscndata); - assert (grpscn == NULL || grpscn->symbols->name != NULL); - - /* Determine the section name. */ - search.name = elf_strptr (fileinfo->elf, fileinfo->shstrndx, shdr->sh_name); - search.type = shdr->sh_type; - search.flags = shdr->sh_flags; - search.entsize = shdr->sh_entsize; - search.grp_signature = grpscn != NULL ? grpscn->symbols->name : NULL; - search.kind = scn_normal; - hval = elf_hash (search.name); - - /* Find already queued sections. */ - queued = ld_section_tab_find (&ld_state.section_tab, hval, &search); - if (queued != NULL) - { - bool is_comdat = 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 == NULL) - { - grpscndata = elf_getdata (grpscn->scn, NULL); - assert (grpscndata != NULL); - } - - /* XXX Possibly unaligned memory access. */ - is_comdat = ((Elf32_Word *) grpscndata->d_buf)[0] & GRP_COMDAT; - } - - if (!is_comdat) - { - /* No COMDAT section, we use the data. */ - scninfo->next = queued->last->next; - queued->last = queued->last->next = scninfo; - - queued->flags = SH_FLAGS_COMBINE (queued->flags, shdr->sh_flags); - queued->align = MAX (queued->align, shdr->sh_addralign); - } - } - else - { - /* We do not use obstacks here since the memory might be - deallocated. */ - queued = (struct scnhead *) xcalloc (sizeof (struct scnhead), 1); - queued->kind = scn_normal; - queued->name = search.name; - queued->type = shdr->sh_type; - queued->flags = shdr->sh_flags; - queued->align = shdr->sh_addralign; - queued->entsize = shdr->sh_entsize; - queued->grp_signature = grpscn != NULL ? grpscn->symbols->name : NULL; - queued->segment_nr = ~0; - queued->last = scninfo->next = scninfo; - - /* 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, int secttype) -{ - size_t scncnt; - size_t cnt; - Elf_Data *symtabdata = NULL; - Elf_Data *xndxdata = NULL; - Elf_Data *versymdata = NULL; - Elf_Data *verdefdata = NULL; - Elf_Data *verneeddata = NULL; - size_t symstridx = 0; - size_t nsymbols = 0; - size_t nlocalsymbols = 0; - bool has_merge_sections = false; - - /* Prerequisites. */ - assert (fileinfo->elf != NULL); - - /* Allocate memory for the sections. */ - if (unlikely (elf_getshnum (fileinfo->elf, &scncnt) < 0)) - error (EXIT_FAILURE, 0, - gettext ("cannot determine number of sections: %s"), - elf_errmsg (-1)); - - fileinfo->scninfo = (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 = 0; cnt < scncnt; ++cnt) - { - /* Store the handle for the section. */ - fileinfo->scninfo[cnt].scn = elf_getscn (fileinfo->elf, cnt); - - /* Get the ELF section header and data. */ - XElf_Shdr *shdr; -#if NATIVE_ELF != 0 - if (fileinfo->scninfo[cnt].shdr == NULL) -#else - if (fileinfo->scninfo[cnt].shdr.sh_type == SHT_NULL) -#endif - { -#if NATIVE_ELF != 0 - shdr = 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 == NULL) - { - /* This should never happen. */ - fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"), - fileinfo->rfname, __FILE__, __LINE__); - return 1; - } - } - else - shdr = &SCNINFO_SHDR (fileinfo->scninfo[cnt].shdr); - - Elf_Data *data = elf_getdata (fileinfo->scninfo[cnt].scn, NULL); - - /* Check whether this section is marked as merge-able. */ - has_merge_sections |= (shdr->sh_flags & SHF_MERGE) != 0; - - /* Get the ELF section header and data. */ - /* Make the file structure available. */ - fileinfo->scninfo[cnt].fileinfo = fileinfo; - - if (unlikely (shdr->sh_type == SHT_SYMTAB) - || unlikely (shdr->sh_type == SHT_DYNSYM)) - { - if (shdr->sh_type == SHT_SYMTAB) - { - assert (fileinfo->symtabdata == NULL); - fileinfo->symtabdata = data; - fileinfo->nsymtab = shdr->sh_size / shdr->sh_entsize; - fileinfo->nlocalsymbols = shdr->sh_info; - fileinfo->symstridx = shdr->sh_link; - } - else - { - assert (fileinfo->dynsymtabdata == NULL); - fileinfo->dynsymtabdata = data; - fileinfo->ndynsymtab = shdr->sh_size / shdr->sh_entsize; - fileinfo->dynsymstridx = shdr->sh_link; - } - - /* If we are looking for the normal symbol table we just - found it. */ - if (secttype == shdr->sh_type) - { - assert (symtabdata == NULL); - symtabdata = data; - symstridx = shdr->sh_link; - nsymbols = shdr->sh_size / shdr->sh_entsize; - nlocalsymbols = shdr->sh_info; - } - } - else if (unlikely (shdr->sh_type == SHT_SYMTAB_SHNDX)) - { - assert (xndxdata == NULL); - fileinfo->xndxdata = xndxdata = data; - } - else if (unlikely (shdr->sh_type == SHT_GNU_versym)) - { - assert (versymdata == 0); - fileinfo->versymdata = versymdata = data; - } - else if (unlikely (shdr->sh_type == SHT_GNU_verdef)) - { - size_t nversions; - - assert (verdefdata == 0); - fileinfo->verdefdata = verdefdata = data; - - /* Allocate the arrays flagging the use of the version and - to track of allocated names. */ - fileinfo->nverdef = nversions = shdr->sh_info; - /* We have NVERSIONS + 1 because the indeces used to access the - sectino start with one; zero represents local binding. */ - fileinfo->verdefused = (XElf_Versym *) - obstack_calloc (&ld_state.smem, - sizeof (XElf_Versym) * (nversions + 1)); - fileinfo->verdefent = (struct Ebl_Strent **) - obstack_alloc (&ld_state.smem, - sizeof (struct Ebl_Strent *) * (nversions + 1)); - } - else if (unlikely (shdr->sh_type == SHT_GNU_verneed)) - { - assert (verneeddata == 0); - fileinfo->verneeddata = verneeddata = data; - } - else if (unlikely (shdr->sh_type == SHT_DYNAMIC)) - { - assert (fileinfo->dynscn == NULL); - fileinfo->dynscn = fileinfo->scninfo[cnt].scn; - } - else if (unlikely (shdr->sh_type == SHT_GROUP)) - { - Elf_Scn *symscn; - XElf_Shdr_vardef (symshdr); - Elf_Data *symdata; - - if (FILEINFO_EHDR (fileinfo->ehdr).e_type != ET_REL) - error (EXIT_FAILURE, 0, gettext ("\ -%s: only files of type ET_REL might contain section groups"), - fileinfo->fname); - - fileinfo->scninfo[cnt].next = fileinfo->groups; - fileinfo->scninfo[cnt].grpid = cnt; - fileinfo->groups = &fileinfo->scninfo[cnt]; - - /* Determine the signature. We create a symbol record for - it. Only the name element is important. */ - fileinfo->scninfo[cnt].symbols = (struct symbol *) - obstack_calloc (&ld_state.smem, sizeof (struct symbol)); - - symscn = elf_getscn (fileinfo->elf, shdr->sh_link); - xelf_getshdr (symscn, symshdr); - symdata = elf_getdata (symscn, NULL); - if (symshdr != 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 != NULL) - { - struct symbol *symbol = fileinfo->scninfo[cnt].symbols; - - symbol->name = elf_strptr (fileinfo->elf, symshdr->sh_link, - sym->st_name); - symbol->symidx = shdr->sh_info; - symbol->file = fileinfo; - } - } - if (fileinfo->scninfo[cnt].symbols->name == 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)); - - /* 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 == false); - } - else if (! SECTION_TYPE_P (&ld_state, shdr->sh_type) - && unlikely ((shdr->sh_flags & SHF_OS_NONCONFORMING) != 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 == relocatable_file_type) - && likely (cnt > 0) - && likely (shdr->sh_type == SHT_PROGBITS - || shdr->sh_type == SHT_RELA - || shdr->sh_type == SHT_REL - || shdr->sh_type == SHT_NOTE - || shdr->sh_type == SHT_NOBITS - || shdr->sh_type == SHT_INIT_ARRAY - || shdr->sh_type == SHT_FINI_ARRAY - || shdr->sh_type == SHT_PREINIT_ARRAY)) - add_section (fileinfo, &fileinfo->scninfo[cnt]); - } - - /* 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 != NULL)) - { - /* In case this file contains merge-able sections we have to - locate the symbols which are in these sections. */ - fileinfo->has_merge_sections = has_merge_sections; - if (likely (has_merge_sections)) - { - fileinfo->symref = (struct symbol **) - obstack_calloc (&ld_state.smem, - nsymbols * sizeof (struct symbol *)); - - /* Only handle the local symbols here. */ - for (cnt = 0; cnt < nlocalsymbols; ++cnt) - { - Elf32_Word shndx; - XElf_Sym_vardef (sym); - - xelf_getsymshndx (symtabdata, xndxdata, cnt, sym, shndx); - if (sym == NULL) - { - /* This should never happen. */ - fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"), - fileinfo->rfname, __FILE__, __LINE__); - return 1; - } - - if (likely (shndx != SHN_XINDEX)) - shndx = sym->st_shndx; - else if (unlikely (shndx == 0)) - { - fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"), - fileinfo->rfname, __FILE__, __LINE__); - return 1; - } - - if (XELF_ST_TYPE (sym->st_info) != STT_SECTION - && (shndx < SHN_LORESERVE || shndx > SHN_HIRESERVE) - && (SCNINFO_SHDR (fileinfo->scninfo[shndx].shdr).sh_flags - & SHF_MERGE)) - { - /* Create a symbol record for this symbol and add it - to the list for this section. */ - struct symbol *newp; - - newp = (struct symbol *) - obstack_calloc (&ld_state.smem, sizeof (struct symbol)); - - newp->symidx = cnt; - newp->scndx = shndx; - newp->file = fileinfo; - fileinfo->symref[cnt] = newp; - - if (fileinfo->scninfo[shndx].symbols == NULL) - fileinfo->scninfo[shndx].symbols = newp->next_in_scn - = newp; - else - { - newp->next_in_scn - = fileinfo->scninfo[shndx].symbols->next_in_scn; - fileinfo->scninfo[shndx].symbols - = fileinfo->scninfo[shndx].symbols->next_in_scn = 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 = (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 = nlocalsymbols; cnt < nsymbols; ++cnt) - { - XElf_Sym_vardef (sym); - Elf32_Word shndx; - xelf_getsymshndx (symtabdata, xndxdata, cnt, sym, shndx); - - if (sym == NULL) - { - /* This should never happen. */ - fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"), - fileinfo->rfname, __FILE__, __LINE__); - return 1; - } - - if (likely (shndx != SHN_XINDEX)) - shndx = sym->st_shndx; - else if (unlikely (shndx == 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 == SHN_ABS) && secttype == SHT_DYNSYM) - continue; - - /* If the DSO uses symbols determine whether this is the default - version. Otherwise we'll ignore the symbol. */ - if (versymdata != NULL) - { - XElf_Versym versym; - - if (xelf_getversym_copy (versymdata, cnt, versym) == NULL) - /* XXX Should we handle faulty input files more graceful? */ - assert (! "xelf_getversym failed"); - - if ((versym & 0x8000) != 0) - /* Ignore the symbol, it's not the default version. */ - continue; - } - - /* See whether we know anything about this symbol. */ - struct symbol search; - search.name = elf_strptr (fileinfo->elf, symstridx, sym->st_name); - unsigned long int hval = 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 == 165832675) - && strcmp (search.name, "_DYNAMIC") == 0) - || (unlikely (hval == 102264335) - && strcmp (search.name, "_GLOBAL_OFFSET_TABLE_") == 0)) - && sym->st_shndx != 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 != relocatable_file_type) - continue; - - struct symbol *oldp = ld_symbol_tab_find (&ld_state.symbol_tab, - hval, &search); - struct symbol *newp; - if (likely (oldp == NULL)) - { - /* No symbol of this name know. Add it. */ - newp = (struct symbol *) obstack_alloc (&ld_state.smem, - sizeof (*newp)); - newp->name = search.name; - newp->size = sym->st_size; - newp->type = XELF_ST_TYPE (sym->st_info); - newp->symidx = cnt; - newp->outsymidx = 0; - newp->outdynsymidx = 0; - newp->scndx = shndx; - newp->file = fileinfo; - newp->defined = newp->scndx != SHN_UNDEF; - newp->common = newp->scndx == SHN_COMMON; - newp->weak = XELF_ST_BIND (sym->st_info) == STB_WEAK; - newp->added = 0; - newp->merged = 0; - newp->need_copy = 0; - newp->on_dsolist = 0; - newp->in_dso = secttype == SHT_DYNSYM; - newp->next_in_scn = NULL; -#ifndef NDEBUG - newp->next = NULL; - newp->previous = NULL; -#endif - - if (newp->scndx == SHN_UNDEF) - { - CDBL_LIST_ADD_REAR (ld_state.unresolved, newp); - ++ld_state.nunresolved; - if (! newp->weak) - ++ld_state.nunresolved_nonweak; - } - else if (newp->scndx == SHN_COMMON) - { - /* Store the alignment requirement. */ - newp->merge.value = 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) != 0)) - /* This cannot happen. */ - abort (); - - fileinfo->symref[cnt] = 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 == 6685956 && strcmp (newp->name, "_init") == 0) - ld_state.init_symbol = newp; - else if (hval == 6672457 && strcmp (newp->name, "_fini") == 0) - ld_state.fini_symbol = newp; - } - else if (unlikely (check_definition (sym, cnt, fileinfo, oldp) != 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 = fileinfo->symref[cnt] = oldp; - - /* Mark the section the symbol we need comes from as used. */ - if (shndx != SHN_UNDEF - && (shndx < SHN_LORESERVE || shndx > SHN_HIRESERVE)) - { - struct scninfo *ignore; - -#ifndef NDEBUG - size_t shnum; - assert (elf_getshnum (fileinfo->elf, &shnum) == 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 == NULL) - fileinfo->scninfo[shndx].symbols = newp->next_in_scn - = newp; - else - { - newp->next_in_scn - = fileinfo->scninfo[shndx].symbols->next_in_scn; - fileinfo->scninfo[shndx].symbols - = fileinfo->scninfo[shndx].symbols->next_in_scn = newp; - } - } - } - } - - /* This file is used. */ - if (likely (fileinfo->file_type == relocatable_file_type)) - { - if (unlikely (ld_state.relfiles == NULL)) - ld_state.relfiles = fileinfo->next = fileinfo; - else - { - fileinfo->next = ld_state.relfiles->next; - ld_state.relfiles = ld_state.relfiles->next = fileinfo; - } - - /* Update some summary information in the state structure. */ - ld_state.nsymtab += fileinfo->nsymtab; - ld_state.nlocalsymbols += fileinfo->nlocalsymbols; - } - else if (likely (fileinfo->file_type == 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 = 0; - - for (runp = fnames; runp != NULL; runp = runp->next) - { - struct usedfiles *curp; - - /* Create a record for the new file. */ - curp = runp->real = ld_new_inputfile (runp->name, relocatable_file_type); - - /* Set flags for group handling. */ - runp->real->group_start = runp->group_start; - runp->real->group_end = runp->group_end; - - /* Read the file and everything else which comes up, including - handling groups. */ - do - res |= FILE_PROCESS (-1, curp, &ld_state, &curp); - while (curp != NULL); - } - - /* Free the list. */ - while (fnames != NULL) - { - runp = fnames; - fnames = 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 = 0; - - if (elf == 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) == ELF_K_NONE)) - { - struct filename_list *fnames; - - /* We don't have to look at this file again. */ - fileinfo->status = closed; - - /* Let's see whether this is a linker script. */ - if (fileinfo->fd != -1) - /* Create a stream from the file handle we know. */ - ldin = fdopen (fileinfo->fd, "r"); - else - { - /* Get the memory for the archive member. */ - char *content; - size_t contentsize; - - /* Get the content of the file. */ - content = elf_rawfile (elf, &contentsize); - if (content == 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 = fmemopen (content, contentsize, "r"); - } - - /* No need for locking. */ - __fsetlocking (ldin, FSETLOCKING_BYCALLER); - - if (ldin == 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 = NULL; - ldlineno = 1; - ld_scan_version_script = 0; - ldin_fname = fileinfo->rfname; - res = ldparse (); - - fclose (ldin); - if (fileinfo->fd != -1 && !fileinfo->fd_passed) - { - /* We won't need the file descriptor again. */ - close (fileinfo->fd); - fileinfo->fd = -1; - } - - elf_end (elf); - - if (unlikely (res != 0)) - /* Something went wrong during parsing. */ - return 1; - - /* This is no ELF file. */ - fileinfo->elf = NULL; - - /* Now we have to handle eventual INPUT and GROUP statements in - the script. Read the files mentioned. */ - fnames = ld_state.srcfiles; - if (fnames != NULL) - { - struct filename_list *oldp; - - /* Convert the list into a normal single-linked list. */ - oldp = fnames; - fnames = fnames->next; - oldp->next = NULL; - - /* Remove the list from the state structure. */ - ld_state.srcfiles = NULL; - - if (unlikely (ld_handle_filename_list (fnames) != 0)) - return 1; - } - - return 0; - } - - /* Store the file info. */ - fileinfo->elf = elf; - - /* The file is ready for action. */ - fileinfo->status = opened; - - return 0; -} - - -static int -add_whole_archive (struct usedfiles *fileinfo) -{ - Elf *arelf; - Elf_Cmd cmd = ELF_C_READ_MMAP_PRIVATE; - int res = 0; - - while ((arelf = elf_begin (fileinfo->fd, cmd, fileinfo->elf)) != NULL) - { - Elf_Arhdr *arhdr = elf_getarhdr (arelf); - struct usedfiles *newp; - - if (arhdr == 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, "/") != 0); - assert (strcmp (arhdr->ar_name, "//") != 0); - - newp = ld_new_inputfile (arhdr->ar_name, relocatable_file_type); - newp->archive_file = 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 = -1; - /* Store the ELF descriptor. */ - newp->elf = arelf; - /* Show that we are open for business. */ - newp->status = opened; - - /* Proces the file, add all the symbols etc. */ - res = file_process2 (newp); - if (unlikely (res != 0)) - break; - - /* Advance to the next archive element. */ - cmd = elf_next (arelf); - } - - return res; -} - - -static int -extract_from_archive (struct usedfiles *fileinfo) -{ - static int archive_seq; - int res = 0; - - /* This is an archive we are not using completely. Give it a - unique number. */ - fileinfo->archive_seq = ++archive_seq; - - /* If there are no unresolved symbols don't do anything. */ - if ((likely (ld_state.extract_rule == defaultextract) - && ld_state.nunresolved_nonweak == 0) - || (unlikely (ld_state.extract_rule == weakextract) - && ld_state.nunresolved == 0)) - return 0; - - Elf_Arsym *syms; - size_t nsyms; - - /* Get all the symbols. */ - syms = elf_getarsym (fileinfo->elf, &nsyms); - if (syms == 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 = 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; - int nround = 0; - do - { - any_used = false; - - size_t cnt; - for (cnt = 0; cnt < nsyms; ++cnt) - { - struct symbol search = { .name = syms[cnt].as_name }; - struct symbol *sym = ld_symbol_tab_find (&ld_state.symbol_tab, - syms[cnt].as_hash, &search); - if (sym != 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) - != 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 = elf_begin (fileinfo->fd, ELF_C_READ_MMAP_PRIVATE, - fileinfo->elf); - arhdr = elf_getarhdr (arelf); - if (arhdr == 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 = ld_new_inputfile (obstack_strdup (&ld_state.smem, - arhdr->ar_name), - relocatable_file_type); - newp->archive_file = 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 = -1; - /* Store the ELF descriptor. */ - newp->elf = arelf; - /* Show that we are open for business. */ - newp->status = in_archive; - - /* Now read the file and add all the symbols. */ - res = file_process2 (newp); - if (unlikely (res != 0)) - return res; - - any_used = true; - } - } - - if (++nround == 1) - { - /* This is an archive therefore it must have a number. */ - assert (fileinfo->archive_seq != 0); - ld_state.last_archive_used = fileinfo->archive_seq; - } - } - while (any_used); - - return res; -} - - -static int -file_process2 (struct usedfiles *fileinfo) -{ - int res; - - if (likely (elf_kind (fileinfo->elf) == ELF_K_ELF)) - { - /* The first time we get here we read the ELF header. */ -#if NATIVE_ELF != 0 - if (likely (fileinfo->ehdr == NULL)) -#else - if (likely (FILEINFO_EHDR (fileinfo->ehdr).e_type == ET_NONE)) -#endif - { - XElf_Ehdr *ehdr; -#if NATIVE_ELF != 0 - ehdr = xelf_getehdr (fileinfo->elf, fileinfo->ehdr); -#else - xelf_getehdr_copy (fileinfo->elf, ehdr, fileinfo->ehdr); -#endif - if (ehdr == NULL) - { - fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"), - fileinfo->rfname, __FILE__, __LINE__); - fileinfo->status = closed; - return 1; - } - - if (FILEINFO_EHDR (fileinfo->ehdr).e_type != ET_REL - && unlikely (FILEINFO_EHDR (fileinfo->ehdr).e_type != 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 = closed; - return 1; - } - - /* Determine the section header string table section index. */ - if (unlikely (elf_getshstrndx (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 = closed; - return 1; - } - } - - /* Now handle the different types of files. */ - if (FILEINFO_EHDR (fileinfo->ehdr).e_type == ET_REL) - { - /* Add all the symbol. Relocatable files have symbol - tables. */ - res = add_relocatable_file (fileinfo, SHT_SYMTAB); - } - else - { - bool has_l_name = fileinfo->file_type == archive_file_type; - - assert (FILEINFO_EHDR (fileinfo->ehdr).e_type == ET_DYN); - - /* If the file is a DT_NEEDED dependency then the type is - already correctly specified. */ - if (fileinfo->file_type != dso_needed_file_type) - fileinfo->file_type = dso_file_type; - - /* We cannot use DSOs when generating relocatable objects. */ - if (ld_state.file_type == 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 = add_relocatable_file (fileinfo, SHT_DYNSYM); - - /* We always have to have a dynamic section. */ - assert (fileinfo->dynscn != 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 = elf_getdata (fileinfo->dynscn, NULL); - /* XXX Should we flag the failure to get the dynamic section? */ - if (dynshdr != NULL) - { - int cnt = dynshdr->sh_size / dynshdr->sh_entsize; - XElf_Dyn_vardef (dyn); - - while (--cnt >= 0) - { - xelf_getdyn (dyndata, cnt, dyn); - if (dyn != NULL) - { - if(dyn->d_tag == DT_NEEDED) - { - struct usedfiles *newp; - - newp = 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 == DT_SONAME) - { - /* We use the DT_SONAME (this is what's there - for). */ - fileinfo->soname = elf_strptr (fileinfo->elf, - dynshdr->sh_link, - dyn->d_un.d_val); - has_l_name = 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 = strlen (fileinfo->fname) + 7; - char *newp; - - newp = (char *) obstack_alloc (&ld_state.smem, len); - strcpy (stpcpy (stpcpy (newp, "lib"), fileinfo->fname), ".so"); - - fileinfo->soname = newp; - } - } - } - else if (likely (elf_kind (fileinfo->elf) == ELF_K_AR)) - { - if (unlikely (ld_state.extract_rule == allextract)) - /* Which this option enabled we have to add all the object - files in the archive. */ - res = add_whole_archive (fileinfo); - else if (ld_state.file_type == 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 = 0; - } - else - /* Extract only the members from the archive which are - currently referenced by unresolved symbols. */ - res = 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 = 0; - - /* By default we go to the next file in the list. */ - *nextp = fileinfo->next; - - /* Set the flag to signal we are looking for a group start. */ - if (unlikely (fileinfo->group_start)) - { - ld_state.group_start_requested = true; - fileinfo->group_start = false; - } - - /* If the file isn't open yet, open it now. */ - if (likely (fileinfo->status == not_opened)) - { - bool fd_passed = true; - - if (likely (fd == -1)) - { - /* Find the file ourselves. */ - int err = open_along_path (fileinfo); - if (unlikely (err != 0)) - /* We allow libraries and DSOs to be named more than once. - Don't report an error to the caller. */ - return err == EAGAIN ? 0 : err; - - fd_passed = false; - } - else - fileinfo->fd = fd; - - /* Remember where we got the descriptor from. */ - fileinfo->fd_passed = fd_passed; - - /* We found the file. Now test whether it is a file type we can - handle. - - XXX Do we have 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 = 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 != 0)) - return res; - } - - /* Now that we have opened the file start processing it. */ - if (likely (fileinfo->status != closed)) - res = file_process2 (fileinfo); - - /* Determine which file to look at next. */ - if (unlikely (fileinfo->group_backref != 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_seq) - { - *nextp = fileinfo->group_backref; - ld_state.last_archive_used = 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 = 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 = NULL; - - runp = runp->next; - } - while (runp != fileinfo->next); - } - } - else if (unlikely (fileinfo->group_end)) - { - /* This is the end of a group. We possibly of 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 != ld_state.tailarchives) - /* The loop would include more than one archive, add the - pointer. */ - { - *nextp = ld_state.tailarchives->group_backref = - ld_state.group_start_archive; - ld_state.last_archive_used = 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 != fileinfo) - { - *nextp = ld_state.group_start_archive; - ld_state.last_archive_used = 0; - } - } - - /* Clear the flags. */ - ld_state.group_start_requested = false; - fileinfo->group_end = 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__ ((__unused__))) -{ - static const char *exts[] = - { - ".so", ".a", NULL - }; - - return exts; -} - - -/* Flag unresolved symbols. */ -static int -ld_generic_flag_unresolved (struct ld_state *statep) -{ - int retval = 0; - - if (ld_state.nunresolved_nonweak > 0) - { - /* Go through the list and determine the unresolved symbols. */ - struct symbol *first; - struct symbol *s; - - s = first = 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_") == 0 - || strcmp (s->name, "_DYNAMIC") == 0) - { - /* We will have to fill in more information later. */ - ld_state.need_got = true; - - /* Remember that we found it. */ - if (s->name[1] == 'G') - ld_state.got_symbol = s; - else - ld_state.dyn_symbol = s; - } - else if (ld_state.file_type != 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 = 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 = s->next; - } - while (s != 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 != -1) - close (fileinfo->fd); - - /* We allocated the resolved file name. */ - if (fileinfo->fname != fileinfo->rfname) - free ((char *) fileinfo->rfname); - - return 0; -} - - -static void -new_generated_scn (enum scn_kind kind, const char *name, int type, int flags, - int entsize, int align) -{ - struct scnhead *newp; - - newp = (struct scnhead *) obstack_calloc (&ld_state.smem, - sizeof (struct scnhead)); - newp->kind = kind; - newp->name = name; - newp->nameent = ebl_strtabadd (ld_state.shstrtab, name, 0); - newp->type = type; - newp->flags = flags; - newp->entsize = entsize; - newp->align = align; - newp->grp_signature = NULL; - newp->used = 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 = REL_TYPE (&ld_state) == DT_REL ? SHT_REL : SHT_RELA; - - /* 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 ()) - { - int ndt_needed; - /* Use any versioning (defined or required)? */ - bool use_versioning = false; - /* Use version requirements? */ - bool need_version = false; - - /* First the .interp section. */ - 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 = 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... - new_generated_scn (scn_dot_hash, ".hash", SHT_HASH, SHF_ALLOC, - sizeof (Elf32_Word), sizeof (Elf32_Word)); - - /* By default we add all DSOs provided on the command line. If - the user added '-z ignore' to the command line we only add - those which are actually used. */ - ndt_needed = ld_state.ignore_unused_dsos ? 0 : ld_state.ndsofiles; - - /* 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 == 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)); - - /* This means we will also need the .got section. */ - ld_state.need_got = true; - - /* Mark all used DSOs as used. Determine whether any referenced - object uses symbol versioning. */ - if (ld_state.from_dso != NULL) - { - struct symbol *srunp = ld_state.from_dso; - - do - { - srunp->file->used = true; - - if (srunp->file->verdefdata != NULL) - { - XElf_Versym versym; - - /* The input DSO uses versioning. */ - use_versioning = true; - /* We reference versions. */ - need_version = true; - - if (xelf_getversym_copy (srunp->file->versymdata, - srunp->symidx, versym) == NULL) - assert (! "xelf_getversym failed"); - - /* We cannot link explicitly with an older - version of a symbol. */ - assert ((versym & 0x8000) == 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] = 1; - - if (++srunp->file->nverdefused == 1) - /* Count the file if it is using versioning. */ - ++ld_state.nverdeffile; - ++ld_state.nverdefused; - } - } - } - while ((srunp = srunp->next) != 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. */ - ndt_needed = 0; - if (ld_state.ndsofiles > 0) - { - struct usedfiles *frunp = ld_state.dsofiles; - - do - if (! ld_state.ignore_unused_dsos || 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 = frunp->next) != 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 = (7 + (ld_state.runpath != NULL - || ld_state.rpath != NULL) - + ndt_needed - + (ld_state.init_symbol != NULL ? 1 : 0) - + (ld_state.fini_symbol != 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 = (ld_state.file_type == relocatable_file_type - || ld_state.strip == 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 == 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 != 0 && ld_state.tempfname != 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 == NULL) - ld_state.outfname = "a.out"; - - size_t outfname_len = strlen (ld_state.outfname); - char *tempfname = (char *) obstack_alloc (&ld_state.smem, - outfname_len + sizeof (".XXXXXX")); - ld_state.tempfname = tempfname; - - int fd; - int try = 0; - while (1) - { - strcpy (mempcpy (tempfname, ld_state.outfname, outfname_len), ".XXXXXX"); - - /* The useof 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) != NULL - && (fd = open (tempfname, O_RDWR | O_EXCL | O_CREAT | O_NOFOLLOW, - ld_state.file_type == relocatable_file_type - ? DEFFILEMODE : ACCESSPERMS)) != -1) - break; - - /* Failed this round. We keep trying a number of times. */ - if (++try >= 10) - error (EXIT_FAILURE, errno, gettext ("cannot create output file")); - } - ld_state.outfd = 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 = ld_state.outelf = elf_begin (fd, - conserve_memory - ? ELF_C_WRITE : ELF_C_WRITE_MMAP, - NULL); - if (elf == 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 != NULL); - - /* Set the machine type. */ - ehdr->e_machine = machine; - - /* Modify it according to the info we have here and now. */ - if (ld_state.file_type == executable_file_type) - ehdr->e_type = ET_EXEC; - else if (ld_state.file_type == dso_file_type) - ehdr->e_type = ET_DYN; - else - { - assert (ld_state.file_type == relocatable_file_type); - ehdr->e_type = ET_REL; - } - - /* Set the ELF version. */ - ehdr->e_version = EV_CURRENT; - - /* Set the endianness. */ - ehdr->e_ident[EI_DATA] = 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 = ld_state.from_dso; - assert (runp != NULL); - - XElf_Off maxalign = 1; - XElf_Off offset = 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 = MAX (SCNINFO_SHDR (runp->file->scninfo[runp->scndx].shdr).sh_addralign, 1); - /* Keep track of the maximum alignment requirement. */ - maxalign = MAX (maxalign, symalign); - - /* Align current position. */ - offset = (offset + symalign - 1) & ~(symalign - 1); - - runp->merge.value = offset; - - offset += runp->size; - } - while ((runp = runp->next) != ld_state.from_dso); - - shdr->sh_type = SHT_NOBITS; - shdr->sh_size = offset; - shdr->sh_addralign = maxalign; -} - - -static void -compute_common_symbol_offset (XElf_Shdr *shdr) -{ - struct symbol *runp = ld_state.common_syms; - assert (runp != NULL); - - XElf_Off maxalign = 1; - XElf_Off offset = 0; - - do - { - /* Determine alignment for the symbol. */ - XElf_Off symalign = runp->merge.value; - - /* Keep track of the maximum alignment requirement. */ - maxalign = MAX (maxalign, symalign); - - /* Align current position. */ - offset = (offset + symalign - 1) & ~(symalign - 1); - - runp->merge.value = offset; - - offset += runp->size; - } - while ((runp = runp->next) != ld_state.common_syms); - - shdr->sh_type = SHT_NOBITS; - shdr->sh_size = offset; - shdr->sh_addralign = maxalign; -} - - -static void -sort_sections_generic (void) -{ - /* XXX TBI */ - abort (); -} - - -static int -match_section (const char *osectname, struct filemask_section_name *sectmask, - 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) != 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 != scn_normal) - { - (*scnhead)->name = osectname; - (*scnhead)->segment_nr = segment_nr; - - /* We have to count note section since they get their own - program header entry. */ - if ((*scnhead)->type == SHT_NOTE) - ++ld_state.nnotesections; - - ld_state.allsections[ld_state.nallsections++] = (*scnhead); - return true; - } - - /* Now we have to match the file names of the input files. Some of - the sections here might not match. */ - runp = (*scnhead)->last->next; - prevp = (*scnhead)->last; - notused = NULL; - - do - { - /* Base of the file name the section comes from. */ - const char *brfname = 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 != NULL - && fnmatch (sectmask->filemask, brfname, 0) != 0) - || (sectmask->excludemask != NULL - && fnmatch (sectmask->excludemask, brfname, 0) == 0)) - { - /* This file does not match the file name masks. */ - if (notused == NULL) - notused = runp; - - prevp = runp; - runp = runp->next; - if (runp == notused) - runp = NULL; - } - /* The section fulfills all requirements, add it to the output - file with the correct section name etc. */ - else - { - struct scninfo *found = runp; - - /* Remove this input section data buffer from the list. */ - if (prevp != runp) - runp = prevp->next = runp->next; - else - { - free (*scnhead); - *scnhead = NULL; - runp = 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 = (struct scnhead *) obstack_calloc (&ld_state.smem, - sizeof (*newp)); - newp->kind = scn_normal; - newp->name = osectname; - newp->type = SCNINFO_SHDR (found->shdr).sh_type; - newp->flags = SCNINFO_SHDR (found->shdr).sh_flags; - newp->segment_nr = segment_nr; - newp->last = found->next = found; - newp->used = true; - newp->relsize = found->relsize; - newp->entsize = SCNINFO_SHDR (found->shdr).sh_entsize; - - /* We have to count note section since they get their own - program header entry. */ - if (newp->type == SHT_NOTE) - ++ld_state.nnotesections; - - ld_state.allsections[ld_state.nallsections++] = newp; - new_section = false; - } - else - { - struct scnhead *queued; - - queued = ld_state.allsections[ld_state.nallsections - 1]; - - found->next = queued->last->next; - queued->last = queued->last->next = 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 != SCNINFO_SHDR (found->shdr).sh_type) - /* XXX Any better choice? */ - queued->type = SHT_PROGBITS; - if (queued->flags != SCNINFO_SHDR (found->shdr).sh_flags) - queued->flags = ebl_sh_flags_combine (ld_state.ebl, - queued->flags, - SCNINFO_SHDR (found->shdr).sh_flags); - - /* Accumulate the relocation section size. */ - queued->relsize += found->relsize; - } - } - } - while (runp != 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 = ld_state.nallsections; - - /* Convert the output segment list in a single-linked list. */ - struct output_segment *segment = ld_state.output_segments->next; - ld_state.output_segments->next = NULL; - ld_state.output_segments = 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 = 0; - size_t segment_nr; - size_t last_writable = ~0; - for (segment_nr = 0; segment != NULL; segment = segment->next, ++segment_nr) - { - struct output_rule *orule; - - for (orule = segment->output_rules; orule != NULL; orule = orule->next) - if (orule->tag == output_section) - { - struct input_rule *irule; - bool new_section = true; - - for (irule = orule->val.section.input; irule != NULL; - irule = irule->next) - if (irule->tag == input_section) - { - size_t cnt; - - for (cnt = 0; cnt < nallsections; ++cnt) - if (temp[cnt] != NULL) - new_section = - match_section (orule->val.section.name, - irule->val.section, &temp[cnt], - new_section, segment_nr); - } - } - - if ((segment->mode & PF_W) != 0) - last_writable = 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 != NULL) - { - if (last_writable == ~0) - error (EXIT_FAILURE, 0, "no writable segment"); - - if (ld_state.allsections[last_writable]->type != 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] = (struct scnhead *) - obstack_calloc (&ld_state.smem, sizeof (struct scnhead)); - - /* Name for the new section. */ - ld_state.allsections[last_writable]->name = ".bss"; - /* Type: NOBITS. */ - ld_state.allsections[last_writable]->type = SHT_NOBITS; - /* Same segment as the last writable section. */ - ld_state.allsections[last_writable]->segment_nr - = ld_state.allsections[last_writable - 1]->segment_nr; - } - } - - /* Create common symbol data block. */ - if (ld_state.ncopy > 0) - { -#if NATIVE_ELF - struct scninfo *si = (struct scninfo *) - obstack_calloc (&ld_state.smem, sizeof (*si) + sizeof (XElf_Shdr)); - si->shdr = (XElf_Shdr *) (si + 1); -#else - struct scninfo *si = (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 = true; - /* Remember for later the section data structure. */ - ld_state.copy_section = si; - - if (likely (ld_state.allsections[last_writable]->last != NULL)) - { - si->next = ld_state.allsections[last_writable]->last->next; - ld_state.allsections[last_writable]->last->next = si; - ld_state.allsections[last_writable]->last = si; - } - else - ld_state.allsections[last_writable]->last = si->next = si; - } - - /* Create common symbol data block. */ - if (ld_state.common_syms != NULL) - { -#if NATIVE_ELF - struct scninfo *si = (struct scninfo *) - obstack_calloc (&ld_state.smem, sizeof (*si) + sizeof (XElf_Shdr)); - si->shdr = (XElf_Shdr *) (si + 1); -#else - struct scninfo *si = (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 = true; - /* Remember for later the section data structure. */ - ld_state.common_section = si; - - if (likely (ld_state.allsections[last_writable]->last != NULL)) - { - si->next = ld_state.allsections[last_writable]->last->next; - ld_state.allsections[last_writable]->last->next = si; - ld_state.allsections[last_writable]->last = si; - } - else - ld_state.allsections[last_writable]->last = si->next = 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 != relocatable_file_type) - { - /* Collect all the relocation sections. They are handled - separately. */ - struct scninfo *list = NULL; - for (cnt = 0; cnt < ld_state.nallsections; ++cnt) - if ((ld_state.allsections[cnt]->type == SHT_REL - || ld_state.allsections[cnt]->type == SHT_RELA) - /* The generated relocation sections are not of any - interest here. */ - && ld_state.allsections[cnt]->last != NULL) - { - if (list == NULL) - list = ld_state.allsections[cnt]->last; - else - { - /* Merge the sections list. */ - struct scninfo *first = list->next; - list->next = ld_state.allsections[cnt]->last->next; - ld_state.allsections[cnt]->last->next = first; - list = ld_state.allsections[cnt]->last; - } - - /* Remove the entry from the section list. */ - ld_state.allsections[cnt] = NULL; - } - ld_state.rellist = list; - - if (ld_state.output_segments == 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 = 0; cnt < ld_state.nallsections; ++cnt) - { - struct scnhead *head = 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 == 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 = 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 = head->last; - do - { - assert (runp->grpid != 0); - - here_groupidx = runp->fileinfo->scninfo[runp->grpid].outscnndx; - if (here_groupidx != 0) - break; - } - while ((runp = runp->next) != head->last); - - if (here_groupidx == 0) - { - /* We need a new section group section. */ - scn = elf_newscn (ld_state.outelf); - xelf_getshdr (scn, shdr); - if (shdr == NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create section for output file: %s"), - elf_errmsg (-1)); - - here_group = (struct scngroup *) xmalloc (sizeof (*here_group)); - here_group->outscnidx = here_groupidx = elf_ndxscn (scn); - here_group->nscns = 0; - here_group->member = NULL; - here_group->next = 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 - = 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 - = runp->fileinfo->scninfo[runp->grpid].symbols; - - ld_state.groups = here_group; - } - else - { - /* Search for the group with this index. */ - here_group = ld_state.groups; - while (here_group->outscnidx != here_groupidx) - here_group = here_group->next; - } - - /* Add the new output section. */ - newp = (struct member *) alloca (sizeof (*newp)); - newp->scn = head; -#ifndef NDT_NEEDED - newp->next = NULL; -#endif - CSNGL_LIST_ADD_REAR (here_group->member, newp); - ++here_group->nscns; - - /* Store the section group index in all input files. */ - runp = head->last; - do - { - assert (runp->grpid != 0); - - if (runp->fileinfo->scninfo[runp->grpid].outscnndx == 0) - runp->fileinfo->scninfo[runp->grpid].outscnndx = here_groupidx; - else - assert (runp->fileinfo->scninfo[runp->grpid].outscnndx - == here_groupidx); - } - while ((runp = runp->next) != head->last); - } - - /* We'll use this section so get it's name in the section header - string table. */ - if (head->kind == scn_normal) - head->nameent = 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 = elf_newscn (ld_state.outelf); - head->scnidx = elf_ndxscn (scn); - xelf_getshdr (scn, shdr); - if (shdr == NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create section for output file: %s"), - elf_errmsg (-1)); - - assert (head->type != SHT_NULL); - assert (head->type != SHT_SYMTAB); - assert (head->type != SHT_DYNSYM || head->kind != scn_normal); - assert (head->type != SHT_STRTAB || head->kind != scn_normal); - assert (head->type != SHT_GROUP); - shdr->sh_type = head->type; - shdr->sh_flags = head->flags; - shdr->sh_addralign = head->align; - shdr->sh_entsize = head->entsize; - assert (shdr->sh_entsize != 0 || (shdr->sh_flags & SHF_MERGE) == 0); - (void) xelf_update_shdr (scn, shdr); - - /* We have to know the section index of the dynamic symbol table - right away. */ - if (head->kind == scn_dot_dynsym) - ld_state.dynsymscnidx = elf_ndxscn (scn); - } - - /* Actually create the section group sections. */ - groups = ld_state.groups; - while (groups != NULL) - { - Elf_Scn *scn; - Elf_Data *data; - Elf32_Word *grpdata; - struct member *runp; - - scn = elf_getscn (ld_state.outelf, groups->outscnidx); - assert (scn != NULL); - - data = elf_newdata (scn); - if (data == NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create section for output file: %s"), - elf_errmsg (-1)); - - data->d_size = (groups->nscns + 1) * sizeof (Elf32_Word); - data->d_buf = grpdata = (Elf32_Word *) xmalloc (data->d_size); - data->d_type = ELF_T_WORD; - data->d_version = EV_CURRENT; - data->d_off = 0; - /* XXX What better to use? */ - data->d_align = sizeof (Elf32_Word); - - /* The first word in the section is the flag word. */ - /* XXX Set COMDATA flag is necessary. */ - grpdata[0] = 0; - - runp = groups->member->next; - cnt = 1; - do - /* Fill in the index of the section. */ - grpdata[cnt++] = runp->scn->scnidx; - while ((runp = runp->next) != groups->member->next); - - groups = 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 = ld_state.default_bind_local; - - if (XELF_ST_BIND (sym->st_info) == STB_LOCAL || sym->st_shndx == 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) == STB_GLOBAL - || XELF_ST_BIND (sym->st_info) == STB_WEAK); - - str = ebl_string (strent); - version = strchr (str, VER_CHR); - if (version != NULL) - { - search.id = strndupa (str, version - str); - if (*++version == VER_CHR) - /* Skip the second '@' signalling a default definition. */ - ++version; - } - else - { - search.id = str; - version = ""; - } - - verp = ld_version_str_tab_find (&ld_state.version_str_tab, - elf_hash (search.id), &search); - while (verp != NULL) - { - /* We have this symbol in the version hash table. Now match the - version name. */ - if (strcmp (verp->u.s.versionname, version) == 0) - /* Match! */ - return verp->u.s.local; - - verp = 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 = ~((XElf_Addr) 0); - - switch (expr->tag) - { - case exp_num: - val = 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 != NULL); - - val = shdr->sh_offset; - } - break; - - case exp_pagesize: - val = 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, ".") != 0) - error (EXIT_FAILURE, 0, gettext ("\ -address computation expression contains variable '%s'"), - expr->val.str); - - val = addr; - break; - - case exp_mult: - val = (eval_expression (expr->val.binary.left, addr) - * eval_expression (expr->val.binary.right, addr)); - break; - - case exp_div: - val = (eval_expression (expr->val.binary.left, addr) - / eval_expression (expr->val.binary.right, addr)); - break; - - case exp_mod: - val = (eval_expression (expr->val.binary.left, addr) - % eval_expression (expr->val.binary.right, addr)); - break; - - case exp_plus: - val = (eval_expression (expr->val.binary.left, addr) - + eval_expression (expr->val.binary.right, addr)); - break; - - case exp_minus: - val = (eval_expression (expr->val.binary.left, addr) - - eval_expression (expr->val.binary.right, addr)); - break; - - case exp_and: - val = (eval_expression (expr->val.binary.left, addr) - & eval_expression (expr->val.binary.right, addr)); - break; - - case exp_or: - val = (eval_expression (expr->val.binary.left, addr) - | eval_expression (expr->val.binary.right, addr)); - break; - - case exp_align: - val = eval_expression (expr->val.child, addr); - if ((val & (val - 1)) != 0) - error (EXIT_FAILURE, 0, gettext ("argument '%" PRIuMAX "' of ALIGN in address computation expression is no power of two"), - (uintmax_t) val); - val = (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 == 0) - return 0; - - /* When we are not optimizing we run only very few tests. */ - if (optlevel <= 0) - { - minsize = maxcnt; - maxsize = maxcnt + 10000 / maxcnt; - } - else - { - /* Does not make much sense to start with a smaller table than - one which has at least four collisions. */ - minsize = MAX (1, maxcnt / 4); - /* We look for a best fit in the range of up to eigth times the - number of elements. */ - maxsize = 2 * maxcnt + (6 * MIN (optlevel, 100) * maxcnt) / 100; - } - bestsize = maxcnt; - bestcost = UINT_MAX; - - /* Array for counting the collisions and chain lengths. */ - counts = (uint32_t *) xmalloc ((maxcnt + 1 + maxsize) * sizeof (uint32_t)); - lengths = &counts[maxcnt + 1]; - - for (size = minsize; size <= 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. */ - for (inner = 0; inner < maxcnt; ++inner) - ++lengths[hashcodes[inner] % size]; - - /* Determine the lengths. */ - maxlength = 0; - for (inner = 0; inner < size; ++inner) - { - ++counts[lengths[inner]]; - - if (lengths[inner] > maxlength) - maxlength = lengths[inner]; - } - - /* Determine successful lookup length. */ - acc = 0; - success = 0; - for (inner = 0; inner <= maxlength; ++inner) - { - acc += inner; - success += 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 = (1.0 * (double) success / (double) maxcnt - + 0.3 * (double) maxcnt / (double) size); - else - factor = (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 = (2 + maxcnt + size) * (factor + 1.0 / 16.0); - -#if 0 - printf ("maxcnt = %d, size = %d, cost = %Ld, success = %g, fail = %g, factor = %g\n", - maxcnt, size, cost, (double) success / (double) maxcnt, (double) maxcnt / (double) size, factor); -#endif - - /* Compare with current best results. */ - if (cost < bestcost) - { - bestcost = cost; - bestsize = size; - } - } - - free (counts); - - return bestsize; -} - - -static XElf_Addr -find_entry_point (void) -{ - XElf_Addr result; - - if (ld_state.entry != NULL) - { - struct symbol search = { .name = ld_state.entry }; - struct symbol *syment; - - syment = ld_symbol_tab_find (&ld_state.symbol_tab, - elf_hash (ld_state.entry), &search); - if (syment != NULL && syment->defined) - { - /* We found the symbol. */ - Elf_Data *data = elf_getdata (elf_getscn (ld_state.outelf, - ld_state.symscnidx), NULL); - - XElf_Sym_vardef (sym); - - sym = NULL; - if (data != NULL) - xelf_getsym (data, ld_state.dblindirect[syment->outsymidx], sym); - - if (sym == NULL && ld_state.need_dynsym && syment->outdynsymidx != 0) - { - /* Use the dynamic symbol table if available. */ - data = elf_getdata (elf_getscn (ld_state.outelf, - ld_state.dynsymscnidx), NULL); - - sym = NULL; - if (data != NULL) - xelf_getsym (data, syment->outdynsymidx, sym); - } - - if (sym != 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 != 0); - } - } - - /* We couldn't find the symbol or none was given. Use the first - address of the ".text" section then. */ - - - result = 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 == executable_file_type) - { - if (ld_state.entry != NULL) - error (0, 0, gettext ("\ -cannot find entry symbol \"%s\": defaulting to %#0*" PRIx64), - ld_state.entry, - xelf_getclass (ld_state.outelf) == ELFCLASS32 ? 10 : 18, - (uint64_t) result); - else - error (0, 0, gettext ("\ -no entry symbol specified: defaulting to %#0*" PRIx64), - xelf_getclass (ld_state.outelf) == 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 != relocatable_file_type); - - XElf_Sym_vardef (sym); - xelf_getsym_ptr (symdata, nsym, sym); - - /* The name offset will be filled in later. */ - sym->st_name = 0; - /* Traditionally: globally visible. */ - sym->st_info = XELF_ST_INFO (STB_GLOBAL, symst->type); - /* No special visibility or so. */ - sym->st_other = 0; - /* 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 != 0); - assert (scnidx < SHN_LORESERVE || scnidx == SHN_ABS); - sym->st_shndx = scnidx; - /* We want the beginning of the section. */ - sym->st_value = 0; - - /* Determine the size of the section. */ - if (scnidx != SHN_ABS) - { - Elf_Data *data = elf_getdata (elf_getscn (ld_state.outelf, scnidx), - NULL); - assert (data != NULL); - sym->st_size = data->d_size; - /* Make sure there is no second data block. */ - assert (elf_getdata (elf_getscn (ld_state.outelf, scnidx), data) - == 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] = symst; - symst->outsymidx = nsym; - - /* Add the name to the string table. */ - symstrent[nsym] = 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 = tag; - dyn->d_un.d_ptr = val; - (void) xelf_update_dyn (data, idx, dyn); -} - - -static void -allocate_version_names (struct usedfiles *runp, struct Ebl_Strtab *dynstrtab) -{ - /* If this DSO has no versions skip it. */ - if (runp->status != opened || runp->verdefdata == NULL) - return; - - /* Add the object name. */ - int offset = 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 != NULL); - xelf_getverdaux (runp->verdefdata, offset + def->vd_aux, aux); - assert (aux != NULL); - - assert (def->vd_ndx <= runp->nverdef); - if (def->vd_ndx == 1 || runp->verdefused[def->vd_ndx] != 0) - { - runp->verdefent[def->vd_ndx] - = ebl_strtabadd (dynstrtab, elf_strptr (runp->elf, - runp->dynsymstridx, - aux->vda_name), 0); - - if (def->vd_ndx > 1) - runp->verdefused[def->vd_ndx] = ld_state.nextveridx++; - } - - if (def->vd_next == 0) - /* That were all versions. */ - break; - - offset += def->vd_next; - } -} - - -XElf_Off -create_verneed_data (XElf_Off offset, Elf_Data *verneeddata, - struct usedfiles *runp, int *ntotal) -{ - size_t verneed_size = xelf_fsize (ld_state.outelf, ELF_T_VNEED, 1); - size_t vernaux_size = xelf_fsize (ld_state.outelf, ELF_T_VNAUX, 1); - int need_offset; - bool filled = false; - GElf_Verneed verneed; - GElf_Vernaux vernaux; - int ndef = 0; -size_t cnt; - - /* If this DSO has no versions skip it. */ - if (runp->nverdefused == 0) - return offset; - - /* We fill in the Verneed record last. Remember the - offset. */ - need_offset = offset; - offset += verneed_size; - - for (cnt = 2; cnt <= runp->nverdef; ++cnt) - if (runp->verdefused[cnt] != 0) - { - assert (runp->verdefent[cnt] != NULL); - - if (filled) - { - vernaux.vna_next = vernaux_size; - (void) gelf_update_vernaux (verneeddata, offset, - &vernaux); - offset += vernaux_size; - } - - vernaux.vna_hash - = elf_hash (ebl_string (runp->verdefent[cnt])); - vernaux.vna_flags = 0; - vernaux.vna_other = runp->verdefused[cnt]; - vernaux.vna_name = ebl_strtaboffset (runp->verdefent[cnt]); - filled = true; - ++ndef; - } - - assert (filled); - vernaux.vna_next = 0; - (void) gelf_update_vernaux (verneeddata, offset, &vernaux); - offset += vernaux_size; - - verneed.vn_version = VER_NEED_CURRENT; - verneed.vn_cnt = ndef; - verneed.vn_file = ebl_strtaboffset (runp->verdefent[1]); - /* The first auxiliary entry is always found directly - after the verneed entry. */ - verneed.vn_aux = verneed_size; - verneed.vn_next = --*ntotal > 0 ? offset - need_offset : 0; - (void) gelf_update_verneed (verneeddata, need_offset, - &verneed); - - return offset; -} - - -/* 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 = NULL; - size_t cnt; - Elf_Scn *symscn = NULL; - Elf_Scn *xndxscn = NULL; - Elf_Scn *strscn = NULL; - struct Ebl_Strtab *strtab = NULL; - struct Ebl_Strtab *dynstrtab = NULL; - XElf_Shdr_vardef (shdr); - Elf_Data *data; - Elf_Data *symdata = NULL; - Elf_Data *xndxdata = NULL; - struct usedfiles *file; - size_t nsym; - size_t nsym_local; - size_t nsym_allocated; - size_t nsym_dyn = 0; - Elf32_Word *dblindirect = NULL; -#ifndef NDEBUG - bool need_xndx; -#endif - Elf_Scn *shstrtab_scn; - size_t shstrtab_ndx; - XElf_Ehdr_vardef (ehdr); - struct Ebl_Strent *symtab_ent = NULL; - struct Ebl_Strent *xndx_ent = NULL; - struct Ebl_Strent *strtab_ent = NULL; - struct Ebl_Strent *shstrtab_ent; - struct scngroup *groups; - Elf_Scn *dynsymscn = NULL; - Elf_Data *dynsymdata = NULL; - Elf_Data *dynstrdata = NULL; - Elf32_Word *hashcodes = NULL; - size_t nsym_dyn_allocated = 0; - Elf_Scn *versymscn = NULL; - Elf_Data *versymdata = NULL; - - if (ld_state.need_symtab) - { - /* First create the symbol table. We need the symbol section itself - and the string table for it. */ - symscn = elf_newscn (ld_state.outelf); - ld_state.symscnidx = elf_ndxscn (symscn); - symdata = elf_newdata (symscn); - if (symdata == NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create symbol table for output file: %s"), - elf_errmsg (-1)); - - symdata->d_type = ELF_T_SYM; - /* This is an estimated size, but it will definitely cap the real value. - We might have to adjust the number later. */ - nsym_allocated = (1 + ld_state.nsymtab + ld_state.nplt + ld_state.ngot - + ld_state.nusedsections + ld_state.nlscript_syms); - symdata->d_size = 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 >= SHN_LORESERVE)) - { - xndxscn = elf_newscn (ld_state.outelf); - ld_state.xndxscnidx = elf_ndxscn (xndxscn); - - xndxdata = elf_newdata (xndxscn); - if (xndxdata == 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 = 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 = xelf_fsize (ld_state.outelf, ELF_T_WORD, - nsym_allocated); - /* The first entry is left empty, clear it here and now. */ - xndxdata->d_buf = memset (xmalloc (xndxdata->d_size), '\0', - xelf_fsize (ld_state.outelf, ELF_T_WORD, - 1)); - xndxdata->d_off = 0; - /* XXX Should use an ebl function. */ - xndxdata->d_align = 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 = elf_getscn (ld_state.outelf, ld_state.dynsymscnidx); - symdata = elf_newdata (symscn); - if (symdata == NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create symbol table for output file: %s"), - elf_errmsg (-1)); - - symdata->d_version = EV_CURRENT; - symdata->d_type = ELF_T_SYM; - /* This is an estimated size, but it will definitely cap the real value. - We might have to adjust the number later. */ - nsym_allocated = (1 + ld_state.nsymtab + ld_state.nplt + ld_state.ngot - - ld_state.nlocalsymbols + ld_state.nlscript_syms); - symdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_SYM, - nsym_allocated); - } - - /* The first entry is left empty, clear it here and now. */ - symdata->d_buf = memset (xmalloc (symdata->d_size), '\0', - xelf_fsize (ld_state.outelf, ELF_T_SYM, 1)); - symdata->d_off = 0; - /* XXX This is ugly but how else can it be done. */ - symdata->d_align = xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1); - - /* Allocate another array to keep track of the handles for the symbol - names. */ - symstrent = (struct Ebl_Strent **) xcalloc (nsym_allocated, - sizeof (struct Ebl_Strent *)); - - /* By starting at 1 we effectively add a null entry. */ - nsym = 1; - - /* Iteration over all sections. */ - for (cnt = 0; cnt < ld_state.nallsections; ++cnt) - { - struct scnhead *head = 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 = elf_getscn (ld_state.outelf, head->scnidx); - - if (unlikely (head->kind == scn_dot_interp)) - { - Elf_Data *outdata = elf_newdata (scn); - if (outdata == 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 = ld_state.interp ?: "/lib/ld.so.1"; - - /* Create the section data. */ - outdata->d_buf = (void *) interp; - outdata->d_size = strlen (interp) + 1; - outdata->d_type = ELF_T_BYTE; - outdata->d_off = 0; - outdata->d_align = 1; - outdata->d_version = EV_CURRENT; - - /* Remember the index of this section. */ - ld_state.interpscnidx = head->scnidx; - - continue; - } - - if (unlikely (head->kind == scn_dot_got)) - { - /* Remember the index of this section. */ - ld_state.gotscnidx = elf_ndxscn (scn); - - /* Give the backend the change to initialize the section. */ - INITIALIZE_GOT (&ld_state, scn); - - continue; - } - - if (unlikely (head->kind == scn_dot_dynrel)) - { - Elf_Data *outdata; - - outdata = elf_newdata (scn); - if (outdata == NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create section for output file: %s"), - elf_errmsg (-1)); - - outdata->d_size = ld_state.relsize_total; - outdata->d_buf = xmalloc (outdata->d_size); - outdata->d_type = (REL_TYPE (&ld_state) == DT_REL - ? ELF_T_REL : ELF_T_RELA); - outdata->d_off = 0; - outdata->d_align = xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1); - - /* Remember the index of this section. */ - ld_state.reldynscnidx = elf_ndxscn (scn); - - continue; - } - - if (unlikely (head->kind == 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 != 0) - ++ld_state.ndynamic; - if (ld_state.dt_flags_1 != 0) - ++ld_state.ndynamic; - if (ld_state.dt_feature_1 != 0) - ++ld_state.ndynamic; - - outdata = elf_newdata (scn); - if (outdata == NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create section for output file: %s"), - elf_errmsg (-1)); - - /* Create the section data. */ - outdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_DYN, - ld_state.ndynamic); - outdata->d_buf = xcalloc (1, outdata->d_size); - outdata->d_type = ELF_T_DYN; - outdata->d_off = 0; - outdata->d_align = xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1); - - /* Remember the index of this section. */ - ld_state.dynamicscnidx = elf_ndxscn (scn); - - continue; - } - - if (unlikely (head->kind == scn_dot_dynsym)) - { - /* We already know the section index. */ - assert (ld_state.dynsymscnidx == elf_ndxscn (scn)); - - continue; - } - - if (unlikely (head->kind == scn_dot_dynstr)) - { - /* Remember the index of this section. */ - ld_state.dynstrscnidx = elf_ndxscn (scn); - - /* Create the string table. */ - dynstrtab = 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 = ld_state.dsofiles; - - do - if (! ld_state.ignore_unused_dsos || frunp->used) - frunp->sonameent = ebl_strtabadd (dynstrtab, frunp->soname, - 0); - while ((frunp = frunp->next) != 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 != NULL || ld_state.rpath != NULL) - { - struct pathelement *startp; - struct pathelement *prunp; - int tag; - size_t len; - char *str; - char *cp; - - if (ld_state.runpath != NULL) - { - startp = ld_state.runpath; - tag = DT_RUNPATH; - } - else - { - startp = ld_state.rpath; - tag = DT_RPATH; - } - - /* Determine how long the string will be. */ - for (len = 0, prunp = startp; prunp != NULL; prunp = prunp->next) - len += strlen (prunp->pname) + 1; - - cp = str = (char *) obstack_alloc (&ld_state.smem, len); - /* Copy the string. */ - for (prunp = startp; prunp != NULL; prunp = prunp->next) - { - cp = stpcpy (cp, prunp->pname); - *cp++ = ':'; - } - /* Remove the last colon. */ - cp[-1] = '\0'; - - /* Remember the values until we can generate the dynamic - section. */ - ld_state.rxxpath_strent = ebl_strtabadd (dynstrtab, str, len); - ld_state.rxxpath_tag = tag; - } - - continue; - } - - if (unlikely (head->kind == scn_dot_hash)) - { - /* Remember the index of this section. */ - ld_state.hashscnidx = elf_ndxscn (scn); - - continue; - } - - if (unlikely (head->kind == scn_dot_plt)) - { - /* Remember the index of this section. */ - ld_state.pltscnidx = elf_ndxscn (scn); - - /* Give the backend the change to initialize the section. */ - INITIALIZE_PLT (&ld_state, scn); - - continue; - } - - if (unlikely (head->kind == scn_dot_pltrel)) - { - /* Remember the index of this section. */ - ld_state.pltrelscnidx = elf_ndxscn (scn); - - /* Give the backend the change to initialize the section. */ - INITIALIZE_PLTREL (&ld_state, scn); - - continue; - } - - if (unlikely (head->kind == scn_dot_version)) - { - /* Remember the index of this section. */ - ld_state.versymscnidx = elf_ndxscn (scn); - - continue; - } - - if (unlikely (head->kind == scn_dot_version_r)) - { - /* Remember the index of this section. */ - ld_state.verneedscnidx = elf_ndxscn (scn); - - continue; - } - - /* If we come here we must be handling a normal section. */ - assert (head->kind == 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 = 0; - sym->st_info = XELF_ST_INFO (STB_LOCAL, STT_SECTION); - sym->st_other = 0; - sym->st_value = 0; - sym->st_size = 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 = head->scnidx; - xndx = 0; - } - else - { - sym->st_shndx = SHN_XINDEX; - xndx = 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 = nsym++; - } - - if (head->type == SHT_REL || head->type == SHT_RELA) - { - /* Remember that we have to fill in the symbol table section - index. */ - if (ld_state.file_type == relocatable_file_type) - { - struct scnlist *newp; - - newp = (struct scnlist *) alloca (sizeof (*newp)); - newp->scnidx = head->scnidx; - newp->scninfo = head->last->next; -#ifndef NDEBUG - newp->next = 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 = head->type == SHT_REL ? ELF_T_REL : ELF_T_RELA; - - data = elf_newdata (scn); - if (data == NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create section for output file: %s"), - elf_errmsg (-1)); - - data->d_size = xelf_fsize (ld_state.outelf, type, head->relsize); - data->d_buf = xcalloc (data->d_size, 1); - data->d_type = type; - data->d_align = xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1); - data->d_off = 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 = head->last->next; - if (runp->symbols == NULL) - { - head->flags &= ~SHF_MERGE; - goto no_merge; - } - head->symbols = runp->symbols; - - while ((runp = runp->next) != head->last->next) - { - if (runp->symbols == NULL) - { - head->flags &= ~SHF_MERGE; - head->symbols = NULL; - goto no_merge; - } - - struct symbol *oldhead = head->symbols->next_in_scn; - - head->symbols->next_in_scn = runp->symbols->next_in_scn; - runp->symbols->next_in_scn = oldhead; - head->symbols = runp->symbols; - } - - /* Create the output section. */ - outdata = elf_newdata (scn); - if (outdata == 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 == 1 - && (head->flags & SHF_STRINGS)) - { - /* Simple, single-byte string matching. */ - struct Ebl_Strtab *mergestrtab; - struct symbol *symrunp; - Elf_Data *locsymdata = NULL; - Elf_Data *locdata = NULL; - - mergestrtab = ebl_strtabinit (false); - - symrunp = head->symbols->next_in_scn; - file = 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 != file) - { - /* Remember the file. */ - file = symrunp->file; - /* Symbol table data from that file. */ - locsymdata = file->symtabdata; - /* String section data. */ - locdata = elf_rawdata (file->scninfo[symrunp->scndx].scn, - NULL); - assert (locdata != 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 = 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 != 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 - = ebl_strtabadd (mergestrtab, - (char *) locdata->d_buf + sym->st_value, - 0); - } - while ((symrunp = symrunp->next_in_scn) - != 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 = runp->symbols; - do - { - symrunp->merge.value - = ebl_strtaboffset (symrunp->merge.handle); - symrunp->merged = 1; - } - while ((symrunp = symrunp->next_in_scn) != runp->symbols); - - /* We don't need the string table anymore. */ - ebl_strtabfree (mergestrtab); - } - else if (likely (SCNINFO_SHDR (head->last->shdr).sh_entsize - == sizeof (wchar_t)) - && likely (head->flags & SHF_STRINGS)) - { - /* Simple, wchar_t string merging. */ - struct Ebl_WStrtab *mergestrtab; - struct symbol *symrunp; - Elf_Data *locsymdata = NULL; - Elf_Data *locdata = NULL; - - mergestrtab = ebl_wstrtabinit (false); - - symrunp = runp->symbols; - file = 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 != file) - { - /* Remember the file. */ - file = symrunp->file; - /* Symbol table data from that file. */ - locsymdata = file->symtabdata; - /* String section data. */ - locdata = elf_rawdata (file->scninfo[symrunp->scndx].scn, - NULL); - assert (locdata != 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 = 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 != 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 - = ebl_wstrtabadd (mergestrtab, - (wchar_t *) ((char *) locdata->d_buf - + sym->st_value), 0); - } - while ((symrunp = symrunp->next_in_scn) != runp->symbols); - - /* All strings have been added. Create the final table. */ - ebl_wstrtabfinalize (mergestrtab, outdata); - - /* Compute the final offsets in the section. */ - symrunp = runp->symbols; - do - { - symrunp->merge.value - = ebl_wstrtaboffset (symrunp->merge.handle); - symrunp->merged = 1; - } - while ((symrunp = symrunp->next_in_scn) != 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 = NULL; - Elf_Data *locdata = NULL; - /* If this is no string section the length of each "string" - is always one. */ - unsigned int len = (head->flags & SHF_STRINGS) ? 0 : 1; - - /* This is the generic string table functionality. Much - slower than the specialized code. */ - mergestrtab - = ebl_gstrtabinit (SCNINFO_SHDR (head->last->shdr).sh_entsize, - false); - - symrunp = runp->symbols; - file = 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 != file) - { - /* Remember the file. */ - file = symrunp->file; - /* Symbol table data from that file. */ - locsymdata = file->symtabdata; - /* String section data. */ - locdata = elf_rawdata (file->scninfo[symrunp->scndx].scn, - NULL); - assert (locdata != 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 = 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 != 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 - = ebl_gstrtabadd (mergestrtab, - (char *) locdata->d_buf + sym->st_value, - len); - } - while ((symrunp = symrunp->next_in_scn) != runp->symbols); - - /* Create the final table. */ - ebl_gstrtabfinalize (mergestrtab, outdata); - - /* Compute the final offsets in the section. */ - symrunp = runp->symbols; - do - { - symrunp->merge.value - = ebl_gstrtaboffset (symrunp->merge.handle); - symrunp->merged = 1; - } - while ((symrunp = symrunp->next_in_scn) != runp->symbols); - - /* We don't need the string table anymore. */ - ebl_gstrtabfree (mergestrtab); - } - } - else - { - no_merge: - assert (head->scnidx == 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 = head->last->next; - offset = 0; - do - { - Elf_Data *outdata = elf_newdata (scn); - if (outdata == 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 != NULL)) - { - data = elf_getdata (runp->scn, NULL); - assert (data != NULL); - - /* We reuse the data buffer in the input file. */ - *outdata = *data; - - /* Given that we read the input file from disk we know there - cannot be another data part. */ - assert (elf_getdata (runp->scn, data) == NULL); - } - else - { - /* Must be a NOBITS section. */ - assert (SCNINFO_SHDR (runp->shdr).sh_type == SHT_NOBITS); - - outdata->d_buf = NULL; /* Not needed. */ - outdata->d_type = ELF_T_BYTE; - outdata->d_version = EV_CURRENT; - outdata->d_size = SCNINFO_SHDR (runp->shdr).sh_size; - outdata->d_align = SCNINFO_SHDR (runp->shdr).sh_addralign; - } - - XElf_Off align = MAX (1, outdata->d_align); - assert (powerof2 (align)); - offset = ((offset + align - 1) & ~(align - 1)); - - runp->offset = offset; - runp->outscnndx = head->scnidx; - runp->allsectionsidx = cnt; - - outdata->d_off = offset; - - offset += outdata->d_size; - } - while ((runp = runp->next) != head->last->next); - - /* If necessary add the additional line to the .comment section. */ - if (ld_state.add_ld_comment - && head->flags == 0 - && head->type == SHT_PROGBITS - && strcmp (head->name, ".comment") == 0 - && head->entsize == 0) - { - Elf_Data *outdata = elf_newdata (scn); - - if (outdata == NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create section for output file: %s"), - elf_errmsg (-1)); - - outdata->d_buf = (void *) "\0ld (Red Hat " PACKAGE ") " VERSION; - outdata->d_size = strlen ((char *) outdata->d_buf + 1) + 2; - outdata->d_off = offset; - outdata->d_type = ELF_T_BYTE; - outdata->d_align = 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 = ebl_strtabinit (true); - if (strtab == NULL) - error (EXIT_FAILURE, errno, gettext ("cannot create string table")); - - -#ifndef NDEBUG - /* Keep track of the use of the XINDEX. */ - need_xndx = 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 = (struct symbol **) xcalloc (nsym_allocated, - sizeof (struct symbol)); - - /* Create the special symbol for the GOT section. */ - if (ld_state.got_symbol != NULL) - { - assert (nsym < nsym_allocated); - fillin_special_symbol (ld_state.got_symbol, ld_state.gotscnidx, - nsym++, symdata, strtab); - } - - /* Similarly for the dynamic section symbol. */ - if (ld_state.dyn_symbol != 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 != NULL) - { - struct symbol *rsym = ld_state.lscript_syms; - do - { - assert (nsym < nsym_allocated); - fillin_special_symbol (rsym, SHN_ABS, nsym++, symdata, strtab); - } - while ((rsym = rsym->next) != NULL); - } - - /* Iterate over all input files to collect the symbols. */ - file = ld_state.relfiles->next; - symdata = 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 != relocatable_file_type - || file->dynsymtabdata == NULL); - - insymdata = file->symtabdata; - assert (insymdata != NULL); - inxndxdata = file->xndxdata; - - maxcnt = file->nsymtab; - - file->symindirect = (Elf32_Word *) xcalloc (maxcnt, sizeof (Elf32_Word)); - - /* The dynamic symbol table does not contain local symbols. So - we skip those entries. */ - for (cnt = ld_state.need_symtab ? 1 : file->nlocalsymbols; cnt < maxcnt; - ++cnt) - { - XElf_Sym_vardef (sym); - Elf32_Word xndx; - struct symbol *defp = NULL; - - xelf_getsymshndx (insymdata, inxndxdata, cnt, sym, xndx); - assert (sym != NULL); - - if (unlikely (XELF_ST_TYPE (sym->st_info) == 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 != SHN_XINDEX) - xndx = sym->st_shndx; - - assert (file->scninfo[xndx].allsectionsidx - < ld_state.nallsections); - file->symindirect[cnt] = ld_state.allsections[file->scninfo[xndx].allsectionsidx]->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 >= strip_all || !ld_state.need_symtab) - /* XXX Do we need these entries? */ - && XELF_ST_TYPE (sym->st_info) == STT_FILE) - continue; - -#if NATIVE_ELF != 0 - /* Copy old data. */ - XElf_Sym *sym2 = sym; - assert (nsym < nsym_allocated); - xelf_getsym (symdata, nsym, sym); - *sym = *sym2; -#endif - - if (sym->st_shndx != SHN_UNDEF - && (sym->st_shndx < SHN_LORESERVE - || sym->st_shndx == 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 >= file->nlocalsymbols); - defp = file->symref[cnt]; - assert (defp != 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 != SHN_XINDEX) - xndx = sym->st_shndx; - - sym->st_value += 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 != NULL); - sym->st_shndx = SHN_XINDEX; - xndx = file->scninfo[xndx].outscnndx; -#ifndef NDEBUG - need_xndx = true; -#endif - } - else - { - sym->st_shndx = file->scninfo[xndx].outscnndx; - xndx = 0; - } - } - else if (sym->st_shndx == SHN_COMMON || sym->st_shndx == SHN_UNDEF) - { - /* Check whether we have a (real) definition for this - symbol. If this is the case we skip this symbol - table entry. */ - assert (cnt >= file->nlocalsymbols); - defp = file->symref[cnt]; - assert (defp != NULL); - - assert (sym->st_shndx != SHN_COMMON || defp->defined); - - if ((sym->st_shndx == SHN_COMMON && !defp->common) - || (sym->st_shndx == 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 = 1; - - /* Adjust the section number for common symbols. */ - if (sym->st_shndx == SHN_COMMON) - { - sym->st_value = (ld_state.common_section->offset - + file->symref[cnt]->merge.value); - assert (ld_state.common_section->outscnndx < SHN_LORESERVE); - sym->st_shndx = ld_state.common_section->outscnndx; - xndx = 0; - } - } - else if (unlikely (sym->st_shndx != 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 != 0 - && (ld_state.strip < strip_everything - || XELF_ST_BIND (sym->st_info) != STB_LOCAL)) - symstrent[nsym] = 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. */ - sym->st_name = 0; - - /* If we had to merge sections we have a completely new - offset for the symbol. */ - if (file->has_merge_sections && file->symref[cnt] != NULL - && file->symref[cnt]->merged) - sym->st_value = file->symref[cnt]->merge.value; - - /* Create the record in the output sections. */ - assert (nsym < nsym_allocated); - xelf_update_symshndx (symdata, xndxdata, nsym, sym, xndx, 0); - - /* 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 == NULL && cnt >= file->nlocalsymbols) - { - defp = file->symref[cnt]; - assert (defp != NULL); - } - - /* Store the reference to the symbol record. The - sorting code will have to keep this array in the - correct order, too. */ - ndxtosym[nsym] = defp; - - /* One more entry finished. */ - if (cnt >= file->nlocalsymbols) - { - assert (file->symref[cnt]->outsymidx == 0); - file->symref[cnt]->outsymidx = nsym; - } - file->symindirect[cnt] = nsym++; - } - } - while ((file = file->next) != ld_state.relfiles->next); - /* Make sure we didn't create the extended section index table for - nothing. */ - assert (xndxdata == NULL || need_xndx); - - - /* Create the version related sections. */ - if (ld_state.verneedscnidx != 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 = ld_state.dsofiles->next; - do - allocate_version_names (runp, dynstrtab); - while ((runp = runp->next) != ld_state.dsofiles->next); - - if (ld_state.needed != NULL) - { - runp = ld_state.needed->next; - do - allocate_version_names (runp, dynstrtab); - while ((runp = runp->next) != 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 = false; - - for (cnt = 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 != NULL); - - if (reduce_symbol_p (sym, symstrent[cnt])) - { - sym->st_info = 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 == strip_everything) - { - symstrent[cnt] = NULL; - any_reduced = 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 = ebl_strtabinit (true); - - for (cnt = 1; cnt < nsym; ++cnt) - if (symstrent[cnt] != NULL) - symstrent[cnt] = ebl_strtabadd (newp, - ebl_string (symstrent[cnt]), 0); - - ebl_strtabfree (strtab); - strtab = 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 != NULL) - { - struct symbol *runp; - size_t plt_base = nsym + ld_state.nfrom_dso - ld_state.nplt; - size_t plt_idx = 0; - size_t obj_idx = 0; - - assert (ld_state.nfrom_dso >= ld_state.nplt); - runp = 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 == STT_FUNC) - { - /* Store the PLT entry number. */ - runp->merge.value = plt_idx + 1; - idx = plt_base + plt_idx++; - } - else - idx = nsym + obj_idx++; - - XElf_Sym_vardef (sym); - xelf_getsym_ptr (symdata, idx, sym); - - sym->st_value = 0; - sym->st_size = runp->size; - sym->st_info = XELF_ST_INFO (runp->weak ? STB_WEAK : STB_GLOBAL, - runp->type); - sym->st_other = STV_DEFAULT; - sym->st_shndx = SHN_UNDEF; - - /* Create the record in the output sections. */ - xelf_update_symshndx (symdata, xndxdata, idx, sym, 0, 0); - - const char *name = runp->name; - size_t namelen = 0; - - if (runp->file->verdefdata != 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) == 0); - - const char *versname - = ebl_string (runp->file->verdefent[versym]); - - size_t versname_len = strlen (versname) + 1; - namelen = strlen (name) + versname_len + 2; - char *newp = (char *) obstack_alloc (&ld_state.smem, namelen); - memcpy (stpcpy (stpcpy (newp, name), "@@"), - versname, versname_len); - name = newp; - } - - symstrent[idx] = ebl_strtabadd (strtab, name, namelen); - - /* Record the initial index in the symbol table. */ - runp->outsymidx = idx; - - /* Remember the symbol record this ELF symbol came from. */ - ndxtosym[idx] = runp; - } - while ((runp = runp->next) != ld_state.from_dso); - - assert (nsym + obj_idx == plt_base); - assert (plt_idx == ld_state.nplt); - nsym = 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 = xelf_fsize (ld_state.outelf, ELF_T_SYM, nsym); - if (unlikely (xndxdata != NULL)) - xndxdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_WORD, nsym); - - /* Create the symbol string table section. */ - strscn = elf_newscn (ld_state.outelf); - ld_state.strscnidx = elf_ndxscn (strscn); - data = elf_newdata (strscn); - xelf_getshdr (strscn, shdr); - if (data == NULL || shdr == 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 = SHT_STRTAB; - assert (shdr->sh_entsize == 0); - - if (unlikely (xelf_update_shdr (strscn, shdr) == 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 = 1; cnt < nsym; ++cnt) - if (symstrent[cnt] != 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 != NULL); - sym->st_name = 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 = dblindirect - = (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 = 1; - cnt = 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 != NULL); - - if (XELF_ST_BIND (locsym->st_info) != STB_LOCAL - && (ld_state.need_symtab || ld_state.export_all_dynamic)) - { - do - { - xelf_getsymshndx (symdata, xndxdata, cnt, globsym, globxndx); - /* This better works. */ - assert (globsym != NULL); - - if (unlikely (XELF_ST_BIND (globsym->st_info) == STB_LOCAL)) - { - /* We swap the two entries. */ -#if NATIVE_ELF != 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 = *locsym; - locsym = &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] = cnt; - dblindirect[cnt] = nsym_local; - - /* And the entries for the symbol names. */ - struct Ebl_Strent *strtmp = symstrent[nsym_local]; - symstrent[nsym_local] = symstrent[cnt]; - symstrent[cnt] = strtmp; - - /* And the mapping from symbol table entry to - struct symbol record. */ - struct symbol *symtmp = ndxtosym[nsym_local]; - ndxtosym[nsym_local] = ndxtosym[cnt]; - ndxtosym[cnt] = symtmp; - - /* Go to the next entry. */ - ++nsym_local; - --cnt; - - break; - } - - dblindirect[cnt] = cnt; - } - while (nsym_local < --cnt); - - break; - } - - dblindirect[nsym_local] = 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] = nsym_local; - - /* Note that it is OK to not use 'xelf_getsymshndx' here. */ - xelf_getsym (symdata, nsym_local, locsym); - /* This better works. */ - assert (locsym != NULL); - - if (XELF_ST_BIND (locsym->st_info) == STB_LOCAL) - ++nsym_local; - } - - - /* We need the versym array right away to keep track of the version - symbols. */ - if (ld_state.versymscnidx != 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 = elf_getscn (ld_state.outelf, ld_state.versymscnidx); - versymdata = elf_newdata (versymscn); - if (versymdata == NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create versioning section: %s"), - elf_errmsg (-1)); - - versymdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_HALF, - nsym - nsym_local + 1); - versymdata->d_buf = xcalloc (1, versymdata->d_size); - versymdata->d_align = xelf_fsize (ld_state.outelf, ELF_T_HALF, 1); - versymdata->d_off = 0; - versymdata->d_type = 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 = 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 = (char *) symdata->d_buf + reduce; - symdata->d_size -= reduce; - - /* Add the version symbol information. */ - if (versymdata != NULL) - { - nsym_dyn = 1; - for (cnt = nsym_local; cnt < nsym; ++cnt, ++nsym_dyn) - { - struct symbol *symp = ndxtosym[cnt]; - - if (symp->file->versymdata != NULL) - { - GElf_Versym versym; - - gelf_getversym (symp->file->versymdata, symp->symidx, - &versym); - - (void) gelf_update_versym (versymdata, nsym_dyn, - &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 = 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 = elf_getscn (ld_state.outelf, ld_state.dynsymscnidx); - dynsymdata = elf_newdata (dynsymscn); - - dynstrdata = elf_newdata (elf_getscn (ld_state.outelf, - ld_state.dynstrscnidx)); - if (dynsymdata == NULL || dynstrdata == NULL) - error (EXIT_FAILURE, 0, gettext ("\ -cannot create dynamic symbol table for output file: %s"), - elf_errmsg (-1)); - - nsym_dyn_allocated = nsym - nsym_local + 1; - dynsymdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_SYM, - nsym_dyn_allocated); - dynsymdata->d_buf = memset (xmalloc (dynsymdata->d_size), '\0', - xelf_fsize (ld_state.outelf, ELF_T_SYM, 1)); - dynsymdata->d_type = ELF_T_SYM; - dynsymdata->d_off = 0; - dynsymdata->d_align = xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1); - - /* We need one more array which contains the hash codes of the - symbol names. */ - hashcodes = (Elf32_Word *) xcalloc (nsym_dyn_allocated, - sizeof (Elf32_Word)); - - /* We have and empty entry at the beginning. */ - nsym_dyn = 1; - - /* We don't mix PLT symbols and others. */ - size_t plt_idx = 1; - size_t obj_idx = 1 + ld_state.nplt; - - /* Populate the table. */ - for (cnt = nsym_local; cnt < nsym; ++cnt) - { - XElf_Sym_vardef (sym); - - xelf_getsym (symdata, cnt, sym); - assert (sym != NULL); - - if (sym->st_shndx == 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) - - if export_all_dynamic is not set and is only defined in - the executable (i.e., it is defined, but not (also) in - in DSO) - - Set symstrent[cnt] to NULL in case an entry is ignored. */ - if (XELF_ST_TYPE (sym->st_info) == STT_FILE - || XELF_ST_VISIBILITY (sym->st_other) == STV_INTERNAL - || XELF_ST_VISIBILITY (sym->st_other) == STV_HIDDEN - || (!ndxtosym[cnt]->in_dso && ndxtosym[cnt]->defined)) - { - symstrent[cnt] = NULL; - continue; - } - - size_t idx; - if (ndxtosym[cnt]->in_dso && ndxtosym[cnt]->type == STT_FUNC) - { - idx = plt_idx++; - assert (idx < 1 + ld_state.nplt); - } - else - { - idx = obj_idx++; - assert (idx < nsym_dyn_allocated); - } - - /* Add the version information. */ - if (versymdata != NULL) - { - struct symbol *symp = ndxtosym[cnt]; - - if (symp->file->verdefdata != NULL) - { - GElf_Versym versym; - - gelf_getversym (symp->file->versymdata, symp->symidx, - &versym); - - (void) gelf_update_versym (versymdata, idx, - &symp->file->verdefused[versym]); - } - else - { - /* XXX Add support for version definitions. */ - GElf_Versym global = VER_NDX_GLOBAL; - (void) gelf_update_versym (versymdata, idx, &global); - } - } - - /* Store the index of the symbol in the dynamic symbol table. */ - ndxtosym[cnt]->outdynsymidx = idx; - - /* Create a new string table entry. */ - const char *str = ndxtosym[cnt]->name; - symstrent[cnt] = ebl_strtabadd (dynstrtab, str, 0); - hashcodes[idx] = elf_hash (str); - ++nsym_dyn; - } - assert (nsym_dyn == obj_idx); - assert (ld_state.nplt + 1 == plt_idx); - - /* Update the information about the symbol section. */ - if (versymdata != NULL) - { - /* Correct the size now that we know how many entries the - dynamic symbol table has. */ - versymdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_HALF, - nsym_dyn); - - /* Add the reference to the symbol table. */ - xelf_getshdr (versymscn, shdr); - assert (shdr != NULL); - - shdr->sh_link = ld_state.dynsymscnidx; - - (void) xelf_update_shdr (versymscn, shdr); - } - } - - if (ld_state.file_type != relocatable_file_type) - { - size_t nbucket; - Elf32_Word *bucket; - Elf32_Word *chain; - size_t nchain; - Elf_Scn *hashscn; - Elf_Data *hashdata; - - /* Finalize the dynamic string table. */ - ebl_strtabfinalize (dynstrtab, dynstrdata); - - /* Determine the "optimal" bucket size. */ - nbucket = optimal_bucket_size (hashcodes, nsym_dyn, ld_state.optlevel); - - /* Create the .hash section data structures. */ - assert (ld_state.hashscnidx != 0); - hashscn = elf_getscn (ld_state.outelf, ld_state.hashscnidx); - xelf_getshdr (hashscn, shdr); - hashdata = elf_newdata (hashscn); - if (shdr == NULL || hashdata == NULL) - error (EXIT_FAILURE, 0, gettext ("\ -cannot create hash table section for output file: %s"), - elf_errmsg (-1)); - - shdr->sh_link = ld_state.dynsymscnidx; - (void) xelf_update_shdr (hashscn, shdr); - - hashdata->d_size = (2 + nsym_dyn + nbucket) * sizeof (Elf32_Word); - hashdata->d_buf = xcalloc (1, hashdata->d_size); - hashdata->d_align = sizeof (Elf32_Word); - hashdata->d_type = ELF_T_WORD; - hashdata->d_off = 0; - - ((Elf32_Word *) hashdata->d_buf)[0] = nbucket; - ((Elf32_Word *) hashdata->d_buf)[1] = nsym_dyn; - bucket = &((Elf32_Word *) hashdata->d_buf)[2]; - chain = &((Elf32_Word *) hashdata->d_buf)[2 + nbucket]; - - /* Haven't yet filled in any chain value. */ - nchain = 0; - - /* Now put the names in. */ - for (cnt = nsym_local; cnt < nsym; ++cnt) - if (symstrent[cnt] != NULL) - { - XElf_Sym_vardef (sym); - size_t hashidx; - size_t dynidx = ndxtosym[cnt]->outdynsymidx; - -#if NATIVE_ELF != 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 != NULL); -#endif - - sym->st_name = ebl_strtaboffset (symstrent[cnt]); - - (void) xelf_update_sym (dynsymdata, dynidx, sym); - - /* Add to the hash table. */ - hashidx = hashcodes[dynidx] % nbucket; - if (bucket[hashidx] == 0) - bucket[hashidx] = dynidx; - else - { - hashidx = bucket[hashidx]; - while (chain[hashidx] != 0) - hashidx = chain[hashidx]; - - chain[hashidx] = dynidx; - } - } - - free (hashcodes); - - /* We don't need the map from the symbol table index to the symbol - structure anymore. */ - free (ndxtosym); - - /* Create the required version section. */ - if (ld_state.verneedscnidx != 0) - { - Elf_Scn *verneedscn; - Elf_Data *verneeddata; - struct usedfiles *runp; - size_t verneed_size = xelf_fsize (ld_state.outelf, ELF_T_VNEED, 1); - size_t vernaux_size = xelf_fsize (ld_state.outelf, ELF_T_VNAUX, 1); - size_t offset; - int ntotal; - - verneedscn = elf_getscn (ld_state.outelf, ld_state.verneedscnidx); - xelf_getshdr (verneedscn, shdr); - verneeddata = elf_newdata (verneedscn); - if (shdr == NULL || verneeddata == NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create versioning data: %s"), - elf_errmsg (-1)); - - verneeddata->d_size = (ld_state.nverdeffile * verneed_size - + ld_state.nverdefused * vernaux_size); - verneeddata->d_buf = xmalloc (verneeddata->d_size); - verneeddata->d_type = ELF_T_VNEED; - verneeddata->d_align = xelf_fsize (ld_state.outelf, ELF_T_WORD, 1); - verneeddata->d_off = 0; - - offset = 0; - ntotal = ld_state.nverdeffile; - runp = ld_state.dsofiles->next; - do - { - offset = create_verneed_data (offset, verneeddata, runp, - &ntotal); - runp = runp->next; - } - while (ntotal > 0 && runp != ld_state.dsofiles->next); - - if (ntotal > 0) - { - runp = ld_state.needed->next; - do - { - offset = create_verneed_data (offset, verneeddata, runp, - &ntotal); - runp = runp->next; - } - while (ntotal > 0 && runp != ld_state.needed->next); - } - - assert (offset == verneeddata->d_size); - - /* Add the needed information to the section header. */ - shdr->sh_link = ld_state.dynstrscnidx; - shdr->sh_info = ld_state.nverdeffile; - (void) xelf_update_shdr (verneedscn, shdr); - } - - /* Adjust the section size. */ - dynsymdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_SYM, nsym_dyn); - if (versymdata != NULL) - versymdata->d_size = 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 = 1; - /* Reference the string table. */ - shdr->sh_link = ld_state.dynstrscnidx; - /* Write the updated info back. */ - (void) xelf_update_shdr (dynsymscn, shdr); - } - else - /* We don't need the map from the symbol table index to the symbol - structure anymore. */ - free (ndxtosym); - - /* We don't need the string table anymore. */ - free (symstrent); - - /* Remember the total number of symbols in the dynamic symbol table. */ - ld_state.ndynsym = nsym_dyn; - - /* Fill in the section header information. */ - symscn = elf_getscn (ld_state.outelf, ld_state.symscnidx); - xelf_getshdr (symscn, shdr); - if (shdr == NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create symbol table for output file: %s"), - elf_errmsg (-1)); - - shdr->sh_type = SHT_SYMTAB; - shdr->sh_link = ld_state.strscnidx; - shdr->sh_info = nsym_local; - shdr->sh_entsize = 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 != 0) - symtab_ent = ebl_strtabadd (ld_state.shstrtab, ".symtab", 8); - if (ld_state.xndxscnidx != 0) - xndx_ent = ebl_strtabadd (ld_state.shstrtab, ".symtab_shndx", 14); - if (ld_state.strscnidx != 0) - strtab_ent = 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 - latter 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 = elf_newscn (ld_state.outelf); - shstrtab_ndx = elf_ndxscn (shstrtab_scn); - if (unlikely (shstrtab_ndx == 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 = ebl_strtabadd (ld_state.shstrtab, ".shstrtab", 10); - if (unlikely (shstrtab_ent == NULL)) - error (EXIT_FAILURE, errno, - gettext ("cannot create section header string section")); - - /* Finalize the section header string table. */ - data = elf_newdata (shstrtab_scn); - if (data == 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 = 0; cnt < ld_state.nallsections; ++cnt) - if (ld_state.allsections[cnt]->scnidx != 0) - { - Elf_Scn *scn; - - scn = elf_getscn (ld_state.outelf, ld_state.allsections[cnt]->scnidx); - - xelf_getshdr (scn, shdr); - assert (shdr != NULL); - - shdr->sh_name = ebl_strtaboffset (ld_state.allsections[cnt]->nameent); - - if (xelf_update_shdr (scn, shdr) == 0) - assert (0); - } - - /* Add the names for the generated sections to the respective - section headers. */ - if (symtab_ent != NULL) - { - Elf_Scn *scn = elf_getscn (ld_state.outelf, ld_state.symscnidx); - - xelf_getshdr (scn, shdr); - /* This cannot fail, we already accessed the header before. */ - assert (shdr != NULL); - - shdr->sh_name = ebl_strtaboffset (symtab_ent); - - (void) xelf_update_shdr (scn, shdr); - } - if (xndx_ent != NULL) - { - Elf_Scn *scn = elf_getscn (ld_state.outelf, ld_state.xndxscnidx); - - xelf_getshdr (scn, shdr); - /* This cannot fail, we already accessed the header before. */ - assert (shdr != NULL); - - shdr->sh_name = ebl_strtaboffset (xndx_ent); - - (void) xelf_update_shdr (scn, shdr); - } - if (strtab_ent != NULL) - { - Elf_Scn *scn = elf_getscn (ld_state.outelf, ld_state.strscnidx); - - xelf_getshdr (scn, shdr); - /* This cannot fail, we already accessed the header before. */ - assert (shdr != NULL); - - shdr->sh_name = ebl_strtaboffset (strtab_ent); - - (void) xelf_update_shdr (scn, shdr); - } - - /* And the section header table section itself. */ - xelf_getshdr (shstrtab_scn, shdr); - if (shdr == NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot create section header string section: %s"), - elf_errmsg (-1)); - - shdr->sh_name = ebl_strtaboffset (shstrtab_ent); - shdr->sh_type = SHT_STRTAB; - - if (unlikely (xelf_update_shdr (shstrtab_scn, shdr) == 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 = ld_state.groups; - while (groups != NULL) - { - Elf_Scn *scn; - struct scngroup *oldp; - Elf32_Word si; - - scn = elf_getscn (ld_state.outelf, groups->outscnidx); - xelf_getshdr (scn, shdr); - assert (shdr != NULL); - - shdr->sh_name = ebl_strtaboffset (groups->nameent); - shdr->sh_type = SHT_GROUP; - shdr->sh_flags = 0; - shdr->sh_link = ld_state.symscnidx; - shdr->sh_entsize = sizeof (Elf32_Word); - - /* Determine the index for the signature symbol. */ - si = groups->symbol->file->symindirect[groups->symbol->symidx]; - if (si == 0) - { - assert (groups->symbol->file->symref[groups->symbol->symidx] - != NULL); - si = groups->symbol->file->symref[groups->symbol->symidx]->outsymidx; - assert (si != 0); - } - shdr->sh_info = ld_state.dblindirect[si]; - - (void) xelf_update_shdr (scn, shdr); - - oldp = groups; - groups = groups->next; - free (oldp); - } - - - if (ld_state.file_type != relocatable_file_type) - { - size_t nphdr; - XElf_Addr addr; - struct output_segment *segment; - Elf_Scn *scn; - Elf32_Word nsec; - XElf_Phdr_vardef (phdr); - - /* 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. */ - nphdr = 0; - segment = ld_state.output_segments; - while (segment != NULL) - { - ++nphdr; - segment = segment->next; - } - - /* Add the number of SHT_NOTE sections. We counted them earlier. */ - nphdr += ld_state.nnotesections; - - /* If we create a DSO or the file is linked against DSOs we have three - more entries: INTERP, PHDR, DYNAMIC. */ - if (dynamically_linked_p ()) - nphdr += 3; - - /* Create the program header structure. */ - if (xelf_newphdr (ld_state.outelf, nphdr) == 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) == -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. */ - nsec = 0; - scn = elf_getscn (ld_state.outelf, ld_state.allsections[nsec]->scnidx); - xelf_getshdr (scn, shdr); - assert (shdr != NULL); - - /* The address we start with is the offset of the first (not - zeroth) section. */ - addr = shdr->sh_offset; - - /* The index of the first loadable segment. */ - nphdr = 1 + (dynamically_linked_p () == true) * 2; - - segment = ld_state.output_segments; - while (segment != NULL) - { - struct output_rule *orule; - bool first_section = true; - XElf_Off nobits_size = 0; - XElf_Off memsize = 0; - - /* the minimum alignment is a page size. */ - segment->align = ld_state.pagesize; - - for (orule = segment->output_rules; orule != NULL; - orule = orule->next) - if (orule->tag == output_section) - { - XElf_Off oldoff; - - /* See whether this output rule corresponds to the next - section. Yes, this is a pointer comparison. */ - if (ld_state.allsections[nsec]->name - != orule->val.section.name) - /* No, ignore this output rule. */ - continue; - - /* We assign addresses only in segments which are actually - loaded. */ - if (segment->mode != 0) - { - /* Adjust the offset of the input sections. */ - struct scninfo *isect; - struct scninfo *first; - - isect = first = ld_state.allsections[nsec]->last; - if (isect != NULL) - do - isect->offset += addr; - while ((isect = isect->next) != first); - - /* Set the address of current section. */ - shdr->sh_addr = addr; - - /* Write the result back. */ - (void) xelf_update_shdr (scn, shdr); - - /* Remember the address. */ - ld_state.allsections[nsec]->addr = addr; - } - - if (first_section) - { - /* The first segment starts at offset zero. */ - if (segment == ld_state.output_segments) - { - segment->offset = 0; - segment->addr = addr - shdr->sh_offset; - } - else - { - segment->offset = shdr->sh_offset; - segment->addr = addr; - } - - /* Determine the maximum alignment requirement. */ - segment->align = MAX (segment->align, shdr->sh_addralign); - - first_section = false; - } - - memsize = shdr->sh_offset - segment->offset + shdr->sh_size; - if (nobits_size != 0 && shdr->sh_type != SHT_NOTE) - error (EXIT_FAILURE, 0, gettext ("\ -internal error: nobits section follows nobits section")); - if (shdr->sh_type == SHT_NOBITS) - nobits_size += 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. */ - oldoff = shdr->sh_offset; - - if (++nsec >= ld_state.nallsections) - break; - - scn = elf_getscn (ld_state.outelf, - ld_state.allsections[nsec]->scnidx); - xelf_getshdr (scn, shdr); - assert (shdr != NULL); - - /* This is the new address resulting from the offsets - in the file. */ - assert (oldoff <= shdr->sh_offset); - addr += shdr->sh_offset - oldoff; - } - else - { - assert (orule->tag == output_assignment); - - if (strcmp (orule->val.assignment->variable, ".") == 0) - /* This is a change of the address. */ - addr = eval_expression (orule->val.assignment->expression, - addr); - else if (orule->val.assignment->sym != 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 = dblindirect[orule->val.assignment->sym->outsymidx]; - xelf_getsym (symdata, idx, sym); - sym->st_value = addr; - (void) xelf_update_sym (symdata, idx, sym); - - idx = orule->val.assignment->sym->outdynsymidx; - if (idx != 0) - { - assert (dynsymdata != NULL); - xelf_getsym (dynsymdata, idx, sym); - sym->st_value = addr; - (void) xelf_update_sym (dynsymdata, idx, sym); - } - } - } - - /* Store the segment parameter for loadable segments. */ - if (segment->mode != 0) - { - xelf_getphdr_ptr (ld_state.outelf, nphdr, phdr); - - phdr->p_type = PT_LOAD; - phdr->p_offset = segment->offset; - phdr->p_vaddr = segment->addr; - phdr->p_paddr = phdr->p_vaddr; - phdr->p_filesz = memsize - nobits_size; - phdr->p_memsz = memsize; - phdr->p_flags = segment->mode; - phdr->p_align = segment->align; - - (void) xelf_update_phdr (ld_state.outelf, nphdr, phdr); - ++nphdr; - } - - segment = segment->next; - } - - /* Create the other program header entries. */ - xelf_getehdr (ld_state.outelf, ehdr); - assert (ehdr != NULL); - - xelf_getphdr_ptr (ld_state.outelf, 1, phdr); - phdr->p_type = PT_PHDR; - phdr->p_offset = ehdr->e_phoff; - phdr->p_vaddr = ld_state.output_segments->addr + phdr->p_offset; - phdr->p_paddr = phdr->p_vaddr; - phdr->p_filesz = ehdr->e_phnum * ehdr->e_phentsize; - phdr->p_memsz = phdr->p_filesz; - phdr->p_flags = 0; /* No need to set PF_R or so. */ - phdr->p_align = xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1); - (void) xelf_update_phdr (ld_state.outelf, 0, phdr); - - - /* Adjust the addresses in the addresses of the symbol according - to the load addresses of the sections. */ - if (ld_state.need_symtab) - for (cnt = 1; cnt < nsym; ++cnt) - { - XElf_Sym_vardef (sym); - Elf32_Word shndx; - - xelf_getsymshndx (symdata, xndxdata, cnt, sym, shndx); - assert (sym != NULL); - - if (sym->st_shndx != SHN_XINDEX) - shndx = 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 += 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 = 1; cnt < nsym_dyn; ++cnt) - { - XElf_Sym_vardef (sym); - - xelf_getsym (dynsymdata, cnt, sym); - assert (sym != 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 += 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 = NULL; - while ((se = ld_symbol_tab_iterate (&ld_state.symbol_tab, &p)) != NULL) - if (! se->in_dso) - { - XElf_Sym_vardef (sym); - - addr = 0; - - if (se->outdynsymidx != 0) - { - xelf_getsym (dynsymdata, se->outdynsymidx, sym); - assert (sym != NULL); - addr = sym->st_value; - } - else if (se->outsymidx != 0) - { - assert (dblindirect[se->outsymidx] != 0); - xelf_getsym (symdata, dblindirect[se->outsymidx], sym); - assert (sym != NULL); - addr = sym->st_value; - } - else - abort (); - - se->merge.value = 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 != 0) - { - assert (ld_state.dynsymscnidx != 0); - scn = elf_getscn (ld_state.outelf, ld_state.reldynscnidx); - xelf_getshdr (scn, shdr); - assert (shdr != NULL); - - shdr->sh_link = ld_state.dynsymscnidx; - - (void) xelf_update_shdr (scn, shdr); - } - - /* Fill in the dynamic segment/section. */ - if (dynamically_linked_p ()) - { - Elf_Scn *outscn; - - assert (ld_state.interpscnidx != 0); - xelf_getshdr (elf_getscn (ld_state.outelf, ld_state.interpscnidx), - shdr); - assert (shdr != NULL); - - /* The interpreter string. */ - // XXX Do we need to support files (DSOs) without interpreters? - xelf_getphdr_ptr (ld_state.outelf, 1, phdr); - phdr->p_type = PT_INTERP; - phdr->p_offset = shdr->sh_offset; - phdr->p_vaddr = shdr->sh_addr; - phdr->p_paddr = phdr->p_vaddr; - phdr->p_filesz = shdr->sh_size; - phdr->p_memsz = phdr->p_filesz; - phdr->p_flags = 0; /* No need to set PF_R or so. */ - phdr->p_align = 1; /* It's a string. */ - - (void) xelf_update_phdr (ld_state.outelf, 1, phdr); - - /* The pointer to the dynamic section. We this we need to - get the information for the dynamic section first. */ - assert (ld_state.dynamicscnidx); - outscn = elf_getscn (ld_state.outelf, ld_state.dynamicscnidx); - xelf_getshdr (outscn, shdr); - assert (shdr != NULL); - - xelf_getphdr_ptr (ld_state.outelf, 2, phdr); - phdr->p_type = PT_DYNAMIC; - phdr->p_offset = shdr->sh_offset; - phdr->p_vaddr = shdr->sh_addr; - phdr->p_paddr = phdr->p_vaddr; - phdr->p_filesz = shdr->sh_size; - phdr->p_memsz = phdr->p_filesz; - phdr->p_flags = 0; /* No need to set PF_R or so. */ - phdr->p_align = shdr->sh_addralign; - - (void) xelf_update_phdr (ld_state.outelf, 2, phdr); - - /* Fill in the reference to the .dynstr section. */ - assert (ld_state.dynstrscnidx != 0); - shdr->sh_link = ld_state.dynstrscnidx; - (void) xelf_update_shdr (outscn, shdr); - - /* And fill the remaining entries. */ - Elf_Data *dyndata = elf_getdata (outscn, NULL); - assert (dyndata != NULL); - - /* Add the DT_NEEDED entries. */ - if (ld_state.ndsofiles > 0) - { - struct usedfiles *runp = ld_state.dsofiles->next; - - do - if (! ld_state.ignore_unused_dsos || runp->used) - { - /* 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 = runp->next) != ld_state.dsofiles->next); - } - - /* We can finish the DT_RUNPATH/DT_RPATH entries now. */ - if (ld_state.rxxpath_strent != 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 != 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 != NULL); - - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, - DT_INIT, sym->st_value); - } - if (ld_state.fini_symbol != 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 != 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 != NULL); - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_HASH, - shdr->sh_addr); - - /* Reference to the symbol table section. */ - assert (ld_state.dynsymscnidx != 0); - xelf_getshdr (elf_getscn (ld_state.outelf, ld_state.dynsymscnidx), - shdr); - assert (shdr != 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 != 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) - { - xelf_getshdr (elf_getscn (ld_state.outelf, ld_state.gotscnidx), - shdr); - assert (shdr != 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 != 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 = REL_TYPE (statep); - xelf_getshdr (elf_getscn (ld_state.outelf, - ld_state.reldynscnidx), shdr); - assert (shdr != 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 == 1); - assert (DT_RELSZ - DT_REL == 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 == 2); - assert (DT_RELENT - DT_REL == 2); - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, - rel + 2, - rel == DT_REL - ? xelf_fsize (ld_state.outelf, ELF_T_REL, 1) - : xelf_fsize (ld_state.outelf, ELF_T_RELA, - 1)); - } - - if (ld_state.verneedscnidx != 0) - { - xelf_getshdr (elf_getscn (ld_state.outelf, - ld_state.verneedscnidx), shdr); - assert (shdr != 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 != 0) - { - xelf_getshdr (elf_getscn (ld_state.outelf, - ld_state.versymscnidx), shdr); - assert (shdr != 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 != 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 != 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 != 0) - new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, - DT_FEATURE_1, ld_state.dt_feature_1); - - assert (ld_state.ndynamic_filled <= 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 != NULL) - { - assert (ld_state.file_type == relocatable_file_type); - Elf_Scn *outscn; - - outscn = elf_getscn (ld_state.outelf, rellist->scnidx); - xelf_getshdr (outscn, shdr); - /* This must not fail since we did it before. */ - assert (shdr != NULL); - - /* Remember the symbol table which belongs to the relocation section. */ - shdr->sh_link = 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 = - 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 = rellist->next; - } - - if (ld_state.rellist != NULL) - { - assert (ld_state.file_type != 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 != NULL); - - /* Set the section header string table index. */ - if (likely (shstrtab_ndx < SHN_HIRESERVE) - && likely (shstrtab_ndx != SHN_XINDEX)) - ehdr->e_shstrndx = shstrtab_ndx; - else - { - /* We have to put the section index in the sh_link field of the - zeroth section header. */ - Elf_Scn *scn = elf_getscn (ld_state.outelf, 0); - - xelf_getshdr (scn, shdr); - if (unlikely (shdr == NULL)) - error (EXIT_FAILURE, 0, - gettext ("cannot get header of 0th section: %s"), - elf_errmsg (-1)); - - shdr->sh_link = shstrtab_ndx; - - (void) xelf_update_shdr (scn, shdr); - - ehdr->e_shstrndx = SHN_XINDEX; - } - - if (ld_state.file_type != relocatable_file_type) - /* DSOs and executables have to define the entry point symbol. */ - ehdr->e_entry = find_entry_point (); - - if (unlikely (xelf_update_ehdr (ld_state.outelf, ehdr) == 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 the what belongs to them. */ - FINALIZE_PLT (statep, nsym, nsym_dyn); - - 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) == -1) - error (EXIT_FAILURE, 0, gettext ("while writing output file: %s"), - elf_errmsg (-1)); - - /* Free the resources. */ - if (elf_end (ld_state.outelf) != 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) != 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) != 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) != 0 - || new_st.st_ino != temp_st.st_ino - || new_st.st_dev != 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 = NULL; - - return 0; -} - - -static bool -ld_generic_special_section_number_p (struct ld_state *statep, size_t number) -{ - /* 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_NULL && type < SHT_NUM) - /* XXX Enable the following two when implemented. */ - // || type == SHT_GNU_LIBLIST - // || type == SHT_CHECKSUM - /* XXX Eventually include SHT_SUNW_move, SHT_SUNW_COMDAT, and - SHT_SUNW_syminfo. */ - || (type >= SHT_GNU_verdef && type <= 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' implementation"), - "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' implementation"), - "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' implementation"), - "initialize_got"); -} - - -static void -ld_generic_finalize_plt (struct ld_state *statep, size_t nsym, size_t nsym_dyn) -{ - /* 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' implementation"), - "rel_type"); - /* Just to keep the compiler calm. */ - return 0; -} - - -static void -ld_generic_count_relocations (struct ld_state *statep, struct scninfo *scninfo) -{ - /* 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' implementation"), - "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' implementation"), - "create_relocations"); -} diff --git a/src/ldlex.c b/src/ldlex.c deleted file mode 100644 index e0bf0a5f..00000000 --- a/src/ldlex.c +++ /dev/null @@ -1,2663 +0,0 @@ -#define yy_create_buffer ld_create_buffer -#define yy_delete_buffer ld_delete_buffer -#define yy_scan_buffer ld_scan_buffer -#define yy_scan_string ld_scan_string -#define yy_scan_bytes ld_scan_bytes -#define yy_flex_debug ld_flex_debug -#define yy_init_buffer ld_init_buffer -#define yy_flush_buffer ld_flush_buffer -#define yy_load_buffer_state ld_load_buffer_state -#define yy_switch_to_buffer ld_switch_to_buffer -#define yyin ldin -#define yyleng ldleng -#define yylex ldlex -#define yyout ldout -#define yyrestart ldrestart -#define yytext ldtext -#define yylineno ldlineno - -#line 20 "ldlex.c" -/* A lexical scanner generated by flex */ - -/* Scanner skeleton version: - * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $ - */ - -#define FLEX_SCANNER -#define YY_FLEX_MAJOR_VERSION 2 -#define YY_FLEX_MINOR_VERSION 5 - -#include <stdio.h> -#include <unistd.h> - - -/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ -#ifdef c_plusplus -#ifndef __cplusplus -#define __cplusplus -#endif -#endif - - -#ifdef __cplusplus - -#include <stdlib.h> - -/* Use prototypes in function declarations. */ -#define YY_USE_PROTOS - -/* The "const" storage-class-modifier is valid. */ -#define YY_USE_CONST - -#else /* ! __cplusplus */ - -#if __STDC__ - -#define YY_USE_PROTOS -#define YY_USE_CONST - -#endif /* __STDC__ */ -#endif /* ! __cplusplus */ - -#ifdef __TURBOC__ - #pragma warn -rch - #pragma warn -use -#include <io.h> -#include <stdlib.h> -#define YY_USE_CONST -#define YY_USE_PROTOS -#endif - -#ifdef YY_USE_CONST -#define yyconst const -#else -#define yyconst -#endif - - -#ifdef YY_USE_PROTOS -#define YY_PROTO(proto) proto -#else -#define YY_PROTO(proto) () -#endif - -/* Returned upon end-of-file. */ -#define YY_NULL 0 - -/* Promotes a possibly negative, possibly signed char to an unsigned - * integer for use as an array index. If the signed char is negative, - * we want to instead treat it as an 8-bit unsigned char, hence the - * double cast. - */ -#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) - -/* Enter a start condition. This macro really ought to take a parameter, - * but we do it the disgusting crufty way forced on us by the ()-less - * definition of BEGIN. - */ -#define BEGIN yy_start = 1 + 2 * - -/* Translate the current start state into a value that can be later handed - * to BEGIN to return to the state. The YYSTATE alias is for lex - * compatibility. - */ -#define YY_START ((yy_start - 1) / 2) -#define YYSTATE YY_START - -/* Action number for EOF rule of a given start state. */ -#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) - -/* Special action meaning "start processing a new file". */ -#define YY_NEW_FILE yyrestart( yyin ) - -#define YY_END_OF_BUFFER_CHAR 0 - -/* Size of default input buffer. */ -#define YY_BUF_SIZE 16384 - -typedef struct yy_buffer_state *YY_BUFFER_STATE; - -extern int yyleng; -extern FILE *yyin, *yyout; - -#define EOB_ACT_CONTINUE_SCAN 0 -#define EOB_ACT_END_OF_FILE 1 -#define EOB_ACT_LAST_MATCH 2 - -/* The funky do-while in the following #define is used to turn the definition - * int a single C statement (which needs a semi-colon terminator). This - * avoids problems with code like: - * - * if ( condition_holds ) - * yyless( 5 ); - * else - * do_something_else(); - * - * Prior to using the do-while the compiler would get upset at the - * "else" because it interpreted the "if" statement as being all - * done when it reached the ';' after the yyless() call. - */ - -/* Return all but the first 'n' matched characters back to the input stream. */ - -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - *yy_cp = yy_hold_char; \ - YY_RESTORE_YY_MORE_OFFSET \ - yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ - YY_DO_BEFORE_ACTION; /* set up yytext again */ \ - } \ - while ( 0 ) - -#define unput(c) yyunput( c, yytext_ptr ) - -/* The following is because we cannot portably get our hands on size_t - * (without autoconf's help, which isn't available because we want - * flex-generated scanners to compile on their own). - */ -typedef unsigned int yy_size_t; - - -struct yy_buffer_state - { - FILE *yy_input_file; - - char *yy_ch_buf; /* input buffer */ - char *yy_buf_pos; /* current position in input buffer */ - - /* Size of input buffer in bytes, not including room for EOB - * characters. - */ - yy_size_t yy_buf_size; - - /* Number of characters read into yy_ch_buf, not including EOB - * characters. - */ - int yy_n_chars; - - /* Whether we "own" the buffer - i.e., we know we created it, - * and can realloc() it to grow it, and should free() it to - * delete it. - */ - int yy_is_our_buffer; - - /* Whether this is an "interactive" input source; if so, and - * if we're using stdio for input, then we want to use getc() - * instead of fread(), to make sure we stop fetching input after - * each newline. - */ - int yy_is_interactive; - - /* Whether we're considered to be at the beginning of a line. - * If so, '^' rules will be active on the next match, otherwise - * not. - */ - int yy_at_bol; - - /* Whether to try to fill the input buffer when we reach the - * end of it. - */ - int yy_fill_buffer; - - int yy_buffer_status; -#define YY_BUFFER_NEW 0 -#define YY_BUFFER_NORMAL 1 - /* When an EOF's been seen but there's still some text to process - * then we mark the buffer as YY_EOF_PENDING, to indicate that we - * shouldn't try reading from the input source any more. We might - * still have a bunch of tokens to match, though, because of - * possible backing-up. - * - * When we actually see the EOF, we change the status to "new" - * (via yyrestart()), so that the user can continue scanning by - * just pointing yyin at a new input file. - */ -#define YY_BUFFER_EOF_PENDING 2 - }; - -static YY_BUFFER_STATE yy_current_buffer = 0; - -/* We provide macros for accessing buffer states in case in the - * future we want to put the buffer states in a more general - * "scanner state". - */ -#define YY_CURRENT_BUFFER yy_current_buffer - - -/* yy_hold_char holds the character lost when yytext is formed. */ -static char yy_hold_char; - -static int yy_n_chars; /* number of characters read into yy_ch_buf */ - - -int yyleng; - -/* Points to current character in buffer. */ -static char *yy_c_buf_p = (char *) 0; -static int yy_init = 1; /* whether we need to initialize */ -static int yy_start = 0; /* start state number */ - -/* Flag which is used to allow yywrap()'s to do buffer switches - * instead of setting up a fresh yyin. A bit of a hack ... - */ -static int yy_did_buffer_switch_on_eof; - -void yyrestart YY_PROTO(( FILE *input_file )); - -void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); -void yy_load_buffer_state YY_PROTO(( void )); -YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); -void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); -void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); -void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); -#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) - -YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); -YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); -YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); - -static void *yy_flex_alloc YY_PROTO(( yy_size_t )); -static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )); -static void yy_flex_free YY_PROTO(( void * )); - -#define yy_new_buffer yy_create_buffer - -#define yy_set_interactive(is_interactive) \ - { \ - if ( ! yy_current_buffer ) \ - yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ - yy_current_buffer->yy_is_interactive = is_interactive; \ - } - -#define yy_set_bol(at_bol) \ - { \ - if ( ! yy_current_buffer ) \ - yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ - yy_current_buffer->yy_at_bol = at_bol; \ - } - -#define YY_AT_BOL() (yy_current_buffer->yy_at_bol) - - -#define YY_USES_REJECT - -#define yywrap() 1 -#define YY_SKIP_YYWRAP -typedef unsigned char YY_CHAR; -FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; -typedef int yy_state_type; -extern int yylineno; -int yylineno = 1; -extern char *yytext; -#define yytext_ptr yytext - -static yy_state_type yy_get_previous_state YY_PROTO(( void )); -static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); -static int yy_get_next_buffer YY_PROTO(( void )); -static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); - -/* Done after the current pattern has been matched and before the - * corresponding action - sets up yytext. - */ -#define YY_DO_BEFORE_ACTION \ - yytext_ptr = yy_bp; \ - yyleng = (int) (yy_cp - yy_bp); \ - yy_hold_char = *yy_cp; \ - *yy_cp = '\0'; \ - yy_c_buf_p = yy_cp; - -#define YY_NUM_RULES 49 -#define YY_END_OF_BUFFER 50 -static yyconst short int yy_acclist[373] = - { 0, - 50, 48, 49, 47, 48, 49, 47, 49, 40, 48, - 49, 41, 48, 49, 31, 48, 49, 32, 48, 49, - 38, 45, 48, 49, 36, 48, 49, 43, 48, 49, - 37, 48, 49, 45, 48, 49, 39, 48, 49, 44, - 45, 48, 49, 44, 45, 48, 49, 33, 48, 49, - 34, 48, 49, 35, 48, 49, 45, 48, 49, 45, - 48, 49, 45, 48, 49, 45, 48, 49, 45, 48, - 49, 45, 48, 49, 45, 48, 49, 45, 48, 49, - 45, 48, 49, 45, 48, 49, 48, 49, 48, 49, - 45, 48, 49, 45, 48, 49, 29, 48, 49, 42, - - 48, 49, 30, 48, 49, 48, 49, 9, 49, 9, - 49, 47, 45, 46, 45, 46, 10, 46, 44, 45, - 46, 44, 45, 46, 44, 45, 46, 45, 46, 44, - 45, 46, 45, 46, 45, 46, 45, 46, 45, 46, - 45, 46, 45, 46, 45, 46, 45, 46, 45, 46, - 45, 46, 45, 46, 45, 46, 45, 46, 28, 45, - 46, 45, 46, 44, 45, 46, 45, 46, 45, 46, - 45, 46, 45, 46, 45, 46, 45, 46, 45, 46, - 45, 46, 45, 46, 45, 46, 45, 46, 45, 46, - 45, 46, 45, 46, 45, 46, 45, 46, 45, 46, - - 44, 45, 46, 45, 46, 45, 46, 45, 46, 45, - 46, 45, 46, 45, 46, 18, 45, 46, 45, 46, - 45, 46, 45, 46, 45, 46, 45, 46, 45, 46, - 26, 45, 46, 45, 46, 45, 46, 45, 46, 11, - 45, 46, 12, 45, 46, 45, 46, 15, 45, 46, - 16, 45, 46, 45, 46, 45, 46, 45, 46, 45, - 46, 45, 46, 45, 46, 45, 46, 45, 46, 45, - 46, 45, 46, 45, 46, 17, 45, 46, 45, 46, - 45, 46, 45, 46, 45, 46, 45, 46, 45, 46, - 45, 46, 45, 46, 19, 2, 6, 45, 46, 45, - - 46, 45, 46, 22, 45, 46, 45, 46, 24, 45, - 46, 45, 46, 27, 45, 46, 14, 4, 1, 8, - 5, 45, 46, 45, 46, 21, 45, 46, 45, 46, - 45, 46, 45, 46, 45, 46, 45, 46, 45, 46, - 3, 7, 45, 46, 45, 46, 23, 45, 46, 45, - 46, 45, 46, 45, 46, 45, 46, 13, 45, 46, - 45, 46, 45, 46, 20, 45, 46, 45, 46, 25, - 45, 46 - } ; - -static yyconst short int yy_accept[212] = - { 0, - 1, 1, 1, 1, 1, 2, 4, 7, 9, 12, - 15, 18, 21, 25, 28, 31, 34, 37, 40, 44, - 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, - 78, 81, 84, 87, 89, 91, 94, 97, 100, 103, - 106, 108, 110, 112, 113, 114, 115, 117, 119, 122, - 125, 128, 130, 133, 135, 137, 139, 141, 143, 145, - 147, 149, 151, 153, 155, 157, 159, 159, 160, 162, - 164, 164, 164, 164, 164, 167, 169, 171, 173, 175, - 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, - 197, 197, 199, 201, 201, 201, 201, 201, 201, 201, - - 204, 206, 208, 210, 212, 214, 216, 219, 221, 223, - 225, 227, 229, 231, 234, 236, 236, 238, 240, 240, - 240, 240, 240, 240, 240, 240, 240, 243, 246, 248, - 251, 254, 256, 258, 260, 262, 264, 266, 268, 270, - 272, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 276, 279, 281, 283, 285, 287, 289, 291, 293, 295, - 296, 296, 297, 297, 297, 297, 298, 298, 298, 300, - 302, 304, 307, 309, 312, 314, 317, 318, 318, 319, - 320, 320, 321, 322, 324, 326, 329, 331, 333, 333, - 333, 335, 337, 339, 341, 342, 343, 345, 347, 350, - - 352, 354, 356, 358, 361, 363, 365, 368, 370, 373, - 373 - } ; - -static yyconst int yy_ec[256] = - { 0, - 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, - 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 2, 1, 1, 4, 1, 5, 6, 1, 7, - 8, 9, 10, 11, 12, 13, 14, 15, 16, 16, - 16, 16, 16, 16, 16, 17, 17, 18, 19, 1, - 20, 1, 21, 1, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 13, 31, 32, 33, 34, 35, 36, - 13, 37, 38, 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 1, 49, 1, 50, 51, 52, 53, - - 54, 55, 56, 13, 57, 13, 58, 59, 58, 60, - 61, 13, 13, 13, 62, 13, 13, 13, 13, 63, - 13, 13, 64, 65, 66, 47, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1 - } ; - -static yyconst int yy_meta[67] = - { 0, - 1, 2, 2, 1, 1, 1, 2, 2, 3, 1, - 1, 1, 3, 1, 3, 3, 3, 2, 2, 1, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 2, 1, 2, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 2, 1, 2 - } ; - -static yyconst short int yy_base[215] = - { 0, - 0, 218, 0, 216, 219, 2141, 65, 67, 2141, 2141, - 2141, 2141, 0, 2141, 2141, 2141, 70, 208, 135, 62, - 2141, 2141, 2141, 0, 70, 127, 158, 171, 192, 211, - 260, 309, 215, 46, 0, 269, 273, 2141, 2141, 2141, - 42, 2141, 43, 70, 0, 0, 330, 0, 48, 322, - 333, 382, 385, 434, 437, 458, 471, 520, 507, 529, - 558, 564, 613, 609, 616, 647, 67, 2141, 666, 670, - 47, 160, 59, 158, 90, 703, 722, 725, 756, 760, - 789, 793, 822, 828, 851, 862, 873, 886, 907, 926, - 89, 945, 964, 65, 159, 158, 67, 157, 153, 985, - - 1004, 1008, 1039, 1042, 1073, 1076, 1107, 1111, 1130, 1161, - 1165, 1169, 1198, 1205, 1227, 155, 1234, 1256, 144, 143, - 139, 140, 137, 127, 112, 113, 1263, 1285, 1292, 1296, - 1325, 1329, 1336, 1365, 1386, 1389, 1420, 1441, 1444, 1465, - 1494, 106, 151, 83, 79, 77, 154, 61, 59, 1500, - 1503, 1534, 1553, 1556, 1587, 1590, 1609, 1640, 1644, 2141, - 58, 2141, 160, 162, 54, 2141, 169, 174, 1648, 1677, - 1698, 1701, 1722, 1735, 1757, 1766, 2141, 43, 2141, 2141, - 37, 2141, 2141, 1779, 1788, 1801, 1810, 1832, 177, 181, - 1839, 1861, 1868, 1892, 2141, 2141, 1901, 1905, 1936, 1945, - - 1958, 1980, 1989, 2002, 2011, 2024, 2047, 2055, 2068, 2141, - 2131, 76, 2134, 2137 - } ; - -static yyconst short int yy_def[215] = - { 0, - 210, 1, 211, 211, 210, 210, 210, 210, 210, 210, - 210, 210, 212, 210, 210, 210, 213, 214, 213, 19, - 210, 210, 210, 212, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 210, 214, 19, 19, 210, 210, 210, - 210, 210, 210, 210, 212, 214, 19, 214, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 210, 210, 19, 19, - 210, 210, 210, 210, 52, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, - 210, 19, 19, 210, 210, 210, 210, 210, 210, 19, - - 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 210, 19, 19, 210, 210, - 210, 210, 210, 210, 210, 210, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 210, 210, 210, 210, 210, 210, 210, 210, 19, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 210, - 210, 210, 210, 210, 210, 210, 210, 210, 19, 19, - 19, 19, 19, 19, 19, 19, 210, 210, 210, 210, - 210, 210, 210, 19, 19, 19, 19, 19, 210, 210, - 19, 19, 19, 19, 210, 210, 19, 19, 19, 19, - - 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, - 210, 210, 210, 210 - } ; - -static yyconst short int yy_nxt[2208] = - { 0, - 6, 7, 8, 6, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 20, 21, 22, 23, - 24, 25, 17, 17, 17, 26, 17, 27, 17, 28, - 29, 17, 17, 17, 30, 31, 17, 32, 17, 17, - 33, 17, 17, 17, 17, 34, 35, 6, 17, 17, - 17, 17, 17, 17, 17, 36, 17, 17, 37, 17, - 17, 17, 17, 38, 39, 40, 44, 44, 44, 44, - 46, 44, 44, 46, 46, 46, 50, 50, 45, 46, - 46, 46, 67, 46, 47, 47, 47, 67, 67, 46, - 47, 190, 53, 68, 53, 71, 73, 189, 72, 74, - - 47, 54, 47, 91, 47, 94, 95, 181, 91, 91, - 47, 178, 47, 168, 68, 167, 46, 97, 98, 53, - 100, 119, 100, 123, 47, 116, 120, 47, 124, 165, - 116, 116, 47, 164, 46, 46, 68, 163, 46, 46, - 46, 47, 47, 47, 46, 46, 46, 100, 46, 49, - 49, 50, 162, 162, 46, 166, 166, 47, 161, 47, - 55, 179, 179, 180, 180, 51, 149, 51, 148, 56, - 182, 182, 47, 47, 47, 183, 183, 52, 195, 195, - 147, 46, 196, 196, 47, 47, 47, 47, 47, 47, - 47, 146, 51, 145, 57, 144, 143, 52, 142, 46, - - 47, 47, 68, 47, 58, 126, 47, 47, 47, 125, - 122, 121, 99, 47, 96, 47, 48, 59, 210, 43, - 47, 41, 47, 210, 47, 47, 47, 47, 47, 47, - 47, 47, 210, 47, 47, 210, 210, 210, 210, 210, - 66, 47, 210, 47, 210, 47, 210, 47, 210, 47, - 60, 210, 210, 47, 47, 210, 210, 47, 210, 210, - 210, 210, 210, 210, 210, 210, 210, 210, 47, 210, - 210, 210, 47, 47, 47, 47, 47, 47, 210, 210, - 210, 61, 210, 47, 47, 47, 210, 47, 47, 47, - 47, 210, 47, 210, 210, 210, 62, 210, 210, 47, - - 210, 47, 47, 47, 210, 47, 210, 210, 210, 210, - 210, 47, 210, 210, 210, 47, 210, 47, 210, 210, - 210, 210, 47, 47, 47, 47, 47, 69, 210, 210, - 47, 47, 210, 70, 63, 47, 50, 50, 64, 47, - 210, 47, 210, 65, 47, 47, 47, 47, 47, 47, - 210, 47, 53, 210, 53, 210, 210, 210, 210, 210, - 47, 210, 47, 47, 47, 47, 47, 210, 210, 210, - 210, 47, 47, 210, 210, 47, 210, 210, 210, 53, - 210, 210, 210, 210, 47, 210, 210, 47, 210, 210, - 47, 210, 47, 210, 210, 47, 75, 75, 75, 47, - - 47, 47, 210, 75, 75, 75, 75, 75, 75, 210, - 210, 210, 47, 210, 47, 47, 210, 47, 210, 210, - 210, 210, 210, 210, 47, 210, 210, 47, 210, 210, - 210, 75, 75, 75, 75, 75, 75, 210, 210, 47, - 210, 210, 47, 210, 47, 210, 210, 47, 47, 47, - 47, 47, 47, 47, 210, 210, 210, 210, 210, 210, - 210, 210, 210, 76, 47, 210, 47, 47, 210, 47, - 210, 210, 47, 47, 47, 77, 47, 210, 210, 47, - 210, 78, 210, 210, 210, 47, 47, 47, 47, 210, - 47, 47, 210, 210, 47, 210, 47, 210, 210, 47, - - 47, 47, 210, 47, 210, 79, 210, 210, 210, 210, - 210, 210, 210, 47, 210, 47, 210, 210, 210, 210, - 47, 47, 47, 47, 210, 210, 210, 210, 47, 210, - 210, 210, 82, 47, 47, 47, 47, 47, 210, 47, - 210, 210, 210, 47, 47, 47, 210, 210, 210, 47, - 47, 210, 47, 210, 210, 80, 210, 210, 81, 47, - 210, 47, 47, 210, 47, 210, 210, 83, 210, 47, - 210, 47, 47, 47, 47, 210, 210, 47, 47, 47, - 47, 210, 47, 210, 210, 84, 47, 210, 47, 210, - 47, 47, 210, 210, 47, 210, 47, 210, 85, 210, - - 47, 210, 210, 210, 210, 210, 47, 210, 210, 210, - 210, 210, 210, 210, 210, 47, 210, 210, 210, 210, - 47, 47, 210, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 210, 86, 210, 210, 210, 210, 47, - 87, 47, 210, 47, 210, 47, 47, 210, 47, 210, - 210, 47, 89, 88, 210, 47, 210, 210, 47, 210, - 210, 47, 47, 47, 210, 210, 47, 210, 210, 210, - 47, 47, 210, 47, 210, 47, 210, 47, 47, 47, - 47, 47, 47, 90, 47, 47, 47, 210, 210, 47, - 210, 210, 210, 210, 210, 210, 47, 210, 47, 210, - - 47, 210, 47, 210, 47, 210, 210, 210, 47, 47, - 210, 210, 47, 210, 210, 210, 210, 47, 47, 47, - 210, 93, 210, 47, 210, 210, 92, 47, 47, 210, - 101, 210, 47, 47, 210, 47, 47, 47, 47, 47, - 47, 47, 210, 210, 210, 47, 210, 210, 210, 210, - 210, 210, 47, 210, 47, 47, 103, 47, 102, 210, - 47, 210, 210, 210, 47, 47, 210, 47, 210, 210, - 47, 47, 47, 210, 47, 47, 47, 210, 210, 47, - 210, 210, 47, 210, 47, 210, 47, 47, 47, 210, - 47, 210, 47, 210, 210, 104, 210, 210, 47, 105, - - 210, 210, 47, 47, 47, 47, 210, 47, 47, 47, - 210, 210, 210, 47, 106, 210, 210, 47, 47, 47, - 210, 47, 47, 47, 210, 47, 210, 210, 107, 210, - 210, 47, 210, 210, 210, 47, 47, 47, 47, 210, - 210, 210, 47, 47, 47, 210, 47, 210, 210, 210, - 47, 47, 47, 109, 47, 47, 210, 108, 47, 210, - 47, 210, 210, 210, 47, 47, 47, 47, 210, 210, - 47, 210, 210, 210, 210, 210, 47, 47, 47, 47, - 210, 47, 210, 47, 47, 47, 210, 47, 47, 47, - 47, 110, 47, 47, 47, 210, 210, 210, 111, 210, - - 47, 47, 47, 47, 47, 112, 210, 210, 47, 210, - 210, 113, 210, 47, 210, 47, 47, 210, 47, 47, - 210, 47, 47, 47, 47, 210, 210, 210, 47, 210, - 47, 210, 210, 210, 210, 47, 210, 47, 210, 47, - 47, 47, 47, 47, 210, 114, 210, 210, 47, 47, - 210, 210, 210, 210, 210, 210, 47, 210, 47, 47, - 47, 47, 210, 115, 47, 210, 210, 210, 47, 47, - 210, 210, 210, 210, 210, 47, 210, 47, 47, 47, - 47, 210, 210, 47, 210, 210, 210, 47, 47, 210, - 210, 210, 210, 210, 47, 117, 47, 210, 210, 47, - - 47, 47, 47, 210, 210, 210, 47, 47, 210, 210, - 210, 210, 210, 118, 210, 47, 210, 47, 47, 47, - 47, 47, 47, 47, 47, 210, 47, 47, 210, 210, - 210, 210, 210, 210, 47, 210, 47, 127, 47, 210, - 47, 210, 47, 210, 210, 210, 47, 47, 210, 210, - 47, 128, 210, 47, 47, 47, 47, 47, 47, 210, - 210, 47, 210, 210, 210, 47, 47, 210, 210, 47, - 47, 47, 47, 210, 47, 210, 210, 130, 129, 210, - 210, 47, 210, 210, 47, 210, 210, 47, 47, 47, - 47, 47, 47, 210, 210, 210, 47, 210, 210, 47, - - 210, 47, 210, 47, 47, 47, 47, 210, 47, 210, - 210, 131, 132, 210, 210, 47, 210, 210, 47, 210, - 210, 47, 47, 47, 210, 47, 47, 47, 210, 210, - 47, 210, 210, 47, 210, 47, 210, 47, 47, 47, - 210, 47, 210, 47, 47, 47, 47, 210, 210, 47, - 133, 210, 210, 47, 210, 210, 210, 210, 210, 210, - 47, 210, 47, 210, 47, 210, 210, 134, 47, 47, - 210, 210, 47, 47, 210, 47, 47, 47, 210, 47, - 47, 47, 210, 47, 47, 47, 210, 47, 136, 210, - 135, 47, 47, 47, 137, 47, 210, 47, 210, 47, - - 210, 47, 210, 47, 210, 210, 210, 47, 210, 210, - 210, 47, 47, 47, 47, 210, 210, 210, 47, 47, - 47, 47, 47, 47, 210, 210, 47, 47, 47, 210, - 47, 47, 138, 210, 210, 47, 210, 47, 210, 210, - 47, 47, 47, 47, 210, 210, 210, 47, 47, 47, - 47, 210, 210, 210, 210, 47, 139, 47, 210, 47, - 47, 210, 47, 210, 47, 210, 47, 47, 210, 47, - 47, 47, 47, 210, 210, 210, 47, 47, 47, 47, - 210, 210, 210, 140, 47, 210, 47, 210, 47, 47, - 210, 47, 210, 47, 210, 47, 47, 210, 47, 47, - - 47, 47, 210, 210, 210, 47, 47, 47, 47, 210, - 47, 47, 47, 47, 141, 47, 150, 47, 47, 210, - 47, 210, 47, 210, 47, 47, 47, 47, 47, 210, - 210, 210, 210, 210, 47, 210, 210, 210, 47, 47, - 47, 47, 47, 47, 47, 47, 210, 47, 210, 47, - 47, 47, 47, 47, 47, 47, 210, 47, 47, 47, - 210, 47, 210, 210, 151, 210, 47, 47, 47, 210, - 210, 47, 210, 210, 152, 210, 210, 210, 47, 47, - 47, 47, 47, 210, 210, 210, 47, 47, 210, 210, - 210, 47, 210, 47, 153, 47, 210, 47, 47, 210, - - 47, 47, 47, 47, 47, 47, 210, 47, 210, 210, - 154, 210, 210, 210, 210, 210, 47, 155, 47, 47, - 210, 47, 47, 210, 210, 210, 210, 47, 47, 210, - 210, 47, 210, 210, 47, 47, 47, 210, 210, 210, - 210, 210, 210, 47, 210, 210, 47, 210, 47, 210, - 47, 47, 47, 156, 210, 47, 47, 47, 47, 47, - 47, 210, 47, 210, 210, 210, 210, 157, 210, 210, - 210, 47, 210, 47, 47, 210, 47, 47, 158, 47, - 47, 47, 47, 47, 210, 210, 47, 210, 210, 210, - 210, 210, 210, 210, 210, 47, 210, 47, 47, 210, - - 210, 47, 210, 47, 210, 210, 47, 47, 47, 47, - 47, 160, 210, 210, 47, 47, 47, 47, 47, 47, - 210, 210, 47, 159, 47, 169, 47, 47, 210, 210, - 47, 210, 47, 47, 210, 47, 47, 210, 210, 210, - 210, 210, 47, 210, 210, 47, 210, 210, 47, 47, - 47, 47, 210, 210, 210, 210, 47, 47, 210, 210, - 47, 210, 47, 210, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 210, 210, 210, 47, 210, 210, 210, - 210, 172, 170, 47, 210, 47, 47, 210, 47, 210, - 210, 47, 210, 210, 210, 47, 47, 171, 47, 210, - - 210, 47, 47, 47, 47, 47, 47, 210, 210, 210, - 47, 210, 210, 47, 210, 47, 210, 47, 47, 47, - 47, 210, 47, 47, 47, 47, 210, 210, 174, 47, - 210, 210, 47, 210, 210, 173, 210, 210, 210, 47, - 210, 47, 210, 210, 47, 210, 210, 47, 210, 47, - 210, 47, 47, 210, 47, 47, 47, 175, 47, 47, - 47, 177, 47, 47, 47, 210, 47, 210, 210, 210, - 47, 47, 47, 176, 47, 210, 47, 210, 47, 210, - 47, 210, 47, 210, 210, 210, 47, 210, 210, 210, - 47, 47, 47, 47, 210, 210, 184, 47, 210, 210, - - 210, 47, 47, 185, 210, 47, 47, 47, 210, 47, - 47, 210, 47, 47, 47, 47, 47, 47, 210, 47, - 210, 210, 210, 186, 210, 210, 210, 210, 47, 210, - 47, 47, 210, 47, 47, 210, 47, 47, 47, 47, - 47, 210, 210, 47, 210, 210, 187, 210, 210, 47, - 47, 47, 47, 210, 47, 47, 210, 210, 47, 210, - 47, 210, 210, 47, 47, 47, 210, 47, 210, 210, - 210, 47, 47, 47, 210, 210, 210, 47, 210, 47, - 47, 47, 47, 210, 47, 188, 210, 47, 210, 47, - 210, 210, 47, 47, 47, 47, 47, 47, 47, 47, - - 210, 210, 47, 47, 47, 191, 210, 210, 47, 47, - 210, 47, 210, 210, 47, 47, 47, 47, 47, 47, - 47, 47, 192, 47, 47, 47, 47, 210, 47, 210, - 47, 47, 210, 47, 210, 210, 47, 210, 210, 193, - 47, 47, 47, 47, 210, 47, 47, 47, 47, 210, - 47, 210, 47, 47, 47, 47, 210, 194, 47, 210, - 210, 210, 47, 47, 47, 210, 210, 47, 197, 47, - 210, 47, 47, 210, 47, 47, 47, 47, 210, 210, - 210, 47, 47, 47, 47, 210, 210, 210, 210, 47, - 210, 47, 210, 47, 47, 210, 47, 198, 47, 210, - - 47, 47, 210, 47, 199, 210, 47, 47, 47, 210, - 47, 210, 210, 200, 210, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 210, 210, 210, 210, - 47, 47, 201, 47, 47, 47, 210, 202, 210, 210, - 210, 210, 210, 47, 210, 210, 210, 47, 210, 47, - 47, 47, 47, 210, 47, 210, 210, 210, 47, 47, - 47, 47, 47, 47, 210, 210, 47, 47, 47, 203, - 210, 210, 47, 47, 47, 47, 210, 47, 47, 210, - 210, 210, 210, 204, 210, 210, 210, 47, 47, 210, - 47, 210, 210, 47, 47, 47, 47, 210, 47, 210, - - 47, 205, 47, 47, 47, 47, 210, 47, 210, 210, - 47, 210, 47, 210, 206, 47, 47, 47, 47, 47, - 47, 47, 47, 210, 210, 47, 47, 47, 210, 210, - 210, 47, 47, 210, 47, 210, 210, 47, 47, 47, - 47, 47, 47, 47, 47, 210, 47, 210, 210, 207, - 210, 47, 210, 47, 47, 210, 47, 210, 210, 47, - 208, 47, 47, 47, 47, 210, 47, 210, 47, 47, - 47, 47, 210, 47, 210, 210, 210, 47, 210, 47, - 210, 47, 47, 47, 47, 47, 47, 47, 210, 47, - 210, 210, 209, 210, 210, 210, 210, 47, 47, 210, - - 47, 210, 210, 210, 47, 210, 210, 210, 210, 47, - 47, 210, 47, 210, 210, 210, 210, 47, 210, 210, - 210, 210, 210, 210, 210, 47, 210, 210, 210, 210, - 47, 42, 42, 42, 47, 210, 47, 46, 210, 46, - 5, 210, 210, 210, 210, 210, 210, 210, 210, 210, - 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, - 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, - 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, - 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, - 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, - - 210, 210, 210, 210, 210, 210, 210 - } ; - -static yyconst short int yy_chk[2208] = - { 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 7, 7, 8, 8, - 17, 44, 44, 17, 17, 17, 20, 20, 212, 17, - 17, 17, 34, 17, 25, 25, 25, 34, 34, 17, - 49, 181, 20, 34, 20, 41, 43, 178, 41, 43, - - 25, 25, 25, 67, 20, 71, 71, 165, 67, 67, - 49, 161, 25, 149, 67, 148, 17, 73, 73, 20, - 75, 94, 75, 97, 20, 91, 94, 25, 97, 146, - 91, 91, 25, 145, 17, 19, 91, 144, 19, 19, - 19, 26, 26, 26, 19, 19, 19, 75, 19, 19, - 19, 19, 143, 143, 19, 147, 147, 26, 142, 26, - 26, 163, 163, 164, 164, 19, 126, 19, 125, 26, - 167, 167, 27, 27, 27, 168, 168, 19, 189, 189, - 124, 19, 190, 190, 26, 28, 28, 28, 27, 26, - 27, 123, 19, 122, 27, 121, 120, 19, 119, 19, - - 27, 28, 116, 28, 28, 99, 29, 29, 29, 98, - 96, 95, 74, 28, 72, 27, 18, 29, 5, 4, - 27, 2, 29, 0, 29, 30, 30, 30, 28, 33, - 33, 33, 0, 28, 29, 0, 0, 0, 0, 0, - 33, 30, 0, 30, 0, 33, 0, 33, 0, 29, - 30, 0, 0, 30, 29, 0, 0, 33, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, - 0, 0, 33, 30, 31, 31, 31, 33, 0, 0, - 0, 31, 0, 36, 36, 36, 0, 37, 37, 37, - 31, 0, 31, 0, 0, 0, 31, 0, 0, 36, - - 0, 36, 31, 37, 0, 37, 0, 0, 0, 0, - 0, 36, 0, 0, 0, 37, 0, 31, 0, 0, - 0, 0, 31, 32, 32, 32, 36, 36, 0, 0, - 37, 36, 0, 37, 32, 37, 50, 50, 32, 32, - 0, 32, 0, 32, 47, 47, 47, 51, 51, 51, - 0, 32, 50, 0, 50, 0, 0, 0, 0, 0, - 47, 0, 47, 51, 50, 51, 32, 0, 0, 0, - 0, 32, 47, 0, 0, 51, 0, 0, 0, 50, - 0, 0, 0, 0, 50, 0, 0, 47, 0, 0, - 51, 0, 47, 0, 0, 51, 52, 52, 52, 53, - - 53, 53, 0, 52, 52, 52, 52, 52, 52, 0, - 0, 0, 52, 0, 52, 53, 0, 53, 0, 0, - 0, 0, 0, 0, 52, 0, 0, 53, 0, 0, - 0, 52, 52, 52, 52, 52, 52, 0, 0, 52, - 0, 0, 53, 0, 52, 0, 0, 53, 54, 54, - 54, 55, 55, 55, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 54, 54, 0, 54, 55, 0, 55, - 0, 0, 56, 56, 56, 55, 54, 0, 0, 55, - 0, 56, 0, 0, 0, 57, 57, 57, 56, 0, - 56, 54, 0, 0, 55, 0, 54, 0, 0, 55, - - 56, 57, 0, 57, 0, 57, 0, 0, 0, 0, - 0, 0, 0, 57, 0, 56, 0, 0, 0, 0, - 56, 59, 59, 59, 0, 0, 0, 0, 57, 0, - 0, 0, 59, 57, 58, 58, 58, 59, 0, 59, - 0, 0, 0, 60, 60, 60, 0, 0, 0, 59, - 58, 0, 58, 0, 0, 58, 0, 0, 58, 60, - 0, 60, 58, 0, 59, 0, 0, 60, 0, 59, - 0, 60, 61, 61, 61, 0, 0, 58, 62, 62, - 62, 0, 58, 0, 0, 61, 60, 0, 61, 0, - 61, 60, 0, 0, 62, 0, 62, 0, 62, 0, - - 61, 0, 0, 0, 0, 0, 62, 0, 0, 0, - 0, 0, 0, 0, 0, 61, 0, 0, 0, 0, - 61, 62, 0, 64, 64, 64, 62, 63, 63, 63, - 65, 65, 65, 0, 63, 0, 0, 0, 0, 64, - 63, 64, 0, 63, 0, 63, 65, 0, 65, 0, - 0, 64, 65, 64, 0, 63, 0, 0, 65, 0, - 0, 66, 66, 66, 0, 0, 64, 0, 0, 0, - 63, 64, 0, 65, 0, 63, 0, 66, 65, 66, - 69, 69, 69, 66, 70, 70, 70, 0, 0, 66, - 0, 0, 0, 0, 0, 0, 69, 0, 69, 0, - - 70, 0, 70, 0, 66, 0, 0, 0, 69, 66, - 0, 0, 70, 0, 0, 0, 0, 76, 76, 76, - 0, 70, 0, 69, 0, 0, 69, 70, 69, 0, - 76, 0, 70, 76, 0, 76, 77, 77, 77, 78, - 78, 78, 0, 0, 0, 76, 0, 0, 0, 0, - 0, 0, 77, 0, 77, 78, 78, 78, 77, 0, - 76, 0, 0, 0, 77, 76, 0, 78, 0, 0, - 79, 79, 79, 0, 80, 80, 80, 0, 0, 77, - 0, 0, 78, 0, 77, 0, 79, 78, 79, 0, - 80, 0, 80, 0, 0, 79, 0, 0, 79, 80, - - 0, 0, 80, 81, 81, 81, 0, 82, 82, 82, - 0, 0, 0, 79, 81, 0, 0, 80, 79, 81, - 0, 81, 80, 82, 0, 82, 0, 0, 82, 0, - 0, 81, 0, 0, 0, 82, 83, 83, 83, 0, - 0, 0, 84, 84, 84, 0, 81, 0, 0, 0, - 82, 81, 83, 84, 83, 82, 0, 83, 84, 0, - 84, 0, 0, 0, 83, 85, 85, 85, 0, 0, - 84, 0, 0, 0, 0, 0, 86, 86, 86, 83, - 0, 85, 0, 85, 83, 84, 0, 87, 87, 87, - 84, 85, 86, 85, 86, 0, 0, 0, 86, 0, - - 88, 88, 88, 87, 86, 87, 0, 0, 85, 0, - 0, 88, 0, 85, 0, 87, 88, 0, 88, 86, - 0, 89, 89, 89, 86, 0, 0, 0, 88, 0, - 87, 0, 0, 0, 0, 87, 0, 89, 0, 89, - 90, 90, 90, 88, 0, 89, 0, 0, 88, 89, - 0, 0, 0, 0, 0, 0, 90, 0, 90, 92, - 92, 92, 0, 90, 89, 0, 0, 0, 90, 89, - 0, 0, 0, 0, 0, 92, 0, 92, 93, 93, - 93, 0, 0, 90, 0, 0, 0, 92, 90, 0, - 0, 0, 0, 0, 93, 92, 93, 0, 0, 100, - - 100, 100, 92, 0, 0, 0, 93, 92, 0, 0, - 0, 0, 0, 93, 0, 100, 0, 100, 101, 101, - 101, 93, 102, 102, 102, 0, 93, 100, 0, 0, - 0, 0, 0, 0, 101, 0, 101, 101, 102, 0, - 102, 0, 100, 0, 0, 0, 101, 100, 0, 0, - 102, 102, 0, 103, 103, 103, 104, 104, 104, 0, - 0, 101, 0, 0, 0, 102, 101, 0, 0, 103, - 102, 103, 104, 0, 104, 0, 0, 104, 103, 0, - 0, 103, 0, 0, 104, 0, 0, 105, 105, 105, - 106, 106, 106, 0, 0, 0, 103, 0, 0, 104, - - 0, 103, 0, 105, 104, 105, 106, 0, 106, 0, - 0, 105, 106, 0, 0, 105, 0, 0, 106, 0, - 0, 107, 107, 107, 0, 108, 108, 108, 0, 0, - 105, 0, 0, 106, 0, 105, 0, 107, 106, 107, - 0, 108, 0, 108, 109, 109, 109, 0, 0, 107, - 108, 0, 0, 108, 0, 0, 0, 0, 0, 0, - 109, 0, 109, 0, 107, 0, 0, 109, 108, 107, - 0, 0, 109, 108, 0, 110, 110, 110, 0, 111, - 111, 111, 0, 112, 112, 112, 0, 109, 111, 0, - 110, 110, 109, 110, 112, 111, 0, 111, 0, 112, - - 0, 112, 0, 110, 0, 0, 0, 111, 0, 0, - 0, 112, 113, 113, 113, 0, 0, 0, 110, 114, - 114, 114, 111, 110, 0, 0, 112, 111, 113, 0, - 113, 112, 113, 0, 0, 114, 0, 114, 0, 0, - 113, 115, 115, 115, 0, 0, 0, 114, 117, 117, - 117, 0, 0, 0, 0, 113, 115, 115, 0, 115, - 113, 0, 114, 0, 117, 0, 117, 114, 0, 115, - 118, 118, 118, 0, 0, 0, 117, 127, 127, 127, - 0, 0, 0, 117, 115, 0, 118, 0, 118, 115, - 0, 117, 0, 127, 0, 127, 117, 0, 118, 128, - - 128, 128, 0, 0, 0, 127, 129, 129, 129, 0, - 130, 130, 130, 118, 118, 128, 129, 128, 118, 0, - 127, 0, 129, 0, 129, 127, 130, 128, 130, 0, - 0, 0, 0, 0, 129, 0, 0, 0, 130, 131, - 131, 131, 128, 132, 132, 132, 0, 128, 0, 129, - 133, 133, 133, 130, 129, 131, 0, 131, 130, 132, - 0, 132, 0, 0, 132, 0, 133, 131, 133, 0, - 0, 132, 0, 0, 133, 0, 0, 0, 133, 134, - 134, 134, 131, 0, 0, 0, 132, 131, 0, 0, - 0, 132, 0, 133, 134, 134, 0, 134, 133, 0, - - 135, 135, 135, 136, 136, 136, 0, 134, 0, 0, - 135, 0, 0, 0, 0, 0, 135, 136, 135, 136, - 0, 136, 134, 0, 0, 0, 0, 134, 135, 0, - 0, 136, 0, 0, 137, 137, 137, 0, 0, 0, - 0, 0, 0, 135, 0, 0, 136, 0, 135, 0, - 137, 136, 137, 137, 0, 138, 138, 138, 139, 139, - 139, 0, 137, 0, 0, 0, 0, 138, 0, 0, - 0, 138, 0, 138, 139, 0, 139, 137, 139, 140, - 140, 140, 137, 138, 0, 0, 139, 0, 0, 0, - 0, 0, 0, 0, 0, 140, 0, 140, 138, 0, - - 0, 139, 0, 138, 0, 0, 139, 140, 141, 141, - 141, 141, 0, 0, 150, 150, 150, 151, 151, 151, - 0, 0, 140, 140, 141, 150, 141, 140, 0, 0, - 150, 0, 150, 151, 0, 151, 141, 0, 0, 0, - 0, 0, 150, 0, 0, 151, 0, 0, 152, 152, - 152, 141, 0, 0, 0, 0, 141, 150, 0, 0, - 151, 0, 150, 0, 152, 151, 152, 153, 153, 153, - 154, 154, 154, 0, 0, 0, 152, 0, 0, 0, - 0, 154, 152, 153, 0, 153, 154, 0, 154, 0, - 0, 152, 0, 0, 0, 153, 152, 153, 154, 0, - - 0, 155, 155, 155, 156, 156, 156, 0, 0, 0, - 153, 0, 0, 154, 0, 153, 0, 155, 154, 155, - 156, 0, 156, 157, 157, 157, 0, 0, 156, 155, - 0, 0, 156, 0, 0, 155, 0, 0, 0, 157, - 0, 157, 0, 0, 155, 0, 0, 156, 0, 155, - 0, 157, 156, 0, 158, 158, 158, 157, 159, 159, - 159, 159, 169, 169, 169, 0, 157, 0, 0, 0, - 158, 157, 158, 158, 159, 0, 159, 0, 169, 0, - 169, 0, 158, 0, 0, 0, 159, 0, 0, 0, - 169, 170, 170, 170, 0, 0, 169, 158, 0, 0, - - 0, 159, 158, 170, 0, 169, 159, 170, 0, 170, - 169, 0, 171, 171, 171, 172, 172, 172, 0, 170, - 0, 0, 0, 171, 0, 0, 0, 0, 171, 0, - 171, 172, 0, 172, 170, 0, 173, 173, 173, 170, - 171, 0, 0, 172, 0, 0, 173, 0, 0, 174, - 174, 174, 173, 0, 173, 171, 0, 0, 172, 0, - 171, 0, 0, 172, 173, 174, 0, 174, 0, 0, - 0, 175, 175, 175, 0, 0, 0, 174, 0, 173, - 176, 176, 176, 0, 173, 175, 0, 175, 0, 175, - 0, 0, 174, 184, 184, 184, 176, 174, 176, 175, - - 0, 0, 185, 185, 185, 184, 0, 0, 176, 184, - 0, 184, 0, 0, 175, 186, 186, 186, 185, 175, - 185, 184, 185, 176, 187, 187, 187, 0, 176, 0, - 185, 186, 0, 186, 0, 0, 184, 0, 0, 187, - 187, 184, 187, 186, 0, 185, 188, 188, 188, 0, - 185, 0, 187, 191, 191, 191, 0, 188, 186, 0, - 0, 0, 188, 186, 188, 0, 0, 187, 191, 191, - 0, 191, 187, 0, 188, 192, 192, 192, 0, 0, - 0, 191, 193, 193, 193, 0, 0, 0, 0, 188, - 0, 192, 0, 192, 188, 0, 191, 192, 193, 0, - - 193, 191, 0, 192, 193, 0, 194, 194, 194, 0, - 193, 0, 0, 194, 0, 197, 197, 197, 192, 198, - 198, 198, 194, 192, 194, 193, 0, 0, 0, 0, - 193, 197, 197, 197, 194, 198, 0, 198, 0, 0, - 0, 0, 0, 197, 0, 0, 0, 198, 0, 194, - 199, 199, 199, 0, 194, 0, 0, 0, 197, 200, - 200, 200, 198, 197, 0, 0, 199, 198, 199, 200, - 0, 0, 201, 201, 201, 200, 0, 200, 199, 0, - 0, 0, 0, 201, 0, 0, 0, 200, 201, 0, - 201, 0, 0, 199, 202, 202, 202, 0, 199, 0, - - 201, 202, 200, 203, 203, 203, 0, 200, 0, 0, - 202, 0, 202, 0, 203, 201, 204, 204, 204, 203, - 201, 203, 202, 0, 0, 205, 205, 205, 0, 0, - 0, 203, 204, 0, 204, 0, 0, 202, 206, 206, - 206, 205, 202, 205, 204, 0, 203, 0, 0, 205, - 0, 203, 0, 205, 206, 0, 206, 0, 0, 204, - 206, 207, 207, 207, 204, 0, 206, 0, 205, 208, - 208, 208, 0, 205, 0, 0, 0, 207, 0, 207, - 0, 206, 209, 209, 209, 208, 206, 208, 0, 207, - 0, 0, 208, 0, 0, 0, 0, 208, 209, 0, - - 209, 0, 0, 0, 207, 0, 0, 0, 0, 207, - 209, 0, 208, 0, 0, 0, 0, 208, 0, 0, - 0, 0, 0, 0, 0, 209, 0, 0, 0, 0, - 209, 211, 211, 211, 213, 0, 213, 214, 0, 214, - 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, - 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, - 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, - 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, - 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, - 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, - - 210, 210, 210, 210, 210, 210, 210 - } ; - -static yy_state_type yy_state_buf[YY_BUF_SIZE + 2], *yy_state_ptr; -static char *yy_full_match; -static int yy_lp; -#define REJECT \ -{ \ -*yy_cp = yy_hold_char; /* undo effects of setting up yytext */ \ -yy_cp = yy_full_match; /* restore poss. backed-over text */ \ -++yy_lp; \ -goto find_rule; \ -} -#define yymore() yymore_used_but_not_detected -#define YY_MORE_ADJ 0 -#define YY_RESTORE_YY_MORE_OFFSET -char *yytext; -#line 1 "/home/drepper/gnu/elfutils/src/ldlex.l" -#define INITIAL 0 -#line 2 "/home/drepper/gnu/elfutils/src/ldlex.l" -/* Copyright (C) 2001, 2002, 2003, 2004 Red Hat, Inc. - Written by Ulrich Drepper <drepper@redhat.com>, 2001. - - This program is Open Source software; you can redistribute it and/or - modify it under the terms of the Open Software License version 1.0 as - published by the Open Source Initiative. - - You should have received a copy of the Open Software License along - with this program; if not, you may obtain a copy of the Open Software - License version 1.0 from http://www.opensource.org/licenses/osl.php or - by writing the Open Source Initiative c/o Lawrence Rosen, Esq., - 3001 King Ranch Road, Ukiah, CA 95482. */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <assert.h> -#include <ctype.h> -#include <elf.h> -#include <error.h> -#include <inttypes.h> -#include <libintl.h> -#include <stdbool.h> -#include <stdio.h> -#include <string.h> - -#include <system.h> -#include <ld.h> -#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) - -/* 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); -#define YY_NEVER_INTERACTIVE 1 -#define IGNORE 1 - -#line 1061 "ldlex.c" - -/* Macros after this point can all be overridden by user definitions in - * section 1. - */ - -#ifndef YY_SKIP_YYWRAP -#ifdef __cplusplus -extern "C" int yywrap YY_PROTO(( void )); -#else -extern int yywrap YY_PROTO(( void )); -#endif -#endif - -#ifndef YY_NO_UNPUT -static void yyunput YY_PROTO(( int c, char *buf_ptr )); -#endif - -#ifndef yytext_ptr -static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); -#endif - -#ifdef YY_NEED_STRLEN -static int yy_flex_strlen YY_PROTO(( yyconst char * )); -#endif - -#ifndef YY_NO_INPUT -#ifdef __cplusplus -static int yyinput YY_PROTO(( void )); -#else -static int input YY_PROTO(( void )); -#endif -#endif - -#if YY_STACK_USED -static int yy_start_stack_ptr = 0; -static int yy_start_stack_depth = 0; -static int *yy_start_stack = 0; -#ifndef YY_NO_PUSH_STATE -static void yy_push_state YY_PROTO(( int new_state )); -#endif -#ifndef YY_NO_POP_STATE -static void yy_pop_state YY_PROTO(( void )); -#endif -#ifndef YY_NO_TOP_STATE -static int yy_top_state YY_PROTO(( void )); -#endif - -#else -#define YY_NO_PUSH_STATE 1 -#define YY_NO_POP_STATE 1 -#define YY_NO_TOP_STATE 1 -#endif - -#ifdef YY_MALLOC_DECL -YY_MALLOC_DECL -#else -#if __STDC__ -#ifndef __cplusplus -#include <stdlib.h> -#endif -#else -/* Just try to get by without declaring the routines. This will fail - * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) - * or sizeof(void*) != sizeof(int). - */ -#endif -#endif - -/* Amount of stuff to slurp up with each read. */ -#ifndef YY_READ_BUF_SIZE -#define YY_READ_BUF_SIZE 8192 -#endif - -/* Copy whatever the last rule matched to the standard output. */ - -#ifndef ECHO -/* This used to be an fputs(), but since the string might contain NUL's, - * we now use fwrite(). - */ -#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) -#endif - -/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, - * is returned in "result". - */ -#ifndef YY_INPUT -#define YY_INPUT(buf,result,max_size) \ - if ( yy_current_buffer->yy_is_interactive ) \ - { \ - int c = '*', n; \ - for ( n = 0; n < max_size && \ - (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ - buf[n] = (char) c; \ - if ( c == '\n' ) \ - buf[n++] = (char) c; \ - if ( c == EOF && ferror( yyin ) ) \ - YY_FATAL_ERROR( "input in flex scanner failed" ); \ - result = n; \ - } \ - else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ - && ferror( yyin ) ) \ - YY_FATAL_ERROR( "input in flex scanner failed" ); -#endif - -/* No semi-colon after return; correct usage is to write "yyterminate();" - - * we don't want an extra ';' after the "return" because that will cause - * some compilers to complain about unreachable statements. - */ -#ifndef yyterminate -#define yyterminate() return YY_NULL -#endif - -/* Number of entries by which start-condition stack grows. */ -#ifndef YY_START_STACK_INCR -#define YY_START_STACK_INCR 25 -#endif - -/* Report a fatal error. */ -#ifndef YY_FATAL_ERROR -#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) -#endif - -/* Default declaration of generated scanner - a define so the user can - * easily add parameters. - */ -#ifndef YY_DECL -#define YY_DECL int yylex YY_PROTO(( void )) -#endif - -/* Code executed at the beginning of each rule, after yytext and yyleng - * have been set up. - */ -#ifndef YY_USER_ACTION -#define YY_USER_ACTION -#endif - -/* Code executed at the end of each rule. */ -#ifndef YY_BREAK -#define YY_BREAK break; -#endif - -#define YY_RULE_SETUP \ - if ( yyleng > 0 ) \ - yy_current_buffer->yy_at_bol = \ - (yytext[yyleng - 1] == '\n'); \ - YY_USER_ACTION - -YY_DECL - { - register yy_state_type yy_current_state; - register char *yy_cp = NULL, *yy_bp = NULL; - register int yy_act; - -#line 79 "/home/drepper/gnu/elfutils/src/ldlex.l" - - if (unlikely (ld_scan_version_script)) - { - ld_scan_version_script = -1; - return kVERSION_SCRIPT; - } - -#line 1223 "ldlex.c" - - if ( yy_init ) - { - yy_init = 0; - -#ifdef YY_USER_INIT - YY_USER_INIT; -#endif - - if ( ! yy_start ) - yy_start = 1; /* first start state */ - - if ( ! yyin ) - yyin = stdin; - - if ( ! yyout ) - yyout = stdout; - - if ( ! yy_current_buffer ) - yy_current_buffer = - yy_create_buffer( yyin, YY_BUF_SIZE ); - - yy_load_buffer_state(); - } - - while ( 1 ) /* loops until end-of-file is reached */ - { - yy_cp = yy_c_buf_p; - - /* Support of yytext. */ - *yy_cp = yy_hold_char; - - /* yy_bp points to the position in yy_ch_buf of the start of - * the current run. - */ - yy_bp = yy_cp; - - yy_current_state = yy_start; - yy_current_state += YY_AT_BOL(); - yy_state_ptr = yy_state_buf; - *yy_state_ptr++ = yy_current_state; -yy_match: - do - { - register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 211 ) - yy_c = yy_meta[(unsigned int) yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - *yy_state_ptr++ = yy_current_state; - ++yy_cp; - } - while ( yy_base[yy_current_state] != 2141 ); - -yy_find_action: - yy_current_state = *--yy_state_ptr; - yy_lp = yy_accept[yy_current_state]; -find_rule: /* we branch to this label when backing up */ - for ( ; ; ) /* until we find what rule we matched */ - { - if ( yy_lp && yy_lp < yy_accept[yy_current_state + 1] ) - { - yy_act = yy_acclist[yy_lp]; - { - yy_full_match = yy_cp; - break; - } - } - --yy_cp; - yy_current_state = *--yy_state_ptr; - yy_lp = yy_accept[yy_current_state]; - } - - YY_DO_BEFORE_ACTION; - - if ( yy_act != YY_END_OF_BUFFER ) - { - int yyl; - for ( yyl = 0; yyl < yyleng; ++yyl ) - if ( yytext[yyl] == '\n' ) - ++yylineno; - } - -do_action: /* This label is used only to access EOF actions. */ - - - switch ( yy_act ) - { /* beginning of action switch */ -case 1: -*yy_cp = yy_hold_char; /* undo effects of setting up yytext */ -yy_c_buf_p = yy_cp = yy_bp + 6; -YY_DO_BEFORE_ACTION; /* set up yytext again */ -YY_RULE_SETUP -#line 86 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ BEGIN (handle_ifdef ()); } - YY_BREAK -case 2: -*yy_cp = yy_hold_char; /* undo effects of setting up yytext */ -yy_c_buf_p = yy_cp = yy_bp + 5; -YY_DO_BEFORE_ACTION; /* set up yytext again */ -YY_RULE_SETUP -#line 87 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ eat_to_eol (true); - push_state (skip_to_endif); - BEGIN (IGNORE); } - YY_BREAK -case 3: -*yy_cp = yy_hold_char; /* undo effects of setting up yytext */ -yy_c_buf_p = yy_cp = yy_bp + 8; -YY_DO_BEFORE_ACTION; /* set up yytext again */ -YY_RULE_SETUP -#line 90 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ eat_to_eol (false); - push_state (skip_to_endif); - BEGIN (IGNORE); } - YY_BREAK -case 4: -*yy_cp = yy_hold_char; /* undo effects of setting up yytext */ -yy_c_buf_p = yy_cp = yy_bp + 6; -YY_DO_BEFORE_ACTION; /* set up yytext again */ -YY_RULE_SETUP -#line 93 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ eat_to_eol (true) ; } - YY_BREAK -case 5: -*yy_cp = yy_hold_char; /* undo effects of setting up yytext */ -yy_c_buf_p = yy_cp = yy_bp + 6; -YY_DO_BEFORE_ACTION; /* set up yytext again */ -YY_RULE_SETUP -#line 95 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ eat_to_eol (false); - push_state (skip_to_endif); } - YY_BREAK -case 6: -*yy_cp = yy_hold_char; /* undo effects of setting up yytext */ -yy_c_buf_p = yy_cp = yy_bp + 5; -YY_DO_BEFORE_ACTION; /* set up yytext again */ -YY_RULE_SETUP -#line 97 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ eat_to_eol (true); - assert (prepdepth > 0); - if (prepstate[prepdepth - 1] == skip_if) - { - /* Back to normal processing. */ - assert (prepdepth == 1); - BEGIN (pop_state ()); - } - } - YY_BREAK -case 7: -*yy_cp = yy_hold_char; /* undo effects of setting up yytext */ -yy_c_buf_p = yy_cp = yy_bp + 8; -YY_DO_BEFORE_ACTION; /* set up yytext again */ -YY_RULE_SETUP -#line 106 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ assert (prepdepth > 0); - if (prepstate[prepdepth - 1] == skip_if) - { - /* Maybe this symbol is defined. */ - pop_state (); - BEGIN (handle_ifdef ()); - } - } - YY_BREAK -case 8: -*yy_cp = yy_hold_char; /* undo effects of setting up yytext */ -yy_c_buf_p = yy_cp = yy_bp + 6; -YY_DO_BEFORE_ACTION; /* set up yytext again */ -YY_RULE_SETUP -#line 114 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ eat_to_eol (true); - BEGIN (pop_state ()); } - YY_BREAK -case 9: -YY_RULE_SETUP -#line 116 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ /* nothing */ } - YY_BREAK -case 10: -YY_RULE_SETUP -#line 119 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ eat_comment (); } - YY_BREAK -case 11: -YY_RULE_SETUP -#line 121 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return kALIGN; } - YY_BREAK -case 12: -YY_RULE_SETUP -#line 122 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return kENTRY; } - YY_BREAK -case 13: -YY_RULE_SETUP -#line 123 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return kEXCLUDE_FILE; } - YY_BREAK -case 14: -YY_RULE_SETUP -#line 124 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return kGLOBAL; } - YY_BREAK -case 15: -YY_RULE_SETUP -#line 125 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return kGROUP; } - YY_BREAK -case 16: -YY_RULE_SETUP -#line 126 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return kINPUT; } - YY_BREAK -case 17: -YY_RULE_SETUP -#line 127 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return kINTERP; } - YY_BREAK -case 18: -YY_RULE_SETUP -#line 128 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return kKEEP; } - YY_BREAK -case 19: -YY_RULE_SETUP -#line 129 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return kLOCAL; } - YY_BREAK -case 20: -YY_RULE_SETUP -#line 130 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return kOUTPUT_FORMAT; } - YY_BREAK -case 21: -YY_RULE_SETUP -#line 131 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return kPAGESIZE; } - YY_BREAK -case 22: -YY_RULE_SETUP -#line 132 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return kPROVIDE; } - YY_BREAK -case 23: -YY_RULE_SETUP -#line 133 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return kSEARCH_DIR; } - YY_BREAK -case 24: -YY_RULE_SETUP -#line 134 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return kSEGMENT; } - YY_BREAK -case 25: -YY_RULE_SETUP -#line 135 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return kSIZEOF_HEADERS; } - YY_BREAK -case 26: -YY_RULE_SETUP -#line 136 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return kSORT; } - YY_BREAK -case 27: -YY_RULE_SETUP -#line 137 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return kVERSION; } - YY_BREAK -case 28: -YY_RULE_SETUP -#line 139 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ int cnt = 1 ; - ldlval.num = 0; - while (cnt < yyleng - 1) - ldlval.num |= attrib_convert (yytext[cnt++]); - return kMODE; } - YY_BREAK -case 29: -YY_RULE_SETUP -#line 145 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return '{'; } - YY_BREAK -case 30: -YY_RULE_SETUP -#line 146 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return '}'; } - YY_BREAK -case 31: -YY_RULE_SETUP -#line 147 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return '('; } - YY_BREAK -case 32: -YY_RULE_SETUP -#line 148 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return ')'; } - YY_BREAK -case 33: -YY_RULE_SETUP -#line 149 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return ':'; } - YY_BREAK -case 34: -YY_RULE_SETUP -#line 150 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return ';'; } - YY_BREAK -case 35: -YY_RULE_SETUP -#line 151 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return '='; } - YY_BREAK -case 36: -YY_RULE_SETUP -#line 152 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ ldlval.op = exp_plus; return kADD_OP; } - YY_BREAK -case 37: -YY_RULE_SETUP -#line 153 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ ldlval.op = exp_minus; return kADD_OP; } - YY_BREAK -case 38: -YY_RULE_SETUP -#line 154 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return '*'; } - YY_BREAK -case 39: -YY_RULE_SETUP -#line 155 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ ldlval.op = exp_div; return kMUL_OP; } - YY_BREAK -case 40: -YY_RULE_SETUP -#line 156 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ ldlval.op = exp_mod; return kMUL_OP; } - YY_BREAK -case 41: -YY_RULE_SETUP -#line 157 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return '&'; } - YY_BREAK -case 42: -YY_RULE_SETUP -#line 158 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return '|'; } - YY_BREAK -case 43: -YY_RULE_SETUP -#line 160 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ return ','; } - YY_BREAK -case 44: -YY_RULE_SETUP -#line 162 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ char *endp; - ldlval.num = strtoumax (yytext, &endp, 0); - if (*endp != '\0') - { - if (tolower (*endp) == 'k') - ldlval.num *= 1024; - else - { - assert (tolower (*endp) == 'm'); - ldlval.num *= 1024 * 1024; - } - } - return kNUM; } - YY_BREAK -case 45: -YY_RULE_SETUP -#line 176 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ ldlval.str = obstack_strndup (&ld_state.smem, - yytext, yyleng); - return kID; } - YY_BREAK -case 46: -YY_RULE_SETUP -#line 180 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ ldlval.str = obstack_strndup (&ld_state.smem, - yytext, yyleng); - return kFILENAME; } - YY_BREAK -case 47: -YY_RULE_SETUP -#line 184 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ /* IGNORE */ } - YY_BREAK -case 48: -YY_RULE_SETUP -#line 186 "/home/drepper/gnu/elfutils/src/ldlex.l" -{ invalid_char (*yytext); } - YY_BREAK -case 49: -YY_RULE_SETUP -#line 188 "/home/drepper/gnu/elfutils/src/ldlex.l" -ECHO; - YY_BREAK -#line 1625 "ldlex.c" - case YY_STATE_EOF(INITIAL): - case YY_STATE_EOF(IGNORE): - yyterminate(); - - case YY_END_OF_BUFFER: - { - /* Amount of text matched not including the EOB char. */ - int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; - - /* Undo the effects of YY_DO_BEFORE_ACTION. */ - *yy_cp = yy_hold_char; - YY_RESTORE_YY_MORE_OFFSET - - if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) - { - /* We're scanning a new file or input source. It's - * possible that this happened because the user - * just pointed yyin at a new source and called - * yylex(). If so, then we have to assure - * consistency between yy_current_buffer and our - * globals. Here is the right place to do so, because - * this is the first action (other than possibly a - * back-up) that will match for the new input source. - */ - yy_n_chars = yy_current_buffer->yy_n_chars; - yy_current_buffer->yy_input_file = yyin; - yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; - } - - /* Note that here we test for yy_c_buf_p "<=" to the position - * of the first EOB in the buffer, since yy_c_buf_p will - * already have been incremented past the NUL character - * (since all states make transitions on EOB to the - * end-of-buffer state). Contrast this with the test - * in input(). - */ - if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) - { /* This was really a NUL. */ - yy_state_type yy_next_state; - - yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; - - yy_current_state = yy_get_previous_state(); - - /* Okay, we're now positioned to make the NUL - * transition. We couldn't have - * yy_get_previous_state() go ahead and do it - * for us because it doesn't know how to deal - * with the possibility of jamming (and we don't - * want to build jamming into it because then it - * will run more slowly). - */ - - yy_next_state = yy_try_NUL_trans( yy_current_state ); - - yy_bp = yytext_ptr + YY_MORE_ADJ; - - if ( yy_next_state ) - { - /* Consume the NUL. */ - yy_cp = ++yy_c_buf_p; - yy_current_state = yy_next_state; - goto yy_match; - } - - else - { - yy_cp = yy_c_buf_p; - goto yy_find_action; - } - } - - else switch ( yy_get_next_buffer() ) - { - case EOB_ACT_END_OF_FILE: - { - yy_did_buffer_switch_on_eof = 0; - - if ( yywrap() ) - { - /* Note: because we've taken care in - * yy_get_next_buffer() to have set up - * yytext, we can now set up - * yy_c_buf_p so that if some total - * hoser (like flex itself) wants to - * call the scanner after we return the - * YY_NULL, it'll still work - another - * YY_NULL will get returned. - */ - yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; - - yy_act = YY_STATE_EOF(YY_START); - goto do_action; - } - - else - { - if ( ! yy_did_buffer_switch_on_eof ) - YY_NEW_FILE; - } - break; - } - - case EOB_ACT_CONTINUE_SCAN: - yy_c_buf_p = - yytext_ptr + yy_amount_of_matched_text; - - yy_current_state = yy_get_previous_state(); - - yy_cp = yy_c_buf_p; - yy_bp = yytext_ptr + YY_MORE_ADJ; - goto yy_match; - - case EOB_ACT_LAST_MATCH: - yy_c_buf_p = - &yy_current_buffer->yy_ch_buf[yy_n_chars]; - - yy_current_state = yy_get_previous_state(); - - yy_cp = yy_c_buf_p; - yy_bp = yytext_ptr + YY_MORE_ADJ; - goto yy_find_action; - } - break; - } - - default: - YY_FATAL_ERROR( - "fatal flex scanner internal error--no action found" ); - } /* end of action switch */ - } /* end of scanning one token */ - } /* end of yylex */ - - -/* yy_get_next_buffer - try to read in a new buffer - * - * Returns a code representing an action: - * EOB_ACT_LAST_MATCH - - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position - * EOB_ACT_END_OF_FILE - end of file - */ - -static int yy_get_next_buffer() - { - register char *dest = yy_current_buffer->yy_ch_buf; - register char *source = yytext_ptr; - register int number_to_move, i; - int ret_val; - - if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) - YY_FATAL_ERROR( - "fatal flex scanner internal error--end of buffer missed" ); - - if ( yy_current_buffer->yy_fill_buffer == 0 ) - { /* Don't try to fill the buffer, so this is an EOF. */ - if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) - { - /* We matched a single character, the EOB, so - * treat this as a final EOF. - */ - return EOB_ACT_END_OF_FILE; - } - - else - { - /* We matched some text prior to the EOB, first - * process it. - */ - return EOB_ACT_LAST_MATCH; - } - } - - /* Try to read more data. */ - - /* First move last chars to start of buffer. */ - number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; - - for ( i = 0; i < number_to_move; ++i ) - *(dest++) = *(source++); - - if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) - /* don't do the read, it's not guaranteed to return an EOF, - * just force an EOF - */ - yy_current_buffer->yy_n_chars = yy_n_chars = 0; - - else - { - int num_to_read = - yy_current_buffer->yy_buf_size - number_to_move - 1; - - while ( num_to_read <= 0 ) - { /* Not enough room in the buffer - grow it. */ -#ifdef YY_USES_REJECT - YY_FATAL_ERROR( -"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); -#else - - /* just a shorter name for the current buffer */ - YY_BUFFER_STATE b = yy_current_buffer; - - int yy_c_buf_p_offset = - (int) (yy_c_buf_p - b->yy_ch_buf); - - if ( b->yy_is_our_buffer ) - { - int new_size = b->yy_buf_size * 2; - - if ( new_size <= 0 ) - b->yy_buf_size += b->yy_buf_size / 8; - else - b->yy_buf_size *= 2; - - b->yy_ch_buf = (char *) - /* Include room in for 2 EOB chars. */ - yy_flex_realloc( (void *) b->yy_ch_buf, - b->yy_buf_size + 2 ); - } - else - /* Can't grow it, we don't own it. */ - b->yy_ch_buf = 0; - - if ( ! b->yy_ch_buf ) - YY_FATAL_ERROR( - "fatal error - scanner input buffer overflow" ); - - yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; - - num_to_read = yy_current_buffer->yy_buf_size - - number_to_move - 1; -#endif - } - - if ( num_to_read > YY_READ_BUF_SIZE ) - num_to_read = YY_READ_BUF_SIZE; - - /* Read in more data. */ - YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), - yy_n_chars, num_to_read ); - - yy_current_buffer->yy_n_chars = yy_n_chars; - } - - if ( yy_n_chars == 0 ) - { - if ( number_to_move == YY_MORE_ADJ ) - { - ret_val = EOB_ACT_END_OF_FILE; - yyrestart( yyin ); - } - - else - { - ret_val = EOB_ACT_LAST_MATCH; - yy_current_buffer->yy_buffer_status = - YY_BUFFER_EOF_PENDING; - } - } - - else - ret_val = EOB_ACT_CONTINUE_SCAN; - - yy_n_chars += number_to_move; - yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; - yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; - - yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; - - return ret_val; - } - - -/* yy_get_previous_state - get the state just before the EOB char was reached */ - -static yy_state_type yy_get_previous_state() - { - register yy_state_type yy_current_state; - register char *yy_cp; - - yy_current_state = yy_start; - yy_current_state += YY_AT_BOL(); - yy_state_ptr = yy_state_buf; - *yy_state_ptr++ = yy_current_state; - - for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) - { - register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 211 ) - yy_c = yy_meta[(unsigned int) yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - *yy_state_ptr++ = yy_current_state; - } - - return yy_current_state; - } - - -/* yy_try_NUL_trans - try to make a transition on the NUL character - * - * synopsis - * next_state = yy_try_NUL_trans( current_state ); - */ - -#ifdef YY_USE_PROTOS -static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state ) -#else -static yy_state_type yy_try_NUL_trans( yy_current_state ) -yy_state_type yy_current_state; -#endif - { - register int yy_is_jam; - - register YY_CHAR yy_c = 1; - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 211 ) - yy_c = yy_meta[(unsigned int) yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 210); - if ( ! yy_is_jam ) - *yy_state_ptr++ = yy_current_state; - - return yy_is_jam ? 0 : yy_current_state; - } - - -#ifndef YY_NO_UNPUT -#ifdef YY_USE_PROTOS -static void yyunput( int c, register char *yy_bp ) -#else -static void yyunput( c, yy_bp ) -int c; -register char *yy_bp; -#endif - { - register char *yy_cp = yy_c_buf_p; - - /* undo effects of setting up yytext */ - *yy_cp = yy_hold_char; - - if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) - { /* need to shift things up to make room */ - /* +2 for EOB chars. */ - register int number_to_move = yy_n_chars + 2; - register char *dest = &yy_current_buffer->yy_ch_buf[ - yy_current_buffer->yy_buf_size + 2]; - register char *source = - &yy_current_buffer->yy_ch_buf[number_to_move]; - - while ( source > yy_current_buffer->yy_ch_buf ) - *--dest = *--source; - - yy_cp += (int) (dest - source); - yy_bp += (int) (dest - source); - yy_current_buffer->yy_n_chars = - yy_n_chars = yy_current_buffer->yy_buf_size; - - if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) - YY_FATAL_ERROR( "flex scanner push-back overflow" ); - } - - *--yy_cp = (char) c; - - if ( c == '\n' ) - --yylineno; - - yytext_ptr = yy_bp; - yy_hold_char = *yy_cp; - yy_c_buf_p = yy_cp; - } -#endif /* ifndef YY_NO_UNPUT */ - - -#ifndef YY_NO_INPUT -#ifdef __cplusplus -static int yyinput() -#else -static int input() -#endif - { - int c; - - *yy_c_buf_p = yy_hold_char; - - if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) - { - /* yy_c_buf_p now points to the character we want to return. - * If this occurs *before* the EOB characters, then it's a - * valid NUL; if not, then we've hit the end of the buffer. - */ - if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) - /* This was really a NUL. */ - *yy_c_buf_p = '\0'; - - else - { /* need more input */ - int offset = yy_c_buf_p - yytext_ptr; - ++yy_c_buf_p; - - switch ( yy_get_next_buffer() ) - { - case EOB_ACT_LAST_MATCH: - /* This happens because yy_g_n_b() - * sees that we've accumulated a - * token and flags that we need to - * try matching the token before - * proceeding. But for input(), - * there's no matching to consider. - * So convert the EOB_ACT_LAST_MATCH - * to EOB_ACT_END_OF_FILE. - */ - - /* Reset buffer status. */ - yyrestart( yyin ); - - /* fall through */ - - case EOB_ACT_END_OF_FILE: - { - if ( yywrap() ) - return EOF; - - if ( ! yy_did_buffer_switch_on_eof ) - YY_NEW_FILE; -#ifdef __cplusplus - return yyinput(); -#else - return input(); -#endif - } - - case EOB_ACT_CONTINUE_SCAN: - yy_c_buf_p = yytext_ptr + offset; - break; - } - } - } - - c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ - *yy_c_buf_p = '\0'; /* preserve yytext */ - yy_hold_char = *++yy_c_buf_p; - - yy_current_buffer->yy_at_bol = (c == '\n'); - if ( yy_current_buffer->yy_at_bol ) - ++yylineno; - - return c; - } -#endif /* YY_NO_INPUT */ - -#ifdef YY_USE_PROTOS -void yyrestart( FILE *input_file ) -#else -void yyrestart( input_file ) -FILE *input_file; -#endif - { - if ( ! yy_current_buffer ) - yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); - - yy_init_buffer( yy_current_buffer, input_file ); - yy_load_buffer_state(); - } - - -#ifdef YY_USE_PROTOS -void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) -#else -void yy_switch_to_buffer( new_buffer ) -YY_BUFFER_STATE new_buffer; -#endif - { - if ( yy_current_buffer == new_buffer ) - return; - - if ( yy_current_buffer ) - { - /* Flush out information for old buffer. */ - *yy_c_buf_p = yy_hold_char; - yy_current_buffer->yy_buf_pos = yy_c_buf_p; - yy_current_buffer->yy_n_chars = yy_n_chars; - } - - yy_current_buffer = new_buffer; - yy_load_buffer_state(); - - /* We don't actually know whether we did this switch during - * EOF (yywrap()) processing, but the only time this flag - * is looked at is after yywrap() is called, so it's safe - * to go ahead and always set it. - */ - yy_did_buffer_switch_on_eof = 1; - } - - -#ifdef YY_USE_PROTOS -void yy_load_buffer_state( void ) -#else -void yy_load_buffer_state() -#endif - { - yy_n_chars = yy_current_buffer->yy_n_chars; - yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; - yyin = yy_current_buffer->yy_input_file; - yy_hold_char = *yy_c_buf_p; - } - - -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) -#else -YY_BUFFER_STATE yy_create_buffer( file, size ) -FILE *file; -int size; -#endif - { - YY_BUFFER_STATE b; - - b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); - if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); - - b->yy_buf_size = size; - - /* yy_ch_buf has to be 2 characters longer than the size given because - * we need to put in 2 end-of-buffer characters. - */ - b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); - if ( ! b->yy_ch_buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); - - b->yy_is_our_buffer = 1; - - yy_init_buffer( b, file ); - - return b; - } - - -#ifdef YY_USE_PROTOS -void yy_delete_buffer( YY_BUFFER_STATE b ) -#else -void yy_delete_buffer( b ) -YY_BUFFER_STATE b; -#endif - { - if ( ! b ) - return; - - if ( b == yy_current_buffer ) - yy_current_buffer = (YY_BUFFER_STATE) 0; - - if ( b->yy_is_our_buffer ) - yy_flex_free( (void *) b->yy_ch_buf ); - - yy_flex_free( (void *) b ); - } - - - -#ifdef YY_USE_PROTOS -void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) -#else -void yy_init_buffer( b, file ) -YY_BUFFER_STATE b; -FILE *file; -#endif - - - { - yy_flush_buffer( b ); - - b->yy_input_file = file; - b->yy_fill_buffer = 1; - -#if YY_ALWAYS_INTERACTIVE - b->yy_is_interactive = 1; -#else -#if YY_NEVER_INTERACTIVE - b->yy_is_interactive = 0; -#else - b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; -#endif -#endif - } - - -#ifdef YY_USE_PROTOS -void yy_flush_buffer( YY_BUFFER_STATE b ) -#else -void yy_flush_buffer( b ) -YY_BUFFER_STATE b; -#endif - - { - if ( ! b ) - return; - - b->yy_n_chars = 0; - - /* We always need two end-of-buffer characters. The first causes - * a transition to the end-of-buffer state. The second causes - * a jam in that state. - */ - b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; - b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; - - b->yy_buf_pos = &b->yy_ch_buf[0]; - - b->yy_at_bol = 1; - b->yy_buffer_status = YY_BUFFER_NEW; - - if ( b == yy_current_buffer ) - yy_load_buffer_state(); - } - - -#ifndef YY_NO_SCAN_BUFFER -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) -#else -YY_BUFFER_STATE yy_scan_buffer( base, size ) -char *base; -yy_size_t size; -#endif - { - YY_BUFFER_STATE b; - - if ( size < 2 || - base[size-2] != YY_END_OF_BUFFER_CHAR || - base[size-1] != YY_END_OF_BUFFER_CHAR ) - /* They forgot to leave room for the EOB's. */ - return 0; - - b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); - if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); - - b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ - b->yy_buf_pos = b->yy_ch_buf = base; - b->yy_is_our_buffer = 0; - b->yy_input_file = 0; - b->yy_n_chars = b->yy_buf_size; - b->yy_is_interactive = 0; - b->yy_at_bol = 1; - b->yy_fill_buffer = 0; - b->yy_buffer_status = YY_BUFFER_NEW; - - yy_switch_to_buffer( b ); - - return b; - } -#endif - - -#ifndef YY_NO_SCAN_STRING -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) -#else -YY_BUFFER_STATE yy_scan_string( yy_str ) -yyconst char *yy_str; -#endif - { - int len; - for ( len = 0; yy_str[len]; ++len ) - ; - - return yy_scan_bytes( yy_str, len ); - } -#endif - - -#ifndef YY_NO_SCAN_BYTES -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) -#else -YY_BUFFER_STATE yy_scan_bytes( bytes, len ) -yyconst char *bytes; -int len; -#endif - { - YY_BUFFER_STATE b; - char *buf; - yy_size_t n; - int i; - - /* Get memory for full buffer, including space for trailing EOB's. */ - n = len + 2; - buf = (char *) yy_flex_alloc( n ); - if ( ! buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); - - for ( i = 0; i < len; ++i ) - buf[i] = bytes[i]; - - buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; - - b = yy_scan_buffer( buf, n ); - if ( ! b ) - YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); - - /* It's okay to grow etc. this buffer, and we should throw it - * away when we're done. - */ - b->yy_is_our_buffer = 1; - - return b; - } -#endif - - -#ifndef YY_NO_PUSH_STATE -#ifdef YY_USE_PROTOS -static void yy_push_state( int new_state ) -#else -static void yy_push_state( new_state ) -int new_state; -#endif - { - if ( yy_start_stack_ptr >= yy_start_stack_depth ) - { - yy_size_t new_size; - - yy_start_stack_depth += YY_START_STACK_INCR; - new_size = yy_start_stack_depth * sizeof( int ); - - if ( ! yy_start_stack ) - yy_start_stack = (int *) yy_flex_alloc( new_size ); - - else - yy_start_stack = (int *) yy_flex_realloc( - (void *) yy_start_stack, new_size ); - - if ( ! yy_start_stack ) - YY_FATAL_ERROR( - "out of memory expanding start-condition stack" ); - } - - yy_start_stack[yy_start_stack_ptr++] = YY_START; - - BEGIN(new_state); - } -#endif - - -#ifndef YY_NO_POP_STATE -static void yy_pop_state() - { - if ( --yy_start_stack_ptr < 0 ) - YY_FATAL_ERROR( "start-condition stack underflow" ); - - BEGIN(yy_start_stack[yy_start_stack_ptr]); - } -#endif - - -#ifndef YY_NO_TOP_STATE -static int yy_top_state() - { - return yy_start_stack[yy_start_stack_ptr - 1]; - } -#endif - -#ifndef YY_EXIT_FAILURE -#define YY_EXIT_FAILURE 2 -#endif - -#ifdef YY_USE_PROTOS -static void yy_fatal_error( yyconst char msg[] ) -#else -static void yy_fatal_error( msg ) -char msg[]; -#endif - { - (void) fprintf( stderr, "%s\n", msg ); - exit( YY_EXIT_FAILURE ); - } - - - -/* Redefine yyless() so it works in section 3 code. */ - -#undef yyless -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - yytext[yyleng] = yy_hold_char; \ - yy_c_buf_p = yytext + n; \ - yy_hold_char = *yy_c_buf_p; \ - *yy_c_buf_p = '\0'; \ - yyleng = n; \ - } \ - while ( 0 ) - - -/* Internal utility routines. */ - -#ifndef yytext_ptr -#ifdef YY_USE_PROTOS -static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) -#else -static void yy_flex_strncpy( s1, s2, n ) -char *s1; -yyconst char *s2; -int n; -#endif - { - register int i; - for ( i = 0; i < n; ++i ) - s1[i] = s2[i]; - } -#endif - -#ifdef YY_NEED_STRLEN -#ifdef YY_USE_PROTOS -static int yy_flex_strlen( yyconst char *s ) -#else -static int yy_flex_strlen( s ) -yyconst char *s; -#endif - { - register int n; - for ( n = 0; s[n]; ++n ) - ; - - return n; - } -#endif - - -#ifdef YY_USE_PROTOS -static void *yy_flex_alloc( yy_size_t size ) -#else -static void *yy_flex_alloc( size ) -yy_size_t size; -#endif - { - return (void *) malloc( size ); - } - -#ifdef YY_USE_PROTOS -static void *yy_flex_realloc( void *ptr, yy_size_t size ) -#else -static void *yy_flex_realloc( ptr, size ) -void *ptr; -yy_size_t size; -#endif - { - /* The cast to (char *) in the following accommodates both - * implementations that use char* generic pointers, and those - * that use void* generic pointers. It works with the latter - * because both ANSI C and C++ allow castless assignment from - * any pointer type to void*, and deal with argument conversions - * as though doing an assignment. - */ - return (void *) realloc( (char *) ptr, size ); - } - -#ifdef YY_USE_PROTOS -static void yy_flex_free( void *ptr ) -#else -static void yy_flex_free( ptr ) -void *ptr; -#endif - { - free( ptr ); - } - -#if YY_MAIN -int main() - { - yylex(); - return 0; - } -#endif -#line 188 "/home/drepper/gnu/elfutils/src/ldlex.l" - - -static void -eat_comment (void) -{ - while (1) - { - int c = input (); - - while (c != '*' && c != EOF) - c = input (); - - if (c == '*') - { - c = input (); - while (c == '*') - c = input (); - if (c == '/') - break; - } - - if (c == 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 = false; - - while (1) - { - int c = input (); - - if (c == EOF) - break; - if (c == '\n') - { - ++yylineno; - break; - } - - if (empty && ! isspace (c) && ! warned) - { - error (0, 0, gettext ("%d: garbage at end of line"), yylineno); - warned = true; - } - } -} - - -static int -attrib_convert (int c) -{ - if (c == 'X') - return PF_X; - if (c == 'W') - return PF_W; - assert (c == 'R'); - return PF_R; -} - - -static void -push_state (enum prepstate state) -{ - if (prepdepth >= MAX_PREPDEPTH) - error (EXIT_FAILURE, 0, gettext ("%d: conditionals nested too deep"), - yylineno); - - prepstate[prepdepth++] = state; -} - - -static int -pop_state (void) -{ - if (prepdepth == 0) - error (0, 0, gettext ("%d: unexpected #endif"), yylineno); - else - --prepdepth; - - return prepdepth == 0 ? INITIAL : IGNORE; -} - - -static int -handle_ifdef (void) -{ - char idbuf[50]; - char *id = idbuf; - size_t idlen = 0; - size_t idmax = sizeof (idbuf); - bool ignore_ws = true; - bool defined = false; - int result; - - while (1) - { - int c = input (); - - if (isspace (c) && ignore_ws) - continue; - - if (c != '_' && (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') - && (idlen == 0 || c < '0' || c > '9')) - { - unput (c); - break; - } - - if (idlen == idmax) - { - char *newp = (char *) alloca (idmax *= 2); - id = memcpy (newp, id, idlen); - } - - id[idlen++] = c; - ignore_ws = false; - } - - /* XXX Compare in a better way. */ - if (idlen == 6 && strncmp (id, "SHARED", 6) == 0) - defined = ld_state.file_type == dso_file_type; - - if (defined) - result = INITIAL; - else - { - push_state (skip_if); - result = 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/ldlex.l b/src/ldlex.l deleted file mode 100644 index 06ea6237..00000000 --- a/src/ldlex.l +++ /dev/null @@ -1,343 +0,0 @@ -%{ -/* Copyright (C) 2001, 2002, 2003, 2004 Red Hat, Inc. - Written by Ulrich Drepper <drepper@redhat.com>, 2001. - - This program is Open Source software; you can redistribute it and/or - modify it under the terms of the Open Software License version 1.0 as - published by the Open Source Initiative. - - You should have received a copy of the Open Software License along - with this program; if not, you may obtain a copy of the Open Software - License version 1.0 from http://www.opensource.org/licenses/osl.php or - by writing the Open Source Initiative c/o Lawrence Rosen, Esq., - 3001 King Ranch Road, Ukiah, CA 95482. */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <assert.h> -#include <ctype.h> -#include <elf.h> -#include <error.h> -#include <inttypes.h> -#include <libintl.h> -#include <stdbool.h> -#include <stdio.h> -#include <string.h> - -#include <system.h> -#include <ld.h> -#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) - -/* 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_.*?]+ -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 = -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) ; } - -<IGNORE>^"#"ifdef/[[:space:]\n] { eat_to_eol (false); - push_state (skip_to_endif); } -<IGNORE>^"#"else/[[:space:]\n] { eat_to_eol (true); - assert (prepdepth > 0); - if (prepstate[prepdepth - 1] == skip_if) - { - /* Back to normal processing. */ - assert (prepdepth == 1); - BEGIN (pop_state ()); - } - } -<IGNORE>^"#"elifdef/[[:space:]] { assert (prepdepth > 0); - if (prepstate[prepdepth - 1] == skip_if) - { - /* Maybe this symbol is defined. */ - pop_state (); - BEGIN (handle_ifdef ()); - } - } -<IGNORE>^"#"endif/[[:space:]\n] { eat_to_eol (true); - BEGIN (pop_state ()); } -<IGNORE>.|\n { /* nothing */ } - - -"/*" { eat_comment (); } - -ALIGN { return kALIGN; } -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}"]" { int cnt = 1 ; - ldlval.num = 0; - while (cnt < yyleng - 1) - ldlval.num |= attrib_convert (yytext[cnt++]); - return kMODE; } - -"{" { return '{'; } -"}" { return '}'; } -"(" { return '('; } -")" { return ')'; } -":" { return ':'; } -";" { return ';'; } -"=" { return '='; } -"+" { ldlval.op = exp_plus; return kADD_OP; } -"-" { ldlval.op = exp_minus; return kADD_OP; } -"*" { return '*'; } -"/" { ldlval.op = exp_div; return kMUL_OP; } -"%" { ldlval.op = exp_mod; return kMUL_OP; } -"&" { return '&'; } -"|" { return '|'; } - -"," { return ','; } - -{HEX}|{OCT}|{DEC} { char *endp; - ldlval.num = strtoumax (yytext, &endp, 0); - if (*endp != '\0') - { - if (tolower (*endp) == 'k') - ldlval.num *= 1024; - else - { - assert (tolower (*endp) == 'm'); - ldlval.num *= 1024 * 1024; - } - } - return kNUM; } - -{ID} { ldlval.str = obstack_strndup (&ld_state.smem, - yytext, yyleng); - return kID; } - -{FILENAMECHAR1}{FILENAMECHAR} { ldlval.str = obstack_strndup (&ld_state.smem, - yytext, yyleng); - return kFILENAME; } - -{WHITE} { /* IGNORE */ } - -. { invalid_char (*yytext); } - -%% - -static void -eat_comment (void) -{ - while (1) - { - int c = input (); - - while (c != '*' && c != EOF) - c = input (); - - if (c == '*') - { - c = input (); - while (c == '*') - c = input (); - if (c == '/') - break; - } - - if (c == 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 = false; - - while (1) - { - int c = input (); - - if (c == EOF) - break; - if (c == '\n') - { - ++yylineno; - break; - } - - if (empty && ! isspace (c) && ! warned) - { - error (0, 0, gettext ("%d: garbage at end of line"), yylineno); - warned = true; - } - } -} - - -static int -attrib_convert (int c) -{ - if (c == 'X') - return PF_X; - if (c == 'W') - return PF_W; - assert (c == 'R'); - return PF_R; -} - - -static void -push_state (enum prepstate state) -{ - if (prepdepth >= MAX_PREPDEPTH) - error (EXIT_FAILURE, 0, gettext ("%d: conditionals nested too deep"), - yylineno); - - prepstate[prepdepth++] = state; -} - - -static int -pop_state (void) -{ - if (prepdepth == 0) - error (0, 0, gettext ("%d: unexpected #endif"), yylineno); - else - --prepdepth; - - return prepdepth == 0 ? INITIAL : IGNORE; -} - - -static int -handle_ifdef (void) -{ - char idbuf[50]; - char *id = idbuf; - size_t idlen = 0; - size_t idmax = sizeof (idbuf); - bool ignore_ws = true; - bool defined = false; - int result; - - while (1) - { - int c = input (); - - if (isspace (c) && ignore_ws) - continue; - - if (c != '_' && (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') - && (idlen == 0 || c < '0' || c > '9')) - { - unput (c); - break; - } - - if (idlen == idmax) - { - char *newp = (char *) alloca (idmax *= 2); - id = memcpy (newp, id, idlen); - } - - id[idlen++] = c; - ignore_ws = false; - } - - /* XXX Compare in a better way. */ - if (idlen == 6 && strncmp (id, "SHARED", 6) == 0) - defined = ld_state.file_type == dso_file_type; - - if (defined) - result = INITIAL; - else - { - push_state (skip_if); - result = 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.c b/src/ldscript.c deleted file mode 100644 index 0f70ca95..00000000 --- a/src/ldscript.c +++ /dev/null @@ -1,2220 +0,0 @@ -/* A Bison parser, made by GNU Bison 1.875c. */ - -/* Skeleton parser for Yacc-like parsing with Bison, - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -/* As a special exception, when this file is copied by Bison into a - Bison output file, you may use that output file without restriction. - This special exception was added by the Free Software Foundation - in version 1.24 of Bison. */ - -/* Written by Richard Stallman by simplifying the original so called - ``semantic'' parser. */ - -/* All symbols defined below should begin with yy or YY, to avoid - infringing on user name space. This should be done even for local - variables, as they might otherwise be expanded by user macros. - There are some unavoidable exceptions within include files to - define necessary library symbols; they are noted "INFRINGES ON - USER NAME SPACE" below. */ - -/* Identify Bison output. */ -#define YYBISON 1 - -/* Skeleton name. */ -#define YYSKELETON_NAME "yacc.c" - -/* Pure parsers. */ -#define YYPURE 0 - -/* Using locations. */ -#define YYLSP_NEEDED 0 - -/* If NAME_PREFIX is specified substitute the variables and functions - names. */ -#define yyparse ldparse -#define yylex ldlex -#define yyerror lderror -#define yylval ldlval -#define yychar ldchar -#define yydebug lddebug -#define yynerrs ldnerrs - - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - kADD_OP = 258, - kALIGN = 259, - kENTRY = 260, - kEXCLUDE_FILE = 261, - kFILENAME = 262, - kGLOBAL = 263, - kGROUP = 264, - kID = 265, - kINPUT = 266, - kINTERP = 267, - kKEEP = 268, - kLOCAL = 269, - kMODE = 270, - kMUL_OP = 271, - kNUM = 272, - kOUTPUT_FORMAT = 273, - kPAGESIZE = 274, - kPROVIDE = 275, - kSEARCH_DIR = 276, - kSEGMENT = 277, - kSIZEOF_HEADERS = 278, - kSORT = 279, - kVERSION = 280, - kVERSION_SCRIPT = 281, - ADD_OP = 282, - MUL_OP = 283 - }; -#endif -#define kADD_OP 258 -#define kALIGN 259 -#define kENTRY 260 -#define kEXCLUDE_FILE 261 -#define kFILENAME 262 -#define kGLOBAL 263 -#define kGROUP 264 -#define kID 265 -#define kINPUT 266 -#define kINTERP 267 -#define kKEEP 268 -#define kLOCAL 269 -#define kMODE 270 -#define kMUL_OP 271 -#define kNUM 272 -#define kOUTPUT_FORMAT 273 -#define kPAGESIZE 274 -#define kPROVIDE 275 -#define kSEARCH_DIR 276 -#define kSEGMENT 277 -#define kSIZEOF_HEADERS 278 -#define kSORT 279 -#define kVERSION 280 -#define kVERSION_SCRIPT 281 -#define ADD_OP 282 -#define MUL_OP 283 - - - - -/* Copy the first part of user declarations. */ -#line 1 "/home/drepper/gnu/elfutils/src/ldscript.y" - -/* Parser for linker scripts. - Copyright (C) 2001, 2002, 2003, 2004 Red Hat, Inc. - Written by Ulrich Drepper <drepper@redhat.com>, 2001. - - This program is Open Source software; you can redistribute it and/or - modify it under the terms of the Open Software License version 1.0 as - published by the Open Source Initiative. - - You should have received a copy of the Open Software License along - with this program; if not, you may obtain a copy of the Open Software - License version 1.0 from http://www.opensource.org/licenses/osl.php or - by writing the Open Source Initiative c/o Lawrence Rosen, Esq., - 3001 King Ranch Road, Ukiah, CA 95482. */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <assert.h> -#include <error.h> -#include <libintl.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <system.h> -#include <ld.h> - -/* 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 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); - - -/* Enabling traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif - -/* Enabling verbose error messages. */ -#ifdef YYERROR_VERBOSE -# undef YYERROR_VERBOSE -# define YYERROR_VERBOSE 1 -#else -# define YYERROR_VERBOSE 0 -#endif - -#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) -#line 58 "/home/drepper/gnu/elfutils/src/ldscript.y" -typedef union YYSTYPE { - 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; -} YYSTYPE; -/* Line 191 of yacc.c. */ -#line 213 "ldscript.c" -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 -# define YYSTYPE_IS_TRIVIAL 1 -#endif - - - -/* Copy the second part of user declarations. */ - - -/* Line 214 of yacc.c. */ -#line 225 "ldscript.c" - -#if ! defined (yyoverflow) || YYERROR_VERBOSE - -# ifndef YYFREE -# define YYFREE free -# endif -# ifndef YYMALLOC -# define YYMALLOC malloc -# endif - -/* The parser invokes alloca or malloc; define the necessary symbols. */ - -# ifdef YYSTACK_USE_ALLOCA -# if YYSTACK_USE_ALLOCA -# define YYSTACK_ALLOC alloca -# endif -# else -# if defined (alloca) || defined (_ALLOCA_H) -# define YYSTACK_ALLOC alloca -# else -# ifdef __GNUC__ -# define YYSTACK_ALLOC __builtin_alloca -# endif -# endif -# endif - -# ifdef YYSTACK_ALLOC - /* Pacify GCC's `empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) -# else -# if defined (__STDC__) || defined (__cplusplus) -# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# endif -# define YYSTACK_ALLOC YYMALLOC -# define YYSTACK_FREE YYFREE -# endif -#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */ - - -#if (! defined (yyoverflow) \ - && (! defined (__cplusplus) \ - || (defined (YYSTYPE_IS_TRIVIAL) && YYSTYPE_IS_TRIVIAL))) - -/* A type that is properly aligned for any stack member. */ -union yyalloc -{ - short yyss; - YYSTYPE yyvs; - }; - -/* The size of the maximum gap between one aligned stack and the next. */ -# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) - -/* The size of an array large to enough to hold all stacks, each with - N elements. */ -# define YYSTACK_BYTES(N) \ - ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ - + YYSTACK_GAP_MAXIMUM) - -/* Copy COUNT objects from FROM to TO. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if defined (__GNUC__) && 1 < __GNUC__ -# define YYCOPY(To, From, Count) \ - __builtin_memcpy (To, From, (Count) * sizeof (*(From))) -# else -# define YYCOPY(To, From, Count) \ - do \ - { \ - register YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (To)[yyi] = (From)[yyi]; \ - } \ - while (0) -# endif -# endif - -/* Relocate STACK from its old location to the new one. The - local variables YYSIZE and YYSTACKSIZE give the old and new number of - elements in the stack, and YYPTR gives the new location of the - stack. Advance YYPTR to a properly aligned location for the next - stack. */ -# define YYSTACK_RELOCATE(Stack) \ - do \ - { \ - YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack, Stack, yysize); \ - Stack = &yyptr->Stack; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (0) - -#endif - -#if defined (__STDC__) || defined (__cplusplus) - typedef signed char yysigned_char; -#else - typedef short yysigned_char; -#endif - -/* YYFINAL -- State number of the termination state. */ -#define YYFINAL 30 -/* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 198 - -/* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 39 -/* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 22 -/* YYNRULES -- Number of rules. */ -#define YYNRULES 62 -/* YYNRULES -- Number of states. */ -#define YYNSTATES 146 - -/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ -#define YYUNDEFTOK 2 -#define YYMAXUTOK 283 - -#define YYTRANSLATE(YYX) \ - ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) - -/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ -static const unsigned char yytranslate[] = -{ - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 28, 2, - 32, 33, 30, 2, 38, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 34, - 2, 37, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 35, 27, 36, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 29, 31 -}; - -#if YYDEBUG -/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in - YYRHS. */ -static const unsigned char yyprhs[] = -{ - 0, 0, 3, 5, 8, 11, 13, 19, 25, 31, - 37, 43, 49, 54, 59, 64, 69, 72, 74, 77, - 82, 85, 89, 96, 99, 101, 103, 108, 111, 117, - 119, 124, 129, 130, 135, 139, 143, 147, 151, 155, - 159, 161, 163, 165, 167, 171, 173, 175, 176, 179, - 181, 186, 192, 199, 202, 204, 207, 210, 214, 217, - 219, 221, 223 -}; - -/* YYRHS -- A `-1'-separated list of the rules' RHS. */ -static const yysigned_char yyrhs[] = -{ - 40, 0, -1, 41, -1, 26, 54, -1, 41, 42, - -1, 42, -1, 5, 32, 10, 33, 34, -1, 21, - 32, 59, 33, 34, -1, 19, 32, 17, 33, 34, - -1, 12, 32, 59, 33, 34, -1, 22, 15, 35, - 43, 36, -1, 22, 1, 35, 43, 36, -1, 9, - 32, 52, 33, -1, 11, 32, 52, 33, -1, 25, - 35, 54, 36, -1, 18, 32, 59, 33, -1, 43, - 44, -1, 44, -1, 45, 34, -1, 10, 35, 46, - 36, -1, 10, 34, -1, 10, 37, 51, -1, 20, - 32, 10, 37, 51, 33, -1, 46, 47, -1, 47, - -1, 48, -1, 13, 32, 48, 33, -1, 45, 34, - -1, 60, 32, 50, 49, 33, -1, 10, -1, 24, - 32, 10, 33, -1, 6, 32, 59, 33, -1, -1, - 4, 32, 51, 33, -1, 32, 51, 33, -1, 51, - 30, 51, -1, 51, 16, 51, -1, 51, 3, 51, - -1, 51, 28, 51, -1, 51, 27, 51, -1, 17, - -1, 10, -1, 23, -1, 19, -1, 52, 53, 59, - -1, 59, -1, 38, -1, -1, 54, 55, -1, 55, - -1, 35, 56, 36, 34, -1, 59, 35, 56, 36, - 34, -1, 59, 35, 56, 36, 59, 34, -1, 56, - 57, -1, 57, -1, 8, 58, -1, 14, 58, -1, - 58, 60, 34, -1, 60, 34, -1, 7, -1, 10, - -1, 59, -1, 30, -1 -}; - -/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ -static const unsigned short yyrline[] = -{ - 0, 128, 128, 129, 133, 134, 137, 142, 146, 151, - 156, 160, 166, 177, 179, 181, 185, 190, 194, 199, - 211, 235, 237, 241, 246, 250, 255, 262, 269, 280, - 282, 286, 289, 292, 297, 299, 305, 311, 317, 323, - 329, 334, 339, 341, 345, 351, 355, 356, 359, 364, - 368, 374, 380, 389, 391, 395, 397, 402, 408, 412, - 414, 418, 420 -}; -#endif - -#if YYDEBUG || YYERROR_VERBOSE -/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. - First, the terminals, then, starting at YYNTOKENS, nonterminals. */ -static const char *const yytname[] = -{ - "$end", "error", "$undefined", "kADD_OP", "kALIGN", "kENTRY", - "kEXCLUDE_FILE", "kFILENAME", "kGLOBAL", "kGROUP", "kID", "kINPUT", - "kINTERP", "kKEEP", "kLOCAL", "kMODE", "kMUL_OP", "kNUM", - "kOUTPUT_FORMAT", "kPAGESIZE", "kPROVIDE", "kSEARCH_DIR", "kSEGMENT", - "kSIZEOF_HEADERS", "kSORT", "kVERSION", "kVERSION_SCRIPT", "'|'", "'&'", - "ADD_OP", "'*'", "MUL_OP", "'('", "')'", "';'", "'{'", "'}'", "'='", - "','", "$accept", "script_or_version", "file", "content", - "outputsections", "outputsection", "assignment", "inputsections", - "inputsection", "sectionname", "sort_opt_name", "exclude_opt", "expr", - "filename_id_list", "comma_opt", "versionlist", "version", - "version_stmt_list", "version_stmt", "filename_id_star_list", - "filename_id", "filename_id_star", 0 -}; -#endif - -# ifdef YYPRINT -/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to - token YYLEX-NUM. */ -static const unsigned short yytoknum[] = -{ - 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 277, 278, 279, 280, 281, 124, 38, 282, - 42, 283, 40, 41, 59, 123, 125, 61, 44 -}; -# endif - -/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ -static const unsigned char yyr1[] = -{ - 0, 39, 40, 40, 41, 41, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 43, 43, 44, 44, - 44, 45, 45, 46, 46, 47, 47, 47, 48, 49, - 49, 50, 50, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 52, 52, 53, 53, 54, 54, - 55, 55, 55, 56, 56, 57, 57, 58, 58, 59, - 59, 60, 60 -}; - -/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ -static const unsigned char yyr2[] = -{ - 0, 2, 1, 2, 2, 1, 5, 5, 5, 5, - 5, 5, 4, 4, 4, 4, 2, 1, 2, 4, - 2, 3, 6, 2, 1, 1, 4, 2, 5, 1, - 4, 4, 0, 4, 3, 3, 3, 3, 3, 3, - 1, 1, 1, 1, 3, 1, 1, 0, 2, 1, - 4, 5, 6, 2, 1, 2, 2, 3, 2, 1, - 1, 1, 1 -}; - -/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state - STATE-NUM when YYTABLE doesn't specify something else to do. Zero - means the default is an error. */ -static const unsigned char yydefact[] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 2, 5, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 59, 60, 0, 3, 49, 0, - 1, 4, 0, 47, 45, 47, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 54, 48, 0, 0, - 12, 46, 0, 13, 0, 15, 0, 0, 0, 0, - 0, 17, 0, 0, 14, 62, 55, 61, 0, 56, - 0, 53, 0, 6, 44, 9, 8, 7, 20, 0, - 0, 0, 11, 16, 18, 10, 0, 58, 50, 0, - 60, 0, 0, 0, 24, 25, 0, 0, 41, 40, - 43, 42, 0, 21, 0, 57, 51, 0, 0, 27, - 19, 23, 32, 0, 0, 0, 0, 0, 0, 0, - 0, 52, 0, 0, 0, 0, 34, 37, 36, 39, - 38, 35, 0, 26, 0, 29, 0, 0, 33, 22, - 0, 0, 28, 31, 0, 30 -}; - -/* YYDEFGOTO[NTERM-NUM]. */ -static const short yydefgoto[] = -{ - -1, 11, 12, 13, 60, 61, 62, 93, 94, 95, - 137, 124, 103, 33, 52, 27, 28, 45, 46, 66, - 67, 96 -}; - -/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing - STATE-NUM. */ -#define YYPACT_NINF -41 -static const short yypact[] = -{ - 107, -28, -20, -13, 34, 77, 85, 88, 91, 33, - 38, 123, 125, -41, 117, 52, 52, 52, 52, 114, - 52, 100, 103, 38, -41, -41, 96, 38, -41, 110, - -41, -41, 115, 64, -41, 67, 116, 118, 120, 127, - 1, 1, 28, 84, 84, 36, -41, -41, 96, 128, - -41, -41, 52, -41, 129, -41, 130, 131, 105, 134, - 75, -41, 133, 79, -41, -41, 84, -41, 135, 84, - 136, -41, 41, -41, -41, -41, -41, -41, -41, 83, - 48, 151, -41, -41, -41, -41, 137, -41, -41, 44, - 138, 140, 139, 17, -41, -41, 142, 144, -41, -41, - -41, -41, 48, 54, 141, -41, -41, 143, 84, -41, - -41, -41, 162, 48, -2, 48, 48, 48, 48, 48, - 48, -41, 146, 148, 97, 6, -41, 54, 54, 58, - 53, -1, 13, -41, 52, -41, 149, 150, -41, -41, - 152, 172, -41, -41, 153, -41 -}; - -/* YYPGOTO[NTERM-NUM]. */ -static const short yypgoto[] = -{ - -41, -41, -41, 175, 147, -40, 29, -41, 98, 76, - -41, -41, 39, 173, -41, 167, -24, 145, 15, 154, - -10, 32 -}; - -/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If - positive, shift that token. If negative, reduce the rule which - number is the opposite. If zero, do what YYDEFACT says. - If YYTABLE_NINF, syntax error. */ -#define YYTABLE_NINF -1 -static const unsigned char yytable[] = -{ - 29, 115, 115, 47, 14, 34, 34, 36, 37, 115, - 39, 58, 15, 29, 116, 116, 115, 29, 47, 16, - 83, 59, 116, 83, 24, 117, 118, 90, 119, 116, - 91, 126, 29, 117, 118, 24, 119, 59, 25, 138, - 117, 118, 74, 119, 43, 24, 139, 65, 25, 43, - 44, 24, 97, 110, 25, 44, 115, 115, 98, 24, - 71, 115, 25, 26, 64, 99, 17, 100, 23, 116, - 116, 101, 70, 26, 116, 68, 68, 89, 106, 107, - 102, 117, 118, 119, 119, 58, 118, 71, 119, 58, - 24, 24, 21, 90, 25, 59, 91, 50, 86, 59, - 53, 86, 51, 59, 43, 51, 22, 135, 92, 18, - 44, 82, 1, 65, 65, 85, 2, 19, 3, 4, - 20, 136, 92, 30, 140, 5, 6, 32, 7, 8, - 1, 38, 9, 10, 2, 40, 3, 4, 41, 78, - 79, 114, 80, 5, 6, 48, 7, 8, 49, 54, - 9, 55, 125, 56, 127, 128, 129, 130, 131, 132, - 57, 104, 73, 75, 76, 77, 81, 84, 123, 87, - 88, 105, 108, 109, 112, 80, 113, 121, 120, 133, - 134, 141, 144, 142, 122, 143, 145, 31, 63, 35, - 42, 111, 0, 72, 0, 0, 0, 0, 69 -}; - -static const short yycheck[] = -{ - 10, 3, 3, 27, 32, 15, 16, 17, 18, 3, - 20, 10, 32, 23, 16, 16, 3, 27, 42, 32, - 60, 20, 16, 63, 7, 27, 28, 10, 30, 16, - 13, 33, 42, 27, 28, 7, 30, 20, 10, 33, - 27, 28, 52, 30, 8, 7, 33, 30, 10, 8, - 14, 7, 4, 36, 10, 14, 3, 3, 10, 7, - 45, 3, 10, 35, 36, 17, 32, 19, 35, 16, - 16, 23, 36, 35, 16, 43, 44, 36, 34, 89, - 32, 27, 28, 30, 30, 10, 28, 72, 30, 10, - 7, 7, 1, 10, 10, 20, 13, 33, 66, 20, - 33, 69, 38, 20, 8, 38, 15, 10, 79, 32, - 14, 36, 5, 30, 30, 36, 9, 32, 11, 12, - 32, 24, 93, 0, 134, 18, 19, 10, 21, 22, - 5, 17, 25, 26, 9, 35, 11, 12, 35, 34, - 35, 102, 37, 18, 19, 35, 21, 22, 33, 33, - 25, 33, 113, 33, 115, 116, 117, 118, 119, 120, - 33, 10, 34, 34, 34, 34, 32, 34, 6, 34, - 34, 34, 32, 34, 32, 37, 32, 34, 37, 33, - 32, 32, 10, 33, 108, 33, 33, 12, 41, 16, - 23, 93, -1, 48, -1, -1, -1, -1, 44 -}; - -/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing - symbol of state STATE-NUM. */ -static const unsigned char yystos[] = -{ - 0, 5, 9, 11, 12, 18, 19, 21, 22, 25, - 26, 40, 41, 42, 32, 32, 32, 32, 32, 32, - 32, 1, 15, 35, 7, 10, 35, 54, 55, 59, - 0, 42, 10, 52, 59, 52, 59, 59, 17, 59, - 35, 35, 54, 8, 14, 56, 57, 55, 35, 33, - 33, 38, 53, 33, 33, 33, 33, 33, 10, 20, - 43, 44, 45, 43, 36, 30, 58, 59, 60, 58, - 36, 57, 56, 34, 59, 34, 34, 34, 34, 35, - 37, 32, 36, 44, 34, 36, 60, 34, 34, 36, - 10, 13, 45, 46, 47, 48, 60, 4, 10, 17, - 19, 23, 32, 51, 10, 34, 34, 59, 32, 34, - 36, 47, 32, 32, 51, 3, 16, 27, 28, 30, - 37, 34, 48, 6, 50, 51, 33, 51, 51, 51, - 51, 51, 51, 33, 32, 10, 24, 49, 33, 33, - 59, 32, 33, 33, 10, 33 -}; - -#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) -# define YYSIZE_T __SIZE_TYPE__ -#endif -#if ! defined (YYSIZE_T) && defined (size_t) -# define YYSIZE_T size_t -#endif -#if ! defined (YYSIZE_T) -# if defined (__STDC__) || defined (__cplusplus) -# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# endif -#endif -#if ! defined (YYSIZE_T) -# define YYSIZE_T unsigned int -#endif - -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) -#define YYEMPTY (-2) -#define YYEOF 0 - -#define YYACCEPT goto yyacceptlab -#define YYABORT goto yyabortlab -#define YYERROR goto yyerrorlab - - -/* Like YYERROR except do call yyerror. This remains here temporarily - to ease the transition to the new meaning of YYERROR, for GCC. - Once GCC version 2 has supplanted version 1, this can go. */ - -#define YYFAIL goto yyerrlab - -#define YYRECOVERING() (!!yyerrstatus) - -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY && yylen == 1) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - yytoken = YYTRANSLATE (yychar); \ - YYPOPSTACK; \ - goto yybackup; \ - } \ - else \ - { \ - yyerror ("syntax error: cannot back up");\ - YYERROR; \ - } \ -while (0) - -#define YYTERROR 1 -#define YYERRCODE 256 - -/* YYLLOC_DEFAULT -- Compute the default location (before the actions - are run). */ - -#ifndef YYLLOC_DEFAULT -# define YYLLOC_DEFAULT(Current, Rhs, N) \ - ((Current).first_line = (Rhs)[1].first_line, \ - (Current).first_column = (Rhs)[1].first_column, \ - (Current).last_line = (Rhs)[N].last_line, \ - (Current).last_column = (Rhs)[N].last_column) -#endif - -/* YYLEX -- calling `yylex' with the right arguments. */ - -#ifdef YYLEX_PARAM -# define YYLEX yylex (YYLEX_PARAM) -#else -# define YYLEX yylex () -#endif - -/* Enable debugging if requested. */ -#if YYDEBUG - -# ifndef YYFPRINTF -# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ -# define YYFPRINTF fprintf -# endif - -# define YYDPRINTF(Args) \ -do { \ - if (yydebug) \ - YYFPRINTF Args; \ -} while (0) - -# define YYDSYMPRINT(Args) \ -do { \ - if (yydebug) \ - yysymprint Args; \ -} while (0) - -# define YYDSYMPRINTF(Title, Token, Value, Location) \ -do { \ - if (yydebug) \ - { \ - YYFPRINTF (stderr, "%s ", Title); \ - yysymprint (stderr, \ - Token, Value); \ - YYFPRINTF (stderr, "\n"); \ - } \ -} while (0) - -/*------------------------------------------------------------------. -| yy_stack_print -- Print the state stack from its BOTTOM up to its | -| TOP (included). | -`------------------------------------------------------------------*/ - -#if defined (__STDC__) || defined (__cplusplus) -static void -yy_stack_print (short *bottom, short *top) -#else -static void -yy_stack_print (bottom, top) - short *bottom; - short *top; -#endif -{ - YYFPRINTF (stderr, "Stack now"); - for (/* Nothing. */; bottom <= top; ++bottom) - YYFPRINTF (stderr, " %d", *bottom); - YYFPRINTF (stderr, "\n"); -} - -# define YY_STACK_PRINT(Bottom, Top) \ -do { \ - if (yydebug) \ - yy_stack_print ((Bottom), (Top)); \ -} while (0) - - -/*------------------------------------------------. -| Report that the YYRULE is going to be reduced. | -`------------------------------------------------*/ - -#if defined (__STDC__) || defined (__cplusplus) -static void -yy_reduce_print (int yyrule) -#else -static void -yy_reduce_print (yyrule) - int yyrule; -#endif -{ - int yyi; - unsigned int yylno = yyrline[yyrule]; - YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ", - yyrule - 1, yylno); - /* Print the symbols being reduced, and their result. */ - for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++) - YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]); - YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]); -} - -# define YY_REDUCE_PRINT(Rule) \ -do { \ - if (yydebug) \ - yy_reduce_print (Rule); \ -} while (0) - -/* Nonzero means print parse trace. It is left uninitialized so that - multiple parsers can coexist. */ -int yydebug; -#else /* !YYDEBUG */ -# define YYDPRINTF(Args) -# define YYDSYMPRINT(Args) -# define YYDSYMPRINTF(Title, Token, Value, Location) -# define YY_STACK_PRINT(Bottom, Top) -# define YY_REDUCE_PRINT(Rule) -#endif /* !YYDEBUG */ - - -/* YYINITDEPTH -- initial size of the parser's stacks. */ -#ifndef YYINITDEPTH -# define YYINITDEPTH 200 -#endif - -/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only - if the built-in stack extension method is used). - - Do not make this value too large; the results are undefined if - SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) - evaluated with infinite-precision integer arithmetic. */ - -#if defined (YYMAXDEPTH) && YYMAXDEPTH == 0 -# undef YYMAXDEPTH -#endif - -#ifndef YYMAXDEPTH -# define YYMAXDEPTH 10000 -#endif - - - -#if YYERROR_VERBOSE - -# ifndef yystrlen -# if defined (__GLIBC__) && defined (_STRING_H) -# define yystrlen strlen -# else -/* Return the length of YYSTR. */ -static YYSIZE_T -# if defined (__STDC__) || defined (__cplusplus) -yystrlen (const char *yystr) -# else -yystrlen (yystr) - const char *yystr; -# endif -{ - register const char *yys = yystr; - - while (*yys++ != '\0') - continue; - - return yys - yystr - 1; -} -# endif -# endif - -# ifndef yystpcpy -# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) -# define yystpcpy stpcpy -# else -/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in - YYDEST. */ -static char * -# if defined (__STDC__) || defined (__cplusplus) -yystpcpy (char *yydest, const char *yysrc) -# else -yystpcpy (yydest, yysrc) - char *yydest; - const char *yysrc; -# endif -{ - register char *yyd = yydest; - register const char *yys = yysrc; - - while ((*yyd++ = *yys++) != '\0') - continue; - - return yyd - 1; -} -# endif -# endif - -#endif /* !YYERROR_VERBOSE */ - - - -#if YYDEBUG -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ - -#if defined (__STDC__) || defined (__cplusplus) -static void -yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep) -#else -static void -yysymprint (yyoutput, yytype, yyvaluep) - FILE *yyoutput; - int yytype; - YYSTYPE *yyvaluep; -#endif -{ - /* Pacify ``unused variable'' warnings. */ - (void) yyvaluep; - - if (yytype < YYNTOKENS) - { - YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); -# ifdef YYPRINT - YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); -# endif - } - else - YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); - - switch (yytype) - { - default: - break; - } - YYFPRINTF (yyoutput, ")"); -} - -#endif /* ! YYDEBUG */ -/*-----------------------------------------------. -| Release the memory associated to this symbol. | -`-----------------------------------------------*/ - -#if defined (__STDC__) || defined (__cplusplus) -static void -yydestruct (int yytype, YYSTYPE *yyvaluep) -#else -static void -yydestruct (yytype, yyvaluep) - int yytype; - YYSTYPE *yyvaluep; -#endif -{ - /* Pacify ``unused variable'' warnings. */ - (void) yyvaluep; - - switch (yytype) - { - - default: - break; - } -} - - -/* Prevent warnings from -Wmissing-prototypes. */ - -#ifdef YYPARSE_PARAM -# if defined (__STDC__) || defined (__cplusplus) -int yyparse (void *YYPARSE_PARAM); -# else -int yyparse (); -# endif -#else /* ! YYPARSE_PARAM */ -#if defined (__STDC__) || defined (__cplusplus) -int yyparse (void); -#else -int yyparse (); -#endif -#endif /* ! YYPARSE_PARAM */ - - - -/* The lookahead symbol. */ -int yychar; - -/* The semantic value of the lookahead symbol. */ -YYSTYPE yylval; - -/* Number of syntax errors so far. */ -int yynerrs; - - - -/*----------. -| yyparse. | -`----------*/ - -#ifdef YYPARSE_PARAM -# if defined (__STDC__) || defined (__cplusplus) -int yyparse (void *YYPARSE_PARAM) -# else -int yyparse (YYPARSE_PARAM) - void *YYPARSE_PARAM; -# endif -#else /* ! YYPARSE_PARAM */ -#if defined (__STDC__) || defined (__cplusplus) -int -yyparse (void) -#else -int -yyparse () - -#endif -#endif -{ - - register int yystate; - register int yyn; - int yyresult; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - /* Lookahead token as an internal (translated) token number. */ - int yytoken = 0; - - /* Three stacks and their tools: - `yyss': related to states, - `yyvs': related to semantic values, - `yyls': related to locations. - - Refer to the stacks thru separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* The state stack. */ - short yyssa[YYINITDEPTH]; - short *yyss = yyssa; - register short *yyssp; - - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs = yyvsa; - register YYSTYPE *yyvsp; - - - -#define YYPOPSTACK (yyvsp--, yyssp--) - - YYSIZE_T yystacksize = YYINITDEPTH; - - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; - - - /* When reducing, the number of symbols on the RHS of the reduced - rule. */ - int yylen; - - YYDPRINTF ((stderr, "Starting parse\n")); - - yystate = 0; - yyerrstatus = 0; - yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ - - /* Initialize stack pointers. - Waste one element of value and location stack - so that they stay on the same level as the state stack. - The wasted elements are never initialized. */ - - yyssp = yyss; - yyvsp = yyvs; - - goto yysetstate; - -/*------------------------------------------------------------. -| yynewstate -- Push a new state, which is found in yystate. | -`------------------------------------------------------------*/ - yynewstate: - /* In all cases, when you get here, the value and location stacks - have just been pushed. so pushing a state here evens the stacks. - */ - yyssp++; - - yysetstate: - *yyssp = yystate; - - if (yyss + yystacksize - 1 <= yyssp) - { - /* Get the current used size of the three stacks, in elements. */ - YYSIZE_T yysize = yyssp - yyss + 1; - -#ifdef yyoverflow - { - /* Give user a chance to reallocate the stack. Use copies of - these so that the &'s don't force the real ones into - memory. */ - YYSTYPE *yyvs1 = yyvs; - short *yyss1 = yyss; - - - /* Each stack pointer address is followed by the size of the - data in use in that stack, in bytes. This used to be a - conditional around just the two extra args, but that might - be undefined if yyoverflow is a macro. */ - yyoverflow ("parser stack overflow", - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - - &yystacksize); - - yyss = yyss1; - yyvs = yyvs1; - } -#else /* no yyoverflow */ -# ifndef YYSTACK_RELOCATE - goto yyoverflowlab; -# else - /* Extend the stack our own way. */ - if (YYMAXDEPTH <= yystacksize) - goto yyoverflowlab; - yystacksize *= 2; - if (YYMAXDEPTH < yystacksize) - yystacksize = YYMAXDEPTH; - - { - short *yyss1 = yyss; - union yyalloc *yyptr = - (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); - if (! yyptr) - goto yyoverflowlab; - YYSTACK_RELOCATE (yyss); - YYSTACK_RELOCATE (yyvs); - -# undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE (yyss1); - } -# endif -#endif /* no yyoverflow */ - - yyssp = yyss + yysize - 1; - yyvsp = yyvs + yysize - 1; - - - YYDPRINTF ((stderr, "Stack size increased to %lu\n", - (unsigned long int) yystacksize)); - - if (yyss + yystacksize - 1 <= yyssp) - YYABORT; - } - - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - - goto yybackup; - -/*-----------. -| yybackup. | -`-----------*/ -yybackup: - -/* Do appropriate processing given the current state. */ -/* Read a lookahead token if we need one and don't already have one. */ -/* yyresume: */ - - /* First try to decide what to do without reference to lookahead token. */ - - yyn = yypact[yystate]; - if (yyn == YYPACT_NINF) - goto yydefault; - - /* Not known => get a lookahead token if don't already have one. */ - - /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ - if (yychar == YYEMPTY) - { - YYDPRINTF ((stderr, "Reading a token: ")); - yychar = YYLEX; - } - - if (yychar <= YYEOF) - { - yychar = yytoken = YYEOF; - YYDPRINTF ((stderr, "Now at end of input.\n")); - } - else - { - yytoken = YYTRANSLATE (yychar); - YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc); - } - - /* If the proper action on seeing token YYTOKEN is to reduce or to - detect an error, take that action. */ - yyn += yytoken; - if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) - goto yydefault; - yyn = yytable[yyn]; - if (yyn <= 0) - { - if (yyn == 0 || yyn == YYTABLE_NINF) - goto yyerrlab; - yyn = -yyn; - goto yyreduce; - } - - if (yyn == YYFINAL) - YYACCEPT; - - /* Shift the lookahead token. */ - YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken])); - - /* Discard the token being shifted unless it is eof. */ - if (yychar != YYEOF) - yychar = YYEMPTY; - - *++yyvsp = yylval; - - - /* Count tokens shifted since error; after three, turn off error - status. */ - if (yyerrstatus) - yyerrstatus--; - - yystate = yyn; - goto yynewstate; - - -/*-----------------------------------------------------------. -| yydefault -- do the default action for the current state. | -`-----------------------------------------------------------*/ -yydefault: - yyn = yydefact[yystate]; - if (yyn == 0) - goto yyerrlab; - goto yyreduce; - - -/*-----------------------------. -| yyreduce -- Do a reduction. | -`-----------------------------*/ -yyreduce: - /* yyn is the number of a rule to reduce with. */ - yylen = yyr2[yyn]; - - /* If YYLEN is nonzero, implement the default value of the action: - `$$ = $1'. - - Otherwise, the following line sets YYVAL to garbage. - This behavior is undocumented and Bison - users should not rely upon it. Assigning to YYVAL - unconditionally makes the parser a bit smaller, and it avoids a - GCC warning that YYVAL may be used uninitialized. */ - yyval = yyvsp[1-yylen]; - - - YY_REDUCE_PRINT (yyn); - switch (yyn) - { - case 3: -#line 130 "/home/drepper/gnu/elfutils/src/ldscript.y" - { add_versions (yyvsp[0].version); } - break; - - case 6: -#line 138 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - if (likely (ld_state.entry == NULL)) - ld_state.entry = yyvsp[-2].str; - } - break; - - case 7: -#line 143 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - ld_new_searchdir (yyvsp[-2].str); - } - break; - - case 8: -#line 147 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - if (likely (ld_state.pagesize == 0)) - ld_state.pagesize = yyvsp[-2].num; - } - break; - - case 9: -#line 152 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - if (likely (ld_state.interp == NULL)) - ld_state.interp = yyvsp[-2].str; - } - break; - - case 10: -#line 157 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - new_segment (yyvsp[-3].num, yyvsp[-1].output_rule); - } - break; - - case 11: -#line 161 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - fputs_unlocked (gettext ("mode for segment invalid\n"), - stderr); - new_segment (0, yyvsp[-1].output_rule); - } - break; - - case 12: -#line 167 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - /* First little optimization. If there is only one - file in the group don't do anything. */ - if (yyvsp[-1].filename_list != yyvsp[-1].filename_list->next) - { - yyvsp[-1].filename_list->next->group_start = 1; - yyvsp[-1].filename_list->group_end = 1; - } - add_inputfiles (yyvsp[-1].filename_list); - } - break; - - case 13: -#line 178 "/home/drepper/gnu/elfutils/src/ldscript.y" - { add_inputfiles (yyvsp[-1].filename_list); } - break; - - case 14: -#line 180 "/home/drepper/gnu/elfutils/src/ldscript.y" - { add_versions (yyvsp[-1].version); } - break; - - case 15: -#line 182 "/home/drepper/gnu/elfutils/src/ldscript.y" - { /* XXX TODO */ } - break; - - case 16: -#line 186 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - yyvsp[0].output_rule->next = yyvsp[-1].output_rule->next; - yyval.output_rule = yyvsp[-1].output_rule->next = yyvsp[0].output_rule; - } - break; - - case 17: -#line 191 "/home/drepper/gnu/elfutils/src/ldscript.y" - { yyval.output_rule = yyvsp[0].output_rule; } - break; - - case 18: -#line 195 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - yyval.output_rule = new_output_rule (output_assignment); - yyval.output_rule->val.assignment = yyvsp[-1].assignment; - } - break; - - case 19: -#line 200 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - yyval.output_rule = new_output_rule (output_section); - yyval.output_rule->val.section.name = yyvsp[-3].str; - yyval.output_rule->val.section.input = yyvsp[-1].input_rule->next; - if (ld_state.strip == strip_debug - && ebl_debugscn_p (ld_state.ebl, yyvsp[-3].str)) - yyval.output_rule->val.section.ignored = true; - else - yyval.output_rule->val.section.ignored = false; - yyvsp[-1].input_rule->next = NULL; - } - break; - - case 20: -#line 212 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - /* This is a short cut for "ID { *(ID) }". */ - yyval.output_rule = new_output_rule (output_section); - yyval.output_rule->val.section.name = yyvsp[-1].str; - yyval.output_rule->val.section.input = new_input_rule (input_section); - yyval.output_rule->val.section.input->next = NULL; - yyval.output_rule->val.section.input->val.section = - (struct filemask_section_name *) - obstack_alloc (&ld_state.smem, - sizeof (struct filemask_section_name)); - yyval.output_rule->val.section.input->val.section->filemask = NULL; - yyval.output_rule->val.section.input->val.section->excludemask = NULL; - yyval.output_rule->val.section.input->val.section->section_name = - new_input_section_name (yyvsp[-1].str, false); - yyval.output_rule->val.section.input->val.section->keep_flag = false; - if (ld_state.strip == strip_debug - && ebl_debugscn_p (ld_state.ebl, yyvsp[-1].str)) - yyval.output_rule->val.section.ignored = true; - else - yyval.output_rule->val.section.ignored = false; - } - break; - - case 21: -#line 236 "/home/drepper/gnu/elfutils/src/ldscript.y" - { yyval.assignment = new_assignment (yyvsp[-2].str, yyvsp[0].expr, false); } - break; - - case 22: -#line 238 "/home/drepper/gnu/elfutils/src/ldscript.y" - { yyval.assignment = new_assignment (yyvsp[-3].str, yyvsp[-1].expr, true); } - break; - - case 23: -#line 242 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - yyvsp[0].input_rule->next = yyvsp[-1].input_rule->next; - yyval.input_rule = yyvsp[-1].input_rule->next = yyvsp[0].input_rule; - } - break; - - case 24: -#line 247 "/home/drepper/gnu/elfutils/src/ldscript.y" - { yyval.input_rule = yyvsp[0].input_rule; } - break; - - case 25: -#line 251 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - yyval.input_rule = new_input_rule (input_section); - yyval.input_rule->val.section = yyvsp[0].filemask_section_name; - } - break; - - case 26: -#line 256 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - yyvsp[-1].filemask_section_name->keep_flag = true; - - yyval.input_rule = new_input_rule (input_section); - yyval.input_rule->val.section = yyvsp[-1].filemask_section_name; - } - break; - - case 27: -#line 263 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - yyval.input_rule = new_input_rule (input_assignment); - yyval.input_rule->val.assignment = yyvsp[-1].assignment; - } - break; - - case 28: -#line 270 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - yyval.filemask_section_name = (struct filemask_section_name *) - obstack_alloc (&ld_state.smem, sizeof (*yyval.filemask_section_name)); - yyval.filemask_section_name->filemask = yyvsp[-4].str; - yyval.filemask_section_name->excludemask = yyvsp[-2].str; - yyval.filemask_section_name->section_name = yyvsp[-1].sectionname; - yyval.filemask_section_name->keep_flag = false; - } - break; - - case 29: -#line 281 "/home/drepper/gnu/elfutils/src/ldscript.y" - { yyval.sectionname = new_input_section_name (yyvsp[0].str, false); } - break; - - case 30: -#line 283 "/home/drepper/gnu/elfutils/src/ldscript.y" - { yyval.sectionname = new_input_section_name (yyvsp[-1].str, true); } - break; - - case 31: -#line 287 "/home/drepper/gnu/elfutils/src/ldscript.y" - { yyval.str = yyvsp[-1].str; } - break; - - case 32: -#line 289 "/home/drepper/gnu/elfutils/src/ldscript.y" - { yyval.str = NULL; } - break; - - case 33: -#line 293 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - yyval.expr = new_expr (exp_align); - yyval.expr->val.child = yyvsp[-1].expr; - } - break; - - case 34: -#line 298 "/home/drepper/gnu/elfutils/src/ldscript.y" - { yyval.expr = yyvsp[-1].expr; } - break; - - case 35: -#line 300 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - yyval.expr = new_expr (exp_mult); - yyval.expr->val.binary.left = yyvsp[-2].expr; - yyval.expr->val.binary.right = yyvsp[0].expr; - } - break; - - case 36: -#line 306 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - yyval.expr = new_expr (yyvsp[-1].op); - yyval.expr->val.binary.left = yyvsp[-2].expr; - yyval.expr->val.binary.right = yyvsp[0].expr; - } - break; - - case 37: -#line 312 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - yyval.expr = new_expr (yyvsp[-1].op); - yyval.expr->val.binary.left = yyvsp[-2].expr; - yyval.expr->val.binary.right = yyvsp[0].expr; - } - break; - - case 38: -#line 318 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - yyval.expr = new_expr (exp_and); - yyval.expr->val.binary.left = yyvsp[-2].expr; - yyval.expr->val.binary.right = yyvsp[0].expr; - } - break; - - case 39: -#line 324 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - yyval.expr = new_expr (exp_or); - yyval.expr->val.binary.left = yyvsp[-2].expr; - yyval.expr->val.binary.right = yyvsp[0].expr; - } - break; - - case 40: -#line 330 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - yyval.expr = new_expr (exp_num); - yyval.expr->val.num = yyvsp[0].num; - } - break; - - case 41: -#line 335 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - yyval.expr = new_expr (exp_id); - yyval.expr->val.str = yyvsp[0].str; - } - break; - - case 42: -#line 340 "/home/drepper/gnu/elfutils/src/ldscript.y" - { yyval.expr = new_expr (exp_sizeof_headers); } - break; - - case 43: -#line 342 "/home/drepper/gnu/elfutils/src/ldscript.y" - { yyval.expr = new_expr (exp_pagesize); } - break; - - case 44: -#line 346 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - struct filename_list *newp = new_filename_listelem (yyvsp[0].str); - newp->next = yyvsp[-2].filename_list->next; - yyval.filename_list = yyvsp[-2].filename_list->next = newp; - } - break; - - case 45: -#line 352 "/home/drepper/gnu/elfutils/src/ldscript.y" - { yyval.filename_list = new_filename_listelem (yyvsp[0].str); } - break; - - case 48: -#line 360 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - yyvsp[0].version->next = yyvsp[-1].version->next; - yyval.version = yyvsp[-1].version->next = yyvsp[0].version; - } - break; - - case 49: -#line 365 "/home/drepper/gnu/elfutils/src/ldscript.y" - { yyval.version = yyvsp[0].version; } - break; - - case 50: -#line 369 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - yyvsp[-2].version->versionname = ""; - yyvsp[-2].version->parentname = NULL; - yyval.version = yyvsp[-2].version; - } - break; - - case 51: -#line 375 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - yyvsp[-2].version->versionname = yyvsp[-4].str; - yyvsp[-2].version->parentname = NULL; - yyval.version = yyvsp[-2].version; - } - break; - - case 52: -#line 381 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - yyvsp[-3].version->versionname = yyvsp[-5].str; - yyvsp[-3].version->parentname = yyvsp[-1].str; - yyval.version = yyvsp[-3].version; - } - break; - - case 53: -#line 390 "/home/drepper/gnu/elfutils/src/ldscript.y" - { yyval.version = merge_versions (yyvsp[-1].version, yyvsp[0].version); } - break; - - case 54: -#line 392 "/home/drepper/gnu/elfutils/src/ldscript.y" - { yyval.version = yyvsp[0].version; } - break; - - case 55: -#line 396 "/home/drepper/gnu/elfutils/src/ldscript.y" - { yyval.version = new_version (NULL, yyvsp[0].id_list); } - break; - - case 56: -#line 398 "/home/drepper/gnu/elfutils/src/ldscript.y" - { yyval.version = new_version (yyvsp[0].id_list, NULL); } - break; - - case 57: -#line 403 "/home/drepper/gnu/elfutils/src/ldscript.y" - { - struct id_list *newp = new_id_listelem (yyvsp[-1].str); - newp->next = yyvsp[-2].id_list->next; - yyval.id_list = yyvsp[-2].id_list->next = newp; - } - break; - - case 58: -#line 409 "/home/drepper/gnu/elfutils/src/ldscript.y" - { yyval.id_list = new_id_listelem (yyvsp[-1].str); } - break; - - case 59: -#line 413 "/home/drepper/gnu/elfutils/src/ldscript.y" - { yyval.str = yyvsp[0].str; } - break; - - case 60: -#line 415 "/home/drepper/gnu/elfutils/src/ldscript.y" - { yyval.str = yyvsp[0].str; } - break; - - case 61: -#line 419 "/home/drepper/gnu/elfutils/src/ldscript.y" - { yyval.str = yyvsp[0].str; } - break; - - case 62: -#line 421 "/home/drepper/gnu/elfutils/src/ldscript.y" - { yyval.str = NULL; } - break; - - - } - -/* Line 1000 of yacc.c. */ -#line 1654 "ldscript.c" - - yyvsp -= yylen; - yyssp -= yylen; - - - YY_STACK_PRINT (yyss, yyssp); - - *++yyvsp = yyval; - - - /* Now `shift' the result of the reduction. Determine what state - that goes to, based on the state we popped back to and the rule - number reduced by. */ - - yyn = yyr1[yyn]; - - yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; - if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) - yystate = yytable[yystate]; - else - yystate = yydefgoto[yyn - YYNTOKENS]; - - goto yynewstate; - - -/*------------------------------------. -| yyerrlab -- here on detecting error | -`------------------------------------*/ -yyerrlab: - /* If not already recovering from an error, report this error. */ - if (!yyerrstatus) - { - ++yynerrs; -#if YYERROR_VERBOSE - yyn = yypact[yystate]; - - if (YYPACT_NINF < yyn && yyn < YYLAST) - { - YYSIZE_T yysize = 0; - int yytype = YYTRANSLATE (yychar); - const char* yyprefix; - char *yymsg; - int yyx; - - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. */ - int yyxbegin = yyn < 0 ? -yyn : 0; - - /* Stay within bounds of both yycheck and yytname. */ - int yychecklim = YYLAST - yyn; - int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; - int yycount = 0; - - yyprefix = ", expecting "; - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) - { - yysize += yystrlen (yyprefix) + yystrlen (yytname [yyx]); - yycount += 1; - if (yycount == 5) - { - yysize = 0; - break; - } - } - yysize += (sizeof ("syntax error, unexpected ") - + yystrlen (yytname[yytype])); - yymsg = (char *) YYSTACK_ALLOC (yysize); - if (yymsg != 0) - { - char *yyp = yystpcpy (yymsg, "syntax error, unexpected "); - yyp = yystpcpy (yyp, yytname[yytype]); - - if (yycount < 5) - { - yyprefix = ", expecting "; - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) - { - yyp = yystpcpy (yyp, yyprefix); - yyp = yystpcpy (yyp, yytname[yyx]); - yyprefix = " or "; - } - } - yyerror (yymsg); - YYSTACK_FREE (yymsg); - } - else - yyerror ("syntax error; also virtual memory exhausted"); - } - else -#endif /* YYERROR_VERBOSE */ - yyerror ("syntax error"); - } - - - - if (yyerrstatus == 3) - { - /* If just tried and failed to reuse lookahead token after an - error, discard it. */ - - if (yychar <= YYEOF) - { - /* If at end of input, pop the error token, - then the rest of the stack, then return failure. */ - if (yychar == YYEOF) - for (;;) - { - YYPOPSTACK; - if (yyssp == yyss) - YYABORT; - YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp); - yydestruct (yystos[*yyssp], yyvsp); - } - } - else - { - YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc); - yydestruct (yytoken, &yylval); - yychar = YYEMPTY; - - } - } - - /* Else will try to reuse lookahead token after shifting the error - token. */ - goto yyerrlab1; - - -/*---------------------------------------------------. -| yyerrorlab -- error raised explicitly by YYERROR. | -`---------------------------------------------------*/ -yyerrorlab: - -#ifdef __GNUC__ - /* Pacify GCC when the user code never invokes YYERROR and the label - yyerrorlab therefore never appears in user code. */ - if (0) - goto yyerrorlab; -#endif - - yyvsp -= yylen; - yyssp -= yylen; - yystate = *yyssp; - goto yyerrlab1; - - -/*-------------------------------------------------------------. -| yyerrlab1 -- common code for both syntax error and YYERROR. | -`-------------------------------------------------------------*/ -yyerrlab1: - yyerrstatus = 3; /* Each real token shifted decrements this. */ - - for (;;) - { - yyn = yypact[yystate]; - if (yyn != YYPACT_NINF) - { - yyn += YYTERROR; - if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) - { - yyn = yytable[yyn]; - if (0 < yyn) - break; - } - } - - /* Pop the current state because it cannot handle the error token. */ - if (yyssp == yyss) - YYABORT; - - YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp); - yydestruct (yystos[yystate], yyvsp); - YYPOPSTACK; - yystate = *yyssp; - YY_STACK_PRINT (yyss, yyssp); - } - - if (yyn == YYFINAL) - YYACCEPT; - - YYDPRINTF ((stderr, "Shifting error token, ")); - - *++yyvsp = yylval; - - - yystate = yyn; - goto yynewstate; - - -/*-------------------------------------. -| yyacceptlab -- YYACCEPT comes here. | -`-------------------------------------*/ -yyacceptlab: - yyresult = 0; - goto yyreturn; - -/*-----------------------------------. -| yyabortlab -- YYABORT comes here. | -`-----------------------------------*/ -yyabortlab: - yyresult = 1; - goto yyreturn; - -#ifndef yyoverflow -/*----------------------------------------------. -| yyoverflowlab -- parser overflow comes here. | -`----------------------------------------------*/ -yyoverflowlab: - yyerror ("parser stack overflow"); - yyresult = 2; - /* Fall through. */ -#endif - -yyreturn: -#ifndef yyoverflow - if (yyss != yyssa) - YYSTACK_FREE (yyss); -#endif - return yyresult; -} - - -#line 424 "/home/drepper/gnu/elfutils/src/ldscript.y" - - -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 = (struct expression *) - obstack_alloc (&ld_state.smem, sizeof (*newp)); - - newp->tag = tag; - return newp; -} - - -static struct input_section_name * -new_input_section_name (const char *name, bool sort_flag) -{ - struct input_section_name *newp = (struct input_section_name *) - obstack_alloc (&ld_state.smem, sizeof (*newp)); - - newp->name = name; - newp->sort_flag = sort_flag; - return newp; -} - - -static struct input_rule * -new_input_rule (int tag) -{ - struct input_rule *newp = (struct input_rule *) - obstack_alloc (&ld_state.smem, sizeof (*newp)); - - newp->tag = tag; - newp->next = newp; - return newp; -} - - -static struct output_rule * -new_output_rule (int tag) -{ - struct output_rule *newp = (struct output_rule *) - memset (obstack_alloc (&ld_state.smem, sizeof (*newp)), - '\0', sizeof (*newp)); - - newp->tag = tag; - newp->next = newp; - return newp; -} - - -static struct assignment * -new_assignment (const char *variable, struct expression *expression, - bool provide_flag) -{ - struct assignment *newp = (struct assignment *) - obstack_alloc (&ld_state.smem, sizeof (*newp)); - - newp->variable = variable; - newp->expression = expression; - newp->sym = NULL; - newp->provide_flag = 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 - = (struct output_segment *) obstack_alloc (&ld_state.smem, sizeof (*newp)); - newp->mode = mode; - newp->next = newp; - - newp->output_rules = output_rule->next; - output_rule->next = NULL; - - /* Enqueue the output segment description. */ - if (ld_state.output_segments == NULL) - ld_state.output_segments = newp; - else - { - newp->next = ld_state.output_segments->next; - ld_state.output_segments = ld_state.output_segments->next = newp; - } - - /* If the output file should be stripped of all symbol set the flag - in the structures of all output sections. */ - if (mode == 0 && ld_state.strip == strip_all) - { - struct output_rule *runp; - - for (runp = newp->output_rules; runp != NULL; runp = runp->next) - if (runp->tag == output_section) - runp->val.section.ignored = 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 = (struct filename_list *) xcalloc (1, sizeof (*newp)); - newp->name = string; - newp->next = newp; - return newp; -} - - -static void -add_inputfiles (struct filename_list *fnames) -{ - assert (fnames != NULL); - - if (ld_state.srcfiles == NULL) - ld_state.srcfiles = fnames; - else - { - struct filename_list *first = ld_state.srcfiles->next; - - ld_state.srcfiles->next = fnames->next; - fnames->next = first; - ld_state.srcfiles->next = fnames; - } -} - - -static _Bool -special_char_p (const char *str) -{ - while (*str != '\0') - { - if (__builtin_expect (*str == '*', 0) - || __builtin_expect (*str == '?', 0) - || __builtin_expect (*str == '[', 0)) - return true; - - ++str; - } - - return false; -} - - -static struct id_list * -new_id_listelem (const char *str) -{ - struct id_list *newp; - - newp = (struct id_list *) obstack_alloc (&ld_state.smem, sizeof (*newp)); - if (str == NULL) - newp->u.id_type = id_all; - else if (__builtin_expect (special_char_p (str), false)) - newp->u.id_type = id_wild; - else - newp->u.id_type = id_str; - newp->id = str; - newp->next = newp; - - return newp; -} - - -static struct version * -new_version (struct id_list *local, struct id_list *global) -{ - struct version *newp; - - newp = (struct version *) obstack_alloc (&ld_state.smem, sizeof (*newp)); - newp->next = newp; - newp->local_names = local; - newp->global_names = global; - newp->versionname = NULL; - newp->parentname = NULL; - - return newp; -} - - -static struct version * -merge_versions (struct version *one, struct version *two) -{ - assert (two->local_names == NULL || two->global_names == NULL); - - if (two->local_names != NULL) - { - if (one->local_names == NULL) - one->local_names = two->local_names; - else - { - two->local_names->next = one->local_names->next; - one->local_names = one->local_names->next = two->local_names; - } - } - else - { - if (one->global_names == NULL) - one->global_names = two->global_names; - else - { - two->global_names->next = one->global_names->next; - one->global_names = one->global_names->next = two->global_names; - } - } - - return one; -} - - -static void -add_id_list (const char *versionname, struct id_list *runp, _Bool local) -{ - struct id_list *lastp = runp; - - if (runp == NULL) - /* Nothing to do. */ - return; - - /* Convert into a simple single-linked list. */ - runp = runp->next; - assert (runp != NULL); - lastp->next = NULL; - - do - if (runp->u.id_type == id_str) - { - struct id_list *curp; - struct id_list *defp; - unsigned long int hval = elf_hash (runp->id); - - curp = runp; - runp = runp->next; - - defp = ld_version_str_tab_find (&ld_state.version_str_tab, hval, curp); - if (defp != NULL) - { - /* There is already a version definition for this symbol. */ - while (strcmp (defp->u.s.versionname, versionname) != 0) - { - if (defp->next == NULL) - { - /* No version like this so far. */ - defp->next = curp; - curp->u.s.local = local; - curp->u.s.versionname = versionname; - curp->next = NULL; - defp = NULL; - break; - } - - defp = defp->next; - } - - if (defp != NULL && defp->u.s.local != local) - error (EXIT_FAILURE, 0, versionname[0] == '\0' - ? gettext ("\ -symbol '%s' in declared both local and global for unnamed version") - : gettext ("\ -symbol '%s' in 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 = local; - curp->u.s.versionname = versionname; - curp->next = NULL; - } - } - else if (runp->u.id_type == 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 = 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 = true; - } - - runp = runp->next; - } - else - { - assert (runp->u.id_type == id_wild); - /* XXX TBI */ - abort (); - } - while (runp != NULL); -} - - -static void -add_versions (struct version *versions) -{ - struct version *lastp = versions; - - if (versions == NULL) - return; - - /* Convert into a simple single-linked list. */ - versions = versions->next; - assert (versions != NULL); - lastp->next = NULL; - - do - { - struct version *oldp; - - add_id_list (versions->versionname, versions->local_names, true); - add_id_list (versions->versionname, versions->global_names, false); - - oldp = versions; - versions = versions->next; - } - while (versions != NULL); -} - diff --git a/src/ldscript.h b/src/ldscript.h deleted file mode 100644 index 6464d8da..00000000 --- a/src/ldscript.h +++ /dev/null @@ -1,116 +0,0 @@ -/* A Bison parser, made by GNU Bison 1.875c. */ - -/* Skeleton parser for Yacc-like parsing with Bison, - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -/* As a special exception, when this file is copied by Bison into a - Bison output file, you may use that output file without restriction. - This special exception was added by the Free Software Foundation - in version 1.24 of Bison. */ - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - kADD_OP = 258, - kALIGN = 259, - kENTRY = 260, - kEXCLUDE_FILE = 261, - kFILENAME = 262, - kGLOBAL = 263, - kGROUP = 264, - kID = 265, - kINPUT = 266, - kINTERP = 267, - kKEEP = 268, - kLOCAL = 269, - kMODE = 270, - kMUL_OP = 271, - kNUM = 272, - kOUTPUT_FORMAT = 273, - kPAGESIZE = 274, - kPROVIDE = 275, - kSEARCH_DIR = 276, - kSEGMENT = 277, - kSIZEOF_HEADERS = 278, - kSORT = 279, - kVERSION = 280, - kVERSION_SCRIPT = 281, - ADD_OP = 282, - MUL_OP = 283 - }; -#endif -#define kADD_OP 258 -#define kALIGN 259 -#define kENTRY 260 -#define kEXCLUDE_FILE 261 -#define kFILENAME 262 -#define kGLOBAL 263 -#define kGROUP 264 -#define kID 265 -#define kINPUT 266 -#define kINTERP 267 -#define kKEEP 268 -#define kLOCAL 269 -#define kMODE 270 -#define kMUL_OP 271 -#define kNUM 272 -#define kOUTPUT_FORMAT 273 -#define kPAGESIZE 274 -#define kPROVIDE 275 -#define kSEARCH_DIR 276 -#define kSEGMENT 277 -#define kSIZEOF_HEADERS 278 -#define kSORT 279 -#define kVERSION 280 -#define kVERSION_SCRIPT 281 -#define ADD_OP 282 -#define MUL_OP 283 - - - - -#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) -#line 58 "/home/drepper/gnu/elfutils/src/ldscript.y" -typedef union YYSTYPE { - 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; -} YYSTYPE; -/* Line 1275 of yacc.c. */ -#line 108 "ldscript.h" -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 -# define YYSTYPE_IS_TRIVIAL 1 -#endif - -extern YYSTYPE ldlval; - - - diff --git a/src/ldscript.y b/src/ldscript.y deleted file mode 100644 index 8f68078d..00000000 --- a/src/ldscript.y +++ /dev/null @@ -1,764 +0,0 @@ -%{ -/* Parser for linker scripts. - Copyright (C) 2001, 2002, 2003, 2004 Red Hat, Inc. - Written by Ulrich Drepper <drepper@redhat.com>, 2001. - - This program is Open Source software; you can redistribute it and/or - modify it under the terms of the Open Software License version 1.0 as - published by the Open Source Initiative. - - You should have received a copy of the Open Software License along - with this program; if not, you may obtain a copy of the Open Software - License version 1.0 from http://www.opensource.org/licenses/osl.php or - by writing the Open Source Initiative c/o Lawrence Rosen, Esq., - 3001 King Ranch Road, Ukiah, CA 95482. */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <assert.h> -#include <error.h> -#include <libintl.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <system.h> -#include <ld.h> - -/* 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 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 kENTRY -%token kEXCLUDE_FILE -%token <str> kFILENAME -%token kGLOBAL -%token kGROUP -%token <str> kID -%token kINPUT -%token kINTERP -%token kKEEP -%token kLOCAL -%token <num> kMODE -%token kMUL_OP -%token <num> 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 <op> kADD_OP -%type <op> kMUL_OP -%type <str> filename_id -%type <str> filename_id_star -%type <str> exclude_opt -%type <expr> expr -%type <sectionname> sort_opt_name -%type <filemask_section_name> sectionname -%type <input_rule> inputsection -%type <input_rule> inputsections -%type <output_rule> outputsection -%type <output_rule> outputsections -%type <assignment> assignment -%type <filename_list> filename_id_list -%type <version> versionlist -%type <version> version -%type <version> version_stmt_list -%type <version> version_stmt -%type <id_list> 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 == NULL)) - ld_state.entry = $3; - } - | kSEARCH_DIR '(' filename_id ')' ';' - { - ld_new_searchdir ($3); - } - | kPAGESIZE '(' kNUM ')' ';' - { - if (likely (ld_state.pagesize == 0)) - ld_state.pagesize = $3; - } - | kINTERP '(' filename_id ')' ';' - { - if (likely (ld_state.interp == NULL)) - ld_state.interp = $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 != $3->next) - { - $3->next->group_start = 1; - $3->group_end = 1; - } - add_inputfiles ($3); - } - | kINPUT '(' filename_id_list ')' - { add_inputfiles ($3); } - | kVERSION '{' versionlist '}' - { add_versions ($3); } - | kOUTPUT_FORMAT '(' filename_id ')' - { /* XXX TODO */ } - ; - -outputsections: outputsections outputsection - { - $2->next = $1->next; - $$ = $1->next = $2; - } - | outputsection - { $$ = $1; } - ; - -outputsection: assignment ';' - { - $$ = new_output_rule (output_assignment); - $$->val.assignment = $1; - } - | kID '{' inputsections '}' - { - $$ = new_output_rule (output_section); - $$->val.section.name = $1; - $$->val.section.input = $3->next; - if (ld_state.strip == strip_debug - && ebl_debugscn_p (ld_state.ebl, $1)) - $$->val.section.ignored = true; - else - $$->val.section.ignored = false; - $3->next = NULL; - } - | kID ';' - { - /* This is a short cut for "ID { *(ID) }". */ - $$ = new_output_rule (output_section); - $$->val.section.name = $1; - $$->val.section.input = new_input_rule (input_section); - $$->val.section.input->next = NULL; - $$->val.section.input->val.section = - (struct filemask_section_name *) - obstack_alloc (&ld_state.smem, - sizeof (struct filemask_section_name)); - $$->val.section.input->val.section->filemask = NULL; - $$->val.section.input->val.section->excludemask = NULL; - $$->val.section.input->val.section->section_name = - new_input_section_name ($1, false); - $$->val.section.input->val.section->keep_flag = false; - if (ld_state.strip == strip_debug - && ebl_debugscn_p (ld_state.ebl, $1)) - $$->val.section.ignored = true; - else - $$->val.section.ignored = false; - } - ; - -assignment: kID '=' expr - { $$ = new_assignment ($1, $3, false); } - | kPROVIDE '(' kID '=' expr ')' - { $$ = new_assignment ($3, $5, true); } - ; - -inputsections: inputsections inputsection - { - $2->next = $1->next; - $$ = $1->next = $2; - } - | inputsection - { $$ = $1; } - ; - -inputsection: sectionname - { - $$ = new_input_rule (input_section); - $$->val.section = $1; - } - | kKEEP '(' sectionname ')' - { - $3->keep_flag = true; - - $$ = new_input_rule (input_section); - $$->val.section = $3; - } - | assignment ';' - { - $$ = new_input_rule (input_assignment); - $$->val.assignment = $1; - } - ; - -sectionname: filename_id_star '(' exclude_opt sort_opt_name ')' - { - $$ = (struct filemask_section_name *) - obstack_alloc (&ld_state.smem, sizeof (*$$)); - $$->filemask = $1; - $$->excludemask = $3; - $$->section_name = $4; - $$->keep_flag = false; - } - ; - -sort_opt_name: kID - { $$ = new_input_section_name ($1, false); } - | kSORT '(' kID ')' - { $$ = new_input_section_name ($3, true); } - ; - -exclude_opt: kEXCLUDE_FILE '(' filename_id ')' - { $$ = $3; } - | - { $$ = NULL; } - ; - -expr: kALIGN '(' expr ')' - { - $$ = new_expr (exp_align); - $$->val.child = $3; - } - | '(' expr ')' - { $$ = $2; } - | expr '*' expr - { - $$ = new_expr (exp_mult); - $$->val.binary.left = $1; - $$->val.binary.right = $3; - } - | expr kMUL_OP expr - { - $$ = new_expr ($2); - $$->val.binary.left = $1; - $$->val.binary.right = $3; - } - | expr kADD_OP expr - { - $$ = new_expr ($2); - $$->val.binary.left = $1; - $$->val.binary.right = $3; - } - | expr '&' expr - { - $$ = new_expr (exp_and); - $$->val.binary.left = $1; - $$->val.binary.right = $3; - } - | expr '|' expr - { - $$ = new_expr (exp_or); - $$->val.binary.left = $1; - $$->val.binary.right = $3; - } - | kNUM - { - $$ = new_expr (exp_num); - $$->val.num = $1; - } - | kID - { - $$ = new_expr (exp_id); - $$->val.str = $1; - } - | kSIZEOF_HEADERS - { $$ = new_expr (exp_sizeof_headers); } - | kPAGESIZE - { $$ = new_expr (exp_pagesize); } - ; - -filename_id_list: filename_id_list comma_opt filename_id - { - struct filename_list *newp = new_filename_listelem ($3); - newp->next = $1->next; - $$ = $1->next = newp; - } - | filename_id - { $$ = new_filename_listelem ($1); } - ; - -comma_opt: ',' - | - ; - -versionlist: versionlist version - { - $2->next = $1->next; - $$ = $1->next = $2; - } - | version - { $$ = $1; } - ; - -version: '{' version_stmt_list '}' ';' - { - $2->versionname = ""; - $2->parentname = NULL; - $$ = $2; - } - | filename_id '{' version_stmt_list '}' ';' - { - $3->versionname = $1; - $3->parentname = NULL; - $$ = $3; - } - | filename_id '{' version_stmt_list '}' filename_id ';' - { - $3->versionname = $1; - $3->parentname = $5; - $$ = $3; - } - ; - -version_stmt_list: - version_stmt_list version_stmt - { $$ = merge_versions ($1, $2); } - | version_stmt - { $$ = $1; } - ; - -version_stmt: kGLOBAL filename_id_star_list - { $$ = new_version (NULL, $2); } - | kLOCAL filename_id_star_list - { $$ = new_version ($2, NULL); } - ; - -filename_id_star_list: - filename_id_star_list filename_id_star ';' - { - struct id_list *newp = new_id_listelem ($2); - newp->next = $1->next; - $$ = $1->next = newp; - } - | filename_id_star ';' - { $$ = new_id_listelem ($1); } - ; - -filename_id: kFILENAME - { $$ = $1; } - | kID - { $$ = $1; } - ; - -filename_id_star: filename_id - { $$ = $1; } - | '*' - { $$ = 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 = (struct expression *) - obstack_alloc (&ld_state.smem, sizeof (*newp)); - - newp->tag = tag; - return newp; -} - - -static struct input_section_name * -new_input_section_name (const char *name, bool sort_flag) -{ - struct input_section_name *newp = (struct input_section_name *) - obstack_alloc (&ld_state.smem, sizeof (*newp)); - - newp->name = name; - newp->sort_flag = sort_flag; - return newp; -} - - -static struct input_rule * -new_input_rule (int tag) -{ - struct input_rule *newp = (struct input_rule *) - obstack_alloc (&ld_state.smem, sizeof (*newp)); - - newp->tag = tag; - newp->next = newp; - return newp; -} - - -static struct output_rule * -new_output_rule (int tag) -{ - struct output_rule *newp = (struct output_rule *) - memset (obstack_alloc (&ld_state.smem, sizeof (*newp)), - '\0', sizeof (*newp)); - - newp->tag = tag; - newp->next = newp; - return newp; -} - - -static struct assignment * -new_assignment (const char *variable, struct expression *expression, - bool provide_flag) -{ - struct assignment *newp = (struct assignment *) - obstack_alloc (&ld_state.smem, sizeof (*newp)); - - newp->variable = variable; - newp->expression = expression; - newp->sym = NULL; - newp->provide_flag = 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 - = (struct output_segment *) obstack_alloc (&ld_state.smem, sizeof (*newp)); - newp->mode = mode; - newp->next = newp; - - newp->output_rules = output_rule->next; - output_rule->next = NULL; - - /* Enqueue the output segment description. */ - if (ld_state.output_segments == NULL) - ld_state.output_segments = newp; - else - { - newp->next = ld_state.output_segments->next; - ld_state.output_segments = ld_state.output_segments->next = newp; - } - - /* If the output file should be stripped of all symbol set the flag - in the structures of all output sections. */ - if (mode == 0 && ld_state.strip == strip_all) - { - struct output_rule *runp; - - for (runp = newp->output_rules; runp != NULL; runp = runp->next) - if (runp->tag == output_section) - runp->val.section.ignored = 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 = (struct filename_list *) xcalloc (1, sizeof (*newp)); - newp->name = string; - newp->next = newp; - return newp; -} - - -static void -add_inputfiles (struct filename_list *fnames) -{ - assert (fnames != NULL); - - if (ld_state.srcfiles == NULL) - ld_state.srcfiles = fnames; - else - { - struct filename_list *first = ld_state.srcfiles->next; - - ld_state.srcfiles->next = fnames->next; - fnames->next = first; - ld_state.srcfiles->next = fnames; - } -} - - -static _Bool -special_char_p (const char *str) -{ - while (*str != '\0') - { - if (__builtin_expect (*str == '*', 0) - || __builtin_expect (*str == '?', 0) - || __builtin_expect (*str == '[', 0)) - return true; - - ++str; - } - - return false; -} - - -static struct id_list * -new_id_listelem (const char *str) -{ - struct id_list *newp; - - newp = (struct id_list *) obstack_alloc (&ld_state.smem, sizeof (*newp)); - if (str == NULL) - newp->u.id_type = id_all; - else if (__builtin_expect (special_char_p (str), false)) - newp->u.id_type = id_wild; - else - newp->u.id_type = id_str; - newp->id = str; - newp->next = newp; - - return newp; -} - - -static struct version * -new_version (struct id_list *local, struct id_list *global) -{ - struct version *newp; - - newp = (struct version *) obstack_alloc (&ld_state.smem, sizeof (*newp)); - newp->next = newp; - newp->local_names = local; - newp->global_names = global; - newp->versionname = NULL; - newp->parentname = NULL; - - return newp; -} - - -static struct version * -merge_versions (struct version *one, struct version *two) -{ - assert (two->local_names == NULL || two->global_names == NULL); - - if (two->local_names != NULL) - { - if (one->local_names == NULL) - one->local_names = two->local_names; - else - { - two->local_names->next = one->local_names->next; - one->local_names = one->local_names->next = two->local_names; - } - } - else - { - if (one->global_names == NULL) - one->global_names = two->global_names; - else - { - two->global_names->next = one->global_names->next; - one->global_names = one->global_names->next = two->global_names; - } - } - - return one; -} - - -static void -add_id_list (const char *versionname, struct id_list *runp, _Bool local) -{ - struct id_list *lastp = runp; - - if (runp == NULL) - /* Nothing to do. */ - return; - - /* Convert into a simple single-linked list. */ - runp = runp->next; - assert (runp != NULL); - lastp->next = NULL; - - do - if (runp->u.id_type == id_str) - { - struct id_list *curp; - struct id_list *defp; - unsigned long int hval = elf_hash (runp->id); - - curp = runp; - runp = runp->next; - - defp = ld_version_str_tab_find (&ld_state.version_str_tab, hval, curp); - if (defp != NULL) - { - /* There is already a version definition for this symbol. */ - while (strcmp (defp->u.s.versionname, versionname) != 0) - { - if (defp->next == NULL) - { - /* No version like this so far. */ - defp->next = curp; - curp->u.s.local = local; - curp->u.s.versionname = versionname; - curp->next = NULL; - defp = NULL; - break; - } - - defp = defp->next; - } - - if (defp != NULL && defp->u.s.local != local) - error (EXIT_FAILURE, 0, versionname[0] == '\0' - ? gettext ("\ -symbol '%s' in declared both local and global for unnamed version") - : gettext ("\ -symbol '%s' in 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 = local; - curp->u.s.versionname = versionname; - curp->next = NULL; - } - } - else if (runp->u.id_type == 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 = 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 = true; - } - - runp = runp->next; - } - else - { - assert (runp->u.id_type == id_wild); - /* XXX TBI */ - abort (); - } - while (runp != NULL); -} - - -static void -add_versions (struct version *versions) -{ - struct version *lastp = versions; - - if (versions == NULL) - return; - - /* Convert into a simple single-linked list. */ - versions = versions->next; - assert (versions != NULL); - lastp->next = NULL; - - do - { - struct version *oldp; - - add_id_list (versions->versionname, versions->local_names, true); - add_id_list (versions->versionname, versions->global_names, false); - - oldp = versions; - versions = versions->next; - } - while (versions != NULL); -} diff --git a/src/libld_elf_i386.map b/src/libld_elf_i386.map deleted file mode 100644 index 703af6d8..00000000 --- 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/nm.c b/src/nm.c deleted file mode 100644 index 1a297054..00000000 --- a/src/nm.c +++ /dev/null @@ -1,1302 +0,0 @@ -/* Print information from ELF file in human-readable form. - Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc. - Written by Ulrich Drepper <drepper@redhat.com>, 2000. - - This program is Open Source software; you can redistribute it and/or - modify it under the terms of the Open Software License version 1.0 as - published by the Open Source Initiative. - - You should have received a copy of the Open Software License along - with this program; if not, you may obtain a copy of the Open Software - License version 1.0 from http://www.opensource.org/licenses/osl.php or - by writing the Open Source Initiative c/o Lawrence Rosen, Esq., - 3001 King Ranch Road, Ukiah, CA 95482. */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <ar.h> -#include <argp.h> -#include <assert.h> -#include <ctype.h> -#include <dwarf.h> -#include <errno.h> -#include <error.h> -#include <fcntl.h> -#include <gelf.h> -#include <inttypes.h> -#include <libdw.h> -#include <libebl.h> -#include <libintl.h> -#include <locale.h> -#include <mcheck.h> -#include <obstack.h> -#include <search.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdio_ext.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <sys/param.h> - -#include <system.h> - - -/* Name and version of program. */ -static void print_version (FILE *stream, struct argp_state *state); -void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; - - -/* Values for the parameters which have no short form. */ -#define OPT_DEFINED 0x100 -#define OPT_MARK_WEAK 0x101 - -/* Definitions of arguments for argp functions. */ -static const struct argp_option options[] = -{ - { NULL, 0, NULL, 0, N_("Output selection:"), 0 }, - { "debug-syms", 'a', NULL, 0, N_("Display debugger-only symbols"), 0 }, - { "defined-only", OPT_DEFINED, NULL, 0, N_("Display only defined symbols"), - 0 }, - { "dynamic", 'D', NULL, 0, - N_("Display dynamic symbols instead of normal symbols"), 0 }, - { "extern-only", 'g', NULL, 0, N_("Display only external symbols"), 0 }, - { "undefined-only", 'u', NULL, 0, N_("Display only undefined symbols"), 0 }, - { "print-armap", 's', NULL, 0, - N_("Include index for symbols from archive members"), 0 }, - - { NULL, 0, NULL, 0, N_("Output format:"), 0 }, - { "print-file-name", 'A', NULL, 0, - N_("Print name of the input file before every symbol"), 0 }, - { NULL, 'o', NULL, OPTION_HIDDEN, "Same as -A", 0 }, - { "format", 'f', "FORMAT", 0, - N_("Use the output format FORMAT. FORMAT can be `bsd', `sysv' or `posix'. The default is `sysv'"), - 0 }, - { NULL, 'B', NULL, 0, N_("Same as --format=bsd"), 0 }, - { "portability", 'P', NULL, 0, N_("Same as --format=posix"), 0 }, - { "radix", 't', "RADIX", 0, N_("Use RADIX for printing symbol values"), 0 }, - { "mark-weak", OPT_MARK_WEAK, NULL, 0, N_("Mark weak symbols"), 0 }, - { "print-size", 'S', NULL, 0, N_("Print size of defined symbols"), 0 }, - - { NULL, 0, NULL, 0, N_("Output options:"), 0 }, - { "numeric-sort", 'n', NULL, 0, N_("Sort symbols numerically by address"), - 0 }, - { "no-sort", 'p', NULL, 0, N_("Do not sort the symbols"), 0 }, - { "reverse-sort", 'r', NULL, 0, N_("Reverse the sense of the sort"), 0 }, - { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 }, - { NULL, 0, NULL, 0, NULL, 0 } -}; - -/* Short description of program. */ -static const char doc[] = N_("List symbols from FILEs (a.out by default)."); - -/* Strings for arguments in help texts. */ -static const char args_doc[] = N_("[FILE...]"); - -/* Prototype for option handler. */ -static error_t parse_opt (int key, char *arg, struct argp_state *state); - -/* Function to print some extra text in the help message. */ -static char *more_help (int key, const char *text, void *input); - -/* Data structure to communicate with argp functions. */ -static struct argp argp = -{ - options, parse_opt, args_doc, doc, NULL, more_help, NULL -}; - - -/* Print symbols in file named FNAME. */ -static int process_file (const char *fname, bool more_than_one); - -/* Handle content of archive. */ -static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname, - const char *suffix); - -/* Handle ELF file. */ -static int handle_elf (Elf *elf, const char *prefix, const char *fname, - const char *suffix); - - -#define INTERNAL_ERROR(fname) \ - error (EXIT_FAILURE, 0, gettext ("%s: INTERNAL ERROR %d (%s-%s): %s"), \ - fname, __LINE__, VERSION, __DATE__, elf_errmsg (-1)) - - -/* Internal representation of symbols. */ -typedef struct GElf_SymX -{ - GElf_Sym sym; - Elf32_Word xndx; - char *where; -} GElf_SymX; - - -/* User-selectable options. */ - -/* The selected output format. */ -static enum -{ - format_sysv = 0, - format_bsd, - format_posix -} format; - -/* Print defined, undefined, or both? */ -static bool hide_undefined; -static bool hide_defined; - -/* Print local symbols also? */ -static bool hide_local; - -/* Nonzero if full filename should precede every symbol. */ -static bool print_file_name; - -/* If true print size of defined symbols in BSD format. */ -static bool print_size; - -/* If true print archive index. */ -static bool print_armap; - -/* If true reverse sorting. */ -static bool reverse_sort; - -/* Type of the section we are printing. */ -static GElf_Word symsec_type = SHT_SYMTAB; - -/* Sorting selection. */ -static enum -{ - sort_name = 0, - sort_numeric, - sort_nosort -} sort; - -/* Radix for printed numbers. */ -static enum -{ - radix_hex = 0, - radix_decimal, - radix_octal -} radix; - -/* If nonzero weak symbols are distinguished from global symbols by adding - a `*' after the identifying letter for the symbol class and type. */ -static bool mark_weak; - - -int -main (int argc, char *argv[]) -{ - int remaining; - int result = 0; - - /* Make memory leak detection possible. */ - mtrace (); - - /* We use no threads here which can interfere with handling a stream. */ - (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER); - (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER); - (void) __fsetlocking (stderr, FSETLOCKING_BYCALLER); - - /* Set locale. */ - (void) setlocale (LC_ALL, ""); - - /* Make sure the message catalog can be found. */ - (void) bindtextdomain (PACKAGE, LOCALEDIR); - - /* Initialize the message catalog. */ - (void) textdomain (PACKAGE); - - /* Parse and process arguments. */ - (void) argp_parse (&argp, argc, argv, 0, &remaining, NULL); - - /* Tell the library which version we are expecting. */ - (void) elf_version (EV_CURRENT); - - if (remaining == argc) - /* The user didn't specify a name so we use a.out. */ - result = process_file ("a.out", false); - else - { - /* Process all the remaining files. */ - const bool more_than_one = remaining + 1 < argc; - - do - result |= process_file (argv[remaining], more_than_one); - while (++remaining < argc); - } - - return result; -} - - -/* Print the version information. */ -static void -print_version (FILE *stream, /*@unused@*/ struct argp_state *state) -{ - fprintf (stream, "nm (%s) %s\n", PACKAGE_NAME, 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\ -"), "2004"); - fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); -} - - -/* Handle program arguments. */ -static error_t -parse_opt (int key, char *arg, /*@unused@*/ struct argp_state *state) -{ - switch (key) - { - case 'a': - /* XXX */ - break; - - case 'f': - if (strcmp (arg, "bsd") == 0) - format = format_bsd; - else if (strcmp (arg, "posix") == 0) - format = format_posix; - else - /* Be bug compatible. The BFD implementation also defaulted to - using the SysV format if nothing else matches. */ - format = format_sysv; - break; - - case 'g': - hide_local = true; - break; - - case 'n': - sort = sort_numeric; - break; - - case 'p': - sort = sort_nosort; - break; - - case 't': - if (strcmp (arg, "10") == 0 || strcmp (arg, "d") == 0) - radix = radix_decimal; - else if (strcmp (arg, "8") == 0 || strcmp (arg, "o") == 0) - radix = radix_octal; - else - radix = radix_hex; - break; - - case 'u': - hide_undefined = false; - hide_defined = true; - break; - - case 'A': - case 'o': - print_file_name = true; - break; - - case 'B': - format = format_bsd; - break; - - case 'D': - symsec_type = SHT_DYNSYM; - break; - - case 'P': - format = format_posix; - break; - - case OPT_DEFINED: - hide_undefined = true; - hide_defined = false; - break; - - case OPT_MARK_WEAK: - mark_weak = true; - break; - - case 'S': - print_size = true; - break; - - case 's': - print_armap = true; - break; - - case 'r': - reverse_sort = true; - break; - - default: - return ARGP_ERR_UNKNOWN; - } - return 0; -} - - -static char * -more_help (int key, const char *text, /*@unused@*/ void *input) -{ - char *buf; - - switch (key) - { - case ARGP_KEY_HELP_EXTRA: - /* We print some extra information. */ - if (asprintf (&buf, gettext ("Please report bugs to %s.\n"), - PACKAGE_BUGREPORT) < 0) - buf = NULL; - return buf; - - default: - break; - } - return (char *) text; -} - - -/* Open the file and determine the type. */ -static int -process_file (const char *fname, bool more_than_one) -{ - /* Open the file. */ - int fd = open (fname, O_RDONLY); - if (fd == -1) - { - error (0, errno, fname); - return 1; - } - - /* Now get the ELF descriptor. */ - Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL); - if (elf != NULL) - { - if (elf_kind (elf) == ELF_K_ELF) - { - int result = handle_elf (elf, more_than_one ? "" : NULL, - fname, NULL); - - if (elf_end (elf) != 0) - INTERNAL_ERROR (fname); - - if (close (fd) != 0) - error (EXIT_FAILURE, errno, gettext ("while close `%s'"), fname); - - return result; - } - else if (elf_kind (elf) == ELF_K_AR) - { - int result = handle_ar (fd, elf, NULL, fname, NULL); - - if (elf_end (elf) != 0) - INTERNAL_ERROR (fname); - - if (close (fd) != 0) - error (EXIT_FAILURE, errno, gettext ("while close `%s'"), fname); - - return result; - } - - /* We cannot handle this type. Close the descriptor anyway. */ - if (elf_end (elf) != 0) - INTERNAL_ERROR (fname); - } - - error (0, 0, gettext ("%s: File format not recognized"), fname); - - return 1; -} - - -static int -handle_ar (int fd, Elf *elf, const char *prefix, const char *fname, - const char *suffix) -{ - size_t fname_len = strlen (fname) + 1; - size_t prefix_len = prefix != NULL ? strlen (prefix) : 0; - char new_prefix[prefix_len + fname_len + 2]; - size_t suffix_len = suffix != NULL ? strlen (suffix) : 0; - char new_suffix[suffix_len + 2]; - Elf *subelf; - Elf_Cmd cmd = ELF_C_READ_MMAP; - int result = 0; - - char *cp = new_prefix; - if (prefix != NULL) - cp = stpcpy (cp, prefix); - cp = stpcpy (cp, fname); - stpcpy (cp, "["); - - cp = new_suffix; - if (suffix != NULL) - cp = stpcpy (cp, suffix); - stpcpy (cp, "]"); - - /* First print the archive index if this is wanted. */ - if (print_armap) - { - Elf_Arsym *arsym = elf_getarsym (elf, NULL); - - if (arsym != NULL) - { - Elf_Arhdr *arhdr = NULL; - size_t arhdr_off = 0; /* Note: 0 is no valid offset. */ - - puts (gettext("\nArchive index:")); - - while (arsym->as_off != 0) - { - if (arhdr_off != arsym->as_off - && (elf_rand (elf, arsym->as_off) != arsym->as_off - || (subelf = elf_begin (fd, cmd, elf)) == NULL - || (arhdr = elf_getarhdr (subelf)) == NULL)) - { - error (0, 0, gettext ("invalid offset %zu for symbol %s"), - arsym->as_off, arsym->as_name); - continue; - } - - printf (gettext ("%s in %s\n"), arsym->as_name, arhdr->ar_name); - - ++arsym; - } - - if (elf_rand (elf, SARMAG) != SARMAG) - { - error (0, 0, - gettext ("cannot reset archive offset to beginning")); - return 1; - } - } - } - - /* Process all the files contained in the archive. */ - while ((subelf = elf_begin (fd, cmd, elf)) != NULL) - { - /* The the header for this element. */ - Elf_Arhdr *arhdr = elf_getarhdr (subelf); - - /* Skip over the index entries. */ - if (strcmp (arhdr->ar_name, "/") != 0 - && strcmp (arhdr->ar_name, "//") != 0) - { - if (elf_kind (subelf) == ELF_K_ELF) - result |= handle_elf (subelf, new_prefix, arhdr->ar_name, - new_suffix); - else if (elf_kind (subelf) == ELF_K_AR) - result |= handle_ar (fd, subelf, new_prefix, arhdr->ar_name, - new_suffix); - else - { - error (0, 0, gettext ("%s%s%s: file format not recognized"), - new_prefix, arhdr->ar_name, new_suffix); - result = 1; - } - } - - /* Get next archive element. */ - cmd = elf_next (subelf); - if (elf_end (subelf) != 0) - INTERNAL_ERROR (fname); - } - - return result; -} - - -/* Mapping of radix and binary class to length. */ -static const int length_map[2][3] = -{ - [ELFCLASS32 - 1] = - { - [radix_hex] = 8, - [radix_decimal] = 10, - [radix_octal] = 11 - }, - [ELFCLASS64 - 1] = - { - [radix_hex] = 16, - [radix_decimal] = 20, - [radix_octal] = 22 - } -}; - - -struct global_name -{ - Dwarf_Global global; - const char *name; -}; - - -static int -global_compare (const void *p1, const void *p2) -{ - const Dwarf_Global *g1 = (const Dwarf_Global *) p1; - const Dwarf_Global *g2 = (const Dwarf_Global *) p2; - - return strcmp (g1->name, g2->name); -} - - -static void *global_root; - - -static int -get_global (Dwarf *dbg, Dwarf_Global *global, void *arg) -{ - tsearch (memcpy (xmalloc (sizeof (Dwarf_Global)), global, - sizeof (Dwarf_Global)), - &global_root, global_compare); - - return DWARF_CB_OK; -} - - -struct local_name -{ - const char *name; - const char *file; - Dwarf_Word lineno; - Dwarf_Addr lowpc; - Dwarf_Addr highpc; -}; - - -static int -local_compare (const void *p1, const void *p2) -{ - struct local_name *g1 = (struct local_name *) p1; - struct local_name *g2 = (struct local_name *) p2; - int result; - - result = strcmp (g1->name, g2->name); - if (result == 0) - { - if (g1->lowpc <= g2->lowpc && g1->highpc >= g2->highpc) - { - /* g2 is contained in g1. Update the data. */ - g2->lowpc = g1->lowpc; - g2->highpc = g1->highpc; - result = 0; - } - else if (g2->lowpc <= g1->lowpc && g2->highpc >= g1->highpc) - { - /* g1 is contained in g2. Update the data. */ - g1->lowpc = g2->lowpc; - g1->highpc = g2->highpc; - result = 0; - } - else - result = g1->lowpc < g2->lowpc ? -1 : 1; - } - - return result; -} - - -static int -get_var_range (Dwarf_Die *die, Dwarf_Word *lowpc, Dwarf_Word *highpc) -{ - Dwarf_Attribute locattr_mem; - Dwarf_Attribute *locattr = dwarf_attr (die, DW_AT_location, &locattr_mem); - if (locattr == NULL) - return 1; - - Dwarf_Loc *loc; - size_t nloc; - if (dwarf_getloclist (locattr, &loc, &nloc) != 0) - return 1; - - /* Interpret the location expressions. */ - // XXX For now just the simple one: - if (nloc == 1 && loc[0].atom == DW_OP_addr) - { - *lowpc = *highpc = loc[0].number; - return 0; - } - - return 1; -} - - - -static void *local_root; - - -static void -get_local_names (Ebl *ebl, Dwarf *dbg) -{ - Dwarf_Off offset = 0; - Dwarf_Off old_offset; - size_t hsize; - - while (dwarf_nextcu (dbg, old_offset = offset, &offset, &hsize, NULL, NULL, - NULL) == 0) - { - Dwarf_Die cudie_mem; - Dwarf_Die *cudie = dwarf_offdie (dbg, old_offset + hsize, &cudie_mem); - - /* If we cannot get the CU DIE there is no need to go on with - this CU. */ - if (cudie == NULL) - continue; - /* This better be a CU DIE. */ - if (dwarf_tag (cudie) != DW_TAG_compile_unit) - continue; - - /* Get the line information. */ - Dwarf_Files *files; - size_t nfiles; - if (dwarf_getsrcfiles (cudie, &files, &nfiles) != 0) - continue; - - Dwarf_Die die_mem; - Dwarf_Die *die = &die_mem; - if (dwarf_child (cudie, die) == 0) - /* Iterate over all immediate children of the CU DIE. */ - do - { - int tag = dwarf_tag (die); - if (tag != DW_TAG_subprogram && tag != DW_TAG_variable) - continue; - - /* We are interested in five attributes: name, decl_file, - decl_line, low_pc, and high_pc. */ - Dwarf_Attribute attr_mem; - Dwarf_Attribute *attr = dwarf_attr (die, DW_AT_name, &attr_mem); - const char *name = dwarf_formstring (attr); - if (name == NULL) - continue; - - Dwarf_Word fileidx; - attr = dwarf_attr (die, DW_AT_decl_file, &attr_mem); - if (dwarf_formudata (attr, &fileidx) != 0 || fileidx >= nfiles) - continue; - - Dwarf_Word lineno; - attr = dwarf_attr (die, DW_AT_decl_line, &attr_mem); - if (dwarf_formudata (attr, &lineno) != 0 || lineno == 0) - continue; - - Dwarf_Addr lowpc; - Dwarf_Addr highpc; - if (tag == DW_TAG_subprogram) - { - if (dwarf_lowpc (die, &lowpc) != 0 - || dwarf_highpc (die, &highpc) != 0) - continue; - } - else - { - if (get_var_range (die, &lowpc, &highpc) != 0) - continue; - } - - /* We have all the information. Create a record. */ - struct local_name *newp - = (struct local_name *) xmalloc (sizeof (*newp)); - newp->name = name; - newp->file = dwarf_filesrc (files, fileidx, NULL, NULL); - newp->lineno = lineno; - newp->lowpc = lowpc; - newp->highpc = highpc; - - /* Since we cannot deallocate individual memory we do not test - for duplicates in the tree. This should not happen anyway. */ - if (tsearch (newp, &local_root, local_compare) == NULL) - error (EXIT_FAILURE, errno, - gettext ("cannot create search tree")); - } - while (dwarf_siblingof (die, die) == 0); - } -} - - -/* Show symbols in SysV format. */ -static void -show_symbols_sysv (Ebl *ebl, GElf_Word strndx, - const char *prefix, const char *fname, const char *fullname, - GElf_SymX *syms, size_t nsyms, int longest_name, - int longest_where) -{ - size_t shnum; - if (elf_getshnum (ebl->elf, &shnum) < 0) - INTERNAL_ERROR (fullname); - - bool scnnames_malloced = shnum * sizeof (const char *) > 128 * 1024; - const char **scnnames; - if (scnnames_malloced) - scnnames = (const char **) xmalloc (sizeof (const char *) * shnum); - else - scnnames = (const char **) alloca (sizeof (const char *) * shnum); - /* Get the section header string table index. */ - size_t shstrndx; - if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) - error (EXIT_FAILURE, 0, - gettext ("cannot get section header string table index")); - - /* Cache the section names. */ - Elf_Scn *scn = NULL; - size_t cnt = 1; - while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) - { - GElf_Shdr shdr_mem; - - assert (elf_ndxscn (scn) == cnt++); - - scnnames[elf_ndxscn (scn)] - = elf_strptr (ebl->elf, shstrndx, - gelf_getshdr (scn, &shdr_mem)->sh_name); - } - - int digits = length_map[gelf_getclass (ebl->elf) - 1][radix]; - - /* We always print this prolog. */ - if (prefix == NULL || 1) - printf (gettext ("\n\nSymbols from %s:\n\n"), fullname); - else - printf (gettext ("\n\nSymbols from %s[%s]:\n\n"), prefix, fname); - - /* The header line. */ - printf (gettext ("%*s%-*s %-*s Class Type %-*s %*s Section\n\n"), - print_file_name ? (int) strlen (fullname) + 1: 0, "", - longest_name, sgettext ("sysv|Name"), - /* TRANS: the "sysv|" parts makes the string unique. */ - digits, sgettext ("sysv|Value"), - /* TRANS: the "sysv|" parts makes the string unique. */ - digits, sgettext ("sysv|Size"), - /* TRANS: the "sysv|" parts makes the string unique. */ - longest_where, sgettext ("sysv|Line")); - - /* Which format string to use (different radix for numbers). */ - const char *fmtstr; - if (radix == radix_hex) - fmtstr = "%-*s|%0*" PRIx64 "|%-6s|%-8s|%*" PRIx64 "|%*s|%s\n"; - else if (radix == radix_decimal) - fmtstr = "%-*s|%*" PRId64 "|%-6s|%-8s|%*" PRId64 "|%*s|%s\n"; - else - fmtstr = "%-*s|%0*" PRIo64 "|%-6s|%-8s|%*" PRIo64 "|%*s|%s\n"; - - /* Iterate over all symbols. */ - for (cnt = 0; cnt < nsyms; ++cnt) - { - const char *symstr = elf_strptr (ebl->elf, strndx, - syms[cnt].sym.st_name); - char symbindbuf[50]; - char symtypebuf[50]; - char secnamebuf[1024]; - - /* If we have to precede the line with the file name. */ - if (print_file_name) - { - fputs_unlocked (fullname, stdout); - putchar_unlocked (':'); - } - - /* Print the actual string. */ - printf (fmtstr, - longest_name, symstr, - digits, syms[cnt].sym.st_value, - ebl_symbol_binding_name (ebl, - GELF_ST_BIND (syms[cnt].sym.st_info), - symbindbuf, sizeof (symbindbuf)), - ebl_symbol_type_name (ebl, GELF_ST_TYPE (syms[cnt].sym.st_info), - symtypebuf, sizeof (symtypebuf)), - digits, syms[cnt].sym.st_size, longest_where, syms[cnt].where, - ebl_section_name (ebl, syms[cnt].sym.st_shndx, syms[cnt].xndx, - secnamebuf, sizeof (secnamebuf), scnnames, - shnum)); - } - - if (scnnames_malloced) - free (scnnames); -} - - -static char -class_type_char (GElf_Sym *sym) -{ - int local_p = GELF_ST_BIND (sym->st_info) == STB_LOCAL; - - /* XXX Add support for architecture specific types and classes. */ - if (sym->st_shndx == SHN_ABS) - return local_p ? 'a' : 'A'; - - if (sym->st_shndx == SHN_UNDEF) - /* Undefined symbols must be global. */ - return 'U'; - - char result = "NDTSFB "[GELF_ST_TYPE (sym->st_info)]; - - return local_p ? tolower (result) : result; -} - - -static void -show_symbols_bsd (Elf *elf, GElf_Ehdr *ehdr, GElf_Word strndx, - const char *prefix, const char *fname, const char *fullname, - GElf_SymX *syms, size_t nsyms) -{ - int digits = length_map[gelf_getclass (elf) - 1][radix]; - - if (prefix != NULL && ! print_file_name) - printf ("\n%s:\n", fname); - - static const char *const fmtstrs[] = - { - [radix_hex] = "%0*" PRIx64 " %c%s %s\n", - [radix_decimal] = "%*" PRId64 " %c%s %s\n", - [radix_octal] = "%0*" PRIo64 " %c%s %s\n" - }; - static const char *const sfmtstrs[] = - { - [radix_hex] = "%2$0*1$" PRIx64 " %7$0*6$" PRIx64 " %3$c%4$s %5$s\n", - [radix_decimal] = "%2$*1$" PRId64 " %7$*6$" PRId64 " %3$c%4$s %5$s\n", - [radix_octal] = "%2$0*1$" PRIo64 " %7$0*6$" PRIo64 " %3$c%4$s %5$s\n" - }; - - /* Iterate over all symbols. */ - for (size_t cnt = 0; cnt < nsyms; ++cnt) - { - const char *symstr = elf_strptr (elf, strndx, syms[cnt].sym.st_name); - - /* Printing entries with a zero-length name makes the output - not very well parseable. Since these entries don't carry - much information we leave them out. */ - if (symstr[0] == '\0') - continue; - - /* If we have to precede the line with the file name. */ - if (print_file_name) - { - fputs_unlocked (fullname, stdout); - putchar_unlocked (':'); - } - - if (syms[cnt].sym.st_shndx == SHN_UNDEF) - printf ("%*s U%s %s\n", - digits, "", - mark_weak - ? (GELF_ST_BIND (syms[cnt].sym.st_info) == STB_WEAK - ? "*" : " ") - : "", - elf_strptr (elf, strndx, syms[cnt].sym.st_name)); - else - printf (print_size ? sfmtstrs[radix] : fmtstrs[radix], - digits, syms[cnt].sym.st_value, - class_type_char (&syms[cnt].sym), - mark_weak - ? (GELF_ST_BIND (syms[cnt].sym.st_info) == STB_WEAK - ? "*" : " ") - : "", - elf_strptr (elf, strndx, syms[cnt].sym.st_name), - digits, (uint64_t) syms[cnt].sym.st_size); - } -} - - -static void -show_symbols_posix (Elf *elf, GElf_Ehdr *ehdr, GElf_Word strndx, - const char *prefix, const char *fname, - const char *fullname, GElf_SymX *syms, size_t nsyms) -{ - if (prefix != NULL && ! print_file_name) - printf ("%s:\n", fullname); - - const char *fmtstr; - if (radix == radix_hex) - fmtstr = "%s %c%s %0*" PRIx64 " %0*" PRIx64 "\n"; - else if (radix == radix_decimal) - fmtstr = "%s %c%s %*" PRId64 " %*" PRId64 "\n"; - else - fmtstr = "%s %c%s %0*" PRIo64 " %0*" PRIo64 "\n"; - - int digits = length_map[gelf_getclass (elf) - 1][radix]; - - /* Iterate over all symbols. */ - for (size_t cnt = 0; cnt < nsyms; ++cnt) - { - const char *symstr = elf_strptr (elf, strndx, syms[cnt].sym.st_name); - - /* Printing entries with a zero-length name makes the output - not very well parseable. Since these entries don't carry - much information we leave them out. */ - if (symstr[0] == '\0') - continue; - - /* If we have to precede the line with the file name. */ - if (print_file_name) - { - fputs_unlocked (fullname, stdout); - putchar_unlocked (':'); - putchar_unlocked (' '); - } - - printf (fmtstr, - symstr, - class_type_char (&syms[cnt].sym), - mark_weak - ? (GELF_ST_BIND (syms[cnt].sym.st_info) == STB_WEAK ? "*" : " ") - : "", - digits, syms[cnt].sym.st_value, - digits, syms[cnt].sym.st_size); - } -} - - -/* Maximum size of memory we allocate on the stack. */ -#define MAX_STACK_ALLOC 65536 - -static void -show_symbols (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, Elf_Scn *xndxscn, - GElf_Shdr *shdr, const char *prefix, const char *fname, - const char *fullname) -{ - int sort_by_name (const void *p1, const void *p2) - { - GElf_SymX *s1 = (GElf_SymX *) p1; - GElf_SymX *s2 = (GElf_SymX *) p2; - int result; - - result = strcmp (elf_strptr (ebl->elf, shdr->sh_link, s1->sym.st_name), - elf_strptr (ebl->elf, shdr->sh_link, s2->sym.st_name)); - - return reverse_sort ? -result : result; - } - - int sort_by_address (const void *p1, const void *p2) - { - GElf_SymX *s1 = (GElf_SymX *) p1; - GElf_SymX *s2 = (GElf_SymX *) p2; - - int result = (s1->sym.st_value < s2->sym.st_value - ? -1 : (s1->sym.st_value == s2->sym.st_value ? 0 : 1)); - - return reverse_sort ? -result : result; - } - - /* Get the section header string table index. */ - size_t shstrndx; - if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) - error (EXIT_FAILURE, 0, - gettext ("cannot get section header string table index")); - - /* The section is that large. */ - size_t size = shdr->sh_size; - /* One entry is this large. */ - size_t entsize = shdr->sh_entsize; - - /* Consistency checks. */ - if (entsize != gelf_fsize (ebl->elf, ELF_T_SYM, 1, ehdr->e_version)) - error (0, 0, - gettext ("%s: entry size in section `%s' is not what we expect"), - fullname, elf_strptr (ebl->elf, shstrndx, shdr->sh_name)); - else if (size % entsize != 0) - error (0, 0, - gettext ("%s: size of section `%s' is not multiple of entry size"), - fullname, elf_strptr (ebl->elf, shstrndx, shdr->sh_name)); - - /* Compute number of entries. Handle buggy entsize values. */ - size_t nentries = size / (entsize ?: 1); - - -#define obstack_chunk_alloc xmalloc -#define obstack_chunk_free free - struct obstack whereob; - obstack_init (&whereob); - - /* Get a DWARF debugging descriptor. It's no problem if this isn't - possible. We just won't print any line number information. */ - Dwarf *dbg = NULL; - if (format == format_sysv) - { - dbg = dwarf_begin_elf (ebl->elf, DWARF_C_READ, NULL); - if (dbg != NULL) - { - (void) dwarf_getpubnames (dbg, get_global, NULL, 0); - - get_local_names (ebl, dbg); - } - } - - /* Allocate the memory. - - XXX We can use a dirty trick here. Since GElf_Sym == Elf64_Sym we - can use the data memory instead of copying again if what we read - is a 64 bit file. */ - GElf_SymX *sym_mem; - if (nentries * sizeof (GElf_SymX) < MAX_STACK_ALLOC) - sym_mem = (GElf_SymX *) alloca (nentries * sizeof (GElf_SymX)); - else - sym_mem = (GElf_SymX *) xmalloc (nentries * sizeof (GElf_SymX)); - - /* Get the data of the section. */ - Elf_Data *data = elf_getdata (scn, NULL); - Elf_Data *xndxdata = elf_getdata (xndxscn, NULL); - if (data == NULL || (xndxscn != NULL && xndxdata == NULL)) - INTERNAL_ERROR (fullname); - - /* Iterate over all symbols. */ - int longest_name = 4; - int longest_where = 4; - size_t nentries_used = 0; - for (size_t cnt = 0; cnt < nentries; ++cnt) - { - GElf_Sym *sym = gelf_getsymshndx (data, xndxdata, cnt, - &sym_mem[nentries_used].sym, - &sym_mem[nentries_used].xndx); - if (sym == NULL) - INTERNAL_ERROR (fullname); - - /* Filter out administrative symbols without a name and those - deselected by ther user with command line options. */ - if ((hide_undefined && sym->st_shndx == SHN_UNDEF) - || (hide_defined && sym->st_shndx != SHN_UNDEF) - || (hide_local && GELF_ST_BIND (sym->st_info) == STB_LOCAL)) - continue; - - sym_mem[nentries_used].where = ""; - if (format == format_sysv) - { - const char *symstr = elf_strptr (ebl->elf, shdr->sh_link, - sym->st_name); - - longest_name = MAX ((size_t) longest_name, strlen (symstr)); - - if (sym->st_shndx != SHN_UNDEF - && GELF_ST_BIND (sym->st_info) != STB_LOCAL - && global_root != NULL) - { - Dwarf_Global fake = { .name = symstr }; - Dwarf_Global **found = tfind (&fake, &global_root, - global_compare); - if (found != NULL) - { - Dwarf_Die die_mem; - Dwarf_Die *die = dwarf_offdie (dbg, (*found)->die_offset, - &die_mem); - - Dwarf_Die cudie_mem; - Dwarf_Die *cudie = NULL; - - Dwarf_Addr lowpc; - Dwarf_Addr highpc; - if (die != NULL - && dwarf_lowpc (die, &lowpc) == 0 - && lowpc <= sym->st_value - && dwarf_highpc (die, &highpc) == 0 - && highpc > sym->st_value) - cudie = dwarf_offdie (dbg, (*found)->cu_offset, - &cudie_mem); - if (cudie != NULL) - { - Dwarf_Line *line = dwarf_getsrc_die (cudie, - sym->st_value); - if (line != NULL) - { - /* We found the line. */ - int lineno; - (void) dwarf_lineno (line, &lineno); - int n; - n = obstack_printf (&whereob, "%s:%d%c", - basename (dwarf_linesrc (line, - NULL, - NULL)), - lineno, '\0'); - sym_mem[nentries_used].where - = obstack_finish (&whereob); - - /* The return value of obstack_print included the - NUL byte, so subtract one. */ - if (--n > (int) longest_where) - longest_where = (size_t) n; - } - } - } - } - - /* Try to find the symol among the local symbols. */ - if (sym_mem[nentries_used].where[0] == '\0') - { - struct local_name fake = - { - .name = symstr, - .lowpc = sym->st_value, - .highpc = sym->st_value, - }; - struct local_name **found = tfind (&fake, &local_root, - local_compare); - if (found != NULL) - { - /* We found the line. */ - int n = obstack_printf (&whereob, "%s:%" PRIu64 "%c", - basename ((*found)->file), - (*found)->lineno, - '\0'); - sym_mem[nentries_used].where = obstack_finish (&whereob); - - /* The return value of obstack_print included the - NUL byte, so subtract one. */ - if (--n > (int) longest_where) - longest_where = (size_t) n; - } - } - } - - /* We use this entry. */ - ++nentries_used; - } - /* Now we know the exact number. */ - nentries = nentries_used; - - /* Sort the entries according to the users wishes. */ - if (sort == sort_name) - qsort (sym_mem, nentries, sizeof (GElf_SymX), sort_by_name); - else if (sort == sort_numeric) - qsort (sym_mem, nentries, sizeof (GElf_SymX), sort_by_address); - - /* Finally print according to the users selection. */ - switch (format) - { - case format_sysv: - show_symbols_sysv (ebl, shdr->sh_link, prefix, fname, - fullname, sym_mem, nentries, longest_name, - longest_where); - break; - - case format_bsd: - show_symbols_bsd (ebl->elf, ehdr, shdr->sh_link, prefix, fname, - fullname, sym_mem, nentries); - break; - - case format_posix: - default: - assert (format == format_posix); - show_symbols_posix (ebl->elf, ehdr, shdr->sh_link, prefix, fname, - fullname, sym_mem, nentries); - break; - } - - /* Free all memory. */ - if (nentries * sizeof (GElf_Sym) >= MAX_STACK_ALLOC) - free (sym_mem); - - obstack_free (&whereob, NULL); - - if (dbg != NULL) - { - tdestroy (global_root, free); - global_root = NULL; - - tdestroy (local_root, free); - local_root = NULL; - - (void) dwarf_end (dbg); - } -} - - -static int -handle_elf (Elf *elf, const char *prefix, const char *fname, - const char *suffix) -{ - size_t prefix_len = prefix == NULL ? 0 : strlen (prefix); - size_t suffix_len = suffix == NULL ? 0 : strlen (suffix); - size_t fname_len = strlen (fname) + 1; - char fullname[prefix_len + 1 + fname_len + suffix_len]; - char *cp = fullname; - Elf_Scn *scn = NULL; - int any = 0; - int result = 0; - GElf_Ehdr ehdr_mem; - GElf_Ehdr *ehdr; - Ebl *ebl; - - /* Get the backend for this object file type. */ - ebl = ebl_openbackend (elf); - - /* We need the ELF header in a few places. */ - ehdr = gelf_getehdr (elf, &ehdr_mem); - if (ehdr == NULL) - INTERNAL_ERROR (fullname); - - /* If we are asked to print the dynamic symbol table and this is - executable or dynamic executable, fail. */ - if (symsec_type == SHT_DYNSYM - && ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) - { - /* XXX Add machine specific object file types. */ - error (0, 0, gettext ("%s%s%s%s: Invalid operation"), - prefix ?: "", prefix ? "(" : "", fname, prefix ? ")" : ""); - result = 1; - goto out; - } - - /* Create the full name of the file. */ - if (prefix != NULL) - cp = mempcpy (cp, prefix, prefix_len); - cp = mempcpy (cp, fname, fname_len); - if (suffix != NULL) - memcpy (cp - 1, suffix, suffix_len + 1); - - /* Find the symbol table. - - XXX Can there be more than one? Do we print all? Currently we do. */ - while ((scn = elf_nextscn (elf, scn)) != NULL) - { - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - - if (shdr == NULL) - INTERNAL_ERROR (fullname); - - if (shdr->sh_type == symsec_type) - { - Elf_Scn *xndxscn = NULL; - - /* We have a symbol table. First make sure we remember this. */ - any = 1; - - /* Look for an extended section index table for this section. */ - if (symsec_type == SHT_SYMTAB) - { - size_t scnndx = elf_ndxscn (scn); - - while ((xndxscn = elf_nextscn (elf, xndxscn)) != NULL) - { - GElf_Shdr xndxshdr_mem; - GElf_Shdr *xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem); - - if (xndxshdr == NULL) - INTERNAL_ERROR (fullname); - - if (xndxshdr->sh_type == SHT_SYMTAB_SHNDX - && xndxshdr->sh_link == scnndx) - break; - } - } - - show_symbols (ebl, ehdr, scn, xndxscn, shdr, prefix, fname, - fullname); - } - } - - if (! any) - { - error (0, 0, gettext ("%s%s%s: no symbols"), - prefix ?: "", prefix ? ":" : "", fname); - result = 1; - } - - out: - /* Close the ELF backend library descriptor. */ - ebl_closebackend (ebl); - - return result; -} diff --git a/src/none_ld.c b/src/none_ld.c deleted file mode 100644 index fb0f0fb2..00000000 --- a/src/none_ld.c +++ /dev/null @@ -1 +0,0 @@ -/* Nothing here. This is just a testimony of automake inflexibility. */ diff --git a/src/readelf.c b/src/readelf.c deleted file mode 100644 index 6129e29d..00000000 --- a/src/readelf.c +++ /dev/null @@ -1,4541 +0,0 @@ -/* Print information from ELF file in human-readable form. - Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc. - Written by Ulrich Drepper <drepper@redhat.com>, 1999. - - This program is Open Source software; you can redistribute it and/or - modify it under the terms of the Open Software License version 1.0 as - published by the Open Source Initiative. - - You should have received a copy of the Open Software License along - with this program; if not, you may obtain a copy of the Open Software - License version 1.0 from http://www.opensource.org/licenses/osl.php or - by writing the Open Source Initiative c/o Lawrence Rosen, Esq., - 3001 King Ranch Road, Ukiah, CA 95482. */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <argp.h> -#include <assert.h> -#include <dwarf.h> -#include <errno.h> -#include <error.h> -#include <fcntl.h> -#include <gelf.h> -#include <inttypes.h> -#include <langinfo.h> -#include <libdw.h> -#include <libebl.h> -#include <libintl.h> -#include <locale.h> -#include <stdbool.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> -#include <sys/param.h> - -#include <system.h> -#include "../libdw/libdwP.h" -#include "../libdw/memory-access.h" - - -/* Name and version of program. */ -static void print_version (FILE *stream, struct argp_state *state); -void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; - -/* Definitions of arguments for argp functions. */ -static const struct argp_option options[] = -{ - { NULL, 0, NULL, 0, N_("Output selection:") }, - { "all", 'a', NULL, 0, N_("Equivalent to: -h -l") }, - { "dynamic", 'd', NULL, 0, N_("Display the dynamic segment") }, - { "file-header", 'h', NULL, 0, N_("Display the ELF file header") }, - { "histogram", 'I', NULL, 0, - N_("Display histogram of bucket list lengths") }, - { "program-headers", 'l', NULL, 0, N_("Display the program headers") }, - { "relocs", 'r', NULL, 0, N_("Display relocations") }, - { "section-headers", 'S', NULL, 0, N_("Display the sections' header") }, - { "symbols", 's', NULL, 0, N_("Display the symbol table") }, - { "version-info", 'V', NULL, 0, N_("Display versioning information") }, - { "debug-dump", 'w', "SECTION", OPTION_ARG_OPTIONAL, - N_("Display DWARF section content. SECTION can be one of abbrev, " - "aranges, frame, info, loc, line, pubnames, str, or macinfo.") }, - { "notes", 'n', NULL, 0, N_("Display the core notes") }, - { "arch-specific", 'A', NULL, 0, - N_("Display architecture specific information (if any)") }, - - { NULL, 0, NULL, 0, N_("Output control:") }, - - { NULL, 0, NULL, 0, NULL } -}; - -/* Short description of program. */ -static const char doc[] = N_("\ -Print information from ELF file in human-readable form."); - -/* Strings for arguments in help texts. */ -static const char args_doc[] = N_("FILE..."); - -/* Prototype for option handler. */ -static error_t parse_opt (int key, char *arg, struct argp_state *state); - -/* Function to print some extra text in the help message. */ -static char *more_help (int key, const char *text, void *input); - -/* Data structure to communicate with argp functions. */ -static struct argp argp = -{ - options, parse_opt, args_doc, doc, NULL, more_help -}; - - -/* Flags set by the option controlling the output. */ - -/* True if any of the control options is set. */ -static bool any_control_option; - -/* True if dynamic segment should be printed. */ -static bool print_dynamic_table; - -/* True if the file header should be printed. */ -static bool print_file_header; - -/* True if the program headers should be printed. */ -static bool print_program_header; - -/* True if relocations should be printed. */ -static bool print_relocations; - -/* True if the section headers should be printed. */ -static bool print_section_header; - -/* True if the symbol table should be printed. */ -static bool print_symbol_table; - -/* True if the version information should be printed. */ -static bool print_version_info; - -/* True if section groups should be printed. */ -static bool print_section_groups; - -/* True if bucket list length histogram should be printed. */ -static bool print_histogram; - -/* True if the architecture specific data should be printed. */ -static bool print_arch; - -/* True if note section content should be printed. */ -static bool print_notes; - -/* Select printing of debugging sections. */ -static enum section_e -{ - section_abbrev = 1, /* .debug_abbrev */ - section_aranges = 2, /* .debug_aranges */ - section_frame = 4, /* .debug_frame or .eh_frame */ - section_info = 8, /* .debug_info */ - section_line = 16, /* .debug_line */ - section_loc = 32, /* .debug_loc */ - section_pubnames = 64,/* .debug_pubnames */ - section_str = 128, /* .debug_str */ - section_macinfo = 256,/* .debug_macinfo */ - section_all = (section_abbrev | section_aranges | section_frame - | section_info | section_line | section_loc - | section_pubnames | section_str | section_macinfo) -} print_debug_sections; - -/* Number of sections in the file. */ -static size_t shnum; - - -/* Declarations of local functions. */ -static void process_file (int fd, Elf *elf, const char *prefix, - const char *fname, bool only_one); -static void process_elf_file (Elf *elf, const char *prefix, const char *fname, - bool only_one); -static void print_ehdr (Ebl *ebl, GElf_Ehdr *ehdr); -static void print_shdr (Ebl *ebl, GElf_Ehdr *ehdr); -static void print_phdr (Ebl *ebl, GElf_Ehdr *ehdr); -static void print_scngrp (Ebl *ebl, GElf_Ehdr *ehdr); -static void print_dynamic (Ebl *ebl, GElf_Ehdr *ehdr); -static void print_relocs (Ebl *ebl, GElf_Ehdr *ehdr); -static void handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, - GElf_Shdr *shdr); -static void handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, - GElf_Shdr *shdr); -static void print_symtab (Ebl *ebl, GElf_Ehdr *ehdr, int type); -static void handle_symtab (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, - GElf_Shdr *shdr); -static void print_verinfo (Ebl *ebl, GElf_Ehdr *ehdr); -static void handle_verneed (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, - GElf_Shdr *shdr); -static void handle_verdef (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, - GElf_Shdr *shdr); -static void handle_versym (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, - GElf_Shdr *shdr); -static void print_debug (Ebl *ebl, GElf_Ehdr *ehdr); -static void handle_hash (Ebl *ebl, GElf_Ehdr *ehdr); -static void handle_notes (Ebl *ebl, GElf_Ehdr *ehdr); -static void print_liblist (Ebl *ebl, GElf_Ehdr *ehdr); - - -int -main (int argc, char *argv[]) -{ - int remaining; - bool only_one; - - /* Set locale. */ - setlocale (LC_ALL, ""); - - /* Initialize the message catalog. */ - textdomain (PACKAGE); - - /* Parse and process arguments. */ - argp_parse (&argp, argc, argv, 0, &remaining, NULL); - - /* If no control option or no ELF file is given punt. */ - if ((any_control_option == 0 && print_debug_sections == 0) - || remaining >= argc) - { - argp_help (&argp, stdout, ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR, - program_invocation_short_name); - exit (1); - } - - /* Before we start tell the ELF library which version we are using. */ - elf_version (EV_CURRENT); - - /* Now process all the files given at the command line. */ - only_one = remaining + 1 == argc; - do - { - int fd; - Elf *elf; - - /* Open the file. */ - fd = open (argv[remaining], O_RDONLY); - if (fd == -1) - { - error (0, errno, gettext ("cannot open input file")); - continue; - } - - /* Create an `Elf' descriptor. */ - elf = elf_begin (fd, ELF_C_READ_MMAP, NULL); - if (elf == NULL) - error (0, 0, gettext ("cannot generate Elf descriptor: %s\n"), - elf_errmsg (-1)); - else - { - process_file (fd, elf, NULL, argv[remaining], only_one); - - /* Now we can close the descriptor. */ - if (elf_end (elf) != 0) - error (0, 0, gettext ("error while closing Elf descriptor: %s"), - elf_errmsg (-1)); - } - - close (fd); - } - while (++remaining < argc); - - return error_message_count != 0; -} - - -/* Handle program arguments. */ -static error_t -parse_opt (int key, char *arg, struct argp_state *state) -{ - switch (key) - { - case 'a': - print_file_header = true; - print_program_header = true; - print_relocations = true; - print_section_header = true; - print_symbol_table = true; - print_version_info = true; - print_dynamic_table = true; - print_section_groups = true; - print_histogram = true; - print_arch = true; - print_notes = true; - any_control_option = true; - break; - case 'A': - print_arch = true; - any_control_option = true; - break; - case 'd': - print_dynamic_table = true; - any_control_option = true; - break; - case 'g': - print_section_groups = true; - any_control_option = true; - break; - case 'h': - print_file_header = true; - any_control_option = true; - break; - case 'I': - print_histogram = true; - any_control_option = true; - break; - case 'l': - print_program_header = true; - any_control_option = true; - break; - case 'n': - print_notes = true; - any_control_option = true; - break; - case 'r': - print_relocations = true; - any_control_option = true; - break; - case 'S': - print_section_header = true; - any_control_option = true; - break; - case 's': - print_symbol_table = true; - any_control_option = true; - break; - case 'V': - print_version_info = true; - any_control_option = true; - break; - case 'w': - if (arg == NULL) - print_debug_sections = section_all; - else if (strcmp (arg, "abbrev") == 0) - print_debug_sections |= section_abbrev; - else if (strcmp (arg, "aranges") == 0) - print_debug_sections |= section_aranges; - else if (strcmp (arg, "frame") == 0) - print_debug_sections |= section_frame; - else if (strcmp (arg, "info") == 0) - print_debug_sections |= section_info; - else if (strcmp (arg, "loc") == 0) - print_debug_sections |= section_loc; - else if (strcmp (arg, "line") == 0) - print_debug_sections |= section_line; - else if (strcmp (arg, "pubnames") == 0) - print_debug_sections |= section_pubnames; - else if (strcmp (arg, "str") == 0) - print_debug_sections |= section_str; - else if (strcmp (arg, "macinfo") == 0) - print_debug_sections |= section_macinfo; - else - { - fprintf (stderr, gettext ("Unknown DWARF debug section `%s'.\n"), - arg); - argp_help (&argp, stderr, ARGP_HELP_SEE, - program_invocation_short_name); - exit (1); - } - break; - default: - return ARGP_ERR_UNKNOWN; - } - return 0; -} - - -static char * -more_help (int key, const char *text, void *input) -{ - char *buf; - - switch (key) - { - case ARGP_KEY_HELP_EXTRA: - /* We print some extra information. */ - if (asprintf (&buf, gettext ("Please report bugs to %s.\n"), - PACKAGE_BUGREPORT) < 0) - buf = NULL; - return buf; - - default: - break; - } - return (char *) text; -} - - -/* Print the version information. */ -static void -print_version (FILE *stream, struct argp_state *state) -{ - fprintf (stream, "readelf (%s) %s\n", PACKAGE_NAME, 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\ -"), "2004"); - fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); -} - - -/* Process one file. */ -static void -process_file (int fd, Elf *elf, const char *prefix, const char *fname, - bool only_one) -{ - /* We can handle two types of files: ELF files and archives. */ - Elf_Kind kind = elf_kind (elf); - struct stat64 st; - - switch (kind) - { - case ELF_K_ELF: - /* Yes! It's an ELF file. */ - process_elf_file (elf, prefix, fname, only_one); - break; - - case ELF_K_AR: - { - Elf *subelf; - Elf_Cmd cmd = ELF_C_READ_MMAP; - size_t prefix_len = prefix == NULL ? 0 : strlen (prefix); - size_t fname_len = strlen (fname) + 1; - char new_prefix[prefix_len + 1 + fname_len]; - char *cp = new_prefix; - - /* Create the full name of the file. */ - if (prefix != NULL) - { - cp = mempcpy (cp, prefix, prefix_len); - *cp++ = ':'; - } - memcpy (cp, fname, fname_len); - - /* It's an archive. We process each file in it. */ - while ((subelf = elf_begin (fd, cmd, elf)) != NULL) - { - kind = elf_kind (subelf); - - /* Call this function recursively. */ - if (kind == ELF_K_ELF || kind == ELF_K_AR) - { - Elf_Arhdr *arhdr = elf_getarhdr (subelf); - assert (arhdr != NULL); - - process_file (fd, subelf, new_prefix, arhdr->ar_name, false); - } - - /* Get next archive element. */ - cmd = elf_next (subelf); - if (elf_end (subelf) != 0) - error (0, 0, - gettext (" error while freeing sub-ELF descriptor: %s\n"), - elf_errmsg (-1)); - } - } - break; - - default: - if (fstat64 (fd, &st) != 0) - error (0, errno, gettext ("cannot stat input file")); - else if (st.st_size == 0) - error (0, 0, gettext ("input file is empty")); - else - /* We cannot do anything. */ - error (0, 0, gettext ("\ -Not an ELF file - it has the wrong magic bytes at the start")); - break; - } -} - - -/* Process one file. */ -static void -process_elf_file (Elf *elf, const char *prefix, const char *fname, - bool only_one) -{ - GElf_Ehdr ehdr_mem; - GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); - Ebl *ebl; - - /* Print the file name. */ - if (!only_one) - { - if (prefix != NULL) - printf ("\n%s(%s):\n\n", prefix, fname); - else - printf ("\n%s:\n\n", fname); - } - - if (ehdr == NULL) - { - error (0, 0, gettext ("cannot read ELF header: %s"), elf_errmsg (-1)); - return; - } - - ebl = ebl_openbackend (elf); - if (ebl == NULL) - { - error (0, errno, gettext ("cannot create EBL handle")); - return; - } - - /* Determine the number of sections. */ - if (elf_getshnum (ebl->elf, &shnum) < 0) - error (EXIT_FAILURE, 0, - gettext ("cannot determine number of sections: %s"), - elf_errmsg (-1)); - - if (print_file_header) - print_ehdr (ebl, ehdr); - if (print_section_header) - print_shdr (ebl, ehdr); - if (print_program_header) - print_phdr (ebl, ehdr); - if (print_section_groups) - print_scngrp (ebl, ehdr); - if (print_dynamic_table) - print_dynamic (ebl, ehdr); - if (print_relocations) - print_relocs (ebl, ehdr); - if (print_histogram) - handle_hash (ebl, ehdr); - if (print_symbol_table) - print_symtab (ebl, ehdr, SHT_DYNSYM); - if (print_version_info) - print_verinfo (ebl, ehdr); - if (print_symbol_table) - print_symtab (ebl, ehdr, SHT_SYMTAB); - if (print_arch) - print_liblist (ebl, ehdr); - if (print_debug_sections != 0) - print_debug (ebl, ehdr); - if (print_notes) - handle_notes (ebl, ehdr); - - ebl_closebackend (ebl); -} - - -/* Print file type. */ -static void -print_file_type (unsigned short int e_type) -{ - if (e_type <= ET_CORE) - { - static const char *knowntypes[] = - { - N_("NONE (None)"), - N_("REL (Relocatable file)"), - N_("EXEC (Executable file)"), - N_("DYN (Shared object file)"), - N_("CORE (Core file)") - }; - puts (gettext (knowntypes[e_type])); - } - else if (e_type >= ET_LOOS && e_type <= ET_HIOS) - printf (gettext ("OS Specific: (%x)\n"), e_type); - else if (e_type >= ET_LOPROC /* && e_type <= ET_HIPROC always true */) - printf (gettext ("Processor Specific: (%x)\n"), e_type); - else - puts ("???"); -} - - -/* Print ELF header. */ -static void -print_ehdr (Ebl *ebl, GElf_Ehdr *ehdr) -{ - char buf[512]; - size_t cnt; - - fputs_unlocked (gettext ("ELF Header:\n Magic: "), stdout); - for (cnt = 0; cnt < EI_NIDENT; ++cnt) - printf (" %02hhx", ehdr->e_ident[cnt]); - - printf (gettext ("\n Class: %s\n"), - ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? "ELF32" - : ehdr->e_ident[EI_CLASS] == ELFCLASS64 ? "ELF64" - : "\?\?\?"); - - printf (gettext (" Data: %s\n"), - ehdr->e_ident[EI_DATA] == ELFDATA2LSB - ? "2's complement, little endian" - : ehdr->e_ident[EI_DATA] == ELFDATA2MSB - ? "2's complement, big endian" : "\?\?\?"); - - printf (gettext (" Version: %hhd %s\n"), - ehdr->e_ident[EI_VERSION], - ehdr->e_ident[EI_VERSION] == EV_CURRENT ? gettext ("(current)") - : "(\?\?\?)"); - - printf (gettext (" OS/ABI: %s\n"), - ebl_osabi_name (ebl, ehdr->e_ident[EI_OSABI], buf, sizeof (buf))); - - printf (gettext (" ABI Version: %hhd\n"), - ehdr->e_ident[EI_ABIVERSION]); - - fputs_unlocked (gettext (" Type: "), stdout); - print_file_type (ehdr->e_type); - - printf (gettext (" Machine: %s\n"), ebl->name); - - printf (gettext (" Version: %d %s\n"), - ehdr->e_version, - ehdr->e_version == EV_CURRENT ? gettext ("(current)") : "(\?\?\?)"); - - printf (gettext (" Entry point address: %#" PRIx64 "\n"), - ehdr->e_entry); - - printf (gettext (" Start of program headers: %" PRId64 " %s\n"), - ehdr->e_phoff, gettext ("(bytes into file)")); - - printf (gettext (" Start of section headers: %" PRId64 " %s\n"), - ehdr->e_shoff, gettext ("(bytes into file)")); - - printf (gettext (" Flags: %s\n"), - ebl_machine_flag_name (ebl, ehdr->e_flags, buf, sizeof (buf))); - - printf (gettext (" Size of this header: %" PRId16 " %s\n"), - ehdr->e_ehsize, gettext ("(bytes)")); - - printf (gettext (" Size of program header entries: %" PRId16 " %s\n"), - ehdr->e_phentsize, gettext ("(bytes)")); - - printf (gettext (" Number of program headers entries: %" PRId16 "\n"), - ehdr->e_phnum); - - printf (gettext (" Size of section header entries: %" PRId16 " %s\n"), - ehdr->e_shentsize, gettext ("(bytes)")); - - printf (gettext (" Number of section headers entries: %" PRId16), - ehdr->e_shnum); - if (ehdr->e_shnum == 0) - { - GElf_Shdr shdr_mem; - GElf_Shdr *shdr; - - shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem); - if (shdr != NULL) - printf (gettext (" (%" PRIu32 " in [0].sh_size)"), - (uint32_t) shdr->sh_size); - else - fputs_unlocked (gettext (" ([0] not available)"), stdout); - } - fputc_unlocked ('\n', stdout); - - if (ehdr->e_shstrndx == SHN_XINDEX) - { - GElf_Shdr shdr_mem; - GElf_Shdr *shdr; - - shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem); - if (shdr != NULL) - /* We managed to get the zeroth section. */ - snprintf (buf, sizeof (buf), gettext (" (%" PRIu32 " in [0].sh_link)"), - (uint32_t) shdr->sh_link); - else - { - strncpy (buf, gettext (" ([0] not available)"), sizeof (buf)); - buf[sizeof (buf) - 1] = '\0'; - } - - printf (gettext (" Section header string table index: XINDEX%s\n\n"), - buf); - } - else - printf (gettext (" Section header string table index: %" PRId16 "\n\n"), - ehdr->e_shstrndx); -} - - -static const char * -get_visibility_type (int value) -{ - switch (value) - { - case STV_DEFAULT: - return "DEFAULT"; - case STV_INTERNAL: - return "INTERNAL"; - case STV_HIDDEN: - return "HIDDEN"; - case STV_PROTECTED: - return "PROTECTED"; - default: - return "???"; - } -} - - -/* Print the section headers. */ -static void -print_shdr (Ebl *ebl, GElf_Ehdr *ehdr) -{ - size_t cnt; - size_t shstrndx; - - if (! print_file_header) - printf (gettext ("\ -There are %d section headers, starting at offset %#" PRIx64 ":\n\ -\n"), - ehdr->e_shnum, ehdr->e_shoff); - - /* Get the section header string table index. */ - if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) - error (EXIT_FAILURE, 0, - gettext ("cannot get section header string table index")); - - puts (gettext ("Section Headers:")); - - if (ehdr->e_ident[EI_CLASS] == ELFCLASS32) - puts (gettext ("[Nr] Name Type Addr Off Size ES Flags Lk Inf Al")); - else - puts (gettext ("[Nr] Name Type Addr Off Size ES Flags Lk Inf Al")); - - for (cnt = 0; cnt < shnum; ++cnt) - { - char buf[128]; - char flagbuf[20]; - char *cp; - Elf_Scn *scn = elf_getscn (ebl->elf, cnt); - GElf_Shdr shdr_mem; - GElf_Shdr *shdr; - - if (scn == NULL) - error (EXIT_FAILURE, 0, gettext ("cannot get section: %s"), - elf_errmsg (-1)); - - /* Get the section header. */ - shdr = gelf_getshdr (scn, &shdr_mem); - if (shdr == NULL) - error (EXIT_FAILURE, 0, gettext ("cannot get section header: %s"), - elf_errmsg (-1)); - - cp = flagbuf; - if (shdr->sh_flags & SHF_WRITE) - *cp++ = 'W'; - if (shdr->sh_flags & SHF_ALLOC) - *cp++ = 'A'; - if (shdr->sh_flags & SHF_EXECINSTR) - *cp++ = 'X'; - if (shdr->sh_flags & SHF_MERGE) - *cp++ = 'M'; - if (shdr->sh_flags & SHF_STRINGS) - *cp++ = 'S'; - if (shdr->sh_flags & SHF_INFO_LINK) - *cp++ = 'I'; - if (shdr->sh_flags & SHF_LINK_ORDER) - *cp++ = 'L'; - if (shdr->sh_flags & SHF_OS_NONCONFORMING) - *cp++ = 'N'; - if (shdr->sh_flags & SHF_GROUP) - *cp++ = 'G'; - if (shdr->sh_flags & SHF_TLS) - *cp++ = 'T'; - if (shdr->sh_flags & SHF_ORDERED) - *cp++ = 'O'; - if (shdr->sh_flags & SHF_EXCLUDE) - *cp++ = 'E'; - *cp = '\0'; - - printf ("[%2zu] %-20s %-12s %0*" PRIx64 " %0*" PRIx64 " %0*" PRIx64 - " %2" PRId64 " %-5s %2" PRId32 " %3" PRId32 - " %2" PRId64 "\n", - cnt, - elf_strptr (ebl->elf, shstrndx, shdr->sh_name) - ?: "<corrupt>", - ebl_section_type_name (ebl, shdr->sh_type, buf, sizeof (buf)), - ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16, shdr->sh_addr, - ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 6 : 8, shdr->sh_offset, - ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 6 : 8, shdr->sh_size, - shdr->sh_entsize, flagbuf, shdr->sh_link, shdr->sh_info, - shdr->sh_addralign); - } - - fputc_unlocked ('\n', stdout); -} - - -/* Print the program header. */ -static void -print_phdr (Ebl *ebl, GElf_Ehdr *ehdr) -{ - size_t cnt; - size_t shstrndx; - - if (ehdr->e_phnum == 0) - /* No program header, this is OK in relocatable objects. */ - return; - - puts (gettext ("Program Headers:")); - if (ehdr->e_ident[EI_CLASS] == ELFCLASS32) - puts (gettext ("\ - Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align")); - else - puts (gettext ("\ - Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align")); - - /* Process all program headers. */ - bool has_relro = false; - GElf_Addr relro_from = 0; - GElf_Addr relro_to = 0; - for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) - { - char buf[128]; - GElf_Phdr mem; - GElf_Phdr *phdr = gelf_getphdr (ebl->elf, cnt, &mem); - - /* If for some reason the header cannot be returned show this. */ - if (phdr == NULL) - { - puts (" ???"); - continue; - } - - printf (" %-14s 0x%06" PRIx64 " 0x%0*" PRIx64 " 0x%0*" PRIx64 - " 0x%06" PRIx64 " 0x%06" PRIx64 " %c%c%c 0x%" PRIx64 "\n", - ebl_segment_type_name (ebl, phdr->p_type, buf, sizeof (buf)), - phdr->p_offset, - ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16, phdr->p_vaddr, - ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16, phdr->p_paddr, - phdr->p_filesz, - phdr->p_memsz, - phdr->p_flags & PF_R ? 'R' : ' ', - phdr->p_flags & PF_W ? 'W' : ' ', - phdr->p_flags & PF_X ? 'E' : ' ', - phdr->p_align); - - if (phdr->p_type == PT_INTERP) - { - /* We can show the user the name of the interpreter. */ - size_t maxsize; - char *filedata = elf_rawfile (ebl->elf, &maxsize); - - if (filedata != NULL && phdr->p_offset < maxsize) - printf (gettext ("\t[Requesting program interpreter: %s]\n"), - filedata + phdr->p_offset); - } - else if (phdr->p_type == PT_GNU_RELRO) - { - has_relro = true; - relro_from = phdr->p_vaddr; - relro_to = relro_from + phdr->p_memsz; - } - } - - /* Get the section header string table index. */ - if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) - error (EXIT_FAILURE, 0, - gettext ("cannot get section header string table index")); - - puts (gettext ("\n Section to Segment mapping:\n Segment Sections...")); - - for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) - { - GElf_Phdr phdr_mem; - GElf_Phdr *phdr = gelf_getphdr (ebl->elf, cnt, &phdr_mem); - size_t inner; - - /* Print the segment number. */ - printf (" %2.2zu ", cnt); - - /* This must not happen. */ - if (phdr == NULL) - error (EXIT_FAILURE, 0, gettext ("cannot get program header: %s"), - elf_errmsg (-1)); - - /* Iterate over the sections. */ - bool in_relro = false; - for (inner = 1; inner < shnum; ++inner) - { - Elf_Scn *scn = elf_getscn (ebl->elf, inner); - GElf_Shdr shdr_mem; - GElf_Shdr *shdr; - - /* It should not happen. */ - if (scn == NULL) - error (EXIT_FAILURE, 0, gettext ("cannot get section: %s"), - elf_errmsg (-1)); - - /* Get the section header. */ - shdr = gelf_getshdr (scn, &shdr_mem); - if (shdr == NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot get section header: %s"), - elf_errmsg (-1)); - - if (shdr->sh_size > 0 - /* Compare allocated sections by VMA, unallocated - sections by file offset. */ - && (shdr->sh_flags & SHF_ALLOC - ? (shdr->sh_addr >= phdr->p_vaddr - && (shdr->sh_addr + shdr->sh_size - <= phdr->p_vaddr + phdr->p_memsz)) - : (shdr->sh_offset >= phdr->p_offset - && (shdr->sh_offset + shdr->sh_size - <= phdr->p_offset + phdr->p_filesz)))) - { - if (has_relro && !in_relro - && shdr->sh_addr >= relro_from - && shdr->sh_addr + shdr->sh_size <= relro_to) - { - fputs_unlocked (" [RELRO:", stdout); - in_relro = true; - } - else if (has_relro && in_relro && shdr->sh_addr >= relro_to) - { - fputs_unlocked ("]", stdout); - in_relro = false; - } - else if (has_relro && in_relro - && shdr->sh_addr + shdr->sh_size > relro_to) - fputs_unlocked ("] <RELRO:", stdout); - - printf (" %s", - elf_strptr (ebl->elf, shstrndx, shdr->sh_name)); - - /* Signal that this sectin is only partially covered. */ - if (has_relro && in_relro - && shdr->sh_addr + shdr->sh_size > relro_to) - { - fputs_unlocked (">", stdout); - in_relro = false; - } - } - } - if (in_relro) - fputs_unlocked ("]", stdout); - - /* Finish the line. */ - fputc_unlocked ('\n', stdout); - } -} - - -static void -handle_scngrp (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) -{ - Elf_Data *data; - Elf32_Word *grpref; - Elf_Scn *symscn; - GElf_Shdr symshdr_mem; - GElf_Shdr *symshdr; - Elf_Data *symdata; - GElf_Sym sym_mem; - size_t cnt; - size_t shstrndx; - - /* Get the data of the section. */ - data = elf_getdata (scn, NULL); - - symscn = elf_getscn (ebl->elf, shdr->sh_link); - symshdr = gelf_getshdr (symscn, &symshdr_mem); - symdata = elf_getdata (symscn, NULL); - - if (data == NULL || data->d_size < sizeof (Elf32_Word) || symshdr == NULL - || symdata == NULL) - return; - - /* Get the section header string table index. */ - if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) - error (EXIT_FAILURE, 0, - gettext ("cannot get section header string table index")); - - grpref = (Elf32_Word *) data->d_buf; - - printf ((grpref[0] & GRP_COMDAT) - ? ngettext ("\ -\nCOMDAT section group [%2zu] '%s' with signature '%s' contains %zu entry:\n", - "\ -\nCOMDAT section group [%2zu] '%s' with signature '%s' contains %zu entries:\n", - data->d_size / sizeof (Elf32_Word) - 1) - : ngettext ("\ -\nSection group [%2zu] '%s' with signature '%s' contains %zu entry:\n", "\ -\nSection group [%2zu] '%s' with signature '%s' contains %zu entries:\n", - data->d_size / sizeof (Elf32_Word) - 1), - elf_ndxscn (scn), - elf_strptr (ebl->elf, shstrndx, shdr->sh_name), - elf_strptr (ebl->elf, symshdr->sh_link, - gelf_getsym (symdata, shdr->sh_info, &sym_mem)->st_name) - ?: gettext ("<INVALID SYMBOL>"), - data->d_size / sizeof (Elf32_Word) - 1); - - for (cnt = 1; cnt < data->d_size / sizeof (Elf32_Word); ++cnt) - { - GElf_Shdr grpshdr_mem; - GElf_Shdr *grpshdr; - - grpshdr = gelf_getshdr (elf_getscn (ebl->elf, grpref[cnt]), - &grpshdr_mem); - - if (grpshdr == NULL) - printf (gettext (" [%2u] <INVALID SECTION>\n"), grpref[cnt]); - else - printf (" [%2u] %s\n", - grpref[cnt], - elf_strptr (ebl->elf, shstrndx, grpshdr->sh_name) - ?: gettext ("<INVALID SECTION>")); - } -} - - -static void -print_scngrp (Ebl *ebl, GElf_Ehdr *ehdr) -{ - /* Find all relocation sections and handle them. */ - Elf_Scn *scn = NULL; - - while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) - { - /* Handle the section if it is a symbol table. */ - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - - if (shdr != NULL && shdr->sh_type == SHT_GROUP) - handle_scngrp (ebl, ehdr, scn, shdr); - } -} - - -static const struct flags -{ - int mask; - const char *str; -} dt_flags[] = - { - { DF_ORIGIN, "ORIGIN" }, - { DF_SYMBOLIC, "SYMBOLIC" }, - { DF_TEXTREL, "TEXTREL" }, - { DF_BIND_NOW, "BIND_NOW" }, - { DF_STATIC_TLS, "STATIC_TLS" } - }; -static const int ndt_flags = sizeof (dt_flags) / sizeof (dt_flags[0]); - -static const struct flags dt_flags_1[] = - { - { DF_1_NOW, "NOW" }, - { DF_1_GLOBAL, "GLOBAL" }, - { DF_1_GROUP, "GROUP" }, - { DF_1_NODELETE, "NODELETE" }, - { DF_1_LOADFLTR, "LOADFLTR" }, - { DF_1_INITFIRST, "INITFIRST" }, - { DF_1_NOOPEN, "NOOPEN" }, - { DF_1_ORIGIN, "ORIGIN" }, - { DF_1_DIRECT, "DIRECT" }, - { DF_1_TRANS, "TRANS" }, - { DF_1_INTERPOSE, "INTERPOSE" }, - { DF_1_NODEFLIB, "NODEFLIB" }, - { DF_1_NODUMP, "NODUMP" }, - { DF_1_CONFALT, "CONFALT" }, - { DF_1_ENDFILTEE, "ENDFILTEE" }, - { DF_1_DISPRELDNE, "DISPRELDNE" }, - { DF_1_DISPRELPND, "DISPRELPND" }, - }; -static const int ndt_flags_1 = sizeof (dt_flags_1) / sizeof (dt_flags_1[0]); - -static const struct flags dt_feature_1[] = - { - { DTF_1_PARINIT, "PARINIT" }, - { DTF_1_CONFEXP, "CONFEXP" } - }; -static const int ndt_feature_1 = (sizeof (dt_feature_1) - / sizeof (dt_feature_1[0])); - -static const struct flags dt_posflag_1[] = - { - { DF_P1_LAZYLOAD, "LAZYLOAD" }, - { DF_P1_GROUPPERM, "GROUPPERM" } - }; -static const int ndt_posflag_1 = (sizeof (dt_posflag_1) - / sizeof (dt_posflag_1[0])); - - -static void -print_flags (int class, GElf_Xword d_val, const struct flags *flags, - int nflags) -{ - bool first = true; - int cnt; - - for (cnt = 0; cnt < nflags; ++cnt) - if (d_val & flags[cnt].mask) - { - if (!first) - putchar_unlocked (' '); - fputs_unlocked (flags[cnt].str, stdout); - d_val &= ~flags[cnt].mask; - first = false; - } - - if (d_val != 0) - { - if (!first) - putchar_unlocked (' '); - printf ("%#0*" PRIx64, class == ELFCLASS32 ? 10 : 18, d_val); - } - - putchar_unlocked ('\n'); -} - - -static void -print_dt_flags (int class, GElf_Xword d_val) -{ - print_flags (class, d_val, dt_flags, ndt_flags); -} - - -static void -print_dt_flags_1 (int class, GElf_Xword d_val) -{ - print_flags (class, d_val, dt_flags_1, ndt_flags_1); -} - - -static void -print_dt_feature_1 (int class, GElf_Xword d_val) -{ - print_flags (class, d_val, dt_feature_1, ndt_feature_1); -} - - -static void -print_dt_posflag_1 (int class, GElf_Xword d_val) -{ - print_flags (class, d_val, dt_posflag_1, ndt_posflag_1); -} - - -static void -handle_dynamic (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) -{ - int class = gelf_getclass (ebl->elf); - GElf_Shdr glink; - Elf_Data *data; - size_t cnt; - size_t shstrndx; - - /* Get the data of the section. */ - data = elf_getdata (scn, NULL); - if (data == NULL) - return; - - /* Get the section header string table index. */ - if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) - error (EXIT_FAILURE, 0, - gettext ("cannot get section header string table index")); - - printf (ngettext ("\ -\nDynamic segment contains %lu entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", - "\ -\nDynamic segment contains %lu entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", - shdr->sh_size / shdr->sh_entsize), - (unsigned long int) (shdr->sh_size / shdr->sh_entsize), - class == ELFCLASS32 ? 10 : 18, shdr->sh_addr, - shdr->sh_offset, - (int) shdr->sh_link, - elf_strptr (ebl->elf, shstrndx, - gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), - &glink)->sh_name)); - fputs_unlocked (gettext (" Type Value\n"), stdout); - - for (cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt) - { - char buf[64]; - GElf_Dyn dynmem; - GElf_Dyn *dyn; - - dyn = gelf_getdyn (data, cnt, &dynmem); - if (dyn == NULL) - break; - - printf (" %-17s ", - ebl_dynamic_tag_name (ebl, dyn->d_tag, buf, sizeof (buf))); - - switch (dyn->d_tag) - { - case DT_NULL: - case DT_DEBUG: - case DT_BIND_NOW: - case DT_TEXTREL: - /* No further output. */ - fputc ('\n', stdout); - break; - - case DT_NEEDED: - printf (gettext ("Shared library: [%s]\n"), - elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val)); - break; - - case DT_SONAME: - printf (gettext ("Library soname: [%s]\n"), - elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val)); - break; - - case DT_RPATH: - printf (gettext ("Library rpath: [%s]\n"), - elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val)); - break; - - case DT_RUNPATH: - printf (gettext ("Library runpath: [%s]\n"), - elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val)); - break; - - case DT_PLTRELSZ: - case DT_RELASZ: - case DT_STRSZ: - case DT_RELSZ: - case DT_RELAENT: - case DT_SYMENT: - case DT_RELENT: - case DT_PLTPADSZ: - case DT_MOVEENT: - case DT_MOVESZ: - case DT_INIT_ARRAYSZ: - case DT_FINI_ARRAYSZ: - case DT_SYMINSZ: - case DT_SYMINENT: - case DT_GNU_CONFLICTSZ: - case DT_GNU_LIBLISTSZ: - printf (gettext ("%" PRId64 " (bytes)\n"), dyn->d_un.d_val); - break; - - case DT_VERDEFNUM: - case DT_VERNEEDNUM: - case DT_RELACOUNT: - case DT_RELCOUNT: - printf ("%" PRId64 "\n", dyn->d_un.d_val); - break; - - case DT_PLTREL: - puts (ebl_dynamic_tag_name (ebl, dyn->d_un.d_val, NULL, 0)); - break; - - case DT_FLAGS: - print_dt_flags (class, dyn->d_un.d_val); - break; - - case DT_FLAGS_1: - print_dt_flags_1 (class, dyn->d_un.d_val); - break; - - case DT_FEATURE_1: - print_dt_feature_1 (class, dyn->d_un.d_val); - break; - - case DT_POSFLAG_1: - print_dt_posflag_1 (class, dyn->d_un.d_val); - break; - - default: - printf ("%#0*" PRIx64 "\n", - class == ELFCLASS32 ? 10 : 18, dyn->d_un.d_val); - break; - } - } -} - - -/* Print the dynamic segment. */ -static void -print_dynamic (Ebl *ebl, GElf_Ehdr *ehdr) -{ - /* Find all relocation sections and handle them. */ - Elf_Scn *scn = NULL; - - while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) - { - /* Handle the section if it is a symbol table. */ - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - - if (shdr != NULL && shdr->sh_type == SHT_DYNAMIC) - { - handle_dynamic (ebl, ehdr, scn, shdr); - break; - } - } -} - - -/* Print relocations. */ -static void -print_relocs (Ebl *ebl, GElf_Ehdr *ehdr) -{ - /* Find all relocation sections and handle them. */ - Elf_Scn *scn = NULL; - - while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) - { - /* Handle the section if it is a symbol table. */ - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - - if (shdr != NULL) - { - if (shdr->sh_type == SHT_REL) - handle_relocs_rel (ebl, ehdr, scn, shdr); - else if (shdr->sh_type == SHT_RELA) - handle_relocs_rela (ebl, ehdr, scn, shdr); - } - } -} - - -/* Handle a relocation section. */ -static void -handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) -{ - int class = gelf_getclass (ebl->elf); - int nentries = shdr->sh_size / shdr->sh_entsize; - int cnt; - Elf_Data *data; - Elf_Scn *symscn; - GElf_Shdr symshdr_mem; - GElf_Shdr *symshdr; - Elf_Data *symdata; - GElf_Shdr destshdr_mem; - GElf_Shdr *destshdr; - Elf_Scn *xndxscn; - Elf_Data *xndxdata = NULL; - size_t shstrndx; - - /* Get the data of the section. */ - data = elf_getdata (scn, NULL); - if (data == NULL) - return; - - /* Get the symbol table information. */ - symscn = elf_getscn (ebl->elf, shdr->sh_link); - symshdr = gelf_getshdr (symscn, &symshdr_mem); - symdata = elf_getdata (symscn, NULL); - - /* Get the section header of the section the relocations are for. */ - destshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_info), - &destshdr_mem); - - if (symshdr == NULL || symdata == NULL || destshdr == NULL) - { - printf (gettext ("\nInvalid symbol table at offset %#0" PRIx64 "\n"), - shdr->sh_offset); - return; - } - - /* Search for the optional extended section index table. */ - xndxscn = NULL; - while ((xndxscn = elf_nextscn (ebl->elf, xndxscn)) != NULL) - { - GElf_Shdr xndxshdr_mem; - GElf_Shdr *xndxshdr; - - xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem); - if (xndxshdr != NULL && xndxshdr->sh_type == SHT_SYMTAB_SHNDX - && xndxshdr->sh_link == elf_ndxscn (symscn)) - { - /* Found it. */ - xndxdata = elf_getdata (xndxscn, NULL); - break; - } - } - - /* Get the section header string table index. */ - if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) - error (EXIT_FAILURE, 0, - gettext ("cannot get section header string table index")); - - if (shdr->sh_info != 0) - printf (ngettext ("\ -\nRelocation section [%2u] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entry:\n", - "\ -\nRelocation section [%2u] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entries:\n", - nentries), - (unsigned int) elf_ndxscn (scn), - elf_strptr (ebl->elf, shstrndx, shdr->sh_name), - (unsigned int) shdr->sh_info, - elf_strptr (ebl->elf, shstrndx, destshdr->sh_name), - shdr->sh_offset, - nentries); - else - /* The .rel.dyn section does not refer to a specific section but - instead of section index zero. Do not try to print a section - name. */ - printf (ngettext ("\ -\nRelocation section [%2u] '%s' at offset %#0" PRIx64 " contains %d entry:\n", - "\ -\nRelocation section [%2u] '%s' at offset %#0" PRIx64 " contains %d entries:\n", - nentries), - (unsigned int) elf_ndxscn (scn), - elf_strptr (ebl->elf, shstrndx, shdr->sh_name), - shdr->sh_offset, - nentries); - fputs_unlocked (class == ELFCLASS32 - ? gettext ("\ - Offset Type Value Name\n") - : gettext ("\ - Offset Type Value Name\n"), - stdout); - - for (cnt = 0; cnt < nentries; ++cnt) - { - GElf_Rel relmem; - GElf_Rel *rel; - - rel = gelf_getrel (data, cnt, &relmem); - if (rel != NULL) - { - char buf[128]; - GElf_Sym symmem; - GElf_Sym *sym; - Elf32_Word xndx; - - sym = gelf_getsymshndx (symdata, xndxdata, GELF_R_SYM (rel->r_info), - &symmem, &xndx); - if (sym == NULL) - printf (" %#0*" PRIx64 " %-20s <%s %ld>\n", - class == ELFCLASS32 ? 10 : 18, rel->r_offset, - ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info)) - /* Avoid the leading R_ which isn't carrying any - information. */ - ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), - buf, sizeof (buf)) + 2 - : gettext ("<INVALID RELOC>"), - gettext ("INVALID SYMBOL"), - (long int) GELF_R_SYM (rel->r_info)); - else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION) - printf (" %#0*" PRIx64 " %-20s %#0*" PRIx64 " %s\n", - class == ELFCLASS32 ? 10 : 18, rel->r_offset, - ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info)) - /* Avoid the leading R_ which isn't carrying any - information. */ - ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), - buf, sizeof (buf)) + 2 - : gettext ("<INVALID RELOC>"), - class == ELFCLASS32 ? 10 : 18, sym->st_value, - elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name)); - else - { - destshdr = gelf_getshdr (elf_getscn (ebl->elf, - sym->st_shndx == SHN_XINDEX - ? xndx : sym->st_shndx), - &destshdr_mem); - - if (shdr == NULL) - printf (" %#0*" PRIx64 " %-20s <%s %ld>\n", - class == ELFCLASS32 ? 10 : 18, rel->r_offset, - ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info)) - /* Avoid the leading R_ which isn't carrying any - information. */ - ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), - buf, sizeof (buf)) + 2 - : gettext ("<INVALID RELOC>"), - gettext ("INVALID SECTION"), - (long int) (sym->st_shndx == SHN_XINDEX - ? xndx : sym->st_shndx)); - else - printf (" %#0*" PRIx64 " %-20s %#0*" PRIx64 " %s\n", - class == ELFCLASS32 ? 10 : 18, rel->r_offset, - ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info)) - /* Avoid the leading R_ which isn't carrying any - information. */ - ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), - buf, sizeof (buf)) + 2 - : gettext ("<INVALID RELOC>"), - class == ELFCLASS32 ? 10 : 18, sym->st_value, - elf_strptr (ebl->elf, shstrndx, destshdr->sh_name)); - } - } - } -} - - -/* Handle a relocation section. */ -static void -handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) -{ - int class = gelf_getclass (ebl->elf); - int nentries = shdr->sh_size / shdr->sh_entsize; - - /* Get the data of the section. */ - Elf_Data *data = elf_getdata (scn, NULL); - if (data == NULL) - return; - - /* Get the symbol table information. */ - Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link); - GElf_Shdr symshdr_mem; - GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem); - Elf_Data *symdata = elf_getdata (symscn, NULL); - - /* Get the section header of the section the relocations are for. */ - GElf_Shdr destshdr_mem; - GElf_Shdr *destshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_info), - &destshdr_mem); - - if (symshdr == NULL || symdata == NULL || destshdr == NULL) - { - printf (gettext ("\nInvalid symbol table at offset %#0" PRIx64 "\n"), - shdr->sh_offset); - return; - } - - /* Search for the optional extended section index table. */ - Elf_Data *xndxdata = NULL; - Elf_Scn *xndxscn = NULL; - while ((xndxscn = elf_nextscn (ebl->elf, xndxscn)) != NULL) - { - GElf_Shdr xndxshdr_mem; - GElf_Shdr *xndxshdr; - - xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem); - if (xndxshdr != NULL && xndxshdr->sh_type == SHT_SYMTAB_SHNDX - && xndxshdr->sh_link == elf_ndxscn (symscn)) - { - /* Found it. */ - xndxdata = elf_getdata (xndxscn, NULL); - break; - } - } - - /* Get the section header string table index. */ - size_t shstrndx; - if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) - error (EXIT_FAILURE, 0, - gettext ("cannot get section header string table index")); - - printf (ngettext ("\ -\nRelocation section [%2zu] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entry:\n", - "\ -\nRelocation section [%2zu] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entries:\n", - nentries), - elf_ndxscn (scn), - elf_strptr (ebl->elf, shstrndx, shdr->sh_name), - (unsigned int) shdr->sh_info, - elf_strptr (ebl->elf, shstrndx, destshdr->sh_name), - shdr->sh_offset, - nentries); - fputs_unlocked (class == ELFCLASS32 - ? gettext ("\ - Offset Type Value Addend Name\n") - : gettext ("\ - Offset Type Value Addend Name\n"), - stdout); - - for (int cnt = 0; cnt < nentries; ++cnt) - { - GElf_Rela relmem; - GElf_Rela *rel = gelf_getrela (data, cnt, &relmem); - if (rel != NULL) - { - char buf[64]; - GElf_Sym symmem; - GElf_Sym *sym; - Elf32_Word xndx; - - sym = gelf_getsymshndx (symdata, xndxdata, GELF_R_SYM (rel->r_info), - &symmem, &xndx); - - if (sym == NULL) - printf (" %#0*" PRIx64 " %-15s <%s %ld>\n", - class == ELFCLASS32 ? 10 : 18, rel->r_offset, - ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info)) - /* Avoid the leading R_ which isn't carrying any - information. */ - ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), - buf, sizeof (buf)) + 2 - : gettext ("<INVALID RELOC>"), - gettext ("INVALID SYMBOL"), - (long int) GELF_R_SYM (rel->r_info)); - else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION) - printf ("\ - %#0*" PRIx64 " %-15s %#0*" PRIx64 " +%5" PRId64 " %s\n", - class == ELFCLASS32 ? 10 : 18, rel->r_offset, - ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info)) - /* Avoid the leading R_ which isn't carrying any - information. */ - ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), - buf, sizeof (buf)) + 2 - : gettext ("<INVALID RELOC>"), - class == ELFCLASS32 ? 10 : 18, sym->st_value, - rel->r_addend, - elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name)); - else - { - destshdr = gelf_getshdr (elf_getscn (ebl->elf, - sym->st_shndx == SHN_XINDEX - ? xndx : sym->st_shndx), - &destshdr_mem); - - if (shdr == NULL) - printf (" %#0*" PRIx64 " %-15s <%s %ld>\n", - class == ELFCLASS32 ? 10 : 18, rel->r_offset, - ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info)) - /* Avoid the leading R_ which isn't carrying any - information. */ - ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), - buf, sizeof (buf)) + 2 - : gettext ("<INVALID RELOC>"), - gettext ("INVALID SECTION"), - (long int) (sym->st_shndx == SHN_XINDEX - ? xndx : sym->st_shndx)); - else - printf ("\ - %#0*" PRIx64 " %-15s %#0*" PRIx64 " +%5" PRId64 " %s\n", - class == ELFCLASS32 ? 10 : 18, rel->r_offset, - ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info)) - /* Avoid the leading R_ which isn't carrying any - information. */ - ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), - buf, sizeof (buf)) + 2 - : gettext ("<INVALID RELOC>"), - class == ELFCLASS32 ? 10 : 18, sym->st_value, - rel->r_addend, - elf_strptr (ebl->elf, shstrndx, destshdr->sh_name)); - } - } - } -} - - -/* Print the program header. */ -static void -print_symtab (Ebl *ebl, GElf_Ehdr *ehdr, int type) -{ - /* Find the symbol table(s). For this we have to search through the - section table. */ - Elf_Scn *scn = NULL; - - while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) - { - /* Handle the section if it is a symbol table. */ - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - - if (shdr != NULL && shdr->sh_type == (GElf_Word) type) - handle_symtab (ebl, ehdr, scn, shdr); - } -} - - -static void -handle_symtab (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) -{ - Elf_Data *versym_data = NULL; - Elf_Data *verneed_data = NULL; - Elf_Data *verdef_data = NULL; - Elf_Data *xndx_data = NULL; - Elf_Scn *runscn; - Elf_Data *data; - int class = gelf_getclass (ebl->elf); - unsigned int nsyms; - unsigned int cnt; - Elf32_Word verneed_stridx = 0; - Elf32_Word verdef_stridx = 0; - GElf_Shdr glink; - size_t shstrndx; - - /* Get the data of the section. */ - data = elf_getdata (scn, NULL); - if (data == NULL) - return; - - /* Find out whether we have other sections we might need. */ - runscn = NULL; - while ((runscn = elf_nextscn (ebl->elf, runscn)) != NULL) - { - GElf_Shdr runshdr_mem; - GElf_Shdr *runshdr = gelf_getshdr (runscn, &runshdr_mem); - - if (runshdr != NULL) - { - if (runshdr->sh_type == SHT_GNU_versym - && runshdr->sh_link == elf_ndxscn (scn)) - /* Bingo, found the version information. Now get the data. */ - versym_data = elf_getdata (runscn, NULL); - else if (runshdr->sh_type == SHT_GNU_verneed) - { - /* This is the information about the needed versions. */ - verneed_data = elf_getdata (runscn, NULL); - verneed_stridx = runshdr->sh_link; - } - else if (runshdr->sh_type == SHT_GNU_verdef) - { - /* This is the information about the defined versions. */ - verdef_data = elf_getdata (runscn, NULL); - verdef_stridx = runshdr->sh_link; - } - else if (runshdr->sh_type == SHT_SYMTAB_SHNDX - && runshdr->sh_link == elf_ndxscn (scn)) - /* Extended section index. */ - xndx_data = elf_getdata (runscn, NULL); - } - } - - /* Get the section header string table index. */ - if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) - error (EXIT_FAILURE, 0, - gettext ("cannot get section header string table index")); - - /* Now we can compute the number of entries in the section. */ - nsyms = data->d_size / (class == ELFCLASS32 - ? sizeof (Elf32_Sym) : sizeof (Elf64_Sym)); - - printf (ngettext ("\nSymbol table [%2u] '%s' contains %u entry:\n", - "\nSymbol table [%2u] '%s' contains %u entries:\n", - nsyms), - (unsigned int) elf_ndxscn (scn), - elf_strptr (ebl->elf, shstrndx, shdr->sh_name), nsyms); - printf (ngettext (" %lu local symbol String table: [%2u] '%s'\n", - " %lu local symbols String table: [%2u] '%s'\n", - shdr->sh_info), - (unsigned long int) shdr->sh_info, - (unsigned int) shdr->sh_link, - elf_strptr (ebl->elf, shstrndx, - gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), - &glink)->sh_name)); - - fputs_unlocked (class == ELFCLASS32 - ? gettext ("\ - Num: Value Size Type Bind Vis Ndx Name\n") - : gettext ("\ - Num: Value Size Type Bind Vis Ndx Name\n"), - stdout); - - for (cnt = 0; cnt < nsyms; ++cnt) - { - char typebuf[64]; - char bindbuf[64]; - char scnbuf[64]; - Elf32_Word xndx; - GElf_Sym sym_mem; - GElf_Sym *sym = gelf_getsymshndx (data, xndx_data, cnt, &sym_mem, &xndx); - - if (sym == NULL) - continue; - - /* Determine the real section index. */ - if (sym->st_shndx != SHN_XINDEX) - xndx = sym->st_shndx; - - printf (gettext ("\ -%5u: %0*" PRIx64 " %6" PRId64 " %-7s %-6s %-9s %6s %s"), - cnt, - class == ELFCLASS32 ? 8 : 16, - sym->st_value, - sym->st_size, - ebl_symbol_type_name (ebl, GELF_ST_TYPE (sym->st_info), - typebuf, sizeof (typebuf)), - ebl_symbol_binding_name (ebl, GELF_ST_BIND (sym->st_info), - bindbuf, sizeof (bindbuf)), - get_visibility_type (GELF_ST_VISIBILITY (sym->st_other)), - ebl_section_name (ebl, sym->st_shndx, xndx, scnbuf, - sizeof (scnbuf), NULL, shnum), - elf_strptr (ebl->elf, shdr->sh_link, sym->st_name)); - - if (versym_data != NULL) - { - /* Get the version information. */ - GElf_Versym versym_mem; - GElf_Versym *versym; - - versym = gelf_getversym (versym_data, cnt, &versym_mem); - - if (versym != NULL && ((*versym & 0x8000) != 0 || *versym > 1)) - { - bool is_nobits = false; - bool check_def = xndx != SHN_UNDEF; - - if (xndx < SHN_LORESERVE || sym->st_shndx == SHN_XINDEX) - { - GElf_Shdr symshdr_mem; - GElf_Shdr *symshdr = - gelf_getshdr (elf_getscn (ebl->elf, xndx), &symshdr_mem); - - is_nobits = (symshdr != NULL - && symshdr->sh_type == SHT_NOBITS); - } - - if (is_nobits || ! check_def) - { - /* We must test both. */ - GElf_Verneed verneed_mem; - GElf_Verneed *verneed; - GElf_Vernaux vernaux_mem; - GElf_Vernaux *vernaux = NULL; - size_t vn_offset = 0; - - verneed = gelf_getverneed (verneed_data, 0, &verneed_mem); - while (verneed != NULL) - { - size_t vna_offset = vn_offset; - - vernaux = gelf_getvernaux (verneed_data, - vna_offset += verneed->vn_aux, - &vernaux_mem); - while (vernaux != NULL - && vernaux->vna_other != *versym - && vernaux->vna_next != 0) - { - /* Update the offset. */ - vna_offset += vernaux->vna_next; - - vernaux = (vernaux->vna_next == 0 - ? NULL - : gelf_getvernaux (verneed_data, - vna_offset, - &vernaux_mem)); - } - - /* Check whether we found the version. */ - if (vernaux != NULL && vernaux->vna_other == *versym) - /* Found it. */ - break; - - vn_offset += verneed->vn_next; - verneed = (verneed->vn_next == 0 - ? NULL - : gelf_getverneed (verneed_data, vn_offset, - &verneed_mem)); - } - - if (vernaux != NULL && vernaux->vna_other == *versym) - { - printf ("@%s (%u)", - elf_strptr (ebl->elf, verneed_stridx, - vernaux->vna_name), - (unsigned int) vernaux->vna_other); - check_def = 0; - } - else if (! is_nobits) - error (0, 0, gettext ("bad dynamic symbol")); - else - check_def = 1; - } - - if (check_def && *versym != 0x8001) - { - /* We must test both. */ - GElf_Verdef verdef_mem; - GElf_Verdef *verdef; - size_t vd_offset = 0; - - verdef = gelf_getverdef (verdef_data, 0, &verdef_mem); - while (verdef != NULL) - { - if (verdef->vd_ndx == (*versym & 0x7fff)) - /* Found the definition. */ - break; - - vd_offset += verdef->vd_next; - verdef = (verdef->vd_next == 0 - ? NULL - : gelf_getverdef (verdef_data, vd_offset, - &verdef_mem)); - } - - if (verdef != NULL) - { - GElf_Verdaux verdaux_mem; - GElf_Verdaux *verdaux; - - verdaux = gelf_getverdaux (verdef_data, - vd_offset + verdef->vd_aux, - &verdaux_mem); - - if (verdaux != NULL) - printf ((*versym & 0x8000) ? "@%s" : "@@%s", - elf_strptr (ebl->elf, verdef_stridx, - verdaux->vda_name)); - } - } - } - } - - putchar ('\n'); - } -} - - -/* Print version information. */ -static void -print_verinfo (Ebl *ebl, GElf_Ehdr *ehdr) -{ - /* Find the version information sections. For this we have to - search through the section table. */ - Elf_Scn *scn = NULL; - - while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) - { - /* Handle the section if it is part of the versioning handling. */ - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - - if (shdr != NULL) - { - if (shdr->sh_type == SHT_GNU_verneed) - handle_verneed (ebl, ehdr, scn, shdr); - else if (shdr->sh_type == SHT_GNU_verdef) - handle_verdef (ebl, ehdr, scn, shdr); - else if (shdr->sh_type == SHT_GNU_versym) - handle_versym (ebl, ehdr, scn, shdr); - } - } -} - - -static const char * -get_ver_flags (unsigned int flags) -{ - static char buf[32]; - char *endp; - - if (flags == 0) - return gettext ("none"); - - if (flags & VER_FLG_BASE) - endp = stpcpy (buf, "BASE "); - else - endp = buf; - - if (flags & VER_FLG_WEAK) - { - if (endp != buf) - endp = stpcpy (endp, "| "); - - endp = stpcpy (endp, "WEAK "); - } - - if (flags & ~(VER_FLG_BASE | VER_FLG_WEAK)) - { - strncpy (endp, gettext ("| <unknown>"), buf + sizeof (buf) - endp); - buf[sizeof (buf) - 1] = '\0'; - } - - return buf; -} - - -static void -handle_verneed (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) -{ - Elf_Data *data; - int class = gelf_getclass (ebl->elf); - GElf_Shdr glink; - int cnt; - unsigned int offset; - size_t shstrndx; - - /* Get the data of the section. */ - data = elf_getdata (scn, NULL); - if (data == NULL) - return; - - /* Get the section header string table index. */ - if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) - error (EXIT_FAILURE, 0, - gettext ("cannot get section header string table index")); - - printf (ngettext ("\ -\nVersion needs section [%2u] '%s' contains %d entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", - "\ -\nVersion needs section [%2u] '%s' contains %d entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", - shdr->sh_info), - (unsigned int) elf_ndxscn (scn), - elf_strptr (ebl->elf, shstrndx, shdr->sh_name), shdr->sh_info, - class == ELFCLASS32 ? 10 : 18, shdr->sh_addr, - shdr->sh_offset, - (unsigned int) shdr->sh_link, - elf_strptr (ebl->elf, shstrndx, - gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), - &glink)->sh_name)); - - offset = 0; - for (cnt = shdr->sh_info; --cnt >= 0; ) - { - GElf_Verneed needmem; - GElf_Verneed *need; - unsigned int auxoffset; - int cnt2; - - /* Get the data at the next offset. */ - need = gelf_getverneed (data, offset, &needmem); - if (need == NULL) - break; - - printf (gettext (" %#06x: Version: %hu File: %s Cnt: %hu\n"), - offset, (unsigned short int) need->vn_version, - elf_strptr (ebl->elf, shdr->sh_link, need->vn_file), - (unsigned short int) need->vn_cnt); - - auxoffset = offset + need->vn_aux; - for (cnt2 = need->vn_cnt; --cnt2 >= 0; ) - { - GElf_Vernaux auxmem; - GElf_Vernaux *aux; - - aux = gelf_getvernaux (data, auxoffset, &auxmem); - if (aux == NULL) - break; - - printf (gettext (" %#06x: Name: %s Flags: %s Version: %hu\n"), - auxoffset, - elf_strptr (ebl->elf, shdr->sh_link, aux->vna_name), - get_ver_flags (aux->vna_flags), - (unsigned short int) aux->vna_other); - - auxoffset += aux->vna_next; - } - - /* Find the next offset. */ - offset += need->vn_next; - } -} - - -static void -handle_verdef (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) -{ - Elf_Data *data; - int class = gelf_getclass (ebl->elf); - GElf_Shdr glink; - int cnt; - unsigned int offset; - size_t shstrndx; - - /* Get the data of the section. */ - data = elf_getdata (scn, NULL); - if (data == NULL) - return; - - /* Get the section header string table index. */ - if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) - error (EXIT_FAILURE, 0, - gettext ("cannot get section header string table index")); - - printf (ngettext ("\ -\nVersion definition section [%2u] '%s' contains %d entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", - "\ -\nVersion definition section [%2u] '%s' contains %d entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", - shdr->sh_info), - (unsigned int) elf_ndxscn (scn), - elf_strptr (ebl->elf, shstrndx, shdr->sh_name), - shdr->sh_info, - class == ELFCLASS32 ? 10 : 18, shdr->sh_addr, - shdr->sh_offset, - (unsigned int) shdr->sh_link, - elf_strptr (ebl->elf, shstrndx, - gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), - &glink)->sh_name)); - - offset = 0; - for (cnt = shdr->sh_info; --cnt >= 0; ) - { - GElf_Verdef defmem; - GElf_Verdef *def; - GElf_Verdaux auxmem; - GElf_Verdaux *aux; - unsigned int auxoffset; - int cnt2; - - /* Get the data at the next offset. */ - def = gelf_getverdef (data, offset, &defmem); - if (def == NULL) - break; - - auxoffset = offset + def->vd_aux; - aux = gelf_getverdaux (data, auxoffset, &auxmem); - if (aux == NULL) - break; - - printf (gettext ("\ - %#06x: Version: %hd Flags: %s Index: %hd Cnt: %hd Name: %s\n"), - offset, def->vd_version, - get_ver_flags (def->vd_flags), - def->vd_ndx, - def->vd_cnt, - elf_strptr (ebl->elf, shdr->sh_link, aux->vda_name)); - - auxoffset += aux->vda_next; - for (cnt2 = 1; cnt2 < def->vd_cnt; ++cnt2) - { - aux = gelf_getverdaux (data, auxoffset, &auxmem); - if (aux == NULL) - break; - - printf (gettext (" %#06x: Parent %d: %s\n"), - auxoffset, cnt2, - elf_strptr (ebl->elf, shdr->sh_link, aux->vda_name)); - - auxoffset += aux->vda_next; - } - - /* Find the next offset. */ - offset += def->vd_next; - } -} - - -static void -handle_versym (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) -{ - Elf_Data *data; - int class = gelf_getclass (ebl->elf); - Elf_Scn *verscn; - GElf_Shdr glink; - Elf_Scn *defscn; - Elf_Scn *needscn; - const char **vername; - const char **filename; - size_t nvername; - unsigned int cnt; - size_t shstrndx; - - /* Get the data of the section. */ - data = elf_getdata (scn, NULL); - if (data == NULL) - return; - - /* Get the section header string table index. */ - if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) - error (EXIT_FAILURE, 0, - gettext ("cannot get section header string table index")); - - /* We have to find the version definition section and extract the - version names. */ - defscn = NULL; - needscn = NULL; - - verscn = NULL; - while ((verscn = elf_nextscn (ebl->elf, verscn)) != NULL) - { - GElf_Shdr vershdr_mem; - GElf_Shdr *vershdr = gelf_getshdr (verscn, &vershdr_mem); - - if (vershdr != NULL) - { - if (vershdr->sh_type == SHT_GNU_verdef) - defscn = verscn; - else if (vershdr->sh_type == SHT_GNU_verneed) - needscn = verscn; - } - } - - if (defscn != NULL || needscn != NULL) - { - /* We have a version information (better should have). Now get - the version names. First find the maximum version number. */ - nvername = 0; - if (defscn != NULL) - { - /* Run through the version definitions and find the highest - index. */ - unsigned int offset = 0; - Elf_Data *defdata; - GElf_Shdr defshdrmem; - GElf_Shdr *defshdr; - - defdata = elf_getdata (defscn, NULL); - if (defdata == NULL) - return; - - defshdr = gelf_getshdr (defscn, &defshdrmem); - if (defshdr == NULL) - return; - - for (cnt = 0; cnt < defshdr->sh_info; ++cnt) - { - GElf_Verdef defmem; - GElf_Verdef *def; - - /* Get the data at the next offset. */ - def = gelf_getverdef (defdata, offset, &defmem); - if (def == NULL) - break; - - nvername = MAX (nvername, (size_t) (def->vd_ndx & 0x7fff)); - - offset += def->vd_next; - } - } - if (needscn != NULL) - { - unsigned int offset = 0; - Elf_Data *needdata; - GElf_Shdr needshdrmem; - GElf_Shdr *needshdr; - - needdata = elf_getdata (needscn, NULL); - if (needdata == NULL) - return; - - needshdr = gelf_getshdr (needscn, &needshdrmem); - if (needshdr == NULL) - return; - - for (cnt = 0; cnt < needshdr->sh_info; ++cnt) - { - GElf_Verneed needmem; - GElf_Verneed *need; - unsigned int auxoffset; - int cnt2; - - /* Get the data at the next offset. */ - need = gelf_getverneed (needdata, offset, &needmem); - if (need == NULL) - break; - - /* Run through the auxiliary entries. */ - auxoffset = offset + need->vn_aux; - for (cnt2 = need->vn_cnt; --cnt2 >= 0; ) - { - GElf_Vernaux auxmem; - GElf_Vernaux *aux; - - aux = gelf_getvernaux (needdata, auxoffset, &auxmem); - if (aux == NULL) - break; - - nvername = MAX (nvername, - (size_t) (aux->vna_other & 0x7fff)); - - auxoffset += aux->vna_next; - } - - offset += need->vn_next; - } - } - - /* This is the number of versions we know about. */ - ++nvername; - - /* Allocate the array. */ - vername = (const char **) alloca (nvername * sizeof (const char *)); - filename = (const char **) alloca (nvername * sizeof (const char *)); - - /* Run through the data structures again and collect the strings. */ - if (defscn != NULL) - { - /* Run through the version definitions and find the highest - index. */ - unsigned int offset = 0; - Elf_Data *defdata; - GElf_Shdr defshdrmem; - GElf_Shdr *defshdr; - - defdata = elf_getdata (defscn, NULL); - if (defdata == NULL) - return; - - defshdr = gelf_getshdr (defscn, &defshdrmem); - if (defshdr == NULL) - return; - - for (cnt = 0; cnt < defshdr->sh_info; ++cnt) - { - GElf_Verdef defmem; - GElf_Verdef *def; - GElf_Verdaux auxmem; - GElf_Verdaux *aux; - - /* Get the data at the next offset. */ - def = gelf_getverdef (defdata, offset, &defmem); - if (def == NULL) - break; - - aux = gelf_getverdaux (defdata, offset + def->vd_aux, &auxmem); - if (aux == NULL) - break; - - vername[def->vd_ndx & 0x7fff] - = elf_strptr (ebl->elf, defshdr->sh_link, aux->vda_name); - filename[def->vd_ndx & 0x7fff] = NULL; - - offset += def->vd_next; - } - } - if (needscn != NULL) - { - unsigned int offset = 0; - Elf_Data *needdata; - GElf_Shdr needshdrmem; - GElf_Shdr *needshdr; - - needdata = elf_getdata (needscn, NULL); - if (needdata == NULL) - return; - - needshdr = gelf_getshdr (needscn, &needshdrmem); - if (needshdr == NULL) - return; - - for (cnt = 0; cnt < needshdr->sh_info; ++cnt) - { - GElf_Verneed needmem; - GElf_Verneed *need; - unsigned int auxoffset; - int cnt2; - - /* Get the data at the next offset. */ - need = gelf_getverneed (needdata, offset, &needmem); - if (need == NULL) - break; - - /* Run through the auxiliary entries. */ - auxoffset = offset + need->vn_aux; - for (cnt2 = need->vn_cnt; --cnt2 >= 0; ) - { - GElf_Vernaux auxmem; - GElf_Vernaux *aux; - - aux = gelf_getvernaux (needdata, auxoffset, &auxmem); - if (aux == NULL) - break; - - vername[aux->vna_other & 0x7fff] - = elf_strptr (ebl->elf, needshdr->sh_link, aux->vna_name); - filename[aux->vna_other & 0x7fff] - = elf_strptr (ebl->elf, needshdr->sh_link, need->vn_file); - - auxoffset += aux->vna_next; - } - - offset += need->vn_next; - } - } - } - else - { - vername = NULL; - nvername = 1; - filename = NULL; - } - - /* Print the header. */ - printf (ngettext ("\ -\nVersion symbols section [%2u] '%s' contains %d entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'", - "\ -\nVersion symbols section [%2u] '%s' contains %d entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'", - shdr->sh_size / shdr->sh_entsize), - (unsigned int) elf_ndxscn (scn), - elf_strptr (ebl->elf, shstrndx, shdr->sh_name), - (int) (shdr->sh_size / shdr->sh_entsize), - class == ELFCLASS32 ? 10 : 18, shdr->sh_addr, - shdr->sh_offset, - (unsigned int) shdr->sh_link, - elf_strptr (ebl->elf, shstrndx, - gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), - &glink)->sh_name)); - - /* Now we can finally look at the actual contents of this section. */ - for (cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt) - { - GElf_Versym symmem; - GElf_Versym *sym; - ssize_t n; - - if (cnt % 2 == 0) - printf ("\n %4d:", cnt); - - sym = gelf_getversym (data, cnt, &symmem); - if (sym == NULL) - break; - - switch (*sym) - { - case 0: - fputs_unlocked (gettext (" 0 *local* "), - stdout); - break; - - case 1: - fputs_unlocked (gettext (" 1 *global* "), - stdout); - break; - - default: - n = printf ("%4d%c%s", - *sym & 0x7fff, *sym & 0x8000 ? 'h' : ' ', - (unsigned int) (*sym & 0x7fff) < nvername - ? vername[*sym & 0x7fff] : "???"); - if ((unsigned int) (*sym & 0x7fff) < nvername - && filename[*sym & 0x7fff] != NULL) - n += printf ("(%s)", filename[*sym & 0x7fff]); - printf ("%*s", MAX (0, 33 - (int) n), " "); - break; - } - } - putchar ('\n'); -} - - -static void -handle_hash (Ebl *ebl, GElf_Ehdr *ehdr) -{ - /* Find the symbol table(s). For this we have to search through the - section table. */ - Elf_Scn *scn = NULL; - size_t shstrndx; - - /* Get the section header string table index. */ - if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) - error (EXIT_FAILURE, 0, - gettext ("cannot get section header string table index")); - - while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) - { - /* Handle the section if it is a symbol table. */ - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - - if (shdr != NULL && shdr->sh_type == SHT_HASH) - { - Elf_Data *data = elf_getdata (scn, NULL); - Elf32_Word nbucket; - Elf32_Word nchain; - Elf32_Word *bucket; - Elf32_Word *chain; - uint32_t *lengths; - uint32_t *counts; - Elf32_Word cnt; - Elf32_Word maxlength = 0; - Elf32_Word nsyms = 0; - uint64_t nzero_counts = 0; - GElf_Shdr glink; - - if (data == NULL) - { - error (0, 0, gettext ("cannot get data for section %d: %s"), - (int) elf_ndxscn (scn), elf_errmsg (-1)); - continue; - } - - nbucket = ((Elf32_Word *) data->d_buf)[0]; - nchain = ((Elf32_Word *) data->d_buf)[1]; - bucket = &((Elf32_Word *) data->d_buf)[2]; - chain = &((Elf32_Word *) data->d_buf)[2 + nbucket]; - - printf (ngettext ("\ -\nHistogram for bucket list length in section [%2u] '%s' (total of %d bucket):\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", - "\ -\nHistogram for bucket list length in section [%2u] '%s' (total of %d buckets):\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", - nbucket), - (unsigned int) elf_ndxscn (scn), - elf_strptr (ebl->elf, shstrndx, shdr->sh_name), - (int) nbucket, - gelf_getclass (ebl->elf) == ELFCLASS32 ? 10 : 18, - shdr->sh_addr, - shdr->sh_offset, - (unsigned int) shdr->sh_link, - elf_strptr (ebl->elf, shstrndx, - gelf_getshdr (elf_getscn (ebl->elf, - shdr->sh_link), - &glink)->sh_name)); - - lengths = (uint32_t *) xcalloc (nbucket, sizeof (uint32_t)); - - for (cnt = 0; cnt < nbucket; ++cnt) - if (bucket[cnt] != 0) - { - Elf32_Word inner; - - inner = bucket[cnt]; - while (inner > 0 && inner < nchain) - { - ++nsyms; - if (maxlength < ++lengths[cnt]) - ++maxlength; - - inner = chain[inner]; - } - } - - counts = (uint32_t *) xcalloc (maxlength + 1, sizeof (uint32_t)); - - for (cnt = 0; cnt < nbucket; ++cnt) - ++counts[lengths[cnt]]; - - if (nbucket > 0) - { - uint64_t success = 0; - Elf32_Word acc; - - puts (gettext (" Length Number % of total Coverage")); - printf (gettext (" 0 %6" PRIu32 " %5.1f%%\n"), - counts[0], (counts[0] * 100.0) / nbucket); - - for (cnt = 1; cnt <= maxlength; ++cnt) - { - nzero_counts += counts[cnt] * cnt; - printf (gettext ("\ -%7d %6" PRIu32 " %5.1f%% %5.1f%%\n"), - (int) cnt, - counts[cnt], (counts[cnt] * 100.0) / nbucket, - (nzero_counts * 100.0) / nsyms); - } - - acc = 0; - for (cnt = 1; cnt <= maxlength; ++cnt) - { - acc += cnt; - success += counts[cnt] * acc; - } - - printf (gettext ("\ - Average number of tests: successful lookup: %f\n\ - unsuccessful lookup: %f\n"), - (double) success / (double) nzero_counts, - (double) nzero_counts / (double) nbucket); - } - - free (counts); - free (lengths); - } - } -} - - -static void -print_liblist (Ebl *ebl, GElf_Ehdr *ehdr) -{ - /* Find the library list sections. For this we have to search - through the section table. */ - Elf_Scn *scn = NULL; - - /* Get the section header string table index. */ - size_t shstrndx; - if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) - error (EXIT_FAILURE, 0, - gettext ("cannot get section header string table index")); - - while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) - { - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - - if (shdr != NULL && shdr->sh_type == SHT_GNU_LIBLIST) - { - int nentries = shdr->sh_size / shdr->sh_entsize; - printf (ngettext ("\ -\nLibrary list section [%2zu] '%s' at offset %#0" PRIx64 " contains %d entry:\n", - "\ -\nLibrary list section [%2zu] '%s' at offset %#0" PRIx64 " contains %d entries:\n", - nentries), - elf_ndxscn (scn), - elf_strptr (ebl->elf, shstrndx, shdr->sh_name), - shdr->sh_offset, - nentries); - - Elf_Data *data = elf_getdata (scn, NULL); - if (data == NULL) - return; - - puts (gettext ("\ - Library Time Stamp Checksum Version Flags")); - - for (int cnt = 0; cnt < nentries; ++cnt) - { - GElf_Lib lib_mem; - GElf_Lib *lib = gelf_getlib (data, cnt, &lib_mem); - if (lib == NULL) - continue; - - time_t t = (time_t) lib->l_time_stamp; - struct tm *tm = gmtime (&t); - if (tm == NULL) - continue; - - printf (" [%2d] %-29s %04u-%02u-%02uT%02u:%02u:%02u %08x %-7u %u\n", - cnt, elf_strptr (ebl->elf, shdr->sh_link, lib->l_name), - tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec, - (unsigned int) lib->l_checksum, - (unsigned int) lib->l_version, - (unsigned int) lib->l_flags); - } - } - } -} - - -static const char * -dwarf_tag_string (unsigned int tag) -{ - static const char *known_tags[] = - { - [DW_TAG_array_type] = "array_type", - [DW_TAG_class_type] = "class_type", - [DW_TAG_entry_point] = "entry_point", - [DW_TAG_enumeration_type] = "enumeration_type", - [DW_TAG_formal_parameter] = "formal_parameter", - [DW_TAG_imported_declaration] = "imported_declaration", - [DW_TAG_label] = "label", - [DW_TAG_lexical_block] = "lexical_block", - [DW_TAG_member] = "member", - [DW_TAG_pointer_type] = "pointer_type", - [DW_TAG_reference_type] = "reference_type", - [DW_TAG_compile_unit] = "compile_unit", - [DW_TAG_string_type] = "string_type", - [DW_TAG_structure_type] = "structure_type", - [DW_TAG_subroutine_type] = "subroutine_type", - [DW_TAG_typedef] = "typedef", - [DW_TAG_union_type] = "union_type", - [DW_TAG_unspecified_parameters] = "unspecified_parameters", - [DW_TAG_variant] = "variant", - [DW_TAG_common_block] = "common_block", - [DW_TAG_common_inclusion] = "common_inclusion", - [DW_TAG_inheritance] = "inheritance", - [DW_TAG_inlined_subroutine] = "inlined_subroutine", - [DW_TAG_module] = "module", - [DW_TAG_ptr_to_member_type] = "ptr_to_member_type", - [DW_TAG_set_type] = "set_type", - [DW_TAG_subrange_type] = "subrange_type", - [DW_TAG_with_stmt] = "with_stmt", - [DW_TAG_access_declaration] = "access_declaration", - [DW_TAG_base_type] = "base_type", - [DW_TAG_catch_block] = "catch_block", - [DW_TAG_const_type] = "const_type", - [DW_TAG_constant] = "constant", - [DW_TAG_enumerator] = "enumerator", - [DW_TAG_file_type] = "file_type", - [DW_TAG_friend] = "friend", - [DW_TAG_namelist] = "namelist", - [DW_TAG_namelist_item] = "namelist_item", - [DW_TAG_packed_type] = "packed_type", - [DW_TAG_subprogram] = "subprogram", - [DW_TAG_template_type_param] = "template_type_param", - [DW_TAG_template_value_param] = "template_value_param", - [DW_TAG_thrown_type] = "thrown_type", - [DW_TAG_try_block] = "try_block", - [DW_TAG_variant_part] = "variant_part", - [DW_TAG_variable] = "variable", - [DW_TAG_volatile_type] = "volatile_type", - }; - const unsigned int nknown_tags = (sizeof (known_tags) - / sizeof (known_tags[0])); - static char buf[40]; - const char *result = NULL; - - if (tag < nknown_tags) - result = known_tags[tag]; - - if (result == NULL) - /* There are a few known extensions. */ - switch (tag) - { - case DW_TAG_MIPS_loop: - result = "MIPS_loop"; - break; - - case DW_TAG_format_label: - result = "format_label"; - break; - - case DW_TAG_function_template: - result = "function_template"; - break; - - case DW_TAG_class_template: - result = "class_template"; - break; - - default: - if (tag < DW_TAG_lo_user) - snprintf (buf, sizeof buf, gettext ("unknown tag %hx"), tag); - else - snprintf (buf, sizeof buf, gettext ("unknown user tag %hx"), tag); - result = buf; - break; - } - - return result; -} - - -static const char * -dwarf_attr_string (unsigned int attrnum) -{ - static const char *known_attrs[] = - { - [DW_AT_sibling] = "sibling", - [DW_AT_location] = "location", - [DW_AT_name] = "name", - [DW_AT_ordering] = "ordering", - [DW_AT_subscr_data] = "subscr_data", - [DW_AT_byte_size] = "byte_size", - [DW_AT_bit_offset] = "bit_offset", - [DW_AT_bit_size] = "bit_size", - [DW_AT_element_list] = "element_list", - [DW_AT_stmt_list] = "stmt_list", - [DW_AT_low_pc] = "low_pc", - [DW_AT_high_pc] = "high_pc", - [DW_AT_language] = "language", - [DW_AT_member] = "member", - [DW_AT_discr] = "discr", - [DW_AT_discr_value] = "discr_value", - [DW_AT_visibility] = "visibility", - [DW_AT_import] = "import", - [DW_AT_string_length] = "string_length", - [DW_AT_common_reference] = "common_reference", - [DW_AT_comp_dir] = "comp_dir", - [DW_AT_const_value] = "const_value", - [DW_AT_containing_type] = "containing_type", - [DW_AT_default_value] = "default_value", - [DW_AT_inline] = "inline", - [DW_AT_is_optional] = "is_optional", - [DW_AT_lower_bound] = "lower_bound", - [DW_AT_producer] = "producer", - [DW_AT_prototyped] = "prototyped", - [DW_AT_return_addr] = "return_addr", - [DW_AT_start_scope] = "start_scope", - [DW_AT_stride_size] = "stride_size", - [DW_AT_upper_bound] = "upper_bound", - [DW_AT_abstract_origin] = "abstract_origin", - [DW_AT_accessibility] = "accessibility", - [DW_AT_address_class] = "address_class", - [DW_AT_artificial] = "artificial", - [DW_AT_base_types] = "base_types", - [DW_AT_calling_convention] = "calling_convention", - [DW_AT_count] = "count", - [DW_AT_data_member_location] = "data_member_location", - [DW_AT_decl_column] = "decl_column", - [DW_AT_decl_file] = "decl_file", - [DW_AT_decl_line] = "decl_line", - [DW_AT_declaration] = "declaration", - [DW_AT_discr_list] = "discr_list", - [DW_AT_encoding] = "encoding", - [DW_AT_external] = "external", - [DW_AT_frame_base] = "frame_base", - [DW_AT_friend] = "friend", - [DW_AT_identifier_case] = "identifier_case", - [DW_AT_macro_info] = "macro_info", - [DW_AT_namelist_items] = "namelist_items", - [DW_AT_priority] = "priority", - [DW_AT_segment] = "segment", - [DW_AT_specification] = "specification", - [DW_AT_static_link] = "static_link", - [DW_AT_type] = "type", - [DW_AT_use_location] = "use_location", - [DW_AT_variable_parameter] = "variable_parameter", - [DW_AT_virtuality] = "virtuality", - [DW_AT_vtable_elem_location] = "vtable_elem_location" - }; - const unsigned int nknown_attrs = (sizeof (known_attrs) - / sizeof (known_attrs[0])); - static char buf[40]; - const char *result = NULL; - - if (attrnum < nknown_attrs) - result = known_attrs[attrnum]; - - if (result == NULL) - /* There are a few known extensions. */ - switch (attrnum) - { - case DW_AT_MIPS_fde: - result = "MIPS_fde"; - break; - - case DW_AT_MIPS_loop_begin: - result = "MIPS_loop_begin"; - break; - - case DW_AT_MIPS_tail_loop_begin: - result = "MIPS_tail_loop_begin"; - break; - - case DW_AT_MIPS_epilog_begin: - result = "MIPS_epilog_begin"; - break; - - case DW_AT_MIPS_loop_unroll_factor: - result = "MIPS_loop_unroll_factor"; - break; - - case DW_AT_MIPS_software_pipeline_depth: - result = "MIPS_software_pipeline_depth"; - break; - - case DW_AT_MIPS_linkage_name: - result = "MIPS_linkage_name"; - break; - - case DW_AT_MIPS_stride: - result = "MIPS_stride"; - break; - - case DW_AT_MIPS_abstract_name: - result = "MIPS_abstract_name"; - break; - - case DW_AT_MIPS_clone_origin: - result = "MIPS_clone_origin"; - break; - - case DW_AT_MIPS_has_inlines: - result = "MIPS_has_inlines"; - break; - - case DW_AT_MIPS_stride_byte: - result = "MIPS_stride_byte"; - break; - - case DW_AT_MIPS_stride_elem: - result = "MIPS_stride_elem"; - break; - - case DW_AT_MIPS_ptr_dopetype: - result = "MIPS_ptr_dopetype"; - break; - - case DW_AT_MIPS_allocatable_dopetype: - result = "MIPS_allocatable_dopetype"; - break; - - case DW_AT_MIPS_assumed_shape_dopetype: - result = "MIPS_assumed_shape_dopetype"; - break; - - case DW_AT_MIPS_assumed_size: - result = "MIPS_assumed_size"; - break; - - case DW_AT_sf_names: - result = "sf_names"; - break; - - case DW_AT_src_info: - result = "src_info"; - break; - - case DW_AT_mac_info: - result = "mac_info"; - break; - - case DW_AT_src_coords: - result = "src_coords"; - break; - - case DW_AT_body_begin: - result = "body_begin"; - break; - - case DW_AT_body_end: - result = "body_end"; - break; - - default: - if (attrnum < DW_AT_lo_user) - snprintf (buf, sizeof buf, gettext ("unknown attribute %hx"), - attrnum); - else - snprintf (buf, sizeof buf, gettext ("unknown user attribute %hx"), - attrnum); - result = buf; - break; - } - - return result; -} - - -static const char * -dwarf_form_string (unsigned int form) -{ - static const char *known_forms[] = - { - [DW_FORM_addr] = "addr", - [DW_FORM_block2] = "block2", - [DW_FORM_block4] = "block4", - [DW_FORM_data2] = "data2", - [DW_FORM_data4] = "data4", - [DW_FORM_data8] = "data8", - [DW_FORM_string] = "string", - [DW_FORM_block] = "block", - [DW_FORM_block1] = "block1", - [DW_FORM_data1] = "data1", - [DW_FORM_flag] = "flag", - [DW_FORM_sdata] = "sdata", - [DW_FORM_strp] = "strp", - [DW_FORM_udata] = "udata", - [DW_FORM_ref_addr] = "ref_addr", - [DW_FORM_ref1] = "ref1", - [DW_FORM_ref2] = "ref2", - [DW_FORM_ref4] = "ref4", - [DW_FORM_ref8] = "ref8", - [DW_FORM_ref_udata] = "ref_udata", - [DW_FORM_indirect] = "indirect" - }; - const unsigned int nknown_forms = (sizeof (known_forms) - / sizeof (known_forms[0])); - static char buf[40]; - const char *result = NULL; - - if (form < nknown_forms) - result = known_forms[form]; - - if (result == NULL) - snprintf (buf, sizeof buf, gettext ("unknown form %" PRIx64), - (uint64_t) form); - - return result; -} - - -static const char * -dwarf_lang_string (unsigned int lang) -{ - static const char *known[] = - { - [DW_LANG_C89] = "ISO C89", - [DW_LANG_C] = "C", - [DW_LANG_Ada83] = "Ada83", - [DW_LANG_C_plus_plus ] = "C++", - [DW_LANG_Cobol74] = "Cobol74", - [DW_LANG_Cobol85] = "Cobol85", - [DW_LANG_Fortran77] = "Fortran77", - [DW_LANG_Fortran90] = "Fortran90", - [DW_LANG_Pascal83] = "Pascal83", - [DW_LANG_Modula2] = "Modula2", - [DW_LANG_Java] = "Java", - [DW_LANG_C99] = "ISO C99", - [DW_LANG_Ada95] = "Ada95", - [DW_LANG_Fortran95] = "Fortran95", - [DW_LANG_PL1] = "PL1" - }; - - if (lang < sizeof (known) / sizeof (known[0])) - return known[lang]; - else if (lang == DW_LANG_Mips_Assembler) - /* This language tag is used for assembler in general. */ - return "Assembler"; - - if (lang >= DW_LANG_lo_user && lang <= DW_LANG_hi_user) - { - static char buf[100]; - snprintf (buf, sizeof (buf), "lo_user+%u", lang - DW_LANG_lo_user); - return buf; - } - - return "???"; -} - - -static void -print_ops (Dwarf *dbg, int level, unsigned int addrsize, Dwarf_Word len, - unsigned char *data) -{ - static const char *known[] = - { - [DW_OP_addr] = "addr", - [DW_OP_deref] = "deref", - [DW_OP_const1u] = "const1u", - [DW_OP_const1s] = "const1s", - [DW_OP_const2u] = "const2u", - [DW_OP_const2s] = "const2s", - [DW_OP_const4u] = "const4u", - [DW_OP_const4s] = "const4s", - [DW_OP_const8u] = "const8u", - [DW_OP_const8s] = "const8s", - [DW_OP_constu] = "constu", - [DW_OP_consts] = "consts", - [DW_OP_dup] = "dup", - [DW_OP_drop] = "drop", - [DW_OP_over] = "over", - [DW_OP_pick] = "pick", - [DW_OP_swap] = "swap", - [DW_OP_rot] = "rot", - [DW_OP_xderef] = "xderef", - [DW_OP_abs] = "abs", - [DW_OP_and] = "and", - [DW_OP_div] = "div", - [DW_OP_minus] = "minus", - [DW_OP_mod] = "mod", - [DW_OP_mul] = "mul", - [DW_OP_neg] = "neg", - [DW_OP_not] = "not", - [DW_OP_or] = "or", - [DW_OP_plus] = "plus", - [DW_OP_plus_uconst] = "plus_uconst", - [DW_OP_shl] = "shl", - [DW_OP_shr] = "shr", - [DW_OP_shra] = "shra", - [DW_OP_xor] = "xor", - [DW_OP_bra] = "bra", - [DW_OP_eq] = "eq", - [DW_OP_ge] = "ge", - [DW_OP_gt] = "gt", - [DW_OP_le] = "le", - [DW_OP_lt] = "lt", - [DW_OP_ne] = "ne", - [DW_OP_skip] = "skip", - [DW_OP_lit0] = "lit0", - [DW_OP_lit1] = "lit1", - [DW_OP_lit2] = "lit2", - [DW_OP_lit3] = "lit3", - [DW_OP_lit4] = "lit4", - [DW_OP_lit5] = "lit5", - [DW_OP_lit6] = "lit6", - [DW_OP_lit7] = "lit7", - [DW_OP_lit8] = "lit8", - [DW_OP_lit9] = "lit9", - [DW_OP_lit10] = "lit10", - [DW_OP_lit11] = "lit11", - [DW_OP_lit12] = "lit12", - [DW_OP_lit13] = "lit13", - [DW_OP_lit14] = "lit14", - [DW_OP_lit15] = "lit15", - [DW_OP_lit16] = "lit16", - [DW_OP_lit17] = "lit17", - [DW_OP_lit18] = "lit18", - [DW_OP_lit19] = "lit19", - [DW_OP_lit20] = "lit20", - [DW_OP_lit21] = "lit21", - [DW_OP_lit22] = "lit22", - [DW_OP_lit23] = "lit23", - [DW_OP_lit24] = "lit24", - [DW_OP_lit25] = "lit25", - [DW_OP_lit26] = "lit26", - [DW_OP_lit27] = "lit27", - [DW_OP_lit28] = "lit28", - [DW_OP_lit29] = "lit29", - [DW_OP_lit30] = "lit30", - [DW_OP_lit31] = "lit31", - [DW_OP_reg0] = "reg0", - [DW_OP_reg1] = "reg1", - [DW_OP_reg2] = "reg2", - [DW_OP_reg3] = "reg3", - [DW_OP_reg4] = "reg4", - [DW_OP_reg5] = "reg5", - [DW_OP_reg6] = "reg6", - [DW_OP_reg7] = "reg7", - [DW_OP_reg8] = "reg8", - [DW_OP_reg9] = "reg9", - [DW_OP_reg10] = "reg10", - [DW_OP_reg11] = "reg11", - [DW_OP_reg12] = "reg12", - [DW_OP_reg13] = "reg13", - [DW_OP_reg14] = "reg14", - [DW_OP_reg15] = "reg15", - [DW_OP_reg16] = "reg16", - [DW_OP_reg17] = "reg17", - [DW_OP_reg18] = "reg18", - [DW_OP_reg19] = "reg19", - [DW_OP_reg20] = "reg20", - [DW_OP_reg21] = "reg21", - [DW_OP_reg22] = "reg22", - [DW_OP_reg23] = "reg23", - [DW_OP_reg24] = "reg24", - [DW_OP_reg25] = "reg25", - [DW_OP_reg26] = "reg26", - [DW_OP_reg27] = "reg27", - [DW_OP_reg28] = "reg28", - [DW_OP_reg29] = "reg29", - [DW_OP_reg30] = "reg30", - [DW_OP_reg31] = "reg31", - [DW_OP_breg0] = "breg0", - [DW_OP_breg1] = "breg1", - [DW_OP_breg2] = "breg2", - [DW_OP_breg3] = "breg3", - [DW_OP_breg4] = "breg4", - [DW_OP_breg5] = "breg5", - [DW_OP_breg6] = "breg6", - [DW_OP_breg7] = "breg7", - [DW_OP_breg8] = "breg8", - [DW_OP_breg9] = "breg9", - [DW_OP_breg10] = "breg10", - [DW_OP_breg11] = "breg11", - [DW_OP_breg12] = "breg12", - [DW_OP_breg13] = "breg13", - [DW_OP_breg14] = "breg14", - [DW_OP_breg15] = "breg15", - [DW_OP_breg16] = "breg16", - [DW_OP_breg17] = "breg17", - [DW_OP_breg18] = "breg18", - [DW_OP_breg19] = "breg19", - [DW_OP_breg20] = "breg20", - [DW_OP_breg21] = "breg21", - [DW_OP_breg22] = "breg22", - [DW_OP_breg23] = "breg23", - [DW_OP_breg24] = "breg24", - [DW_OP_breg25] = "breg25", - [DW_OP_breg26] = "breg26", - [DW_OP_breg27] = "breg27", - [DW_OP_breg28] = "breg28", - [DW_OP_breg29] = "breg29", - [DW_OP_breg30] = "breg30", - [DW_OP_breg31] = "breg31", - [DW_OP_regx] = "regx", - [DW_OP_fbreg] = "fbreg", - [DW_OP_bregx] = "bregx", - [DW_OP_piece] = "piece", - [DW_OP_deref_size] = "deref_size", - [DW_OP_xderef_size] = "xderef_size", - [DW_OP_nop] = "nop", - [DW_OP_push_object_address] = "push_object_address", - [DW_OP_call2] = "call2", - [DW_OP_call4] = "call4", - [DW_OP_call_ref] = "call_ref", - }; - - Dwarf_Word offset = 0; - while (len-- > 0) - { - size_t op = *((unsigned char *) data); - ++data; - - switch (op) - { - case DW_OP_call_ref: - case DW_OP_addr:; - /* Address operand. */ - Dwarf_Word addr; - if (addrsize == 4) - addr = read_4ubyte_unaligned (dbg, data); - else - { - assert (addrsize == 8); - addr = read_8ubyte_unaligned (dbg, data); - } - data += addrsize; - len -= addrsize; - - printf (" %*s [%4" PRIuMAX "] %s %" PRIuMAX "\n", - (int) (20 + level * 2), "", (uintmax_t) offset, - known[op] ?: "???", (uintmax_t) addr); - offset += 1 + addrsize; - break; - - case DW_OP_deref_size: /* XXX Correct? */ - case DW_OP_xderef_size: /* XXX Correct? */ - case DW_OP_pick: - case DW_OP_const1u: - printf (" %*s [%4" PRIuMAX "] %s %" PRIu8 "\n", - (int) (20 + level * 2), "", (uintmax_t) offset, - known[op] ?: "???", *((uint8_t *) data)); - ++data; - --len; - offset += 2; - break; - - case DW_OP_const2u: - printf (" %*s [%4" PRIuMAX "] %s %" PRIu16 "\n", - (int) (20 + level * 2), "", (uintmax_t) offset, - known[op] ?: "???", read_2ubyte_unaligned (dbg, data)); - len -= 2; - data += 2; - offset += 3; - break; - - case DW_OP_const4u: - printf (" %*s [%4" PRIuMAX "] %s %" PRIu32 "\n", - (int) (20 + level * 2), "", (uintmax_t) offset, - known[op] ?: "???", read_4ubyte_unaligned (dbg, data)); - len -= 4; - data += 4; - offset += 5; - break; - - case DW_OP_const8u: - printf (" %*s [%4" PRIuMAX "] %s %" PRIu64 "\n", - (int) (20 + level * 2), "", (uintmax_t) offset, - known[op] ?: "???", read_8ubyte_unaligned (dbg, data)); - len -= 8; - data += 8; - offset += 9; - break; - - case DW_OP_const1s: - printf (" %*s [%4" PRIuMAX "] %s %" PRId8 "\n", - (int) (20 + level * 2), "", (uintmax_t) offset, - known[op] ?: "???", *((int8_t *) data)); - ++data; - --len; - offset += 2; - break; - - case DW_OP_const2s: - printf (" %*s [%4" PRIuMAX "] %s %" PRId16 "\n", - (int) (20 + level * 2), "", (uintmax_t) offset, - known[op] ?: "???", read_2sbyte_unaligned (dbg, data)); - len -= 2; - data += 2; - offset += 3; - break; - - case DW_OP_const4s: - printf (" %*s [%4" PRIuMAX "] %s %" PRId32 "\n", - (int) (20 + level * 2), "", (uintmax_t) offset, - known[op] ?: "???", read_4sbyte_unaligned (dbg, data)); - len -= 4; - data += 4; - offset += 5; - break; - - case DW_OP_const8s: - printf (" %*s [%4" PRIuMAX "] %s %" PRId64 "\n", - (int) (20 + level * 2), "", (uintmax_t) offset, - known[op] ?: "???", read_8sbyte_unaligned (dbg, data)); - len -= 8; - data += 8; - offset += 9; - break; - - case DW_OP_piece: /* XXX Correct? */ - case DW_OP_regx: - case DW_OP_plus_uconst: - case DW_OP_constu:; - unsigned char *start = data; - unsigned int uleb; - get_uleb128 (uleb, data); - printf (" %*s [%4" PRIuMAX "] %s %u\n", - (int) (20 + level * 2), "", (uintmax_t) offset, - known[op] ?: "???", uleb); - len -= data - start; - offset += 1 + (data - start); - break; - - case DW_OP_fbreg: - case DW_OP_breg0 ... DW_OP_breg31: - case DW_OP_consts: - start = data; - unsigned int sleb; - get_sleb128 (sleb, data); - printf (" %*s [%4" PRIuMAX "] %s %d\n", - (int) (20 + level * 2), "", (uintmax_t) offset, - known[op] ?: "???", sleb); - len -= data - start; - offset += 1 + (data - start); - break; - - case DW_OP_bregx: - start = data; - get_uleb128 (uleb, data); - get_sleb128 (sleb, data); - printf (" %*s [%4" PRIuMAX "] %s %u %d\n", - (int) (20 + level * 2), "", (uintmax_t) offset, - known[op] ?: "???", uleb, sleb); - len -= data - start; - offset += 1 + (data - start); - break; - - case DW_OP_call2: - case DW_OP_call4: - case DW_OP_skip: - case DW_OP_bra: - printf (" %*s [%4" PRIuMAX "] %s %" PRIuMAX "\n", - (int) (20 + level * 2), "", (uintmax_t) offset, - known[op] ?: "???", - (uintmax_t) (offset + read_2sbyte_unaligned (dbg, data))); - len -= 2; - data += 2; - offset += 3; - break; - - default: - /* No Operand. */ - printf (" %*s [%4" PRIuMAX "] %s\n", - (int) (20 + level * 2), "", (uintmax_t) offset, - known[op] ?: "???"); - ++offset; - break; - } - } -} - - -static void -print_debug_abbrev_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, - GElf_Shdr *shdr, Dwarf *dbg) -{ - printf (gettext ("\nDWARF section '%s' at offset %#" PRIx64 ":\n" - " [ Code]\n"), - ".debug_abbrev", (uint64_t) shdr->sh_offset); - - Dwarf_Off offset = 0; - while (1) - { - size_t length; - Dwarf_Abbrev abbrev; - - if (dwarf_offabbrev (dbg, offset, &length, &abbrev) != 0) - { - printf (gettext (" *** error while reading abbreviation: %s\n"), - dwarf_errmsg (-1)); - break; - } - - if (length == 1) - /* This is the NUL byte at the end of the section. */ - break; - - /* We know these calls can never fail. */ - unsigned int code = dwarf_getabbrevcode (&abbrev); - unsigned int tag = dwarf_getabbrevtag (&abbrev); - int has_children = dwarf_abbrevhaschildren (&abbrev); - - printf (gettext (" [%5u] offset: %" PRId64 - ", children: %s, tag: %s\n"), - code, (int64_t) offset, - has_children ? gettext ("yes") : gettext ("no"), - dwarf_tag_string (tag)); - - size_t cnt = 0; - unsigned int name; - unsigned int form; - Dwarf_Off enoffset; - while (dwarf_getabbrevattr (&abbrev, cnt, &name, &form, &enoffset) == 0) - { - printf (" attr: %s, form: %s, offset: %#" PRIx64 "\n", - dwarf_attr_string (name), dwarf_form_string (form), - (uint64_t) enoffset); - - ++cnt; - } - - offset += length; - } -} - - -/* Print content of DWARF .debug_aranges section. We fortunately do - not have to know a bit about the structure of the section, libdwarf - takes care of it. */ -static void -print_debug_aranges_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, - GElf_Shdr *shdr, Dwarf *dbg) -{ - Dwarf_Aranges *aranges; - size_t cnt; - if (dwarf_getaranges (dbg, &aranges, &cnt) != 0) - { - error (0, 0, gettext ("cannot get .debug_aranges content: %s"), - dwarf_errmsg (-1)); - return; - } - - printf (ngettext ("\ -\nDWARF section '%s' at offset %#" PRIx64 " contains %zu entry:\n", - "\ -\nDWARF section '%s' at offset %#" PRIx64 " contains %zu entries:\n", - cnt), - ".debug_aranges", (uint64_t) shdr->sh_offset, cnt); - - /* Compute floor(log16(cnt)). */ - size_t tmp = cnt; - int digits = 1; - while (tmp >= 16) - { - ++digits; - tmp >>= 4; - } - - for (size_t n = 0; n < cnt; ++n) - { - Dwarf_Arange *runp = dwarf_onearange (aranges, n); - if (runp == NULL) - { - printf ("cannot get arange %zu: %s\n", n, dwarf_errmsg (-1)); - return; - } - - Dwarf_Addr start; - Dwarf_Word length; - Dwarf_Off offset; - - if (dwarf_getarangeinfo (runp, &start, &length, &offset) != 0) - printf (gettext (" [%*zu] ???\n"), digits, n); - else - printf (gettext (" [%*zu] start: %0#*" PRIx64 - ", length: %5" PRIu64 ", CU DIE offset: %6" - PRId64 "\n"), - digits, n, ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 10 : 18, - (uint64_t) start, (uint64_t) length, (int64_t) offset); - } -} - - -static void -print_debug_frame_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, - GElf_Shdr *shdr, Dwarf *dbg) -{ -} - - -struct attrcb_args -{ - Dwarf *dbg; - int level; - unsigned int addrsize; - Dwarf_Off cu_offset; -}; - - -static int -attr_callback (Dwarf_Attribute *attrp, void *arg) -{ - struct attrcb_args *cbargs = (struct attrcb_args *) arg; - const int level = cbargs->level; - - unsigned int attr = dwarf_whatattr (attrp); - if (unlikely (attr == 0)) - { - error (0, 0, gettext ("cannot get attribute code: %s"), - dwarf_errmsg (-1)); - return DWARF_CB_ABORT; - } - - unsigned int form = dwarf_whatform (attrp); - if (unlikely (form == 0)) - { - error (0, 0, gettext ("cannot get attribute form: %s"), - dwarf_errmsg (-1)); - return DWARF_CB_ABORT; - } - - switch (form) - { - case DW_FORM_addr:; - Dwarf_Addr addr; - if (unlikely (dwarf_formaddr (attrp, &addr) != 0)) - { - attrval_out: - error (0, 0, gettext ("cannot get attribute value: %s"), - dwarf_errmsg (-1)); - return DWARF_CB_ABORT; - } - printf (" %*s%-20s %#0*" PRIxMAX "\n", - (int) (level * 2), "", dwarf_attr_string (attr), - (int) (cbargs->addrsize * 2), (uintmax_t) addr); - break; - - case DW_FORM_indirect: - case DW_FORM_strp: - case DW_FORM_string:; - const char *str = dwarf_formstring (attrp); - if (unlikely (str == NULL)) - goto attrval_out; - printf (" %*s%-20s \"%s\"\n", - (int) (level * 2), "", dwarf_attr_string (attr), str); - break; - - case DW_FORM_ref_addr: - case DW_FORM_ref_udata: - case DW_FORM_ref8: - case DW_FORM_ref4: - case DW_FORM_ref2: - case DW_FORM_ref1:; - Dwarf_Off ref; - if (unlikely (dwarf_formref (attrp, &ref) != 0)) - goto attrval_out; - - printf (" %*s%-20s [%6" PRIxMAX "]\n", - (int) (level * 2), "", dwarf_attr_string (attr), - (uintmax_t) (ref + cbargs->cu_offset)); - break; - - case DW_FORM_udata: - case DW_FORM_sdata: - case DW_FORM_data8: - case DW_FORM_data4: - case DW_FORM_data2: - case DW_FORM_data1:; - Dwarf_Word num; - if (unlikely (dwarf_formudata (attrp, &num) != 0)) - goto attrval_out; - - if (attr == DW_AT_language) - { - printf (" %*s%-20s %s (%d)\n", - (int) (level * 2), "", dwarf_attr_string (attr), - dwarf_lang_string (num), (int) num); - break; - } - - printf (" %*s%-20s %" PRIuMAX "\n", - (int) (level * 2), "", dwarf_attr_string (attr), - (uintmax_t) num); - break; - - case DW_FORM_flag:; - bool flag; - if (unlikely (dwarf_formflag (attrp, &flag) != 0)) - goto attrval_out; - - printf (" %*s%-20s %s\n", - (int) (level * 2), "", dwarf_attr_string (attr), - nl_langinfo (flag ? YESSTR : NOSTR)); - break; - - case DW_FORM_block4: - case DW_FORM_block2: - case DW_FORM_block1: - case DW_FORM_block:; - Dwarf_Block block; - if (unlikely (dwarf_formblock (attrp, &block) != 0)) - goto attrval_out; - - printf (" %*s%-20s %" PRIxMAX " byte block\n", - (int) (level * 2), "", dwarf_attr_string (attr), - (uintmax_t) block.length); - - if (attr == DW_AT_data_member_location) - print_ops (cbargs->dbg, level, cbargs->addrsize, block.length, - block.data); - break; - - default: - printf (" %*s%-20s [form: %d] ???\n", - (int) (level * 2), "", dwarf_attr_string (attr), - (int) form); - break; - } - - return DWARF_CB_OK; -} - - -static void -print_debug_info_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, - GElf_Shdr *shdr, Dwarf *dbg) -{ - printf (gettext ("\ -\nDWARF section '%s' at offset %#" PRIx64 ":\n [Offset]\n"), - ".debug_info", (uint64_t) shdr->sh_offset); - - /* If the section is empty we don't have to do anything. */ - if (shdr->sh_size == 0) - return; - - size_t maxdies = 20; - Dwarf_Die *dies = (Dwarf_Die *) xmalloc (maxdies * sizeof (Dwarf_Die)); - - Dwarf_Off offset = 0; - - /* New compilation unit. */ - size_t cuhl; - //Dwarf_Half version; - Dwarf_Off abbroffset; - uint8_t addrsize; - uint8_t offsize; - Dwarf_Off nextcu; - next_cu: - if (dwarf_nextcu (dbg, offset, &nextcu, &cuhl, &abbroffset, &addrsize, - &offsize) != 0) - goto do_return; - - printf (gettext (" Compilation unit at offset %" PRIu64 ":\n" - " Version: %" PRIu16 ", Abbreviation section offset: %" - PRIu64 ", Address size: %" PRIu8 ", Offset size: %" PRIu8 "\n"), - (uint64_t) offset, /*version*/2, abbroffset, addrsize, offsize); - - - struct attrcb_args args; - args.dbg = dbg; - args.addrsize = addrsize; - args.cu_offset = offset; - - offset += cuhl; - - int level = 0; - - if (unlikely (dwarf_offdie (dbg, offset, &dies[level]) == NULL)) - { - error (0, 0, gettext ("cannot get DIE at offset %" PRIu64 - " in section '%s': %s"), - (uint64_t) offset, ".debug_info", dwarf_errmsg (-1)); - goto do_return; - } - - do - { - offset = dwarf_dieoffset (&dies[level]); - if (offset == -1l) - { - error (0, 0, gettext ("cannot get DIE offset: %s"), - dwarf_errmsg (-1)); - goto do_return; - } - - int tag = dwarf_tag (&dies[level]); - if (tag == DW_TAG_invalid) - { - error (0, 0, gettext ("cannot get tag of DIE at offset %" PRIu64 - " in section '%s': %s"), - (uint64_t) offset, ".debug_info", dwarf_errmsg (-1)); - goto do_return; - } - - static const char *const lowtags[] = - { - [DW_TAG_array_type] = "array_type", - [DW_TAG_class_type] = "class_type", - [DW_TAG_entry_point] = "entry_point", - [DW_TAG_enumeration_type] = "enumeration_type", - [DW_TAG_formal_parameter] = "formal_parameter", - [DW_TAG_imported_declaration] = "imported_declaration", - [DW_TAG_label] = "label", - [DW_TAG_lexical_block] = "lexical_block", - [DW_TAG_member] = "member", - [DW_TAG_pointer_type] = "pointer_type", - [DW_TAG_reference_type] = "reference_type", - [DW_TAG_compile_unit] = "compile_unit", - [DW_TAG_string_type] = "string_type", - [DW_TAG_structure_type] = "structure_type", - [DW_TAG_subroutine_type] = "subroutine_type", - [DW_TAG_typedef] = "typedef", - [DW_TAG_union_type] = "union_type", - [DW_TAG_unspecified_parameters] = "unspecified_parameters", - [DW_TAG_variant] = "variant", - [DW_TAG_common_block] = "common_block", - [DW_TAG_common_inclusion] = "common_inclusion", - [DW_TAG_inheritance] = "inheritance", - [DW_TAG_inlined_subroutine] = "inlined_subroutine", - [DW_TAG_module] = "module", - [DW_TAG_ptr_to_member_type] = "ptr_to_member_type", - [DW_TAG_set_type] = "set_type", - [DW_TAG_subrange_type] = "subrange_type", - [DW_TAG_with_stmt] = "with_stmt", - [DW_TAG_access_declaration] = "access_declaration", - [DW_TAG_base_type] = "base_type", - [DW_TAG_catch_block] = "catch_block", - [DW_TAG_const_type] = "const_type", - [DW_TAG_constant] = "constant", - [DW_TAG_enumerator] = "enumerator", - [DW_TAG_file_type] = "file_type", - [DW_TAG_friend] = "friend", - [DW_TAG_namelist] = "namelist", - [DW_TAG_namelist_item] = "namelist_item", - [DW_TAG_packed_type] = "packed_type", - [DW_TAG_subprogram] = "subprogram", - [DW_TAG_template_type_param] = "template_type_param", - [DW_TAG_template_value_param] = "template_value_param", - [DW_TAG_thrown_type] = "thrown_type", - [DW_TAG_try_block] = "try_block", - [DW_TAG_variant_part] = "variant_part", - [DW_TAG_variable] = "variable", - [DW_TAG_volatile_type] = "volatile_type" - }; - - const char *tagstr; - switch (tag) - { - case DW_TAG_lo_user: - tagstr = "lo_user"; - break; - - case DW_TAG_MIPS_loop: - tagstr = "MIPS_loop"; - break; - - case DW_TAG_format_label: - tagstr = "format_label"; - break; - - case DW_TAG_function_template: - tagstr = "function_template"; - break; - - case DW_TAG_class_template: - tagstr = "class_template"; - break; - case DW_TAG_hi_user: - tagstr = "hi_user"; - break; - - default: - if (tag < sizeof (lowtags) / sizeof (lowtags[0])) - tagstr = lowtags[tag]; - else - tagstr = "???"; - break; - } - - printf (" [%6" PRIx64 "] %*s%s\n", - (uint64_t) offset, (int) (level * 2), "", tagstr); - - /* Print the attribute values. */ - args.level = level; - (void) dwarf_getattrs (&dies[level], attr_callback, &args, 0); - - /* Make room for the next level's DIE. */ - if (level + 1 == maxdies) - dies = (Dwarf_Die *) xrealloc (dies, - (maxdies += 10) - * sizeof (Dwarf_Die)); - - int res = dwarf_child (&dies[level], &dies[level + 1]); - if (res > 0) - { - while ((res = dwarf_siblingof (&dies[level], &dies[level])) == 1) - if (level-- == 0) - break; - - if (res == -1) - { - error (0, 0, gettext ("cannot get next DIE: %s\n"), - dwarf_errmsg (-1)); - goto do_return; - } - } - else if (unlikely (res < 0)) - { - error (0, 0, gettext ("cannot get next DIE: %s"), - dwarf_errmsg (-1)); - goto do_return; - } - else - ++level; - } - while (level >= 0); - - offset = nextcu; - if (offset != 0) - goto next_cu; - - do_return: - free (dies); -} - - -static void -print_debug_line_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, - GElf_Shdr *shdr, Dwarf *dbg) -{ - printf (gettext ("\ -\nDWARF section '%s' at offset %#" PRIx64 ":\n"), - ".debug_line", (uint64_t) shdr->sh_offset); - - if (shdr->sh_size == 0) - return; - - /* There is no functionality in libdw to read the information in the - way it is represented here. Hardcode the decoder. */ - Elf_Data *data = elf_getdata (scn, NULL); - if (data == NULL || data->d_buf == NULL) - { - error (0, 0, gettext ("cannot get line data section data: %s"), - elf_errmsg (-1)); - return; - } - - const unsigned char *linep = (const unsigned char *) data->d_buf; - const unsigned char *lineendp; - - while (linep - < (lineendp = (const unsigned char *) data->d_buf + data->d_size)) - { - size_t start_offset = linep - (const unsigned char *) data->d_buf; - - Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep); - unsigned int length = 4; - if (unlikely (unit_length == 0xffffffff)) - { - if (unlikely (linep + 8 > lineendp)) - { - invalid_data: - error (0, 0, gettext ("invalid data in section [%zu] '%s'"), - elf_ndxscn (scn), ".debug_line"); - return; - } - unit_length = read_8ubyte_unaligned_inc (dbg, linep); - length = 8; - } - - /* Check whether we have enough room in the section. */ - if (unit_length < 2 + length + 5 * 1 - || unlikely (linep + unit_length > lineendp)) - goto invalid_data; - lineendp = linep + unit_length; - - /* The next element of the header is the version identifier. */ - uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep); - - /* Next comes the header length. */ - Dwarf_Word header_length; - if (length == 4) - header_length = read_4ubyte_unaligned_inc (dbg, linep); - else - header_length = read_8ubyte_unaligned_inc (dbg, linep); - //const unsigned char *header_start = linep; - - /* Next the minimum instruction length. */ - uint_fast8_t minimum_instr_len = *linep++; - - /* Then the flag determining the default value of the is_stmt - register. */ - uint_fast8_t default_is_stmt = *linep++; - - /* Now the line base. */ - int_fast8_t line_base = *((const int_fast8_t *) linep); - ++linep; - - /* And the line range. */ - uint_fast8_t line_range = *linep++; - - /* The opcode base. */ - uint_fast8_t opcode_base = *linep++; - - /* Print what we got so far. */ - printf (gettext ("\n" - " Length: %" PRIu64 "\n" - " DWARF version: %" PRIuFAST16 "\n" - " Prologue length: %" PRIu64 "\n" - " Minimum instruction length: %" PRIuFAST8 "\n" - " Initial value if '%s': %" PRIuFAST8 "\n" - " Line base: %" PRIdFAST8 "\n" - " Line range: %" PRIuFAST8 "\n" - " Opcode base: %" PRIuFAST8 "\n" - "\n" - "Opcodes:\n"), - (uint64_t) unit_length, version, (uint64_t) header_length, - minimum_instr_len, "is_stmt", default_is_stmt, line_base, - line_range, opcode_base); - - if (unlikely (linep + opcode_base - 1 >= lineendp)) - goto invalid_data; - int opcode_base_l10 = 1; - unsigned int tmp = opcode_base; - while (tmp > 10) - { - tmp /= 10; - ++opcode_base_l10; - } - const uint8_t *standard_opcode_lengths = linep - 1; - for (uint_fast8_t cnt = 1; cnt < opcode_base; ++cnt) - printf (ngettext (" [%*" PRIuFAST8 "] %hhu argument\n", - " [%*" PRIuFAST8 "] %hhu arguments\n", - (int) linep[cnt - 1]), - opcode_base_l10, cnt, linep[cnt - 1]); - linep += opcode_base - 1; - if (unlikely (linep >= lineendp)) - goto invalid_data; - - puts (gettext ("\nDirectory table:")); - while (*linep != 0) - { - unsigned char *endp = memchr (linep, '\0', lineendp - linep); - if (endp == NULL) - goto invalid_data; - - printf (" %s\n", (char *) linep); - - linep = endp + 1; - } - /* Skip the final NUL byte. */ - ++linep; - - if (unlikely (linep >= lineendp)) - goto invalid_data; - puts (gettext ("\nFile name table:\n" - " Entry Dir Time Size Name")); - for (unsigned int cnt = 1; *linep != 0; ++cnt) - { - /* First comes the file name. */ - char *fname = (char *) linep; - unsigned char *endp = memchr (fname, '\0', lineendp - linep); - if (endp == NULL) - goto invalid_data; - linep = endp + 1; - - /* Then the index. */ - unsigned int diridx; - get_uleb128 (diridx, linep); - - /* Next comes the modification time. */ - unsigned int mtime; - get_uleb128 (mtime, linep); - - /* Finally the length of the file. */ - unsigned int fsize; - get_uleb128 (fsize, linep); - - printf (" %-5u %-5u %-9u %-9u %s\n", - cnt, diridx, mtime, fsize, fname); - } - /* Skip the final NUL byte. */ - ++linep; - - puts (gettext ("\nLine number statements:")); - Dwarf_Word address = 0; - size_t line = 1; - uint_fast8_t is_stmt = default_is_stmt; - - /* Default address value, in case we do not find the CU. */ - size_t address_size - = elf_getident (ebl->elf, NULL)[EI_CLASS] == ELFCLASS32 ? 4 : 8; - - /* Determine the CU this block is for. */ - Dwarf_Off cuoffset; - Dwarf_Off ncuoffset = 0; - size_t hsize; - while (dwarf_nextcu (dbg, cuoffset = ncuoffset, &ncuoffset, &hsize, - NULL, NULL, NULL) == 0) - { - Dwarf_Die cudie; - if (dwarf_offdie (dbg, cuoffset + hsize, &cudie) == NULL) - continue; - Dwarf_Attribute stmt_list; - if (dwarf_attr (&cudie, DW_AT_stmt_list, &stmt_list) == NULL) - continue; - Dwarf_Word lineoff; - if (dwarf_formudata (&stmt_list, &lineoff) != 0) - continue; - if (lineoff == start_offset) - { - /* Found the CU. */ - address_size = cudie.cu->address_size; - break; - } - } - - while (linep < lineendp) - { - unsigned int u128; - int s128; - - /* Read the opcode. */ - unsigned int opcode = *linep++; - - /* Is this a special opcode? */ - if (likely (opcode >= opcode_base)) - { - /* Yes. Handling this is quite easy since the opcode value - is computed with - - opcode = (desired line increment - line_base) - + (line_range * address advance) + opcode_base - */ - int line_increment = (line_base - + (opcode - opcode_base) % line_range); - unsigned int address_increment = (minimum_instr_len - * ((opcode - opcode_base) - / line_range)); - - /* Perform the increments. */ - line += line_increment; - address += address_increment; - - printf (gettext ("\ - special opcode %u: address+%u = %#" PRIx64 ", line%+d = %zu\n"), - opcode, address_increment, (uint64_t) address, - line_increment, line); - } - else if (opcode == 0) - { - /* This an extended opcode. */ - if (unlikely (linep + 2 > lineendp)) - goto invalid_data; - - /* The length. */ - unsigned int len = *linep++; - - if (unlikely (linep + len > lineendp)) - goto invalid_data; - - /* The sub-opcode. */ - opcode = *linep++; - - printf (gettext (" extended opcode %u: "), opcode); - - switch (opcode) - { - case DW_LNE_end_sequence: - puts (gettext ("end of sequence")); - - /* Reset the registers we care about. */ - address = 0; - line = 1; - is_stmt = default_is_stmt; - break; - - case DW_LNE_set_address: - if (address_size == 4) - address = read_4ubyte_unaligned_inc (dbg, linep); - else - address = read_8ubyte_unaligned_inc (dbg, linep); - printf (gettext ("set address to %#" PRIx64 "\n"), - (uint64_t) address); - break; - - case DW_LNE_define_file: - { - char *fname = (char *) linep; - unsigned char *endp = memchr (linep, '\0', - lineendp - linep); - if (endp == NULL) - goto invalid_data; - linep = endp + 1; - - unsigned int diridx; - get_uleb128 (diridx, linep); - Dwarf_Word mtime; - get_uleb128 (mtime, linep); - Dwarf_Word filelength; - get_uleb128 (filelength, linep); - - printf (gettext ("\ -define new file: dir=%u, mtime=%" PRIu64 ", length=%" PRIu64 ", name=%s\n"), - diridx, (uint64_t) mtime, (uint64_t) filelength, - fname); - } - break; - - default: - /* Unknown, ignore it. */ - puts (gettext ("unknown opcode")); - linep += len - 1; - break; - } - } - else if (opcode <= DW_LNS_set_epilog_begin) - { - /* This is a known standard opcode. */ - switch (opcode) - { - case DW_LNS_copy: - /* Takes no argument. */ - puts (gettext (" copy")); - break; - - case DW_LNS_advance_pc: - /* Takes one uleb128 parameter which is added to the - address. */ - get_uleb128 (u128, linep); - address += minimum_instr_len * u128; - printf (gettext ("\ - advance address by %u to %#" PRIx64 "\n"), - u128, (uint64_t) address); - break; - - case DW_LNS_advance_line: - /* Takes one sleb128 parameter which is added to the - line. */ - get_sleb128 (s128, linep); - line += s128; - printf (gettext ("\ - advance line by constant %d to %" PRId64 "\n"), - s128, (int64_t) line); - break; - - case DW_LNS_set_file: - /* Takes one uleb128 parameter which is stored in file. */ - get_uleb128 (u128, linep); - printf (gettext (" set file to %" PRIu64 "\n"), - (uint64_t) u128); - break; - - case DW_LNS_set_column: - /* Takes one uleb128 parameter which is stored in column. */ - if (unlikely (standard_opcode_lengths[opcode] != 1)) - goto invalid_data; - - get_uleb128 (u128, linep); - printf (gettext (" set column to %" PRIu64 "\n"), - (uint64_t) u128); - break; - - case DW_LNS_negate_stmt: - /* Takes no argument. */ - is_stmt = 1 - is_stmt; - printf (gettext (" set '%s' to %" PRIuFAST8 "\n"), - "is_stmt", is_stmt); - break; - - case DW_LNS_set_basic_block: - /* Takes no argument. */ - puts (gettext (" set basic block flag")); - break; - - case DW_LNS_const_add_pc: - /* Takes no argument. */ - u128 = (minimum_instr_len - * ((255 - opcode_base) / line_range)); - address += u128; - printf (gettext ("\ - advance address by constant %u to %#" PRIx64 "\n"), - u128, (uint64_t) address); - break; - - case DW_LNS_fixed_advance_pc: - /* Takes one 16 bit parameter which is added to the - address. */ - if (unlikely (standard_opcode_lengths[opcode] != 1)) - goto invalid_data; - - u128 = read_2ubyte_unaligned_inc (dbg, linep); - address += u128; - printf (gettext ("\ - advance address by fixed value %u to %#" PRIx64 "\n"), - u128, (uint64_t) address); - break; - - case DW_LNS_set_prologue_end: - /* Takes no argument. */ - puts (gettext (" set prologue end flag")); - break; - - case DW_LNS_set_epilog_begin: - /* Takes no argument. */ - puts (gettext (" set epilogue begin flag")); - break; - } - } - else - { - /* This is a new opcode the generator but not we know about. - Read the parameters associated with it but then discard - everything. Read all the parameters for this opcode. */ - printf (ngettext (" unknown opcode with %" PRIu8 " parameter:", - " unknown opcode with %" PRIu8 " parameters:", - standard_opcode_lengths[opcode]), - standard_opcode_lengths[opcode]); - for (int n = standard_opcode_lengths[opcode]; n > 0; --n) - { - get_uleb128 (u128, linep); - if (n != standard_opcode_lengths[opcode]) - putc_unlocked (',', stdout); - printf (" %u", u128); - } - - /* Next round, ignore this opcode. */ - continue; - } - } - } - - /* There must only be one data block. */ - assert (elf_getdata (scn, data) == NULL); -} - - -static void -print_debug_loc_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, - GElf_Shdr *shdr, Dwarf *dbg) -{ - printf (gettext ("\ -\nDWARF section '%s' at offset %#" PRIx64 ":\n"), - ".debug_loc", (uint64_t) shdr->sh_offset); - - // XXX add something -} - - -struct mac_culist -{ - Dwarf_Die die; - Dwarf_Off offset; - Dwarf_Files *files; - struct mac_culist *next; -}; - - -static int -mac_compare (const void *p1, const void *p2) -{ - struct mac_culist *m1 = (struct mac_culist *) p1; - struct mac_culist *m2 = (struct mac_culist *) p2; - - if (m1->offset < m2->offset) - return -1; - if (m1->offset > m2->offset) - return 1; - return 0; -} - - -static void -print_debug_macinfo_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, - GElf_Shdr *shdr, Dwarf *dbg) -{ - printf (gettext ("\ -\nDWARF section '%s' at offset %#" PRIx64 ":\n"), - ".debug_macinfo", (uint64_t) shdr->sh_offset); - putc_unlocked ('\n', stdout); - - /* There is no function in libdw to iterate over the raw content of - the section but it is easy enough to do. */ - Elf_Data *data = elf_getdata (scn, NULL); - if (data == NULL || data->d_buf == NULL) - { - error (0, 0, gettext ("cannot get macro information section data: %s"), - elf_errmsg (-1)); - return; - } - - /* Get the source file information for all CUs. */ - Dwarf_Off offset; - Dwarf_Off ncu = 0; - size_t hsize; - struct mac_culist *culist = NULL; - size_t nculist = 0; - while (dwarf_nextcu (dbg, offset = ncu, &ncu, &hsize, NULL, NULL, NULL) == 0) - { - Dwarf_Die cudie; - if (dwarf_offdie (dbg, offset + hsize, &cudie) == NULL) - continue; - - Dwarf_Attribute attr; - if (dwarf_attr (&cudie, DW_AT_macro_info, &attr) == NULL) - continue; - - Dwarf_Word macoff; - if (dwarf_formudata (&attr, &macoff) != 0) - continue; - - struct mac_culist *newp = (struct mac_culist *) alloca (sizeof (*newp)); - newp->die = cudie; - newp->offset = macoff; - newp->files = NULL; - newp->next = culist; - culist = newp; - ++nculist; - } - - /* Convert the list into an array for easier consumption. */ - struct mac_culist *cus = (struct mac_culist *) alloca ((nculist + 1) - * sizeof (*cus)); - /* Add sentinel. */ - cus[nculist].offset = data->d_size; - if (nculist > 0) - { - for (size_t cnt = nculist - 1; culist != NULL; --cnt) - { - assert (cnt < nculist); - cus[cnt] = *culist; - culist = culist->next; - } - - /* Sort the array according to the offset in the .debug_macinfo - section. Note we keep the sentinel at the end. */ - qsort (cus, nculist, sizeof (*cus), mac_compare); - } - - const unsigned char *readp = (const unsigned char *) data->d_buf; - const unsigned char *readendp = readp + data->d_size; - int level = 1; - - while (readp < readendp) - { - unsigned int opcode = *readp++; - unsigned int u128; - unsigned int u128_2; - const unsigned char *endp; - - switch (opcode) - { - case DW_MACINFO_define: - case DW_MACINFO_undef: - case DW_MACINFO_vendor_ext: - /* For the first two opcodes the parameters are - line, string - For the latter - number, string. - We can treat these cases together. */ - get_uleb128 (u128, readp); - - endp = memchr (readp, '\0', readendp - readp); - if (endp == NULL) - { - printf (gettext ("\ -%*s*** non-terminated string at end of section"), - level, ""); - return; - } - - if (opcode == DW_MACINFO_define) - printf ("%*s#define %s, line %u\n", - level, "", (char *) readp, u128); - else if (opcode == DW_MACINFO_undef) - printf ("%*s#undef %s, line %u\n", - level, "", (char *) readp, u128); - else - printf (" #vendor-ext %s, number %u\n", (char *) readp, u128); - - readp = endp + 1; - break; - - case DW_MACINFO_start_file: - /* The two parameters are line and file index, in this order. */ - get_uleb128 (u128, readp); - get_uleb128 (u128_2, readp); - - /* Find the CU DIE for this file. */ - ptrdiff_t macoff = readp - (const unsigned char *) data->d_buf; - const char *fname = "???"; - if (macoff >= cus[0].offset) - { - while (macoff >= cus[1].offset) - ++cus; - - if (cus[0].files == NULL - && dwarf_getsrcfiles (&cus[0].die, &cus[0].files, NULL) != 0) - cus[0].files = (Dwarf_Files *) -1l; - - if (cus[0].files != (Dwarf_Files *) -1l) - fname = (dwarf_filesrc (cus[0].files, u128_2, NULL, NULL) - ?: "???"); - } - - printf ("%*sstart_file %u, [%u] %s\n", - level, "", u128, u128_2, fname); - ++level; - break; - - case DW_MACINFO_end_file: - --level; - printf ("%*send_file\n", level, ""); - /* Nothing more to do. */ - break; - - default: - // XXX gcc seems to generate files with a trailing zero. - if (opcode != 0 || readp != readendp) - printf ("%*s*** invalid opcode %u\n", level, "", opcode); - break; - } - } -} - - -/* Callback for printing global names. */ -static int -print_pubnames (Dwarf *dbg, Dwarf_Global *global, void *arg) -{ - int *np = (int *) arg; - - printf (gettext (" [%5d] DIE offset: %6" PRId64 - ", CU DIE offset: %6" PRId64 ", name: %s\n"), - (*np)++, global->die_offset, global->cu_offset, global->name); - - return 0; -} - - -/* Print the known exported symbols in the DWARF section '.debug_pubnames'. */ -static void -print_debug_pubnames_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, - GElf_Shdr *shdr, Dwarf *dbg) -{ - printf (gettext ("\nDWARF section '%s' at offset %#" PRIx64 ":\n"), - ".debug_pubnames", (uint64_t) shdr->sh_offset); - - int n = 0; - (void) dwarf_getpubnames (dbg, print_pubnames, &n, 0); -} - -/* Print the content of the DWARF string section '.debug_str'. */ -static void -print_debug_str_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, - GElf_Shdr *shdr, Dwarf *dbg) -{ - /* Compute floor(log16(shdr->sh_size)). */ - GElf_Addr tmp = shdr->sh_size; - int digits = 1; - while (tmp >= 16) - { - ++digits; - tmp >>= 4; - } - digits = MAX (4, digits); - - printf (gettext ("\nDWARF section '%s' at offset %#" PRIx64 ":\n" - " %*s String\n"), - ".debug_str", (uint64_t) shdr->sh_offset, - /* TRANS: the debugstr| prefix makes the string unique. */ - digits + 2, sgettext ("debugstr|Offset")); - - Dwarf_Off offset = 0; - while (offset < shdr->sh_size) - { - size_t len; - const char *str = dwarf_getstring (dbg, offset, &len); - if (str == NULL) - { - printf (gettext (" *** error while reading strings: %s\n"), - dwarf_errmsg (-1)); - break; - } - - printf (" [%*" PRIx64 "] \"%s\"\n", digits, (uint64_t) offset, str); - - offset += len + 1; - } -} - - -static void -print_debug (Ebl *ebl, GElf_Ehdr *ehdr) -{ - /* Find the version information sections. For this we have to - search through the section table. */ - Dwarf *dbg; - Elf_Scn *scn; - size_t shstrndx; - - /* Before we start the real work get a debug context descriptor. */ - dbg = dwarf_begin_elf (ebl->elf, DWARF_C_READ, NULL); - if (dbg == NULL) - { - error (0, 0, gettext ("cannot get debug context descriptor: %s"), - dwarf_errmsg (-1)); - return; - } - - /* Get the section header string table index. */ - if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) - error (EXIT_FAILURE, 0, - gettext ("cannot get section header string table index")); - - scn = NULL; - while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) - { - /* Handle the section if it is part of the versioning handling. */ - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - - if (shdr != NULL || shdr->sh_type != SHT_PROGBITS) - { - static const struct - { - const char *name; - enum section_e bitmask; - void (*fp) (Ebl *, GElf_Ehdr *, Elf_Scn *, GElf_Shdr *, Dwarf *); - } debug_sections[] = - { -#define NEW_SECTION(name) \ - { ".debug_" #name, section_##name, print_debug_##name##_section } - NEW_SECTION (abbrev), - NEW_SECTION (aranges), - NEW_SECTION (frame), - NEW_SECTION (info), - NEW_SECTION (line), - NEW_SECTION (loc), - NEW_SECTION (pubnames), - NEW_SECTION (str), - NEW_SECTION (macinfo), - { ".eh_frame", section_frame, print_debug_frame_section } - }; - const int ndebug_sections = (sizeof (debug_sections) - / sizeof (debug_sections[0])); - const char *name = elf_strptr (ebl->elf, shstrndx, - shdr->sh_name); - int n; - - for (n = 0; n < ndebug_sections; ++n) - if (strcmp (name, debug_sections[n].name) == 0) - { - if (print_debug_sections & debug_sections[n].bitmask) - debug_sections[n].fp (ebl, ehdr, scn, shdr, dbg); - break; - } - } - } - - /* We are done with the DWARF handling. */ - dwarf_end (dbg); -} - - -static void -handle_notes (Ebl *ebl, GElf_Ehdr *ehdr) -{ - int class = gelf_getclass (ebl->elf); - size_t cnt; - - /* We have to look through the program header to find the note - sections. There can be more than one. */ - for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) - { - GElf_Phdr mem; - GElf_Phdr *phdr = gelf_getphdr (ebl->elf, cnt, &mem); - - if (phdr == NULL || phdr->p_type != PT_NOTE) - /* Not what we are looking for. */ - continue; - - printf (gettext ("\ -\nNote segment of %" PRId64 " bytes at offset %#0" PRIx64 ":\n"), - phdr->p_filesz, phdr->p_offset); - - char *notemem = gelf_rawchunk (ebl->elf, phdr->p_offset, phdr->p_filesz); - if (notemem == NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot get content of note section: %s"), - elf_errmsg (-1)); - - fputs_unlocked (gettext (" Owner Data size Type\n"), stdout); - - - /* Handle the note section content. It consists of one or more - entries each of which consists of five parts: - - - a 32-bit name length - - a 32-bit descriptor length - - a 32-bit type field - - the NUL-terminated name, length as specified in the first field - - the descriptor, length as specified in the second field - - The variable sized fields are padded to 32- or 64-bits - depending on whether the file is a 32- or 64-bit ELF file. - */ - size_t align = class == ELFCLASS32 ? 4 : 8; -#define ALIGNED_LEN(len) (((len) + align - 1) & ~(align - 1)) - - size_t idx = 0; - while (idx < phdr->p_filesz) - { - /* XXX Handle 64-bit note section entries correctly. */ - struct - { - uint32_t namesz; - uint32_t descsz; - uint32_t type; - char name[0]; - } *noteentry = (__typeof (noteentry)) (notemem + idx); - - if (idx + 12 > phdr->p_filesz - || (idx + 12 + ALIGNED_LEN (noteentry->namesz) - + ALIGNED_LEN (noteentry->descsz) > phdr->p_filesz)) - /* This entry isn't completely contained in the note - section. Ignore it. */ - break; - - char buf[100]; - char buf2[100]; - printf (gettext (" %-13.*s %9" PRId32 " %s\n"), - (int) noteentry->namesz, noteentry->name, - noteentry->descsz, - ehdr->e_type == ET_CORE - ? ebl_core_note_type_name (ebl, noteentry->type, - buf, sizeof (buf)) - : ebl_object_note_type_name (ebl, noteentry->type, - buf2, sizeof (buf2))); - - /* Filter out invalid entries. */ - if (memchr (noteentry->name, '\0', noteentry->namesz) != NULL - /* XXX For now help broken Linux kernels. */ - || 1) - { - if (ehdr->e_type == ET_CORE) - ebl_core_note (ebl, noteentry->name, noteentry->type, - noteentry->descsz, - ¬eentry->name[ALIGNED_LEN (noteentry->namesz)]); - else - ebl_object_note (ebl, noteentry->name, noteentry->type, - noteentry->descsz, - ¬eentry->name[ALIGNED_LEN (noteentry->namesz)]); - } - - /* Move to the next entry. */ - idx += (12 + ALIGNED_LEN (noteentry->namesz) - + ALIGNED_LEN (noteentry->descsz)); - } - - gelf_freechunk (ebl->elf, notemem); - } -} diff --git a/src/sectionhash.c b/src/sectionhash.c deleted file mode 100644 index dc559409..00000000 --- a/src/sectionhash.c +++ /dev/null @@ -1,69 +0,0 @@ -/* Section hash table implementation. - Copyright (C) 2001, 2002 Red Hat, Inc. - Written by Ulrich Drepper <drepper@redhat.com>, 2001. - - This program is Open Source software; you can redistribute it and/or - modify it under the terms of the Open Software License version 1.0 as - published by the Open Source Initiative. - - You should have received a copy of the Open Software License along - with this program; if not, you may obtain a copy of the Open Software - License version 1.0 from http://www.opensource.org/licenses/osl.php or - by writing the Open Source Initiative c/o Lawrence Rosen, Esq., - 3001 King Ranch Road, Ukiah, CA 95482. */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <string.h> - -#include <elf-knowledge.h> -#include <ld.h> - - -/* Comparison function for sections. */ -static int -scnhead_compare (struct scnhead *one, struct scnhead *two) -{ - int result = strcmp (one->name, two->name); - - if (result == 0) - { - result = one->type - two->type; - - if (result == 0) - { - GElf_Xword diff = (SH_FLAGS_IMPORTANT (one->flags) - - SH_FLAGS_IMPORTANT (two->flags)); - result = diff < 0 ? -1 : diff == 0 ? 0 : 1; - - if (result == 0) - { - result = one->entsize - two->entsize; - - if (result == 0) - { - result = (one->grp_signature == NULL - ? (two->grp_signature == NULL ? 0 : -1) - : (two->grp_signature == NULL - ? 1 : strcmp (one->grp_signature, - two->grp_signature))); - - if (result == 0) - result = 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 50bcb9c8..00000000 --- a/src/sectionhash.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright (C) 2001, 2002 Red Hat, Inc. - Written by Ulrich Drepper <drepper@redhat.com>, 2001. - - This program is Open Source software; you can redistribute it and/or - modify it under the terms of the Open Software License version 1.0 as - published by the Open Source Initiative. - - You should have received a copy of the Open Software License along - with this program; if not, you may obtain a copy of the Open Software - License version 1.0 from http://www.opensource.org/licenses/osl.php or - by writing the Open Source Initiative c/o Lawrence Rosen, Esq., - 3001 King Ranch Road, Ukiah, CA 95482. */ - -#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 <dynamicsizehash.h> - -#endif /* sectionhash.h */ diff --git a/src/size.c b/src/size.c deleted file mode 100644 index e9edb677..00000000 --- a/src/size.c +++ /dev/null @@ -1,698 +0,0 @@ -/* Print size information from ELF file. - Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc. - Written by Ulrich Drepper <drepper@redhat.com>, 2000. - - This program is Open Source software; you can redistribute it and/or - modify it under the terms of the Open Software License version 1.0 as - published by the Open Source Initiative. - - You should have received a copy of the Open Software License along - with this program; if not, you may obtain a copy of the Open Software - License version 1.0 from http://www.opensource.org/licenses/osl.php or - by writing the Open Source Initiative c/o Lawrence Rosen, Esq., - 3001 King Ranch Road, Ukiah, CA 95482. */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <argp.h> -#include <error.h> -#include <fcntl.h> -#include <gelf.h> -#include <inttypes.h> -#include <libelf.h> -#include <libintl.h> -#include <locale.h> -#include <mcheck.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdio_ext.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <sys/param.h> - -#include <system.h> - - -/* Name and version of program. */ -static void print_version (FILE *stream, struct argp_state *state); -void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; - - -/* Values for the parameters which have no short form. */ -#define OPT_FORMAT 0x100 -#define OPT_RADIX 0x101 - -/* Definitions of arguments for argp functions. */ -static const struct argp_option options[] = -{ - { NULL, 0, NULL, 0, N_("Output format:") }, - { "format", OPT_FORMAT, "FORMAT", 0, N_("Use the output format FORMAT. FORMAT can be `bsd' or `sysv'. The default is `bsd'") }, - { NULL, 'A', NULL, 0, N_("Same as `--format=sysv'") }, - { NULL, 'B', NULL, 0, N_("Same as `--format=bsd'") }, - { "radix", OPT_RADIX, "RADIX", 0, N_("Use RADIX for printing symbol values") }, - { NULL, 'd', NULL, 0, N_("Same as `--radix=10'") }, - { NULL, 'o', NULL, 0, N_("Same as `--radix=8'") }, - { NULL, 'x', NULL, 0, N_("Same as `--radix=16'") }, - { NULL, 'f', NULL, 0, N_("Similar to `--format=sysv' output but in one line") }, - - { NULL, 0, NULL, 0, N_("Output options:") }, - { NULL, 'F', NULL, 0, N_("Print size and permission flags for loadable segments") }, - { "totals", 't', NULL, 0, N_("Display the total sizes (bsd only)") }, - { NULL, 0, NULL, 0, NULL } -}; - -/* Short description of program. */ -static const char doc[] = N_("\ -List section sizes of FILEs (a.out by default)."); - -/* Strings for arguments in help texts. */ -static const char args_doc[] = N_("[FILE...]"); - -/* Prototype for option handler. */ -static error_t parse_opt (int key, char *arg, struct argp_state *state); - -/* Function to print some extra text in the help message. */ -static char *more_help (int key, const char *text, void *input); - -/* Data structure to communicate with argp functions. */ -static struct argp argp = -{ - options, parse_opt, args_doc, doc, NULL, more_help -}; - - -/* Print symbols in file named FNAME. */ -static int process_file (const char *fname); - -/* Handle content of archive. */ -static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname); - -/* Handle ELF file. */ -static void handle_elf (Elf *elf, const char *fullname, const char *fname); - -/* Show total size. */ -static void show_bsd_totals (void); - -#define INTERNAL_ERROR(fname) \ - error (EXIT_FAILURE, 0, gettext ("%s: INTERNAL ERROR %d (%s-%s): %s"), \ - fname, __LINE__, VERSION, __DATE__, elf_errmsg (-1)) - - -/* User-selectable options. */ - -/* The selected output format. */ -static enum -{ - format_bsd = 0, - format_sysv, - format_sysv_one_line, - format_segments -} format; - -/* Radix for printed numbers. */ -static enum -{ - radix_decimal = 0, - radix_hex, - radix_octal -} radix; - - -/* Mapping of radix and binary class to length. */ -static const int length_map[2][3] = -{ - [ELFCLASS32 - 1] = - { - [radix_hex] = 8, - [radix_decimal] = 10, - [radix_octal] = 11 - }, - [ELFCLASS64 - 1] = - { - [radix_hex] = 16, - [radix_decimal] = 20, - [radix_octal] = 22 - } -}; - -/* True if total sizes should be printed. */ -static bool totals; -/* To print the total sizes in a reasonable format remember the higest - "class" of ELF binaries processed. */ -static int totals_class; - - -int -main (int argc, char *argv[]) -{ - int remaining; - int result = 0; - - /* Make memory leak detection possible. */ - mtrace (); - - /* 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, LOCALEDIR); - - /* Initialize the message catalog. */ - textdomain (PACKAGE); - - /* Parse and process arguments. */ - argp_parse (&argp, argc, argv, 0, &remaining, NULL); - - - /* Tell the library which version we are expecting. */ - elf_version (EV_CURRENT); - - if (remaining == argc) - /* The user didn't specify a name so we use a.out. */ - result = process_file ("a.out"); - else - /* Process all the remaining files. */ - do - result |= process_file (argv[remaining]); - while (++remaining < argc); - - /* Print the total sizes but only if the output format is BSD and at - least one file has been correctly read (i.e., we recognized the - class). */ - if (totals && format == format_bsd && totals_class != 0) - show_bsd_totals (); - - return result; -} - - -/* Print the version information. */ -static void -print_version (FILE *stream, struct argp_state *state) -{ - fprintf (stream, "size (%s) %s\n", PACKAGE_NAME, 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\ -"), "2004"); - fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); -} - - -/* Handle program arguments. */ -static error_t -parse_opt (int key, char *arg, struct argp_state *state) -{ - switch (key) - { - case 'd': - radix = radix_decimal; - break; - - case 'f': - format = format_sysv_one_line; - break; - - case 'o': - radix = radix_octal; - break; - - case 'x': - radix = radix_hex; - break; - - case 'A': - format = format_sysv; - break; - - case 'B': - format = format_bsd; - break; - - case 'F': - format = format_segments; - break; - - case OPT_FORMAT: - if (strcmp (arg, "bsd") == 0 || strcmp (arg, "berkeley") == 0) - format = format_bsd; - else if (strcmp (arg, "sysv") == 0) - format = format_sysv; - else - error (EXIT_FAILURE, 0, gettext ("Invalid format: %s"), arg); - break; - - case OPT_RADIX: - if (strcmp (arg, "x") == 0 || strcmp (arg, "16") == 0) - radix = radix_hex; - else if (strcmp (arg, "d") == 0 || strcmp (arg, "10") == 0) - radix = radix_decimal; - else if (strcmp (arg, "o") == 0 || strcmp (arg, "8") == 0) - radix = radix_octal; - else - error (EXIT_FAILURE, 0, gettext ("Invalid radix: %s"), arg); - break; - - case 't': - totals = true; - break; - - default: - return ARGP_ERR_UNKNOWN; - } - return 0; -} - - -static char * -more_help (int key, const char *text, void *input) -{ - char *buf; - - switch (key) - { - case ARGP_KEY_HELP_EXTRA: - /* We print some extra information. */ - if (asprintf (&buf, gettext ("Please report bugs to %s.\n"), - PACKAGE_BUGREPORT) < 0) - buf = NULL; - return buf; - - default: - break; - } - return (char *) text; -} - - -static int -process_file (const char *fname) -{ - /* Open the file and determine the type. */ - int fd; - Elf *elf; - - /* Open the file. */ - fd = open (fname, O_RDONLY); - if (fd == -1) - { - error (0, errno, fname); - return 1; - } - - /* Now get the ELF descriptor. */ - elf = elf_begin (fd, ELF_C_READ_MMAP, NULL); - if (elf != NULL) - { - if (elf_kind (elf) == ELF_K_ELF) - { - handle_elf (elf, NULL, fname); - - if (elf_end (elf) != 0) - INTERNAL_ERROR (fname); - - if (close (fd) != 0) - error (EXIT_FAILURE, errno, gettext ("while close `%s'"), fname); - - return 0; - } - else - return handle_ar (fd, elf, NULL, fname); - - /* We cannot handle this type. Close the descriptor anyway. */ - if (elf_end (elf) != 0) - INTERNAL_ERROR (fname); - } - - error (0, 0, gettext ("%s: file format not recognized"), fname); - - return 1; -} - - -/* Print the BSD-style header. This is done exactly once. */ -static void -print_header (Elf *elf) -{ - static int done; - - if (! done) - { - int ddigits = length_map[gelf_getclass (elf) - 1][radix_decimal]; - int xdigits = length_map[gelf_getclass (elf) - 1][radix_hex]; - - printf ("%*s %*s %*s %*s %*s %s\n", - ddigits - 2, sgettext ("bsd|text"), - ddigits - 2, sgettext ("bsd|data"), - ddigits - 2, sgettext ("bsd|bss"), - ddigits - 2, sgettext ("bsd|dec"), - xdigits - 2, sgettext ("bsd|hex"), - sgettext ("bsd|filename")); - - done = 1; - } -} - - -static int -handle_ar (int fd, Elf *elf, const char *prefix, const char *fname) -{ - Elf *subelf; - Elf_Cmd cmd = ELF_C_READ_MMAP; - size_t prefix_len = prefix == NULL ? 0 : strlen (prefix); - size_t fname_len = strlen (fname) + 1; - char new_prefix[prefix_len + 1 + fname_len]; - int result = 0; - char *cp = new_prefix; - - /* Create the full name of the file. */ - if (prefix != NULL) - { - cp = mempcpy (cp, prefix, prefix_len); - *cp++ = ':'; - } - memcpy (cp, fname, fname_len); - - /* Process all the files contained in the archive. */ - while ((subelf = elf_begin (fd, cmd, elf)) != NULL) - { - /* The the header for this element. */ - Elf_Arhdr *arhdr = elf_getarhdr (subelf); - - if (elf_kind (subelf) == ELF_K_ELF) - handle_elf (subelf, new_prefix, arhdr->ar_name); - else if (elf_kind (subelf) == ELF_K_AR) - result |= handle_ar (fd, subelf, new_prefix, arhdr->ar_name); - /* else signal error??? */ - - /* Get next archive element. */ - cmd = elf_next (subelf); - if (elf_end (subelf) != 0) - INTERNAL_ERROR (fname); - } - - if (elf_end (elf) != 0) - INTERNAL_ERROR (fname); - - if (close (fd) != 0) - error (EXIT_FAILURE, errno, gettext ("while closing `%s'"), fname); - - return result; -} - - -/* Show sizes in SysV format. */ -static void -show_sysv (Elf *elf, const char *prefix, const char *fname, - const char *fullname) -{ - size_t shstrndx; - Elf_Scn *scn = NULL; - GElf_Shdr shdr_mem; - int maxlen = 10; - int digits = length_map[gelf_getclass (elf) - 1][radix]; - const char *fmtstr; - GElf_Off total = 0; - - /* Get the section header string table index. */ - if (elf_getshstrndx (elf, &shstrndx) < 0) - error (EXIT_FAILURE, 0, - gettext ("cannot get section header string table index")); - - /* First round over the sections: determine the longest section name. */ - while ((scn = elf_nextscn (elf, scn)) != NULL) - { - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - - if (shdr == NULL) - INTERNAL_ERROR (fullname); - - /* Ignore all sections which are not used at runtime. */ - if ((shdr->sh_flags & SHF_ALLOC) != 0) - maxlen = MAX (maxlen, - strlen (elf_strptr (elf, shstrndx, shdr->sh_name))); - } - - fputs_unlocked (fname, stdout); - if (prefix != NULL) - printf (gettext (" (ex %s)"), prefix); - printf (":\n%-*s %*s %*s\n", - maxlen, sgettext ("sysv|section"), - digits - 2, sgettext ("sysv|size"), - digits, sgettext ("sysv|addr")); - - if (radix == radix_hex) - fmtstr = "%-*s %*" PRIx64 " %*" PRIx64 "\n"; - else if (radix == radix_decimal) - fmtstr = "%-*s %*" PRId64 " %*" PRId64 "\n"; - else - fmtstr = "%-*s %*" PRIo64 " %*" PRIo64 "\n"; - - /* Iterate over all sections. */ - while ((scn = elf_nextscn (elf, scn)) != NULL) - { - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - - /* Ignore all sections which are not used at runtime. */ - if ((shdr->sh_flags & SHF_ALLOC) != 0) - { - printf (fmtstr, - maxlen, elf_strptr (elf, shstrndx, shdr->sh_name), - digits - 2, shdr->sh_size, - digits, shdr->sh_addr); - - total += shdr->sh_size; - } - } - - if (radix == radix_hex) - printf ("%-*s %*" PRIx64 "\n\n\n", maxlen, sgettext ("sysv|Total"), - digits - 2, total); - else if (radix == radix_decimal) - printf ("%-*s %*" PRId64 "\n\n\n", maxlen, sgettext ("sysv|Total"), - digits - 2, total); - else - printf ("%-*s %*" PRIo64 "\n\n\n", maxlen, sgettext ("sysv|Total"), - digits - 2, total); -} - - -/* Show sizes in SysV format in one line. */ -static void -show_sysv_one_line (Elf *elf, const char *prefix, const char *fname, - const char *fullname) -{ - size_t shstrndx; - Elf_Scn *scn = NULL; - GElf_Shdr shdr_mem; - const char *fmtstr; - GElf_Off total = 0; - int first = 1; - - /* Get the section header string table index. */ - if (elf_getshstrndx (elf, &shstrndx) < 0) - error (EXIT_FAILURE, 0, - gettext ("cannot get section header string table index")); - - if (radix == radix_hex) - fmtstr = "%" PRIx64 "(%s)"; - else if (radix == radix_decimal) - fmtstr = "%" PRId64 "(%s)"; - else - fmtstr = "%" PRIo64 "(%s)"; - - /* Iterate over all sections. */ - while ((scn = elf_nextscn (elf, scn)) != NULL) - { - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - - /* Ignore all sections which are not used at runtime. */ - if ((shdr->sh_flags & SHF_ALLOC) == 0) - continue; - - if (! first) - fputs_unlocked (" + ", stdout); - first = 0; - - printf (fmtstr, shdr->sh_size, - elf_strptr (elf, shstrndx, shdr->sh_name)); - - total += shdr->sh_size; - } - - if (radix == radix_hex) - printf (" = %#" PRIx64 "\n", total); - else if (radix == radix_decimal) - printf (" = %" PRId64 "\n", total); - else - printf (" = %" PRIo64 "\n", total); -} - - -/* Variables to add up the sizes of all files. */ -static uintmax_t total_textsize; -static uintmax_t total_datasize; -static uintmax_t total_bsssize; - - -/* Show sizes in BSD format. */ -static void -show_bsd (Elf *elf, const char *prefix, const char *fname, - const char *fullname) -{ - Elf_Scn *scn = NULL; - GElf_Shdr shdr_mem; - GElf_Off textsize = 0; - GElf_Off datasize = 0; - GElf_Off bsssize = 0; - int ddigits = length_map[gelf_getclass (elf) - 1][radix_decimal]; - int xdigits = length_map[gelf_getclass (elf) - 1][radix_hex]; - - /* Iterate over all sections. */ - while ((scn = elf_nextscn (elf, scn)) != NULL) - { - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - - if (shdr == NULL) - INTERNAL_ERROR (fullname); - - /* Ignore all sections which are not marked as loaded. */ - if ((shdr->sh_flags & SHF_ALLOC) == 0) - continue; - - if ((shdr->sh_flags & SHF_WRITE) == 0) - textsize += shdr->sh_size; - else if (shdr->sh_type == SHT_NOBITS) - bsssize += shdr->sh_size; - else - datasize += shdr->sh_size; - } - - printf ("%*" PRId64 " %*" PRId64 " %*" PRId64 " %*" PRId64 " %*" - PRIx64 " %s", - ddigits - 2, textsize, - ddigits - 2, datasize, - ddigits - 2, bsssize, - ddigits - 2, textsize + datasize + bsssize, - xdigits - 2, textsize + datasize + bsssize, - fname); - if (prefix != NULL) - printf (gettext (" (ex %s)"), prefix); - fputs_unlocked ("\n", stdout); - - total_textsize += textsize; - total_datasize += datasize; - total_bsssize += bsssize; - - totals_class = MAX (totals_class, gelf_getclass (elf)); -} - - -/* Show total size. */ -static void -show_bsd_totals (void) -{ - int ddigits = length_map[totals_class - 1][radix_decimal]; - int xdigits = length_map[totals_class - 1][radix_hex]; - - printf ("%*" PRIuMAX " %*" PRIuMAX " %*" PRIuMAX " %*" PRIuMAX " %*" - PRIxMAX " %s", - ddigits - 2, total_textsize, - ddigits - 2, total_datasize, - ddigits - 2, total_bsssize, - ddigits - 2, total_textsize + total_datasize + total_bsssize, - xdigits - 2, total_textsize + total_datasize + total_bsssize, - gettext ("(TOTALS)\n")); -} - - -/* Show size and permission of loadable segments. */ -static void -show_segments (Elf *elf, const char *prefix, const char *fname, - const char *fullname) -{ - GElf_Ehdr ehdr_mem; - GElf_Ehdr *ehdr; - size_t cnt; - GElf_Off total = 0; - int first = 1; - - ehdr = gelf_getehdr (elf, &ehdr_mem); - if (ehdr == NULL) - INTERNAL_ERROR (fullname); - - for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) - { - GElf_Phdr phdr_mem; - GElf_Phdr *phdr; - - phdr = gelf_getphdr (elf, cnt, &phdr_mem); - if (phdr == NULL) - INTERNAL_ERROR (fullname); - - if (phdr->p_type != PT_LOAD) - /* Only load segments. */ - continue; - - if (! first) - fputs_unlocked (" + ", stdout); - first = 0; - - printf (radix == radix_hex ? "%" PRIx64 "(%c%c%c)" - : (radix == radix_decimal ? "%" PRId64 "(%c%c%c)" - : "%" PRIo64 "(%c%c%c)"), - phdr->p_memsz, - (phdr->p_flags & PF_R) == 0 ? '-' : 'r', - (phdr->p_flags & PF_W) == 0 ? '-' : 'w', - (phdr->p_flags & PF_X) == 0 ? '-' : 'x'); - - total += phdr->p_memsz; - } - - if (radix == radix_hex) - printf (" = %#" PRIx64 "\n", total); - else if (radix == radix_decimal) - printf (" = %" PRId64 "\n", total); - else - printf (" = %" PRIo64 "\n", total); -} - - -static void -handle_elf (Elf *elf, const char *prefix, const char *fname) -{ - size_t prefix_len = prefix == NULL ? 0 : strlen (prefix); - size_t fname_len = strlen (fname) + 1; - char fullname[prefix_len + 1 + fname_len]; - char *cp = fullname; - - /* Create the full name of the file. */ - if (prefix != NULL) - { - cp = mempcpy (cp, prefix, prefix_len); - *cp++ = ':'; - } - memcpy (cp, fname, fname_len); - - if (format == format_sysv) - show_sysv (elf, prefix, fname, fullname); - else if (format == format_sysv_one_line) - show_sysv_one_line (elf, prefix, fname, fullname); - else if (format == format_segments) - show_segments (elf, prefix, fname, fullname); - else - { - print_header (elf); - - show_bsd (elf, prefix, fname, fullname); - } -} diff --git a/src/strip.c b/src/strip.c deleted file mode 100644 index e5c4289c..00000000 --- a/src/strip.c +++ /dev/null @@ -1,1769 +0,0 @@ -/* Discard section not used at runtime from object files. - Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc. - Written by Ulrich Drepper <drepper@redhat.com>, 2000. - - This program is Open Source software; you can redistribute it and/or - modify it under the terms of the Open Software License version 1.0 as - published by the Open Source Initiative. - - You should have received a copy of the Open Software License along - with this program; if not, you may obtain a copy of the Open Software - License version 1.0 from http://www.opensource.org/licenses/osl.php or - by writing the Open Source Initiative c/o Lawrence Rosen, Esq., - 3001 King Ranch Road, Ukiah, CA 95482. */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <argp.h> -#include <assert.h> -#include <byteswap.h> -#include <endian.h> -#include <error.h> -#include <fcntl.h> -#include <gelf.h> -#include <libelf.h> -#include <libintl.h> -#include <locale.h> -#include <mcheck.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdio_ext.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <sys/param.h> -#include <sys/time.h> - -#include <elf-knowledge.h> -#include <libebl.h> -#include <system.h> - - -/* Name and version of program. */ -static void print_version (FILE *stream, struct argp_state *state); -void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; - - -/* Values for the parameters which have no short form. */ -#define OPT_REMOVE_COMMENT 0x100 -#define OPT_PERMISSIVE 0x101 - - -/* Definitions of arguments for argp functions. */ -static const struct argp_option options[] = -{ - { NULL, 0, NULL, 0, N_("Output selection:") }, - { NULL, 'o', "FILE", 0, N_("Place stripped output into FILE") }, - { NULL, 'f', "FILE", 0, N_("Extract the removed sections into FILE") }, - - { NULL, 0, NULL, 0, N_("Output options:") }, - { "strip-debug", 'g', NULL, 0, N_("Remove all debugging symbols") }, - { "preserve-dates", 'p', NULL, 0, - N_("Copy modified/access timestamps to the output") }, - { "remove-comment", OPT_REMOVE_COMMENT, NULL, 0, - N_("Remove .comment section") }, - { "permissive", OPT_PERMISSIVE, NULL, 0, - N_("Relax a few rules to handle slightly broken ELF files") }, - { NULL, 0, NULL, 0, NULL } -}; - -/* Short description of program. */ -static const char doc[] = N_("Discard symbols from object files."); - -/* Strings for arguments in help texts. */ -static const char args_doc[] = N_("[FILE...]"); - -/* Prototype for option handler. */ -static error_t parse_opt (int key, char *arg, struct argp_state *state); - -/* Function to print some extra text in the help message. */ -static char *more_help (int key, const char *text, void *input); - -/* Data structure to communicate with argp functions. */ -static struct argp argp = -{ - options, parse_opt, args_doc, doc, NULL, more_help -}; - - -/* Print symbols in file named FNAME. */ -static int process_file (const char *fname); - -/* Handle one ELF file. */ -static int handle_elf (int fd, Elf *elf, const char *prefix, - const char *fname, mode_t mode, struct timeval tvp[2]); - -/* Handle all files contained in the archive. */ -static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname, - struct timeval tvp[2]); - -#define INTERNAL_ERROR(fname) \ - error (EXIT_FAILURE, 0, gettext ("%s: INTERNAL ERROR %d (%s-%s): %s"), \ - fname, __LINE__, VERSION, __DATE__, elf_errmsg (-1)) - - -/* Name of the output file. */ -static const char *output_fname; - -/* Name of the debug output file. */ -static const char *debug_fname; - -/* If true output files shall have same date as the input file. */ -static bool preserve_dates; - -/* If true .comment sections will be removed. */ -static bool remove_comment; - -/* If true remove all debug sections. */ -static bool remove_debug; - -/* If true relax some ELF rules for input files. */ -static bool permissive; - - -int -main (int argc, char *argv[]) -{ - int remaining; - int result = 0; - - /* Make memory leak detection possible. */ - mtrace (); - - /* 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, LOCALEDIR); - - /* Initialize the message catalog. */ - textdomain (PACKAGE); - - /* Parse and process arguments. */ - argp_parse (&argp, argc, argv, 0, &remaining, NULL); - - /* Tell the library which version we are expecting. */ - elf_version (EV_CURRENT); - - if (remaining == argc) - /* The user didn't specify a name so we use a.out. */ - result = process_file ("a.out"); - else - { - /* If we have seen the `-o' or '-f' option there must be exactly one - input file. */ - if ((output_fname != NULL || debug_fname != NULL) - && remaining + 1 < argc) - error (EXIT_FAILURE, 0, gettext ("\ -Only one input file allowed together with '-o' and '-f'")); - - /* Process all the remaining files. */ - do - result |= process_file (argv[remaining]); - while (++remaining < argc); - } - - return result; -} - - -/* Print the version information. */ -static void -print_version (FILE *stream, struct argp_state *state) -{ - fprintf (stream, "strip (%s) %s\n", PACKAGE_NAME, 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\ -"), "2004"); - fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); -} - - -/* Handle program arguments. */ -static error_t -parse_opt (int key, char *arg, struct argp_state *state) -{ - switch (key) - { - case 'f': - debug_fname = arg; - break; - - case 'o': - output_fname = arg; - break; - - case 'p': - preserve_dates = true; - break; - - case OPT_REMOVE_COMMENT: - remove_comment = true; - break; - - case 'g': - remove_debug = true; - break; - - case OPT_PERMISSIVE: - permissive = true; - break; - - default: - return ARGP_ERR_UNKNOWN; - } - return 0; -} - - -static char * -more_help (int key, const char *text, void *input) -{ - char *buf; - - switch (key) - { - case ARGP_KEY_HELP_EXTRA: - /* We print some extra information. */ - if (asprintf (&buf, gettext ("Please report bugs to %s.\n"), - PACKAGE_BUGREPORT) < 0) - buf = NULL; - return buf; - - default: - break; - } - return (char *) text; -} - - -static int -process_file (const char *fname) -{ - /* If we have to preserve the modify and access timestamps get them - now. We cannot use fstat() after opening the file since the open - would change the access time. */ - struct stat64 pre_st; - struct timeval tv[2]; - again: - if (preserve_dates) - { - if (stat64 (fname, &pre_st) != 0) - { - error (0, errno, gettext ("cannot stat input file \"%s\""), fname); - return 1; - } - - /* If we have to preserve the timestamp, we need it in the - format utimes() understands. */ - TIMESPEC_TO_TIMEVAL (&tv[0], &pre_st.st_atim); - TIMESPEC_TO_TIMEVAL (&tv[1], &pre_st.st_mtim); - } - - /* Open the file. */ - int fd = open (fname, O_RDWR); - if (fd == -1) - { - error (0, errno, gettext ("while opening \"%s\""), fname); - return 1; - } - - /* We always use fstat() even if we called stat() before. This is - done to make sure the information returned by stat() is for the - same file. */ - struct stat64 st; - if (fstat64 (fd, &st) != 0) - { - error (0, errno, gettext ("cannot stat input file \"%s\""), fname); - return 1; - } - /* Paranoid mode on. */ - if (preserve_dates - && (st.st_ino != pre_st.st_ino || st.st_dev != pre_st.st_dev)) - { - /* We detected a race. Try again. */ - close (fd); - goto again; - } - - /* Now get the ELF descriptor. */ - Elf *elf = elf_begin (fd, ELF_C_RDWR, NULL); - int result; - switch (elf_kind (elf)) - { - case ELF_K_ELF: - result = handle_elf (fd, elf, NULL, fname, st.st_mode & ACCESSPERMS, - preserve_dates ? tv : NULL); - break; - - case ELF_K_AR: - /* It is not possible to strip the content of an archive direct - the output to a specific file. */ - if (unlikely (output_fname != NULL)) - { - error (0, 0, gettext ("%s: cannot use -o when stripping archive"), - fname); - result = 1; - } - else - result = handle_ar (fd, elf, NULL, fname, preserve_dates ? tv : NULL); - break; - - default: - error (0, 0, gettext ("%s: File format not recognized"), fname); - result = 1; - break; - } - - if (unlikely (elf_end (elf) != 0)) - INTERNAL_ERROR (fname); - - close (fd); - - return result; -} - - -/* Maximum size of array allocated on stack. */ -#define MAX_STACK_ALLOC (400 * 1024) - - -static uint32_t -crc32_file (int fd, uint32_t *resp) -{ - unsigned char buffer[1024 * 8]; - uint32_t crc = 0; - ssize_t count; - - /* We have to rewind. */ - if (lseek (fd, 0, SEEK_SET) < 0) - return 1; - - while ((count = TEMP_FAILURE_RETRY (read (fd, buffer, sizeof (buffer)))) > 0) - crc = crc32 (crc, buffer, count); - - *resp = crc; - - return count != 0; -} - - -static int -handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, - mode_t mode, struct timeval tvp[2]) -{ - size_t prefix_len = prefix == NULL ? 0 : strlen (prefix); - size_t fname_len = strlen (fname) + 1; - char *fullname = alloca (prefix_len + 1 + fname_len); - char *cp = fullname; - Elf *newelf; - Elf *debugelf = NULL; - char *tmp_debug_fname = NULL; - int result = 0; - GElf_Ehdr ehdr_mem; - GElf_Ehdr *ehdr; - size_t shstrndx; - size_t shnum; - struct shdr_info - { - Elf_Scn *scn; - GElf_Shdr shdr; - Elf_Data *data; - const char *name; - Elf32_Word idx; /* Index in new file. */ - Elf32_Word old_sh_link; /* Original value of shdr.sh_link. */ - Elf32_Word symtab_idx; - Elf32_Word version_idx; - Elf32_Word group_idx; - Elf32_Word group_cnt; - Elf_Scn *newscn; - struct Ebl_Strent *se; - Elf32_Word *newsymidx; - } *shdr_info = NULL; - Elf_Scn *scn; - size_t cnt; - size_t idx; - bool changes; - GElf_Ehdr newehdr_mem; - GElf_Ehdr *newehdr; - GElf_Ehdr debugehdr_mem; - GElf_Ehdr *debugehdr; - struct Ebl_Strtab *shst = NULL; - uint32_t debug_crc; - bool any_symtab_changes = false; - Elf_Data *shstrtab_data = NULL; - - /* Create the full name of the file. */ - if (prefix != NULL) - { - cp = mempcpy (cp, prefix, prefix_len); - *cp++ = ':'; - } - memcpy (cp, fname, fname_len); - - /* If we are not replacing the input file open a new file here. */ - if (output_fname != NULL) - { - fd = open (output_fname, O_RDWR | O_CREAT, mode); - if (unlikely (fd == -1)) - { - error (0, errno, gettext ("cannot open `%s'"), output_fname); - return 1; - } - } - - int debug_fd = -1; - - /* Get the EBL handling. The -g option is currently the only reason - we need EBL so dont open the backend unless necessary. */ - Ebl *ebl = NULL; - if (remove_debug) - { - ebl = ebl_openbackend (elf); - if (ebl == NULL) - { - error (0, errno, gettext ("cannot open EBL backend")); - result = 1; - goto fail; - } - } - - /* Open the additional file the debug information will be stored in. */ - if (debug_fname != NULL) - { - /* Create a temporary file name. We do not want to overwrite - the debug file if the file would not contain any - information. */ - size_t debug_fname_len = strlen (debug_fname); - tmp_debug_fname = (char *) alloca (debug_fname_len + sizeof (".XXXXXX")); - strcpy (mempcpy (tmp_debug_fname, debug_fname, debug_fname_len), - ".XXXXXX"); - - debug_fd = mkstemp (tmp_debug_fname); - if (unlikely (debug_fd == -1)) - { - error (0, errno, gettext ("cannot open `%s'"), debug_fname); - result = 1; - goto fail; - } - } - - /* Get the information from the old file. */ - ehdr = gelf_getehdr (elf, &ehdr_mem); - if (ehdr == NULL) - INTERNAL_ERROR (fname); - - /* Get the section header string table index. */ - if (unlikely (elf_getshstrndx (elf, &shstrndx) < 0)) - error (EXIT_FAILURE, 0, - gettext ("cannot get section header string table index")); - - /* We now create a new ELF descriptor for the same file. We - construct it almost exactly in the same way with some information - dropped. */ - if (output_fname != NULL) - newelf = elf_begin (fd, ELF_C_WRITE_MMAP, NULL); - else - newelf = elf_clone (elf, ELF_C_EMPTY); - - if (unlikely (gelf_newehdr (newelf, gelf_getclass (elf)) == 0) - || (ehdr->e_type != ET_REL - && unlikely (gelf_newphdr (newelf, ehdr->e_phnum) == 0))) - { - error (0, 0, gettext ("cannot create new file `%s': %s"), - output_fname, elf_errmsg (-1)); - goto fail; - } - - /* Copy over the old program header if needed. */ - if (ehdr->e_type != ET_REL) - for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) - { - GElf_Phdr phdr_mem; - GElf_Phdr *phdr; - - phdr = gelf_getphdr (elf, cnt, &phdr_mem); - if (phdr == NULL - || unlikely (gelf_update_phdr (newelf, cnt, phdr) == 0)) - INTERNAL_ERROR (fname); - } - - if (debug_fname != NULL) - { - /* Also create an ELF descriptor for the debug file */ - debugelf = elf_begin (debug_fd, ELF_C_WRITE_MMAP, NULL); - if (unlikely (gelf_newehdr (debugelf, gelf_getclass (elf)) == 0) - || (ehdr->e_type != ET_REL - && unlikely (gelf_newphdr (debugelf, ehdr->e_phnum) == 0))) - { - error (0, 0, gettext ("cannot create new file `%s': %s"), - debug_fname, elf_errmsg (-1)); - goto fail_close; - } - - /* Copy over the old program header if needed. */ - if (ehdr->e_type != ET_REL) - for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) - { - GElf_Phdr phdr_mem; - GElf_Phdr *phdr; - - phdr = gelf_getphdr (elf, cnt, &phdr_mem); - if (phdr == NULL - || unlikely (gelf_update_phdr (debugelf, cnt, phdr) == 0)) - INTERNAL_ERROR (fname); - } - } - - /* Number of sections. */ - if (unlikely (elf_getshnum (elf, &shnum) < 0)) - { - error (0, 0, gettext ("cannot determine number of sections: %s"), - elf_errmsg (-1)); - goto fail_close; - } - - /* Storage for section information. We leave room for two more - entries since we unconditionally create a section header string - table. Maybe some weird tool created an ELF file without one. - The other one is used for the debug link section. */ - if ((shnum + 2) * sizeof (struct shdr_info) > MAX_STACK_ALLOC) - shdr_info = (struct shdr_info *) xcalloc (shnum + 2, - sizeof (struct shdr_info)); - else - { - shdr_info = (struct shdr_info *) alloca ((shnum + 2) - * sizeof (struct shdr_info)); - memset (shdr_info, '\0', (shnum + 2) * sizeof (struct shdr_info)); - } - - /* Prepare section information data structure. */ - scn = NULL; - cnt = 1; - while ((scn = elf_nextscn (elf, scn)) != NULL) - { - /* This should always be true (i.e., there should not be any - holes in the numbering). */ - assert (elf_ndxscn (scn) == cnt); - - shdr_info[cnt].scn = scn; - - /* Get the header. */ - if (gelf_getshdr (scn, &shdr_info[cnt].shdr) == NULL) - INTERNAL_ERROR (fname); - - /* Get the name of the section. */ - shdr_info[cnt].name = elf_strptr (elf, shstrndx, - shdr_info[cnt].shdr.sh_name); - if (shdr_info[cnt].name == NULL) - { - error (0, 0, gettext ("illformed file `%s'"), fname); - goto fail_close; - } - - /* Mark them as present but not yet investigated. */ - shdr_info[cnt].idx = 1; - - /* Remember the shdr.sh_link value. */ - shdr_info[cnt].old_sh_link = shdr_info[cnt].shdr.sh_link; - - /* Sections in files other than relocatable object files which - are not loaded can be freely moved by us. In relocatable - object files everything can be moved. */ - if (ehdr->e_type == ET_REL - || (shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) == 0) - shdr_info[cnt].shdr.sh_offset = 0; - - /* If this is an extended section index table store an - appropriate reference. */ - if (unlikely (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB_SHNDX)) - { - assert (shdr_info[shdr_info[cnt].shdr.sh_link].symtab_idx == 0); - shdr_info[shdr_info[cnt].shdr.sh_link].symtab_idx = cnt; - } - else if (unlikely (shdr_info[cnt].shdr.sh_type == SHT_GROUP)) - { - Elf32_Word *grpref; - size_t inner; - - /* Cross-reference the sections contained in the section - group. */ - shdr_info[cnt].data = elf_getdata (shdr_info[cnt].scn, NULL); - if (shdr_info[cnt].data == NULL) - INTERNAL_ERROR (fname); - - /* XXX Fix for unaligned access. */ - grpref = (Elf32_Word *) shdr_info[cnt].data->d_buf; - for (inner = 1; - inner < shdr_info[cnt].data->d_size / sizeof (Elf32_Word); - ++inner) - shdr_info[grpref[inner]].group_idx = cnt; - - if (inner == 1 || (inner == 2 && (grpref[0] & GRP_COMDAT) == 0)) - /* If the section group contains only one element and this - is n COMDAT section we can drop it right away. */ - shdr_info[cnt].idx = 0; - else - shdr_info[cnt].group_cnt = inner - 1; - } - else if (unlikely (shdr_info[cnt].shdr.sh_type == SHT_GNU_versym)) - { - assert (shdr_info[shdr_info[cnt].shdr.sh_link].version_idx == 0); - shdr_info[shdr_info[cnt].shdr.sh_link].version_idx = cnt; - } - - /* If this section is part of a group make sure it is not - discarded right away. */ - if ((shdr_info[cnt].shdr.sh_flags & SHF_GROUP) != 0) - { - assert (shdr_info[cnt].group_idx != 0); - - if (shdr_info[shdr_info[cnt].group_idx].idx == 0) - { - /* The section group section will be removed. */ - shdr_info[cnt].group_idx = 0; - shdr_info[cnt].shdr.sh_flags &= ~SHF_GROUP; - } - } - - /* Increment the counter. */ - ++cnt; - } - - /* Now determine which sections can go away. The general rule is that - all sections which are not used at runtime are stripped out. But - there are a few exceptions: - - - special sections named ".comment" and ".note" are kept - - OS or architecture specific sections are kept since we might not - know how to handle them - - if a section is referred to from a section which is not removed - in the sh_link or sh_info element it cannot be removed either - */ - for (cnt = 1; cnt < shnum; ++cnt) - /* Check whether the section can be removed. */ - if (SECTION_STRIP_P (ebl, elf, ehdr, &shdr_info[cnt].shdr, - shdr_info[cnt].name, remove_comment, remove_debug)) - { - /* For now assume this section will be removed. */ - shdr_info[cnt].idx = 0; - - idx = shdr_info[cnt].group_idx; - while (idx != 0) - { - /* If the references section group is a normal section - group and has one element remaining, or if it is an - empty COMDAT section group it is removed. */ - bool is_comdat; - - /* The section group data is already loaded. */ - assert (shdr_info[idx].data != NULL); - - is_comdat = (((Elf32_Word *) shdr_info[idx].data->d_buf)[0] - & GRP_COMDAT) != 0; - - --shdr_info[idx].group_cnt; - if ((!is_comdat && shdr_info[idx].group_cnt == 1) - || (is_comdat && shdr_info[idx].group_cnt == 0)) - { - shdr_info[idx].idx = 0; - /* Continue recursively. */ - idx = shdr_info[idx].group_idx; - } - else - break; - } - } - - /* Mark the SHT_NULL section as handled. */ - shdr_info[0].idx = 2; - - - /* Handle exceptions: section groups and cross-references. We might - have to repeat this a few times since the resetting of the flag - might propagate. */ - do - { - changes = false; - - for (cnt = 1; cnt < shnum; ++cnt) - { - if (shdr_info[cnt].idx == 0) - { - /* If a relocation section is marked as being removed make - sure the section it is relocating is removed, too. */ - if ((shdr_info[cnt].shdr.sh_type == SHT_REL - || shdr_info[cnt].shdr.sh_type == SHT_RELA) - && shdr_info[shdr_info[cnt].shdr.sh_info].idx != 0) - shdr_info[cnt].idx = 1; - } - - if (shdr_info[cnt].idx == 1) - { - /* The content of symbol tables we don't remove must not - reference any section which we do remove. Otherwise - we cannot remove the section. */ - if (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM - || shdr_info[cnt].shdr.sh_type == SHT_SYMTAB) - { - Elf_Data *symdata; - Elf_Data *xndxdata; - size_t elsize; - - /* Make sure the data is loaded. */ - if (shdr_info[cnt].data == NULL) - { - shdr_info[cnt].data - = elf_getdata (shdr_info[cnt].scn, NULL); - if (shdr_info[cnt].data == NULL) - INTERNAL_ERROR (fname); - } - symdata = shdr_info[cnt].data; - - /* If there is an extended section index table load it - as well. */ - if (shdr_info[cnt].symtab_idx != 0 - && shdr_info[shdr_info[cnt].symtab_idx].data == NULL) - { - assert (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB); - - shdr_info[shdr_info[cnt].symtab_idx].data - = elf_getdata (shdr_info[shdr_info[cnt].symtab_idx].scn, - NULL); - if (shdr_info[shdr_info[cnt].symtab_idx].data == NULL) - INTERNAL_ERROR (fname); - } - xndxdata = shdr_info[shdr_info[cnt].symtab_idx].data; - - /* Go through all symbols and make sure the section they - reference is not removed. */ - elsize = gelf_fsize (elf, ELF_T_SYM, 1, ehdr->e_version); - - for (size_t inner = 0; - inner < shdr_info[cnt].data->d_size / elsize; - ++inner) - { - GElf_Sym sym_mem; - Elf32_Word xndx; - GElf_Sym *sym; - size_t scnidx; - - sym = gelf_getsymshndx (symdata, xndxdata, inner, - &sym_mem, &xndx); - if (sym == NULL) - INTERNAL_ERROR (fname); - - scnidx = sym->st_shndx; - if (scnidx == SHN_UNDEF || scnidx >= shnum - || (scnidx >= SHN_LORESERVE - && scnidx <= SHN_HIRESERVE - && scnidx != SHN_XINDEX) - /* Don't count in the section symbols. */ - || GELF_ST_TYPE (sym->st_info) == STT_SECTION) - /* This is no section index, leave it alone. */ - continue; - else if (scnidx == SHN_XINDEX) - scnidx = xndx; - - if (shdr_info[scnidx].idx == 0) - { - /* Mark this section as used. */ - shdr_info[scnidx].idx = 1; - changes |= scnidx < cnt; - } - } - } - - /* Cross referencing happens: - - for the cases the ELF specification says. That are - + SHT_DYNAMIC in sh_link to string table - + SHT_HASH in sh_link to symbol table - + SHT_REL and SHT_RELA in sh_link to symbol table - + SHT_SYMTAB and SHT_DYNSYM in sh_link to string table - + SHT_GROUP in sh_link to symbol table - + SHT_SYMTAB_SHNDX in sh_link to symbol table - Other (OS or architecture-specific) sections might as - well use this field so we process it unconditionally. - - references inside section groups - - specially marked references in sh_info if the SHF_INFO_LINK - flag is set - */ - - if (shdr_info[shdr_info[cnt].shdr.sh_link].idx == 0) - { - shdr_info[shdr_info[cnt].shdr.sh_link].idx = 1; - changes |= shdr_info[cnt].shdr.sh_link < cnt; - } - - /* Handle references through sh_info. */ - if (SH_INFO_LINK_P (&shdr_info[cnt].shdr) - && shdr_info[shdr_info[cnt].shdr.sh_info].idx == 0) - { - shdr_info[shdr_info[cnt].shdr.sh_info].idx = 1; - changes |= shdr_info[cnt].shdr.sh_info < cnt; - } - - /* Mark the section as investigated. */ - shdr_info[cnt].idx = 2; - } - } - } - while (changes); - - /* Write out a copy of all the sections to the debug output file. - The ones that are not removed in the stripped file are SHT_NOBITS */ - if (debug_fname != NULL) - { - for (cnt = 1; cnt < shnum; ++cnt) - { - Elf_Data *debugdata; - GElf_Shdr debugshdr; - int discard_section; - - scn = elf_newscn (debugelf); - if (scn == NULL) - error (EXIT_FAILURE, 0, - gettext ("while generating output file: %s"), - elf_errmsg (-1)); - - discard_section = shdr_info[cnt].idx > 0 && cnt != ehdr->e_shstrndx; - - /* Set the section header in the new file. */ - debugshdr = shdr_info[cnt].shdr; - if (discard_section) - debugshdr.sh_type = SHT_NOBITS; - - if (unlikely (gelf_update_shdr (scn, &debugshdr)) == 0) - /* There cannot be any overflows. */ - INTERNAL_ERROR (fname); - - /* Get the data from the old file if necessary. */ - if (shdr_info[cnt].data == NULL) - { - shdr_info[cnt].data = elf_getdata (shdr_info[cnt].scn, NULL); - if (shdr_info[cnt].data == NULL) - INTERNAL_ERROR (fname); - } - - /* Set the data. This is done by copying from the old file. */ - debugdata = elf_newdata (scn); - if (debugdata == NULL) - INTERNAL_ERROR (fname); - - /* Copy the structure. */ - *debugdata = *shdr_info[cnt].data; - if (discard_section) - debugdata->d_buf = NULL; - } - - /* Finish the ELF header. Fill in the fields not handled by - libelf from the old file. */ - debugehdr = gelf_getehdr (debugelf, &debugehdr_mem); - if (debugehdr == NULL) - INTERNAL_ERROR (fname); - - memcpy (debugehdr->e_ident, ehdr->e_ident, EI_NIDENT); - debugehdr->e_type = ehdr->e_type; - debugehdr->e_machine = ehdr->e_machine; - debugehdr->e_version = ehdr->e_version; - debugehdr->e_entry = ehdr->e_entry; - debugehdr->e_flags = ehdr->e_flags; - debugehdr->e_shstrndx = ehdr->e_shstrndx; - - if (unlikely (gelf_update_ehdr (debugelf, debugehdr)) == 0) - { - error (0, 0, gettext ("%s: error while creating ELF header: %s"), - debug_fname, elf_errmsg (-1)); - result = 1; - goto fail_close; - } - - /* Finally write the file. */ - if (unlikely (elf_update (debugelf, ELF_C_WRITE)) == -1) - { - error (0, 0, gettext ("while writing `%s': %s"), - debug_fname, elf_errmsg (-1)); - result = 1; - goto fail_close; - } - - /* Create the real output file. First rename, then change the - mode. */ - if (rename (tmp_debug_fname, debug_fname) != 0 - || fchmod (debug_fd, mode) != 0) - { - error (0, errno, gettext ("while creating '%s'"), debug_fname); - result = 1; - goto fail_close; - } - - /* The temporary file does not exist anymore. */ - tmp_debug_fname = NULL; - - /* Compute the checksum which we will add to the executable. */ - if (crc32_file (debug_fd, &debug_crc) != 0) - { - error (0, errno, - gettext ("while computing checksum for debug information")); - unlink (debug_fname); - result = 1; - goto fail_close; - } - - } - - /* Mark the section header string table as unused, we will create - a new one. */ - shdr_info[shstrndx].idx = 0; - - /* We need a string table for the section headers. */ - shst = ebl_strtabinit (true); - if (shst == NULL) - error (EXIT_FAILURE, errno, gettext ("while preparing output for `%s'"), - output_fname ?: fname); - - /* Assign new section numbers. */ - shdr_info[0].idx = 0; - for (cnt = idx = 1; cnt < shnum; ++cnt) - if (shdr_info[cnt].idx > 0) - { - shdr_info[cnt].idx = idx++; - - /* Create a new section. */ - shdr_info[cnt].newscn = elf_newscn (newelf); - if (shdr_info[cnt].newscn == NULL) - error (EXIT_FAILURE, 0, gettext ("while generating output file: %s"), - elf_errmsg (-1)); - - assert (elf_ndxscn (shdr_info[cnt].newscn) == shdr_info[cnt].idx); - - /* Add this name to the section header string table. */ - shdr_info[cnt].se = ebl_strtabadd (shst, shdr_info[cnt].name, 0); - } - - /* Test whether we are doing anything at all. */ - if (cnt == idx) - /* Nope, all removable sections are already gone. */ - goto fail_close; - - /* Create the reference to the file with the debug info. */ - if (debug_fname != NULL) - { - char *debug_basename; - off_t crc_offset; - - /* Add the section header string table section name. */ - shdr_info[cnt].se = ebl_strtabadd (shst, ".gnu_debuglink", 15); - shdr_info[cnt].idx = idx++; - - /* Create the section header. */ - shdr_info[cnt].shdr.sh_type = SHT_PROGBITS; - shdr_info[cnt].shdr.sh_flags = 0; - shdr_info[cnt].shdr.sh_addr = 0; - shdr_info[cnt].shdr.sh_link = SHN_UNDEF; - shdr_info[cnt].shdr.sh_info = SHN_UNDEF; - shdr_info[cnt].shdr.sh_entsize = 0; - shdr_info[cnt].shdr.sh_addralign = 4; - /* We set the offset to zero here. Before we write the ELF file the - field must have the correct value. This is done in the final - loop over all section. Then we have all the information needed. */ - shdr_info[cnt].shdr.sh_offset = 0; - - /* Create the section. */ - shdr_info[cnt].newscn = elf_newscn (newelf); - if (shdr_info[cnt].newscn == NULL) - error (EXIT_FAILURE, 0, - gettext ("while create section header section: %s"), - elf_errmsg (-1)); - assert (elf_ndxscn (shdr_info[cnt].newscn) == shdr_info[cnt].idx); - - shdr_info[cnt].data = elf_newdata (shdr_info[cnt].newscn); - if (shdr_info[cnt].data == NULL) - error (EXIT_FAILURE, 0, gettext ("cannot allocate section data: %s"), - elf_errmsg (-1)); - - debug_basename = basename (debug_fname); - crc_offset = strlen (debug_basename) + 1; - /* Align to 4 byte boundary */ - crc_offset = ((crc_offset - 1) & ~3) + 4; - - shdr_info[cnt].data->d_align = 4; - shdr_info[cnt].shdr.sh_size = shdr_info[cnt].data->d_size - = crc_offset + 4; - shdr_info[cnt].data->d_buf = xcalloc (1, shdr_info[cnt].data->d_size); - - strcpy (shdr_info[cnt].data->d_buf, debug_basename); - /* Store the crc value in the correct byteorder */ - if ((__BYTE_ORDER == __LITTLE_ENDIAN - && ehdr->e_ident[EI_DATA] == ELFDATA2MSB) - || (__BYTE_ORDER == __BIG_ENDIAN - && ehdr->e_ident[EI_DATA] == ELFDATA2LSB)) - debug_crc = bswap_32 (debug_crc); - memcpy ((char *)shdr_info[cnt].data->d_buf + crc_offset, - (char *) &debug_crc, 4); - - /* One more section done. */ - ++cnt; - } - - /* Index of the section header table in the shdr_info array. */ - size_t shdridx = cnt; - - /* Add the section header string table section name. */ - shdr_info[cnt].se = ebl_strtabadd (shst, ".shstrtab", 10); - shdr_info[cnt].idx = idx; - - /* Create the section header. */ - shdr_info[cnt].shdr.sh_type = SHT_STRTAB; - shdr_info[cnt].shdr.sh_flags = 0; - shdr_info[cnt].shdr.sh_addr = 0; - shdr_info[cnt].shdr.sh_link = SHN_UNDEF; - shdr_info[cnt].shdr.sh_info = SHN_UNDEF; - shdr_info[cnt].shdr.sh_entsize = 0; - /* We set the offset to zero here. Before we write the ELF file the - field must have the correct value. This is done in the final - loop over all section. Then we have all the information needed. */ - shdr_info[cnt].shdr.sh_offset = 0; - shdr_info[cnt].shdr.sh_addralign = 1; - - /* Create the section. */ - shdr_info[cnt].newscn = elf_newscn (newelf); - if (shdr_info[cnt].newscn == NULL) - error (EXIT_FAILURE, 0, - gettext ("while create section header section: %s"), - elf_errmsg (-1)); - assert (elf_ndxscn (shdr_info[cnt].newscn) == idx); - - /* Finalize the string table and fill in the correct indices in the - section headers. */ - shstrtab_data = elf_newdata (shdr_info[cnt].newscn); - if (shstrtab_data == NULL) - error (EXIT_FAILURE, 0, - gettext ("while create section header string table: %s"), - elf_errmsg (-1)); - ebl_strtabfinalize (shst, shstrtab_data); - - /* We have to set the section size. */ - shdr_info[cnt].shdr.sh_size = shstrtab_data->d_size; - - /* Update the section information. */ - GElf_Off lastoffset = 0; - for (cnt = 1; cnt <= shdridx; ++cnt) - if (shdr_info[cnt].idx > 0) - { - Elf_Data *newdata; - - scn = elf_getscn (newelf, shdr_info[cnt].idx); - assert (scn != NULL); - - /* Update the name. */ - shdr_info[cnt].shdr.sh_name = ebl_strtaboffset (shdr_info[cnt].se); - - /* Update the section header from the input file. Some fields - might be section indeces which now have to be adjusted. */ - if (shdr_info[cnt].shdr.sh_link != 0) - shdr_info[cnt].shdr.sh_link = - shdr_info[shdr_info[cnt].shdr.sh_link].idx; - - if (shdr_info[cnt].shdr.sh_type == SHT_GROUP) - { - assert (shdr_info[cnt].data != NULL); - - Elf32_Word *grpref = (Elf32_Word *) shdr_info[cnt].data->d_buf; - for (size_t inner = 0; - inner < shdr_info[cnt].data->d_size / sizeof (Elf32_Word); - ++inner) - grpref[inner] = shdr_info[grpref[inner]].idx; - } - - /* Handle the SHT_REL, SHT_RELA, and SHF_INFO_LINK flag. */ - if (SH_INFO_LINK_P (&shdr_info[cnt].shdr)) - shdr_info[cnt].shdr.sh_info = - shdr_info[shdr_info[cnt].shdr.sh_info].idx; - - /* Get the data from the old file if necessary. We already - created the data for the section header string table. */ - if (cnt < shnum) - { - if (shdr_info[cnt].data == NULL) - { - shdr_info[cnt].data = elf_getdata (shdr_info[cnt].scn, NULL); - if (shdr_info[cnt].data == NULL) - INTERNAL_ERROR (fname); - } - - /* Set the data. This is done by copying from the old file. */ - newdata = elf_newdata (scn); - if (newdata == NULL) - INTERNAL_ERROR (fname); - - /* Copy the structure. */ - *newdata = *shdr_info[cnt].data; - - /* We know the size. */ - shdr_info[cnt].shdr.sh_size = shdr_info[cnt].data->d_size; - - /* We have to adjust symtol tables. The st_shndx member might - have to be updated. */ - if (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM - || shdr_info[cnt].shdr.sh_type == SHT_SYMTAB) - { - Elf_Data *versiondata = NULL; - Elf_Data *shndxdata = NULL; - - size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1, - ehdr->e_version); - - if (shdr_info[cnt].symtab_idx != 0) - { - assert (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB_SHNDX); - /* This section has extended section information. - We have to modify that information, too. */ - shndxdata = elf_getdata (shdr_info[shdr_info[cnt].symtab_idx].scn, - NULL); - - assert ((versiondata->d_size / sizeof (Elf32_Word)) - >= shdr_info[cnt].data->d_size / elsize); - } - - if (shdr_info[cnt].version_idx != 0) - { - assert (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM); - /* This section has associated version - information. We have to modify that - information, too. */ - versiondata = elf_getdata (shdr_info[shdr_info[cnt].version_idx].scn, - NULL); - - assert ((versiondata->d_size / sizeof (GElf_Versym)) - >= shdr_info[cnt].data->d_size / elsize); - } - - shdr_info[cnt].newsymidx - = (Elf32_Word *) xcalloc (shdr_info[cnt].data->d_size - / elsize, sizeof (Elf32_Word)); - - bool last_was_local = true; - size_t destidx; - size_t inner; - for (destidx = inner = 1; - inner < shdr_info[cnt].data->d_size / elsize; - ++inner) - { - Elf32_Word sec; - GElf_Sym sym_mem; - Elf32_Word xshndx; - GElf_Sym *sym = gelf_getsymshndx (shdr_info[cnt].data, - shndxdata, inner, - &sym_mem, &xshndx); - if (sym == NULL) - INTERNAL_ERROR (fname); - - if (sym->st_shndx == SHN_UNDEF - || (sym->st_shndx >= shnum - && sym->st_shndx != SHN_XINDEX)) - { - /* This is no section index, leave it alone - unless it is moved. */ - if (destidx != inner - && gelf_update_symshndx (shdr_info[cnt].data, - shndxdata, - destidx, sym, - xshndx) == 0) - INTERNAL_ERROR (fname); - - shdr_info[cnt].newsymidx[inner] = destidx++; - - if (last_was_local - && GELF_ST_BIND (sym->st_info) != STB_LOCAL) - { - last_was_local = false; - shdr_info[cnt].shdr.sh_info = destidx - 1; - } - - continue; - } - - /* Get the full section index, if necessary from the - XINDEX table. */ - if (sym->st_shndx != SHN_XINDEX) - sec = shdr_info[sym->st_shndx].idx; - else - { - assert (shndxdata != NULL); - - sec = shdr_info[xshndx].idx; - } - - if (sec != 0) - { - GElf_Section nshndx; - Elf32_Word nxshndx; - - if (sec < SHN_LORESERVE) - { - nshndx = sec; - nxshndx = 0; - } - else - { - nshndx = SHN_XINDEX; - nxshndx = sec; - } - - assert (sec < SHN_LORESERVE || shndxdata != NULL); - - if ((inner != destidx || nshndx != sym->st_shndx - || (shndxdata != NULL && nxshndx != xshndx)) - && (sym->st_shndx = nshndx, - gelf_update_symshndx (shdr_info[cnt].data, - shndxdata, - destidx, sym, - nxshndx) == 0)) - INTERNAL_ERROR (fname); - - shdr_info[cnt].newsymidx[inner] = destidx++; - - if (last_was_local - && GELF_ST_BIND (sym->st_info) != STB_LOCAL) - { - last_was_local = false; - shdr_info[cnt].shdr.sh_info = destidx - 1; - } - } - else - /* This is a section symbol for a section which has - been removed. */ - assert (GELF_ST_TYPE (sym->st_info) == STT_SECTION); - } - - if (destidx != inner) - { - /* The size of the symbol table changed. */ - shdr_info[cnt].shdr.sh_size = newdata->d_size - = destidx * elsize; - any_symtab_changes = true; - } - else - { - /* The symbol table didn't really change. */ - free (shdr_info[cnt].newsymidx); - shdr_info[cnt].newsymidx = NULL; - } - } - } - - /* If we have to, compute the offset of the section. */ - if (shdr_info[cnt].shdr.sh_offset == 0) - shdr_info[cnt].shdr.sh_offset - = ((lastoffset + shdr_info[cnt].shdr.sh_addralign - 1) - & ~((GElf_Off) (shdr_info[cnt].shdr.sh_addralign - 1))); - - /* Set the section header in the new file. */ - if (unlikely (gelf_update_shdr (scn, &shdr_info[cnt].shdr) == 0)) - /* There cannot be any overflows. */ - INTERNAL_ERROR (fname); - - /* Remember the last section written so far. */ - GElf_Off filesz = (shdr_info[cnt].shdr.sh_type != SHT_NOBITS - ? shdr_info[cnt].shdr.sh_size : 0); - if (lastoffset < shdr_info[cnt].shdr.sh_offset + filesz) - lastoffset = shdr_info[cnt].shdr.sh_offset + filesz; - } - - /* Adjust symbol references if symbol tables changed. */ - if (any_symtab_changes) - { - /* Find all relocation sections which use this - symbol table. */ - for (cnt = 1; cnt <= shdridx; ++cnt) - { - if (shdr_info[cnt].idx == 0) - /* Ignore sections which are discarded. */ - continue; - - if (shdr_info[cnt].shdr.sh_type == SHT_REL - || shdr_info[cnt].shdr.sh_type == SHT_RELA) - { - /* If the symbol table hasn't changed, do not do anything. */ - if (shdr_info[shdr_info[cnt].old_sh_link].newsymidx == NULL) - continue; - - Elf32_Word *newsymidx - = shdr_info[shdr_info[cnt].old_sh_link].newsymidx; - Elf_Data *d = elf_getdata (elf_getscn (newelf, - shdr_info[cnt].idx), - NULL); - assert (d != NULL); - size_t nrels = (shdr_info[cnt].shdr.sh_size - / shdr_info[cnt].shdr.sh_entsize); - - if (shdr_info[cnt].shdr.sh_type == SHT_REL) - for (size_t relidx = 0; relidx < nrels; ++relidx) - { - GElf_Rel rel_mem; - if (gelf_getrel (d, relidx, &rel_mem) == NULL) - INTERNAL_ERROR (fname); - - size_t symidx = GELF_R_SYM (rel_mem.r_info); - if (newsymidx[symidx] != symidx) - { - rel_mem.r_info - = GELF_R_INFO (newsymidx[symidx], - GELF_R_TYPE (rel_mem.r_info)); - - if (gelf_update_rel (d, relidx, &rel_mem) == 0) - INTERNAL_ERROR (fname); - } - } - else - for (size_t relidx = 0; relidx < nrels; ++relidx) - { - GElf_Rela rel_mem; - if (gelf_getrela (d, relidx, &rel_mem) == NULL) - INTERNAL_ERROR (fname); - - size_t symidx = GELF_R_SYM (rel_mem.r_info); - if (newsymidx[symidx] != symidx) - { - rel_mem.r_info - = GELF_R_INFO (newsymidx[symidx], - GELF_R_TYPE (rel_mem.r_info)); - - if (gelf_update_rela (d, relidx, &rel_mem) == 0) - INTERNAL_ERROR (fname); - } - } - } - else if (shdr_info[cnt].shdr.sh_type == SHT_HASH) - { - /* We have to recompute the hash table. */ - Elf32_Word symtabidx = shdr_info[cnt].old_sh_link; - - /* We do not have to do anything if the symbol table was - not changed. */ - if (shdr_info[symtabidx].newsymidx == NULL) - continue; - - /* The symbol version section in the new file. */ - scn = elf_getscn (newelf, shdr_info[cnt].idx); - - /* The symbol table data. */ - Elf_Data *symd = elf_getdata (elf_getscn (newelf, - shdr_info[symtabidx].idx), - NULL); - assert (symd != NULL); - - /* The hash table data. */ - Elf_Data *hashd = elf_getdata (scn, NULL); - assert (hashd != NULL); - - if (shdr_info[cnt].shdr.sh_entsize == sizeof (Elf32_Word)) - { - /* Sane arches first. */ - Elf32_Word *bucket = (Elf32_Word *) hashd->d_buf; - - size_t strshndx = shdr_info[symtabidx].old_sh_link; - size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1, - ehdr->e_version); - - /* Convert to the correct byte order. */ - if (gelf_xlatetom (newelf, hashd, hashd, - BYTE_ORDER == LITTLE_ENDIAN - ? ELFDATA2LSB : ELFDATA2MSB) == NULL) - INTERNAL_ERROR (fname); - - /* Adjust the nchain value. The symbol table size - changed. We keep the same size for the bucket array. */ - bucket[1] = symd->d_size / elsize; - Elf32_Word nbucket = bucket[0]; - bucket += 2; - Elf32_Word *chain = bucket + nbucket; - - /* New size of the section. */ - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - shdr->sh_size = hashd->d_size - = (2 + symd->d_size / elsize + nbucket) - * sizeof (Elf32_Word); - (void) gelf_update_shdr (scn, shdr); - - /* Clear the arrays. */ - memset (bucket, '\0', - (symd->d_size / elsize + nbucket) - * sizeof (Elf32_Word)); - - for (size_t inner = shdr_info[symtabidx].shdr.sh_info; - inner < symd->d_size / elsize; ++inner) - { - GElf_Sym sym_mem; - GElf_Sym *sym = gelf_getsym (symd, inner, &sym_mem); - assert (sym != NULL); - - const char *name = elf_strptr (elf, strshndx, - sym->st_name); - assert (name != NULL); - size_t hidx = elf_hash (name) % nbucket; - - if (bucket[hidx] == 0) - bucket[hidx] = inner; - else - { - hidx = bucket[hidx]; - - while (chain[hidx] != 0) - hidx = chain[hidx]; - - chain[hidx] = inner; - } - } - } - else - { - /* Alpha and S390 64-bit use 64-bit SHT_HASH entries. */ - assert (shdr_info[cnt].shdr.sh_entsize - == sizeof (Elf64_Xword)); - - Elf64_Xword *bucket = (Elf64_Xword *) hashd->d_buf; - - size_t strshndx = shdr_info[symtabidx].old_sh_link; - size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1, - ehdr->e_version); - - /* Convert to the correct byte order. */ - if (gelf_xlatetom (newelf, hashd, hashd, - BYTE_ORDER == LITTLE_ENDIAN - ? ELFDATA2LSB : ELFDATA2MSB) == NULL) - INTERNAL_ERROR (fname); - - /* Adjust the nchain value. The symbol table size - changed. We keep the same size for the bucket array. */ - bucket[1] = symd->d_size / elsize; - Elf64_Xword nbucket = bucket[0]; - bucket += 2; - Elf64_Xword *chain = bucket + nbucket; - - /* New size of the section. */ - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - shdr->sh_size = hashd->d_size - = (2 + symd->d_size / elsize + nbucket) - * sizeof (Elf64_Xword); - (void) gelf_update_shdr (scn, shdr); - - /* Clear the arrays. */ - memset (bucket, '\0', - (symd->d_size / elsize + nbucket) - * sizeof (Elf64_Xword)); - - for (size_t inner = shdr_info[symtabidx].shdr.sh_info; - inner < symd->d_size / elsize; ++inner) - { - GElf_Sym sym_mem; - GElf_Sym *sym = gelf_getsym (symd, inner, &sym_mem); - assert (sym != NULL); - - const char *name = elf_strptr (elf, strshndx, - sym->st_name); - assert (name != NULL); - size_t hidx = elf_hash (name) % nbucket; - - if (bucket[hidx] == 0) - bucket[hidx] = inner; - else - { - hidx = bucket[hidx]; - - while (chain[hidx] != 0) - hidx = chain[hidx]; - - chain[hidx] = inner; - } - } - } - - /* Convert back to the file byte order. */ - if (gelf_xlatetof (newelf, hashd, hashd, - BYTE_ORDER == LITTLE_ENDIAN - ? ELFDATA2LSB : ELFDATA2MSB) == NULL) - INTERNAL_ERROR (fname); - } - else if (shdr_info[cnt].shdr.sh_type == SHT_GNU_versym) - { - /* If the symbol table changed we have to adjust the - entries. */ - Elf32_Word symtabidx = shdr_info[cnt].old_sh_link; - - /* We do not have to do anything if the symbol table was - not changed. */ - if (shdr_info[symtabidx].newsymidx == NULL) - continue; - - /* The symbol version section in the new file. */ - scn = elf_getscn (newelf, shdr_info[cnt].idx); - - /* The symbol table data. */ - Elf_Data *symd = elf_getdata (elf_getscn (newelf, - shdr_info[symtabidx].idx), - NULL); - assert (symd != NULL); - - /* The version symbol data. */ - Elf_Data *verd = elf_getdata (scn, NULL); - assert (verd != NULL); - - /* Convert to the correct byte order. */ - if (gelf_xlatetom (newelf, verd, verd, - BYTE_ORDER == LITTLE_ENDIAN - ? ELFDATA2LSB : ELFDATA2MSB) == NULL) - INTERNAL_ERROR (fname); - - /* The symbol version array. */ - GElf_Half *verstab = (GElf_Half *) verd->d_buf; - - /* New indices of the symbols. */ - Elf32_Word *newsymidx = shdr_info[symtabidx].newsymidx; - - /* Walk through the list and */ - size_t elsize = gelf_fsize (elf, verd->d_type, 1, - ehdr->e_version); - for (size_t inner = 1; inner < verd->d_size / elsize; ++inner) - if (newsymidx[inner] != 0) - /* Overwriting the same array works since the - reordering can only move entries to lower indices - in the array. */ - verstab[newsymidx[inner]] = verstab[inner]; - - /* New size of the section. */ - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - shdr->sh_size = verd->d_size - = gelf_fsize (newelf, verd->d_type, - symd->d_size / gelf_fsize (elf, symd->d_type, 1, - ehdr->e_version), - ehdr->e_version); - (void) gelf_update_shdr (scn, shdr); - - /* Convert back to the file byte order. */ - if (gelf_xlatetof (newelf, verd, verd, - BYTE_ORDER == LITTLE_ENDIAN - ? ELFDATA2LSB : ELFDATA2MSB) == NULL) - INTERNAL_ERROR (fname); - } - else if (shdr_info[cnt].shdr.sh_type == SHT_GROUP) - { - /* Check whether the associated symbol table changed. */ - if (shdr_info[shdr_info[cnt].old_sh_link].newsymidx != NULL) - { - /* Yes the symbol table changed. Update the section - header of the section group. */ - scn = elf_getscn (newelf, shdr_info[cnt].idx); - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - assert (shdr != NULL); - - size_t stabidx = shdr_info[cnt].old_sh_link; - shdr->sh_info = shdr_info[stabidx].newsymidx[shdr->sh_info]; - - (void) gelf_update_shdr (scn, shdr); - } - } - } - } - - /* Finally finish the ELF header. Fill in the fields not handled by - libelf from the old file. */ - newehdr = gelf_getehdr (newelf, &newehdr_mem); - if (newehdr == NULL) - INTERNAL_ERROR (fname); - - memcpy (newehdr->e_ident, ehdr->e_ident, EI_NIDENT); - newehdr->e_type = ehdr->e_type; - newehdr->e_machine = ehdr->e_machine; - newehdr->e_version = ehdr->e_version; - newehdr->e_entry = ehdr->e_entry; - newehdr->e_flags = ehdr->e_flags; - newehdr->e_phoff = ehdr->e_phoff; - /* We need to position the section header table. */ - const size_t offsize = gelf_fsize (elf, ELF_T_OFF, 1, EV_CURRENT); - newehdr->e_shoff = ((shdr_info[shdridx].shdr.sh_offset - + shdr_info[shdridx].shdr.sh_size + offsize - 1) - & ~((GElf_Off) (offsize - 1))); - newehdr->e_shentsize = gelf_fsize (elf, ELF_T_SHDR, 1, EV_CURRENT); - - /* The new section header string table index. */ - if (likely (idx < SHN_HIRESERVE) && likely (idx != SHN_XINDEX)) - newehdr->e_shstrndx = idx; - else - { - /* The index does not fit in the ELF header field. */ - shdr_info[0].scn = elf_getscn (elf, 0); - - if (gelf_getshdr (shdr_info[0].scn, &shdr_info[0].shdr) == NULL) - INTERNAL_ERROR (fname); - - shdr_info[0].shdr.sh_link = idx; - (void) gelf_update_shdr (shdr_info[0].scn, &shdr_info[0].shdr); - - newehdr->e_shstrndx = SHN_XINDEX; - } - - if (gelf_update_ehdr (newelf, newehdr) == 0) - { - error (0, 0, gettext ("%s: error while creating ELF header: %s"), - fname, elf_errmsg (-1)); - return 1; - } - - /* We have everything from the old file. */ - if (elf_cntl (elf, ELF_C_FDDONE) != 0) - { - error (0, 0, gettext ("%s: error while reading the file: %s"), - fname, elf_errmsg (-1)); - return 1; - } - - /* The ELF library better follows our layout when this is not a - relocatable object file. */ - elf_flagelf (newelf, ELF_C_SET, - (ehdr->e_type != ET_REL ? ELF_F_LAYOUT : 0) - | (permissive ? ELF_F_PERMISSIVE : 0)); - - /* Finally write the file. */ - if (elf_update (newelf, ELF_C_WRITE) == -1) - { - error (0, 0, gettext ("while writing `%s': %s"), - fname, elf_errmsg (-1)); - result = 1; - } - - fail_close: - if (shdr_info != NULL) - { - /* For some sections we might have created an table to map symbol - table indices. */ - if (any_symtab_changes) - for (cnt = 1; cnt <= shdridx; ++cnt) - free (shdr_info[cnt].newsymidx); - - /* Free the memory. */ - if ((shnum + 2) * sizeof (struct shdr_info) > MAX_STACK_ALLOC) - free (shdr_info); - } - - /* Free other resources. */ - if (shstrtab_data != NULL) - free (shstrtab_data->d_buf); - if (shst != NULL) - ebl_strtabfree (shst); - - /* That was it. Close the descriptors. */ - if (elf_end (newelf) != 0) - { - error (0, 0, gettext ("error while finishing `%s': %s"), fname, - elf_errmsg (-1)); - result = 1; - } - - if (debugelf != NULL && elf_end (debugelf) != 0) - { - error (0, 0, gettext ("error while finishing `%s': %s"), debug_fname, - elf_errmsg (-1)); - result = 1; - } - - fail: - /* Close the EBL backend. */ - if (ebl != NULL) - ebl_closebackend (ebl); - - /* Close debug file descriptor, if opened */ - if (debug_fd >= 0) - { - if (tmp_debug_fname != NULL) - unlink (tmp_debug_fname); - close (debug_fd); - } - - /* If requested, preserve the timestamp. */ - if (tvp != NULL) - { - if (futimes (fd, tvp) != 0) - { - error (0, errno, gettext ("\ -cannot set access and modification date of \"%s\""), - output_fname ?: fname); - result = 1; - } - } - - /* Close the file descriptor if we created a new file. */ - if (output_fname != NULL) - close (fd); - - return result; -} - - -static int -handle_ar (int fd, Elf *elf, const char *prefix, const char *fname, - struct timeval tvp[2]) -{ - size_t prefix_len = prefix == NULL ? 0 : strlen (prefix); - size_t fname_len = strlen (fname) + 1; - char new_prefix[prefix_len + 1 + fname_len]; - char *cp = new_prefix; - - /* Create the full name of the file. */ - if (prefix != NULL) - { - cp = mempcpy (cp, prefix, prefix_len); - *cp++ = ':'; - } - memcpy (cp, fname, fname_len); - - - /* Process all the files contained in the archive. */ - Elf *subelf; - Elf_Cmd cmd = ELF_C_RDWR; - int result = 0; - while ((subelf = elf_begin (fd, cmd, elf)) != NULL) - { - /* The the header for this element. */ - Elf_Arhdr *arhdr = elf_getarhdr (subelf); - - if (elf_kind (subelf) == ELF_K_ELF) - result |= handle_elf (fd, subelf, new_prefix, arhdr->ar_name, 0, NULL); - else if (elf_kind (subelf) == ELF_K_AR) - result |= handle_ar (fd, subelf, new_prefix, arhdr->ar_name, NULL); - - /* Get next archive element. */ - cmd = elf_next (subelf); - if (unlikely (elf_end (subelf) != 0)) - INTERNAL_ERROR (fname); - } - - if (tvp != NULL) - { - if (unlikely (futimes (fd, tvp) != 0)) - { - error (0, errno, gettext ("\ -cannot set access and modification date of \"%s\""), fname); - result = 1; - } - } - - if (unlikely (close (fd) != 0)) - error (EXIT_FAILURE, errno, gettext ("while closing `%s'"), fname); - - return result; -} diff --git a/src/symbolhash.c b/src/symbolhash.c deleted file mode 100644 index da2ae6f6..00000000 --- a/src/symbolhash.c +++ /dev/null @@ -1,29 +0,0 @@ -/* Symbol hash table implementation. - Copyright (C) 2001, 2002 Red Hat, Inc. - Written by Ulrich Drepper <drepper@redhat.com>, 2001. - - This program is Open Source software; you can redistribute it and/or - modify it under the terms of the Open Software License version 1.0 as - published by the Open Source Initiative. - - You should have received a copy of the Open Software License along - with this program; if not, you may obtain a copy of the Open Software - License version 1.0 from http://www.opensource.org/licenses/osl.php or - by writing the Open Source Initiative c/o Lawrence Rosen, Esq., - 3001 King Ranch Road, Ukiah, CA 95482. */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <string.h> - -#include <ld.h> - -/* 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 a8798c2a..00000000 --- a/src/symbolhash.h +++ /dev/null @@ -1,24 +0,0 @@ -/* Copyright (C) 2001, 2002 Red Hat, Inc. - Written by Ulrich Drepper <drepper@redhat.com>, 2001. - - This program is Open Source software; you can redistribute it and/or - modify it under the terms of the Open Software License version 1.0 as - published by the Open Source Initiative. - - You should have received a copy of the Open Software License along - with this program; if not, you may obtain a copy of the Open Software - License version 1.0 from http://www.opensource.org/licenses/osl.php or - by writing the Open Source Initiative c/o Lawrence Rosen, Esq., - 3001 King Ranch Road, Ukiah, CA 95482. */ - -#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 <dynamicsizehash.h> - -#endif /* symbolhash.h */ diff --git a/src/unaligned.h b/src/unaligned.h deleted file mode 100644 index 524b35c8..00000000 --- a/src/unaligned.h +++ /dev/null @@ -1,98 +0,0 @@ -/* Unaligned memory access functionality. - Copyright (C) 2000, 2001, 2002, 2003 Red Hat, Inc. - Written by Ulrich Drepper <drepper@redhat.com>, 2001. - - This program is Open Source software; you can redistribute it and/or - modify it under the terms of the Open Software License version 1.0 as - published by the Open Source Initiative. - - You should have received a copy of the Open Software License along - with this program; if not, you may obtain a copy of the Open Software - License version 1.0 from http://www.opensource.org/licenses/osl.php or - by writing the Open Source Initiative c/o Lawrence Rosen, Esq., - 3001 King Ranch Road, Ukiah, CA 95482. */ - -#ifndef _UNALIGNED_H -#define _UNALIGNED_H 1 - -#include <byteswap.h> -#include <endian.h> - - -#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 == 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 = target_bswap_16 (value)) -#define store_4ubyte_unaligned(ptr, value) \ - (void) (((union u_4ubyte_unaligned *) (ptr))->u = target_bswap_32 (value)) -#define store_8ubyte_unaligned(ptr, value) \ - (void) (((union u_8ubyte_unaligned *) (ptr))->u = target_bswap_64 (value)) - - -/* 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 == BYTE_ORDER -# define add_2ubyte_unaligned(ptr, value) \ - (void) (((union u_2ubyte_unaligned *) (ptr))->u += value) -# define add_4ubyte_unaligned(ptr, value) \ - (void) (((union u_4ubyte_unaligned *) (ptr))->u += value) -# define add_8ubyte_unaligned(ptr, value) \ - (void) (((union u_8ubyte_unaligned *) (ptr))->u += value) -#else -# define add_2ubyte_unaligned(ptr, value) \ - do { \ - union u_2ubyte_unaligned *_ptr = (ptr); \ - uint16_t _val = bswap_16 (_ptr->u) + (value); \ - _ptr->u = bswap_16 (_val); \ - } while (0) -# define add_4ubyte_unaligned(ptr, value) \ - do { \ - union u_4ubyte_unaligned *_ptr = (ptr); \ - uint32_t _val = bswap_32 (_ptr->u) + (value); \ - _ptr->u = bswap_32 (_val); \ - } while (0) -# define add_8ubyte_unaligned(ptr, value) \ - do { \ - union u_8ubyte_unaligned *_ptr = (ptr); \ - uint64_t _val = bswap_64 (_ptr->u) + (value); \ - _ptr->u = bswap_64 (_val); \ - } while (0) -#endif - -#endif /* unaligned.h */ diff --git a/src/versionhash.c b/src/versionhash.c deleted file mode 100644 index 79b2e105..00000000 --- a/src/versionhash.c +++ /dev/null @@ -1,28 +0,0 @@ -/* Version symbol hash table implementation. - Copyright (C) 2001, 2002 Red Hat, Inc. - Written by Ulrich Drepper <drepper@redhat.com>, 2001. - - This program is Open Source software; you can redistribute it and/or - modify it under the terms of the Open Software License version 1.0 as - published by the Open Source Initiative. - - You should have received a copy of the Open Software License along - with this program; if not, you may obtain a copy of the Open Software - License version 1.0 from http://www.opensource.org/licenses/osl.php or - by writing the Open Source Initiative c/o Lawrence Rosen, Esq., - 3001 King Ranch Road, Ukiah, CA 95482. */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <string.h> - -#include <ld.h> - -/* 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 243aeeb5..00000000 --- a/src/versionhash.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright (C) 2001, 2002 Red Hat, Inc. - Written by Ulrich Drepper <drepper@redhat.com>, 2001. - - This program is Open Source software; you can redistribute it and/or - modify it under the terms of the Open Software License version 1.0 as - published by the Open Source Initiative. - - You should have received a copy of the Open Software License along - with this program; if not, you may obtain a copy of the Open Software - License version 1.0 from http://www.opensource.org/licenses/osl.php or - by writing the Open Source Initiative c/o Lawrence Rosen, Esq., - 3001 King Ranch Road, Ukiah, CA 95482. */ - -#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 <dynamicsizehash.h> - -#endif /* versionhash.h */ diff --git a/src/xelf.h b/src/xelf.h deleted file mode 100644 index ab36e002..00000000 --- a/src/xelf.h +++ /dev/null @@ -1,387 +0,0 @@ -/* Macros to enable writing native and generic ELF access code. - Copyright (C) 2003 Red Hat, Inc. - Written by Ulrich Drepper <drepper@redhat.com>, 2003. - - This program is Open Source software; you can redistribute it and/or - modify it under the terms of the Open Software License version 1.0 as - published by the Open Source Initiative. - - You should have received a copy of the Open Software License along - with this program; if not, you may obtain a copy of the Open Software - License version 1.0 from http://www.opensource.org/licenses/osl.php or - by writing the Open Source Initiative c/o Lawrence Rosen, Esq., - 3001 King Ranch Road, Ukiah, CA 95482. */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <libebl.h> - - -/* By default the linker is handling all architectures. But it can - be configured to be a native-only linker. */ -#if NATIVE_ELF == 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 = elf32_getehdr (elf) -# define xelf_getehdr_copy(elf, name, copy) \ - (copy) = *(name = 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 = elf32_getphdr (elf) + idx -# define xelf_getphdr_ptr(elf, idx, name) name = elf32_getphdr (elf) + idx -# 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 = elf32_getshdr (scn) -# define xelf_getshdr_copy(scn, name, copy) \ - (copy) = *(name = 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 = &((Elf32_Sym *) (data)->d_buf)[idx] -# define xelf_getsym_ptr(data, idx, name) \ - name = &((Elf32_Sym *) (data)->d_buf)[idx] -# define xelf_getsymshndx(data, ndxdata, idx, name1, name2) \ - (name1 = &((Elf32_Sym *) ((data)->d_buf))[idx]); \ - name2 = (unlikely ((ndxdata) != 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, datachanged) \ - if (datachanged) \ - ((Elf32_Sym *) ((data)->d_buf))[idx] = *name1; \ - if (unlikely (ndxdata != NULL)) \ - ((Elf32_Word *) ((ndxdata)->d_buf))[idx] = name2 - -# define XElf_Versym_vardef(name) Elf32_Versym name -# define xelf_getversym_copy(data, idx, name) \ - (name = ((Elf32_Versym *) ((data)->d_buf))[idx], &name) - -# define XElf_Dyn_vardef(name) Elf32_Dyn *name -# define xelf_getdyn(data, idx, name) \ - name = &((Elf32_Dyn *) ((data)->d_buf))[idx] -# define xelf_getdyn_ptr(data, idx, name) \ - name = &((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 = &((Elf32_Rel *) ((data)->d_buf))[idx] -# define xelf_getrel_ptr(data, idx, name) \ - name = &((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 = &((Elf32_Rela *) ((data)->d_buf))[idx] -# define xelf_getrela_ptr(data, idx, name) \ - name = &((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 = ((Elf32_Verdef *) ((char *) ((data)->d_buf) + (offset))) - -# define XElf_Verdaux_vardef(name) Elf32_Verdaux *name -# define xelf_getverdaux(data, offset, name) \ - name = ((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 = 1; break; \ - case ELF_T_ADDR: fsize = sizeof (Elf32_Addr); break; \ - case ELF_T_DYN: fsize = sizeof (Elf32_Dyn); break; \ - case ELF_T_EHDR: fsize = sizeof (Elf32_Ehdr); break; \ - case ELF_T_HALF: fsize = sizeof (Elf32_Half); break; \ - case ELF_T_OFF: fsize = sizeof (Elf32_Off); break; \ - case ELF_T_PHDR: fsize = sizeof (Elf32_Phdr); break; \ - case ELF_T_RELA: fsize = sizeof (Elf32_Rela); break; \ - case ELF_T_REL: fsize = sizeof (Elf32_Rel); break; \ - case ELF_T_SHDR: fsize = sizeof (Elf32_Shdr); break; \ - case ELF_T_SWORD: fsize = sizeof (Elf32_Sword); break; \ - case ELF_T_SYM: fsize = sizeof (Elf32_Sym); break; \ - case ELF_T_WORD: fsize = sizeof (Elf32_Word); break; \ - case ELF_T_XWORD: fsize = sizeof (Elf32_Xword); break; \ - case ELF_T_SXWORD: fsize = sizeof (Elf32_Sxword); break; \ - case ELF_T_VDEF: fsize = sizeof (Elf32_Verdef); break; \ - case ELF_T_VDAUX: fsize = sizeof (Elf32_Verdaux); break; \ - case ELF_T_VNEED: fsize = sizeof (Elf32_Verneed); break; \ - case ELF_T_VNAUX: fsize = sizeof (Elf32_Vernaux); break; \ - case ELF_T_NHDR: fsize = sizeof (Elf32_Nhdr); break; \ - case ELF_T_SYMINFO: fsize = sizeof (Elf32_Syminfo); break; \ - case ELF_T_MOVE: fsize = sizeof (Elf32_Move); break; \ - default: fsize = 0; break; \ - } \ - fsize * (cnt); }) \ - : gelf_fsize (elf, type, cnt, EV_CURRENT)) -#elif NATIVE_ELF == 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 = elf64_getehdr (elf) -# define xelf_getehdr_copy(elf, name, copy) \ - (copy) = *(name = 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 = elf64_getphdr (elf) + idx -# define xelf_getphdr_ptr(elf, idx, name) name = elf64_getphdr (elf) + idx -# 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 = elf64_getshdr (scn) -# define xelf_getshdr_copy(scn, name, copy) \ - (copy) = *(name = 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 = &((Elf64_Sym *) (data)->d_buf)[idx] -# define xelf_getsym_ptr(data, idx, name) \ - name = &((Elf64_Sym *) (data)->d_buf)[idx] -# define xelf_getsymshndx(data, ndxdata, idx, name1, name2) \ - (name1 = &((Elf64_Sym *) ((data)->d_buf))[idx]); \ - name2 = (unlikely ((ndxdata) != 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, datachanged) \ - if (datachanged) \ - ((Elf64_Sym *) ((data)->d_buf))[idx] = *name1; \ - if (ndxdata != NULL) \ - (((Elf32_Word *) ((ndxdata)->d_buf))[idx] = name2) - -# define XElf_Versym_vardef(name) Elf64_Versym name -# define xelf_getversym_copy(data, idx, name) \ - (name = ((Elf64_Versym *) ((data)->d_buf))[idx], (&name)) - -# define XElf_Dyn_vardef(name) Elf64_Dyn *name -# define xelf_getdyn(data, idx, name) \ - name = &((Elf64_Dyn *) ((data)->d_buf))[idx] -# define xelf_getdyn_ptr(data, idx, name) \ - name = &((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 = &((Elf64_Rel *) ((data)->d_buf))[idx] -# define xelf_getrel_ptr(data, idx, name) \ - name = &((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 = &((Elf64_Rela *) ((data)->d_buf))[idx] -# define xelf_getrela_ptr(data, idx, name) \ - name = &((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 = ((Elf64_Verdef *) ((char *) ((data)->d_buf) + (offset))) - -# define XElf_Verdaux_vardef(name) Elf64_Verdaux *name -# define xelf_getverdaux(data, offset, name) \ - name = ((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 = 1; break; \ - case ELF_T_ADDR: fsize = sizeof (Elf64_Addr); break; \ - case ELF_T_DYN: fsize = sizeof (Elf64_Dyn); break; \ - case ELF_T_EHDR: fsize = sizeof (Elf64_Ehdr); break; \ - case ELF_T_HALF: fsize = sizeof (Elf64_Half); break; \ - case ELF_T_OFF: fsize = sizeof (Elf64_Off); break; \ - case ELF_T_PHDR: fsize = sizeof (Elf64_Phdr); break; \ - case ELF_T_RELA: fsize = sizeof (Elf64_Rela); break; \ - case ELF_T_REL: fsize = sizeof (Elf64_Rel); break; \ - case ELF_T_SHDR: fsize = sizeof (Elf64_Shdr); break; \ - case ELF_T_SWORD: fsize = sizeof (Elf64_Sword); break; \ - case ELF_T_SYM: fsize = sizeof (Elf64_Sym); break; \ - case ELF_T_WORD: fsize = sizeof (Elf64_Word); break; \ - case ELF_T_XWORD: fsize = sizeof (Elf64_Xword); break; \ - case ELF_T_SXWORD: fsize = sizeof (Elf64_Sxword); break; \ - case ELF_T_VDEF: fsize = sizeof (Elf64_Verdef); break; \ - case ELF_T_VDAUX: fsize = sizeof (Elf64_Verdaux); break; \ - case ELF_T_VNEED: fsize = sizeof (Elf64_Verneed); break; \ - case ELF_T_VNAUX: fsize = sizeof (Elf64_Vernaux); break; \ - case ELF_T_NHDR: fsize = sizeof (Elf64_Nhdr); break; \ - case ELF_T_SYMINFO: fsize = sizeof (Elf64_Syminfo); break; \ - case ELF_T_MOVE: fsize = sizeof (Elf64_Move); break; \ - default: fsize = 0; break; \ - } \ - fsize * (cnt); }) \ - : gelf_fsize (elf, type, cnt, EV_CURRENT)) -#else -# include <gelf.h> - -/* 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 = gelf_getehdr (elf, &name##_mem) -# define xelf_getehdr_copy(elf, name, copy) \ - name = 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 = gelf_getphdr (elf, idx, &name##_mem) -# define xelf_getphdr_ptr(elf, idx, name) \ - name = &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 = gelf_getshdr (scn, &name##_mem) -# define xelf_getshdr_copy(scn, name, copy) \ - name = 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 = gelf_getsym (data, idx, &name##_mem) -# define xelf_getsym_ptr(data, idx, name) \ - name = &name##_mem -# define xelf_getsymshndx(data, ndxdata, idx, name1, name2) \ - name1 = 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, datachanged) \ - 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 = gelf_getdyn (data, idx, &name##_mem) -# define xelf_getdyn_ptr(data, idx, name) \ - name = &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 = gelf_getrel (data, idx, &name##_mem) -# define xelf_getrel_ptr(data, idx, name) \ - name = &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 = gelf_getrela (data, idx, &name##_mem) -# define xelf_getrela_ptr(data, idx, name) \ - name = &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 = 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 = 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 diff --git a/src/ylwrap b/src/ylwrap deleted file mode 100644 index e8abf827..00000000 --- a/src/ylwrap +++ /dev/null @@ -1,154 +0,0 @@ -#! /bin/sh -# ylwrap - wrapper for lex/yacc invocations. -# Copyright 1996, 1997, 1998, 1999, 2001 Free Software Foundation, Inc. -# Written by Tom Tromey <tromey@cygnus.com>. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -# Usage: -# ylwrap INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]... -# * INPUT is the input file -# * OUTPUT is file PROG generates -# * DESIRED is file we actually want -# * PROGRAM is program to run -# * ARGS are passed to PROG -# Any number of OUTPUT,DESIRED pairs may be used. - -# The input. -input="$1" -shift -case "$input" in - [\\/]* | ?:[\\/]*) - # Absolute path; do nothing. - ;; - *) - # Relative path. Make it absolute. - input="`pwd`/$input" - ;; -esac - -pairlist= -while test "$#" -ne 0; do - if test "$1" = "--"; then - shift - break - fi - pairlist="$pairlist $1" - shift -done - -# The program to run. -prog="$1" -shift -# Make any relative path in $prog absolute. -case "$prog" in - [\\/]* | ?:[\\/]*) ;; - *[\\/]*) prog="`pwd`/$prog" ;; -esac - -# FIXME: add hostname here for parallel makes that run commands on -# other machines. But that might take us over the 14-char limit. -dirname=ylwrap$$ -trap "cd `pwd`; rm -rf $dirname > /dev/null 2>&1" 1 2 3 15 -mkdir $dirname || exit 1 - -cd $dirname - -$prog ${1+"$@"} "$input" -status=$? - -if test $status -eq 0; then - set X $pairlist - shift - first=yes - # Since DOS filename conventions don't allow two dots, - # the DOS version of Bison writes out y_tab.c instead of y.tab.c - # and y_tab.h instead of y.tab.h. Test to see if this is the case. - y_tab_nodot="no" - if test -f y_tab.c || test -f y_tab.h; then - y_tab_nodot="yes" - fi - - # The directory holding the input. - input_dir=`echo "$input" | sed -e 's,\([\\/]\)[^\\/]*$,\1,'` - # Quote $INPUT_DIR so we can use it in a regexp. - # FIXME: really we should care about more than `.' and `\'. - input_rx=`echo "$input_dir" | sed 's,\\\\,\\\\\\\\,g;s,\\.,\\\\.,g'` - - while test "$#" -ne 0; do - from="$1" - # Handle y_tab.c and y_tab.h output by DOS - if test $y_tab_nodot = "yes"; then - if test $from = "y.tab.c"; then - from="y_tab.c" - else - if test $from = "y.tab.h"; then - from="y_tab.h" - fi - fi - fi - if test -f "$from"; then - # If $2 is an absolute path name, then just use that, - # otherwise prepend `../'. - case "$2" in - [\\/]* | ?:[\\/]*) target="$2";; - *) target="../$2";; - esac - - # Edit out `#line' or `#' directives. - # - # We don't want the resulting debug information to point at - # an absolute srcdir; it is better for it to just mention the - # .y file with no path. - # - # We want to use the real output file name, not yy.lex.c for - # instance. - # - # We want the include guards to be adjusted too. - FROM=`echo "$from" | sed \ - -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\ - -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'` - TARGET=`echo "$2" | sed \ - -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\ - -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'` - sed "/^#/{s,$input_rx,,;s,$from,$2,;s,$FORM,$TO,;}" "$from" >"$target" || - status=$? - else - # A missing file is only an error for the first file. This - # is a blatant hack to let us support using "yacc -d". If -d - # is not specified, we don't want an error when the header - # file is "missing". - if test $first = yes; then - status=1 - fi - fi - shift - shift - first=no - done -else - status=$? -fi - -# Remove the directory. -cd .. -rm -rf $dirname - -exit $status |
