diff options
author | Alan Modra <amodra@gmail.com> | 2019-09-09 23:07:35 +0930 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2019-09-11 13:44:22 +0930 |
commit | d871d478061f10b0879c688e2fa941407e9137aa (patch) | |
tree | 4f564ccc452de8255f2eecfecfb931de03ad2093 | |
parent | cb7f4b298e5e0a3ab4fb6b13aa89e970478597bc (diff) | |
download | gdb-d871d478061f10b0879c688e2fa941407e9137aa.zip gdb-d871d478061f10b0879c688e2fa941407e9137aa.tar.gz gdb-d871d478061f10b0879c688e2fa941407e9137aa.tar.bz2 |
Move elf32.em and elf-generic.em functions
Many ELF linker targets support multiple "emulations" and thus have
multiple copies of elf32.em being compiled and linked into ld. This
patch moves much of elf32.em and elf-generic.em into files which will
be compiled just once, resulting in a 20% decrease in ld size for
--enable-targets=all.
* Makefile.am (ALL_EMUL_EXTRA_OFILES): Add ldelf and ldelfgen.
(CFILES, HFILES, EXTRA_ld_new_SOURCES): Likewise.
* configure.tgt: Formatting.
(targ_extra_ofiles): Init to ldelf.o ldelfgen.o, reset to just
ldelfgen.o for generic ELF targets, and empty for non-ELF.
* emultempl/aarch64elf.em (gldaarch64_layout_sections_again): Use
ldelf_map_segments.
(gld${EMULATION_NAME}_after_allocation): Likewise.
(real_func, aarch64_for_each_input_file_wrapper),
(aarch64_lang_for_each_input_file): Delete.
(lang_for_each_input_file): Don't define.
* emultempl/alphaelf.em (alpha_after_parse): Use ldelf_map_segments.
* emultempl/armelf.em (gldarm_layout_sections_again): Likewise.
(gld${EMULATION_NAME}_after_allocation): Likewise.
(real_func, arm_for_each_input_file_wrapper),
(arm_lang_for_each_input_file): Delete.
(lang_for_each_input_file): Don't define.
* emultempl/cr16elf.em (cr16elf_after_parse): Use ldelf_map_segments.
* emultempl/crxelf.em (crxelf_after_parse): Likewise. Delete
declaration.
* emultempl/cskyelf.em (gldcsky_layout_sections_again): Use
ldelf_map_segments.
(gld${EMULATION_NAME}_after_allocation): Likewise.
(real_func, csky_for_each_input_file_wrapper),
(csky_lang_for_each_input_file): Delete.
(lang_for_each_input_file): Don't define.
* emultempl/genelf.em: Include ldelfgen.h.
(gld${EMULATION_NAME}_before_allocation): Use ldelf_map_segments.
* emultempl/hppaelf.em (hppaelf_after_parse): Likewise.
(hppaelf_layout_sections_again): Likewise.
(gld${EMULATION_NAME}_after_allocation): Likewise.
(real_func, hppa_for_each_input_file_wrapper),
(hppa_lang_for_each_input_file): Delete.
(lang_for_each_input_file): Don't define.
* emultempl/ia64elf.em (ia64elf_after_parse): Use ldelf_map_segments.
* emultempl/m68hc1xelf.em (real_func),
(m68hc11_for_each_input_file_wrapper),
(m68hc11_lang_for_each_input_file): Delete.
(lang_for_each_input_file): Don't define.
* emultempl/metagelf.em (metagelf_layout_sections_again): Use
ldelf_map_segments.
(gld${EMULATION_NAME}_after_allocation): Likewise.
(real_func, metag_for_each_input_file_wrapper),
(metag_lang_for_each_input_file): Delete.
(lang_for_each_input_file): Don't define.
* emultempl/mipself.em (real_func),
(mips_for_each_input_file_wrapper),
(mips_lang_for_each_input_file): Delete.
(lang_for_each_input_file): Don't define.
* emultempl/mmo.em: Don't include elf-bfd.h, do include ldelfgen.h.
(gld${EMULATION_NAME}_after_allocation): Use ldelf_map_segments.
* emultempl/nds32elf.em (nds32_elf_after_parse): Use ldelf_after_parse.
(nds32_elf_after_allocation): Comment fix.
* emultempl/nios2elf.em (nios2elf_layout_sections_again): Use
ldelf_map_segments.
(gld${EMULATION_NAME}_after_allocation): Likewise.
(real_func, nios2_for_each_input_file_wrapper),
(nios2_lang_for_each_input_file): Delete.
(lang_for_each_input_file): Don't define.
* emultempl/ppc32elf.em (gld${EMULATION_NAME}_load_symbols): Delete
declaration.
(ppc_recognized_file): Call ldelf_load_symbols.
* emultempl/ppc64elf.em (ppc_layout_sections_again): Likewise.
(gld${EMULATION_NAME}_after_allocation): Likewise.
(real_func, ppc_for_each_input_file_wrapper),
(ppc_lang_for_each_input_file): Delete.
(lang_for_each_input_file): Don't define.
(gld${EMULATION_NAME}_load_symbols): Don't declare.
(ppc64_recognized_file): Call ldelf_load_symbols.
* emultempl/riscvelf.em (gld${EMULATION_NAME}_after_allocation):
Use ldelf_map_segments.
* emultempl/spuelf.em (spu_place_special_section): Use
ldelf_place_orphan.
* emultempl/tic6xdsbt.em (gld${EMULATION_NAME}_after_allocation):
Use ldelf_map_segments.
* emultempl/vms.em: Include ldelfgen.h.
(gld${EMULATION_NAME}_after_allocation): Use ldelf_map_segments.
* emultempl/elf32.em: Remove unnecessary headers, include ldelf.h
and ldelfgen.h. Move much of file content to..
* ldelf.c: ..here. New file.
* ldelf.h: New file.
* emultempl/elf-generic.em: Move gld${EMULATION_NAME}_map_segments..
* ldelfgen.c: ..to here.
* ldelfgen.h: New file.
* ldlang.c (lang_for_each_input_file): Adjust to only call func
on real files.
(lang_for_each_file): Likewise.
* po/SRC-POTFILES.in: Regenerate.
* Makefile.in: Regenerate.
33 files changed, 2914 insertions, 2693 deletions
diff --git a/ld/ChangeLog b/ld/ChangeLog index 955d460..18d2c05 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,5 +1,97 @@ 2019-09-11 Alan Modra <amodra@gmail.com> + * Makefile.am (ALL_EMUL_EXTRA_OFILES): Add ldelf and ldelfgen. + (CFILES, HFILES, EXTRA_ld_new_SOURCES): Likewise. + * configure.tgt: Formatting. + (targ_extra_ofiles): Init to ldelf.o ldelfgen.o, reset to just + ldelfgen.o for generic ELF targets, and empty for non-ELF. + * emultempl/aarch64elf.em (gldaarch64_layout_sections_again): Use + ldelf_map_segments. + (gld${EMULATION_NAME}_after_allocation): Likewise. + (real_func, aarch64_for_each_input_file_wrapper), + (aarch64_lang_for_each_input_file): Delete. + (lang_for_each_input_file): Don't define. + * emultempl/alphaelf.em (alpha_after_parse): Use ldelf_map_segments. + * emultempl/armelf.em (gldarm_layout_sections_again): Likewise. + (gld${EMULATION_NAME}_after_allocation): Likewise. + (real_func, arm_for_each_input_file_wrapper), + (arm_lang_for_each_input_file): Delete. + (lang_for_each_input_file): Don't define. + * emultempl/cr16elf.em (cr16elf_after_parse): Use ldelf_map_segments. + * emultempl/crxelf.em (crxelf_after_parse): Likewise. Delete + declaration. + * emultempl/cskyelf.em (gldcsky_layout_sections_again): Use + ldelf_map_segments. + (gld${EMULATION_NAME}_after_allocation): Likewise. + (real_func, csky_for_each_input_file_wrapper), + (csky_lang_for_each_input_file): Delete. + (lang_for_each_input_file): Don't define. + * emultempl/genelf.em: Include ldelfgen.h. + (gld${EMULATION_NAME}_before_allocation): Use ldelf_map_segments. + * emultempl/hppaelf.em (hppaelf_after_parse): Likewise. + (hppaelf_layout_sections_again): Likewise. + (gld${EMULATION_NAME}_after_allocation): Likewise. + (real_func, hppa_for_each_input_file_wrapper), + (hppa_lang_for_each_input_file): Delete. + (lang_for_each_input_file): Don't define. + * emultempl/ia64elf.em (ia64elf_after_parse): Use ldelf_map_segments. + * emultempl/m68hc1xelf.em (real_func), + (m68hc11_for_each_input_file_wrapper), + (m68hc11_lang_for_each_input_file): Delete. + (lang_for_each_input_file): Don't define. + * emultempl/metagelf.em (metagelf_layout_sections_again): Use + ldelf_map_segments. + (gld${EMULATION_NAME}_after_allocation): Likewise. + (real_func, metag_for_each_input_file_wrapper), + (metag_lang_for_each_input_file): Delete. + (lang_for_each_input_file): Don't define. + * emultempl/mipself.em (real_func), + (mips_for_each_input_file_wrapper), + (mips_lang_for_each_input_file): Delete. + (lang_for_each_input_file): Don't define. + * emultempl/mmo.em: Don't include elf-bfd.h, do include ldelfgen.h. + (gld${EMULATION_NAME}_after_allocation): Use ldelf_map_segments. + * emultempl/nds32elf.em (nds32_elf_after_parse): Use ldelf_after_parse. + (nds32_elf_after_allocation): Comment fix. + * emultempl/nios2elf.em (nios2elf_layout_sections_again): Use + ldelf_map_segments. + (gld${EMULATION_NAME}_after_allocation): Likewise. + (real_func, nios2_for_each_input_file_wrapper), + (nios2_lang_for_each_input_file): Delete. + (lang_for_each_input_file): Don't define. + * emultempl/ppc32elf.em (gld${EMULATION_NAME}_load_symbols): Delete + declaration. + (ppc_recognized_file): Call ldelf_load_symbols. + * emultempl/ppc64elf.em (ppc_layout_sections_again): Likewise. + (gld${EMULATION_NAME}_after_allocation): Likewise. + (real_func, ppc_for_each_input_file_wrapper), + (ppc_lang_for_each_input_file): Delete. + (lang_for_each_input_file): Don't define. + (gld${EMULATION_NAME}_load_symbols): Don't declare. + (ppc64_recognized_file): Call ldelf_load_symbols. + * emultempl/riscvelf.em (gld${EMULATION_NAME}_after_allocation): + Use ldelf_map_segments. + * emultempl/spuelf.em (spu_place_special_section): Use + ldelf_place_orphan. + * emultempl/tic6xdsbt.em (gld${EMULATION_NAME}_after_allocation): + Use ldelf_map_segments. + * emultempl/vms.em: Include ldelfgen.h. + (gld${EMULATION_NAME}_after_allocation): Use ldelf_map_segments. + * emultempl/elf32.em: Remove unnecessary headers, include ldelf.h + and ldelfgen.h. Move much of file content to.. + * ldelf.c: ..here. New file. + * ldelf.h: New file. + * emultempl/elf-generic.em: Move gld${EMULATION_NAME}_map_segments.. + * ldelfgen.c: ..to here. + * ldelfgen.h: New file. + * ldlang.c (lang_for_each_input_file): Adjust to only call func + on real files. + (lang_for_each_file): Likewise. + * po/SRC-POTFILES.in: Regenerate. + * Makefile.in: Regenerate. + +2019-09-11 Alan Modra <amodra@gmail.com> + * ldmisc.c: Don't #include elf-bfd.h or coff-bfd.h. (vfinfo): Use bfd_group_name. diff --git a/ld/Makefile.am b/ld/Makefile.am index 0509c2e..c56559d 100644 --- a/ld/Makefile.am +++ b/ld/Makefile.am @@ -467,7 +467,9 @@ ALL_64_EMULATIONS = $(ALL_64_EMULATION_SOURCES:.c=.@OBJEXT@) ALL_EMUL_EXTRA_OFILES = \ deffilep.@OBJEXT@ \ - pe-dll.@OBJEXT@ + pe-dll.@OBJEXT@ \ + ldelf.@OBJEXT@ \ + ldelfgen.@OBJEXT@ ALL_64_EMUL_EXTRA_OFILES = \ pep-dll.@OBJEXT@ @@ -475,12 +477,12 @@ ALL_64_EMUL_EXTRA_OFILES = \ CFILES = ldctor.c ldemul.c ldexp.c ldfile.c ldlang.c \ ldmain.c ldmisc.c ldver.c ldwrite.c lexsup.c \ mri.c ldcref.c pe-dll.c pep-dll.c ldlex-wrapper.c \ - $(PLUGIN_C) ldbuildid.c + $(PLUGIN_C) ldbuildid.c ldelf.c ldelfgen.c HFILES = ld.h ldctor.h ldemul.h ldexp.h ldfile.h \ ldlang.h ldlex.h ldmain.h ldmisc.h ldver.h \ ldwrite.h mri.h deffile.h pe-dll.h pep-dll.h \ - elf-hints-local.h $(PLUGIN_H) ldbuildid.h + elf-hints-local.h $(PLUGIN_H) ldbuildid.h ldelf.h ldelfgen.h GENERATED_CFILES = ldgram.c ldlex.c deffilep.c GENERATED_HFILES = ldgram.h ldemul-list.h deffilep.h @@ -951,7 +953,7 @@ $(ALL_EMULATION_SOURCES) $(ALL_64_EMULATION_SOURCES): $(GEN_DEPENDS) # We need this for automake to use YLWRAP. EXTRA_ld_new_SOURCES = deffilep.y ldlex.l # Allow dependency tracking to work for these files, too. -EXTRA_ld_new_SOURCES += pep-dll.c pe-dll.c +EXTRA_ld_new_SOURCES += pep-dll.c pe-dll.c ldelf.c ldelfgen.c ld_new_SOURCES = ldgram.y ldlex-wrapper.c lexsup.c ldlang.c mri.c ldctor.c ldmain.c \ ldwrite.c ldexp.c ldemul.c ldver.c ldmisc.c ldfile.c ldcref.c $(PLUGIN_C) \ diff --git a/ld/Makefile.in b/ld/Makefile.in index 9898392..d509f62 100644 --- a/ld/Makefile.in +++ b/ld/Makefile.in @@ -952,7 +952,9 @@ ALL_64_EMULATION_SOURCES = \ ALL_64_EMULATIONS = $(ALL_64_EMULATION_SOURCES:.c=.@OBJEXT@) ALL_EMUL_EXTRA_OFILES = \ deffilep.@OBJEXT@ \ - pe-dll.@OBJEXT@ + pe-dll.@OBJEXT@ \ + ldelf.@OBJEXT@ \ + ldelfgen.@OBJEXT@ ALL_64_EMUL_EXTRA_OFILES = \ pep-dll.@OBJEXT@ @@ -960,12 +962,12 @@ ALL_64_EMUL_EXTRA_OFILES = \ CFILES = ldctor.c ldemul.c ldexp.c ldfile.c ldlang.c \ ldmain.c ldmisc.c ldver.c ldwrite.c lexsup.c \ mri.c ldcref.c pe-dll.c pep-dll.c ldlex-wrapper.c \ - $(PLUGIN_C) ldbuildid.c + $(PLUGIN_C) ldbuildid.c ldelf.c ldelfgen.c HFILES = ld.h ldctor.h ldemul.h ldexp.h ldfile.h \ ldlang.h ldlex.h ldmain.h ldmisc.h ldver.h \ ldwrite.h mri.h deffile.h pe-dll.h pep-dll.h \ - elf-hints-local.h $(PLUGIN_H) ldbuildid.h + elf-hints-local.h $(PLUGIN_H) ldbuildid.h ldelf.h ldelfgen.h GENERATED_CFILES = ldgram.c ldlex.c deffilep.c GENERATED_HFILES = ldgram.h ldemul-list.h deffilep.h @@ -991,8 +993,9 @@ GEN_DEPENDS = $(srcdir)/genscripts.sh stringify.sed # Allow dependency tracking to work for these files, too. # Dependency tracking for the generated emulation files. -EXTRA_ld_new_SOURCES = deffilep.y ldlex.l pep-dll.c pe-dll.c \ - $(ALL_EMULATION_SOURCES) $(ALL_64_EMULATION_SOURCES) +EXTRA_ld_new_SOURCES = deffilep.y ldlex.l pep-dll.c pe-dll.c ldelf.c \ + ldelfgen.c $(ALL_EMULATION_SOURCES) \ + $(ALL_64_EMULATION_SOURCES) ld_new_SOURCES = ldgram.y ldlex-wrapper.c lexsup.c ldlang.c mri.c ldctor.c ldmain.c \ ldwrite.c ldexp.c ldemul.c ldver.c ldmisc.c ldfile.c ldcref.c $(PLUGIN_C) \ ldbuildid.c @@ -1491,6 +1494,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldbuildid.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldcref.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldctor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldelf.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldelfgen.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldemul.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldexp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldfile.Po@am__quote@ diff --git a/ld/configure.tgt b/ld/configure.tgt index c81bc8a..608db30 100644 --- a/ld/configure.tgt +++ b/ld/configure.tgt @@ -36,7 +36,7 @@ targ_extra_emuls= targ_extra_libpath= -targ_extra_ofiles= +targ_extra_ofiles="ldelf.o ldelfgen.o" targ64_extra_emuls= targ64_extra_libpath= @@ -46,43 +46,63 @@ targ64_extra_libpath= # break the alpha sorting. case "${targ}" in aarch64_be-*-elf) targ_emul=aarch64elfb - targ_extra_emuls="aarch64elf aarch64elf32 aarch64elf32b armelfb armelf" ;; + targ_extra_emuls="aarch64elf aarch64elf32 aarch64elf32b armelfb armelf" + ;; aarch64-*-elf | aarch64-*-rtems*) targ_emul=aarch64elf - targ_extra_emuls="aarch64elf32 aarch64elf32b aarch64elfb armelf armelfb" ;; + targ_extra_emuls="aarch64elf32 aarch64elf32b aarch64elfb armelf armelfb" + ;; aarch64-*-cloudabi*) targ_emul=aarch64cloudabi - targ_extra_emuls=aarch64cloudabib ;; + targ_extra_emuls=aarch64cloudabib + ;; aarch64-*-freebsd*) targ_emul=aarch64fbsd - targ_extra_emuls="aarch64fbsdb aarch64elf" ;; + targ_extra_emuls="aarch64fbsdb aarch64elf" + ;; aarch64-*-fuchsia*) targ_emul=aarch64elf - targ_extra_emuls="aarch64elfb armelf armelfb" ;; + targ_extra_emuls="aarch64elfb armelf armelfb" + ;; aarch64_be-*-linux-gnu_ilp32) targ_emul=aarch64linux32b targ_extra_libpath="aarch64linuxb aarch64linux aarch64linux32 armelfb_linux_eabi armelf_linux_eabi" - targ_extra_emuls="aarch64elfb aarch64elf aarch64elf32 aarch64elf32b armelfb armelf $targ_extra_libpath" ;; + targ_extra_emuls="aarch64elfb aarch64elf aarch64elf32 aarch64elf32b armelfb armelf $targ_extra_libpath" + ;; aarch64-*-linux-gnu_ilp32) targ_emul=aarch64linux32 targ_extra_libpath="aarch64linux aarch64linuxb aarch64linux32b armelfb_linux_eabi armelf_linux_eabi" - targ_extra_emuls="aarch64elf aarch64elf32 aarch64elf32b aarch64elfb armelf armelfb $targ_extra_libpath" ;; + targ_extra_emuls="aarch64elf aarch64elf32 aarch64elf32b aarch64elfb armelf armelfb $targ_extra_libpath" + ;; aarch64_be-*-linux*) targ_emul=aarch64linuxb targ_extra_libpath="aarch64linux aarch64linux32 aarch64linux32b armelfb_linux_eabi armelf_linux_eabi" - targ_extra_emuls="aarch64elfb aarch64elf aarch64elf32 aarch64elf32b armelfb armelf $targ_extra_libpath" ;; + targ_extra_emuls="aarch64elfb aarch64elf aarch64elf32 aarch64elf32b armelfb armelf $targ_extra_libpath" + ;; aarch64-*-linux*) targ_emul=aarch64linux targ_extra_libpath="aarch64linuxb aarch64linux32 aarch64linux32b armelfb_linux_eabi armelf_linux_eabi" - targ_extra_emuls="aarch64elf aarch64elf32 aarch64elf32b aarch64elfb armelf armelfb $targ_extra_libpath" ;; + targ_extra_emuls="aarch64elf aarch64elf32 aarch64elf32b aarch64elfb armelf armelfb $targ_extra_libpath" + ;; alpha*-*-freebsd* | alpha*-*-kfreebsd*-gnu) targ_emul=elf64alpha_fbsd targ_extra_emuls="elf64alpha alpha" - tdir_alpha=`echo ${targ_alias} | sed -e 's/freebsd/freebsdecoff/'` ;; -alpha*-*-linux*ecoff*) targ_emul=alpha targ_extra_emuls=elf64alpha - tdir_elf64alpha=`echo ${targ_alias} | sed -e 's/ecoff//'` ;; -alpha*-*-linux-*) targ_emul=elf64alpha targ_extra_emuls=alpha - tdir_alpha=`echo ${targ_alias} | sed -e 's/linux\(-gnu\)*/linux\1ecoff/'` ;; -alpha*-*-osf*) targ_emul=alpha ;; -alpha*-*-gnu*) targ_emul=elf64alpha ;; -alpha*-*-netbsd*) targ_emul=elf64alpha_nbsd ;; -alpha*-*-openbsd*) targ_emul=elf64alpha ;; + tdir_alpha=`echo ${targ_alias} | sed -e 's/freebsd/freebsdecoff/'` + ;; +alpha*-*-linux*ecoff*) targ_emul=alpha + targ_extra_emuls=elf64alpha + tdir_elf64alpha=`echo ${targ_alias} | sed -e 's/ecoff//'` + ;; +alpha*-*-linux-*) targ_emul=elf64alpha + targ_extra_emuls=alpha + tdir_alpha=`echo ${targ_alias} | sed -e 's/linux\(-gnu\)*/linux\1ecoff/'` + ;; +alpha*-*-osf*) targ_emul=alpha + targ_extra_ofiles= + ;; +alpha*-*-gnu*) targ_emul=elf64alpha + ;; +alpha*-*-netbsd*) targ_emul=elf64alpha_nbsd + ;; +alpha*-*-openbsd*) targ_emul=elf64alpha + ;; alpha*-*-*vms*) targ_emul=alphavms + targ_extra_ofiles= ;; arc*-*-elf*) targ_emul=arcelf targ_extra_emuls="arcelf_prof arclinux arclinux_nps arclinux_prof arcv2elf arcv2elfx" @@ -97,29 +117,45 @@ arc*-*-linux*) case "${with_cpu}" in esac targ_extra_emuls="${targ_extra_emuls} arclinux_prof arcelf arcelf_prof arcv2elf arcv2elfx" ;; -arm*-*-cegcc*) targ_emul=arm_wince_pe ; targ_extra_ofiles="deffilep.o pe-dll.o" - LIB_PATH='${tooldir}/lib/w32api' ;; +arm*-*-cegcc*) targ_emul=arm_wince_pe + targ_extra_ofiles="deffilep.o pe-dll.o" + LIB_PATH='${tooldir}/lib/w32api' + ;; arm-wince-pe | arm-*-wince | arm*-*-mingw32ce*) - targ_emul=arm_wince_pe ; targ_extra_ofiles="deffilep.o pe-dll.o" ;; -arm-*-pe) targ_emul=armpe ; targ_extra_ofiles="deffilep.o pe-dll.o" ;; + targ_emul=arm_wince_pe + targ_extra_ofiles="deffilep.o pe-dll.o" + ;; +arm-*-pe) targ_emul=armpe + targ_extra_ofiles="deffilep.o pe-dll.o" + ;; arm*b-*-freebsd*) targ_emul=armelfb_fbsd - targ_extra_emuls="armelf_fbsd armelf" ;; + targ_extra_emuls="armelf_fbsd armelf" + ;; arm*-*-freebsd* | arm-*-kfreebsd*-gnu) targ_emul=armelf_fbsd - targ_extra_emuls="armelfb_fbsd armelf" ;; + targ_extra_emuls="armelfb_fbsd armelf" + ;; armeb-*-netbsdelf*) targ_emul=armelfb_nbsd; - targ_extra_emuls="armelf_nbsd armelf" ;; + targ_extra_emuls="armelf_nbsd armelf" + ;; arm-*-netbsdelf*) targ_emul=armelf_nbsd; - targ_extra_emuls="armelfb_nbsd armelf" ;; -arm-*-nto*) targ_emul=armnto ;; -arm-*-phoenix*) targ_emul=armelf ;; + targ_extra_emuls="armelfb_nbsd armelf" + ;; +arm-*-nto*) targ_emul=armnto + ;; +arm-*-phoenix*) targ_emul=armelf + ;; armeb-*-elf | armeb-*-eabi*) - targ_emul=armelfb ;; + targ_emul=armelfb + ;; arm-*-elf | arm*-*-eabi* | arm-*-rtems*) - targ_emul=armelf ;; + targ_emul=armelf + ;; arm*-*-symbianelf*) targ_emul=armsymbian;; -arm-*-kaos*) targ_emul=armelf ;; -arm9e-*-elf) targ_emul=armelf ;; +arm-*-kaos*) targ_emul=armelf + ;; +arm9e-*-elf) targ_emul=armelf + ;; arm*b-*-linux-*eabi*) targ_emul=armelfb_linux_eabi targ_extra_emuls=armelf_linux_eabi targ_extra_libpath=$targ_extra_emuls @@ -161,8 +197,10 @@ arm*-*-uclinux*) targ_emul=armelf_linux targ_extra_emuls="armelf armelfb armelfb_linux" targ_extra_libpath="armelfb_linux" ;; -arm-*-vxworks) targ_emul=armelf_vxworks ;; -arm*-*-conix*) targ_emul=armelf ;; +arm-*-vxworks) targ_emul=armelf_vxworks + ;; +arm*-*-conix*) targ_emul=armelf + ;; arm*-*-fuchsia*) targ_emul=armelf_fuchsia targ_extra_emuls="armelfb_fuchsia armelf armelfb" ;; @@ -182,15 +220,19 @@ bfin-*-linux-uclibc*) targ_emul=elf32bfinfd; targ_extra_emuls="elf32bfin" targ_extra_libpath=$targ_extra_emuls ;; -bpf-*-*) targ_emul=elf64bpf ;; -cr16-*-elf*) targ_emul=elf32cr16 ;; +bpf-*-*) targ_emul=elf64bpf + ;; +cr16-*-elf*) targ_emul=elf32cr16 + ;; cr16c-*-elf*) targ_emul=elf32cr16c ;; cris-*-*aout*) targ_emul=crisaout targ_extra_emuls="criself crislinux" - targ_extra_libpath=$targ_extra_emuls ;; + targ_extra_libpath=$targ_extra_emuls + ;; cris-*-linux-* | crisv32-*-linux-*) - targ_emul=crislinux ;; + targ_emul=crislinux + ;; cris-*-* | crisv32-*-*) targ_emul=criself targ_extra_emuls="crisaout crislinux" targ_extra_libpath=$targ_extra_emuls @@ -198,75 +240,123 @@ cris-*-* | crisv32-*-*) targ_emul=criself crx-*-elf*) targ_emul=elf32crx ;; -csky-*-elf*) targ_emul=cskyelf ;; -csky-*-linux*) targ_emul=cskyelf_linux ;; +csky-*-elf*) targ_emul=cskyelf + ;; +csky-*-linux*) targ_emul=cskyelf_linux + ;; -d10v-*-*) targ_emul=d10velf ;; -d30v-*-*ext*) targ_emul=d30v_e; targ_extra_emuls="d30velf d30v_o" ;; -d30v-*-*onchip*) targ_emul=d30v_o; targ_extra_emuls="d30velf d30v_e" ;; -d30v-*-*) targ_emul=d30velf; targ_extra_emuls="d30v_e d30v_o" +d10v-*-*) targ_emul=d10velf + ;; +d30v-*-*ext*) targ_emul=d30v_e + targ_extra_emuls="d30velf d30v_o" + targ_extra_ofiles=ldelfgen.o + ;; +d30v-*-*onchip*) targ_emul=d30v_o + targ_extra_emuls="d30velf d30v_e" + targ_extra_ofiles=ldelfgen.o + ;; +d30v-*-*) targ_emul=d30velf + targ_extra_emuls="d30v_e d30v_o" + targ_extra_ofiles=ldelfgen.o ;; dlx-*-elf*) targ_emul=elf32_dlx + targ_extra_ofiles=ldelfgen.o ;; epiphany-*-*) targ_emul=elf32epiphany targ_extra_emuls="elf32epiphany_4x4" ;; -fido*-*-elf*) targ_emul=m68kelf ;; +fido*-*-elf*) targ_emul=m68kelf + ;; fr30-*-*) targ_emul=elf32fr30 + targ_extra_ofiles=ldelfgen.o + ;; +frv-*-*linux*) targ_emul=elf32frvfd ;; -frv-*-*linux*) targ_emul=elf32frvfd ;; -frv-*-*) targ_emul=elf32frv ; targ_extra_emuls="elf32frvfd" +frv-*-*) targ_emul=elf32frv + targ_extra_emuls="elf32frvfd" ;; moxie-*-moxiebox*) targ_emul=moxiebox + targ_extra_ofiles=ldelfgen.o ;; moxie-*-*) targ_emul=elf32moxie + targ_extra_ofiles=ldelfgen.o ;; h8300-*-elf* | h8300-*-rtems*) targ_emul=h8300elf; - targ_extra_emuls="h8300helf h8300self h8300hnelf h8300snelf h8300sxelf h8300sxnelf" ;; + targ_extra_emuls="h8300helf h8300self h8300hnelf h8300snelf h8300sxelf h8300sxnelf" + ;; h8300-*-linux*) targ_emul=h8300elf_linux; - targ_extra_emuls="h8300helf_linux h8300self_linux h8300sxelf_linux" ;; -hppa*64*-*-linux-*) targ_emul=hppa64linux ;; -hppa*64*-hpux*) targ_emul=elf64hppa ;; -hppa*-*-linux-*) targ_emul=hppalinux ;; -hppa*-*-*elf*) targ_emul=hppaelf ;; -hppa*-*-lites*) targ_emul=hppaelf ;; -hppa*-*-netbsd*) targ_emul=hppanbsd ;; + targ_extra_emuls="h8300helf_linux h8300self_linux h8300sxelf_linux" + ;; +hppa*64*-*-linux-*) targ_emul=hppa64linux + ;; +hppa*64*-hpux*) targ_emul=elf64hppa + ;; +hppa*-*-linux-*) targ_emul=hppalinux + ;; +hppa*-*-*elf*) targ_emul=hppaelf + ;; +hppa*-*-lites*) targ_emul=hppaelf + ;; +hppa*-*-netbsd*) targ_emul=hppanbsd + ;; hppa*-*-openbsd*) targ_emul=hppaobsd ;; -i[3-7]86-*-nto-qnx*) targ_emul=i386nto ;; -i[3-7]86-*-go32) targ_emul=i386go32 ;; -i[3-7]86-*-msdosdjgpp*) targ_emul=i386go32 ;; -i[3-7]86-*-lynxos*) targ_emul=i386lynx ;; +i[3-7]86-*-nto-qnx*) targ_emul=i386nto + ;; +i[3-7]86-*-go32) targ_emul=i386go32 + targ_extra_ofiles= + ;; +i[3-7]86-*-msdosdjgpp*) targ_emul=i386go32 + targ_extra_ofiles= + ;; +i[3-7]86-*-lynxos*) targ_emul=i386lynx + ;; i[3-7]86-*-aros*) targ_emul=elf_i386 - targ_extra_emuls=elf_iamcu ;; + targ_extra_emuls=elf_iamcu + ;; i[3-7]86-*-rdos*) targ_emul=elf_i386 - targ_extra_emuls=elf_iamcu ;; -x86_64-*-rdos*) targ_emul=elf64rdos ;; -x86_64-*-cloudabi*) targ_emul=elf_x86_64_cloudabi ;; -i[3-7]86-*-bsd) targ_emul=i386bsd ;; -i[3-7]86-*-bsd386) targ_emul=i386bsd ;; -i[3-7]86-*-bsdi*) targ_emul=i386bsd ;; + targ_extra_emuls=elf_iamcu + ;; +x86_64-*-rdos*) targ_emul=elf64rdos + ;; +x86_64-*-cloudabi*) targ_emul=elf_x86_64_cloudabi + ;; +i[3-7]86-*-bsd) targ_emul=i386bsd + targ_extra_ofiles= + ;; +i[3-7]86-*-bsd386) targ_emul=i386bsd + targ_extra_ofiles= + ;; +i[3-7]86-*-bsdi*) targ_emul=i386bsd + targ_extra_ofiles= + ;; i[3-7]86-*-linux-*) targ_emul=elf_i386 targ_extra_emuls="elf_iamcu" targ64_extra_emuls="elf_x86_64 elf32_x86_64 elf_l1om elf_k1om" - targ64_extra_libpath="elf_x86_64 elf32_x86_64" ;; + targ64_extra_libpath="elf_x86_64 elf32_x86_64" + ;; x86_64-*-linux-gnux32) targ_emul=elf32_x86_64 targ_extra_emuls="elf_x86_64 elf_i386 elf_iamcu elf_l1om elf_k1om" targ_extra_libpath="elf_i386 elf_iamcu elf_x86_64 elf_l1om elf_k1om" tdir_elf_iamcu=`echo ${targ_alias} | sed -e 's/x86_64/i386/' -e 's/-linux-gnux32/-linux-gnu/'` - tdir_elf_i386=`echo ${targ_alias} | sed -e 's/x86_64/i386/' -e 's/-linux-gnux32/-linux-gnu/'` ;; + tdir_elf_i386=`echo ${targ_alias} | sed -e 's/x86_64/i386/' -e 's/-linux-gnux32/-linux-gnu/'` + ;; x86_64-*-linux-*) targ_emul=elf_x86_64 targ_extra_emuls="elf32_x86_64 elf_i386 elf_iamcu elf_l1om elf_k1om" targ_extra_libpath="elf_i386 elf32_x86_64 elf_l1om elf_k1om" - tdir_elf_i386=`echo ${targ_alias} | sed -e 's/x86_64/i386/'` ;; + tdir_elf_i386=`echo ${targ_alias} | sed -e 's/x86_64/i386/'` + ;; i[3-7]86-*-redox*) targ_emul=elf_i386 - targ_extra_emuls=elf_x86_64 ;; + targ_extra_emuls=elf_x86_64 + ;; x86_64-*-redox*) targ_emul=elf_x86_64 - targ_extra_emuls=elf_i386 ;; + targ_extra_emuls=elf_i386 + ;; i[3-7]86-*-sysv[45]*) targ_emul=elf_i386 - targ_extra_emuls=elf_iamcu ;; + targ_extra_emuls=elf_iamcu + ;; i[3-7]86-*-solaris2*) targ_emul=elf_i386_sol2 targ_extra_emuls="elf_i386_ldso elf_i386 elf_iamcu elf_x86_64_sol2 elf_x86_64 elf_l1om elf_k1om" targ_extra_libpath=$targ_extra_emuls @@ -275,9 +365,11 @@ x86_64-*-solaris2*) targ_emul=elf_x86_64_sol2 targ_extra_emuls="elf_x86_64 elf_i386_sol2 elf_i386_ldso elf_i386 elf_iamcu elf_l1om elf_k1om" targ_extra_libpath=$targ_extra_emuls - tdir_elf_i386=`echo ${targ_alias} | sed -e 's/x86_64/i386/'` ;; + tdir_elf_i386=`echo ${targ_alias} | sed -e 's/x86_64/i386/'` + ;; i[3-7]86-*-unixware) targ_emul=elf_i386 - targ_extra_emuls=elf_iamcu ;; + targ_extra_emuls=elf_iamcu + ;; i[3-7]86-*-solaris*) targ_emul=elf_i386_ldso targ_extra_emuls="elf_i386" targ_extra_libpath=$targ_extra_emuls @@ -286,9 +378,11 @@ i[3-7]86-*-netbsdelf* | \ i[3-7]86-*-netbsd*-gnu* | \ i[3-7]86-*-knetbsd*-gnu) targ_emul=elf_i386 - targ_extra_emuls="elf_iamcu" ;; + targ_extra_emuls="elf_iamcu" + ;; i[3-7]86-*-netbsdpe*) targ_emul=i386pe - targ_extra_ofiles="deffilep.o pe-dll.o" ;; + targ_extra_ofiles="deffilep.o pe-dll.o" + ;; x86_64-*-netbsd*) targ_emul=elf_x86_64 targ_extra_emuls="elf_i386 elf_iamcu elf_l1om elf_k1om" tdir_elf_iamcu=`echo ${targ_alias} | \ @@ -304,12 +398,15 @@ x86_64-*-netbsd*) targ_emul=elf_x86_64 *-netbsdelf*) ;; *) tdir_elf_i386=`echo ${tdir_elf_i386} | \ sed -e 's/netbsd/netbsdelf/'`;; - esac ;; + esac + ;; i[3-7]86-*-elfiamcu) targ_emul=elf_iamcu - targ_extra_emuls=elf_i386 ;; + targ_extra_emuls=elf_i386 + ;; i[3-7]86-*-elf* | i[3-7]86-*-rtems*) targ_emul=elf_i386 - targ_extra_emuls=elf_iamcu ;; + targ_extra_emuls=elf_iamcu + ;; x86_64-*-elf* | x86_64-*-rtems* | x86_64-*-fuchsia*) targ_emul=elf_x86_64 targ_extra_emuls="elf_i386 elf_iamcu elf32_x86_64 elf_l1om elf_k1om" @@ -317,12 +414,15 @@ x86_64-*-elf* | x86_64-*-rtems* | x86_64-*-fuchsia*) tdir_elf_i386=`echo ${targ_alias} | sed -e 's/x86_64/i386/'` ;; i[3-7]86-*-dragonfly*) targ_emul=elf_i386 - targ_extra_emuls="elf_iamcu i386bsd" ;; + targ_extra_emuls="elf_iamcu i386bsd" + ;; x86_64-*-dragonfly*) targ_emul=elf_x86_64 - targ_extra_emuls="elf_i386 elf_iamcu elf_l1om elf_k1om" ;; + targ_extra_emuls="elf_i386 elf_iamcu elf_l1om elf_k1om" + ;; i[3-7]86-*-freebsd* | i[3-7]86-*-kfreebsd*-gnu) targ_emul=elf_i386_fbsd - targ_extra_emuls="elf_i386 elf_iamcu i386bsd" ;; + targ_extra_emuls="elf_i386 elf_iamcu i386bsd" + ;; x86_64-*-freebsd* | x86_64-*-kfreebsd*-gnu) targ_emul=elf_x86_64_fbsd targ_extra_emuls="elf_i386_fbsd elf_x86_64 elf_i386 elf_iamcu elf_l1om elf_l1om_fbsd elf_k1om elf_k1om_fbsd" @@ -332,35 +432,55 @@ x86_64-*-freebsd* | x86_64-*-kfreebsd*-gnu) tdir_elf_iamcu=`echo ${targ_alias} \ | sed -e 's/x86_64/i386/'` tdir_elf_i386=`echo ${targ_alias} \ - | sed -e 's/x86_64/i386/'` ;; + | sed -e 's/x86_64/i386/'` + ;; i[3-7]86-*-gnu*) targ_emul=elf_i386 - targ_extra_emuls=elf_iamcu ;; -i[3-7]86-*-msdos*) targ_emul=i386msdos; targ_extra_emuls=i386aout ;; -i[3-7]86-*-moss*) targ_emul=i386moss; targ_extra_emuls=i386msdos ;; + targ_extra_emuls=elf_iamcu + ;; +i[3-7]86-*-msdos*) targ_emul=i386msdos + targ_extra_emuls=i386aout + targ_extra_ofiles= + ;; +i[3-7]86-*-moss*) targ_emul=i386moss + targ_extra_emuls=i386msdos + targ_extra_ofiles= + ;; i[3-7]86-*-winnt*) targ_emul=i386pe ; - targ_extra_ofiles="deffilep.o pe-dll.o" ;; + targ_extra_ofiles="deffilep.o pe-dll.o" + ;; i[3-7]86-*-pe) targ_emul=i386pe ; - targ_extra_ofiles="deffilep.o pe-dll.o" ;; + targ_extra_ofiles="deffilep.o pe-dll.o" + ;; i[3-7]86-*-cygwin*) targ_emul=i386pe ; targ_extra_ofiles="deffilep.o pe-dll.o" ; - test "$targ" != "$host" && LIB_PATH='${tooldir}/lib/w32api' ;; + test "$targ" != "$host" && LIB_PATH='${tooldir}/lib/w32api' + ;; i[3-7]86-*-mingw32*) targ_emul=i386pe ; - targ_extra_ofiles="deffilep.o pe-dll.o" ;; + targ_extra_ofiles="deffilep.o pe-dll.o" + ;; x86_64-*-pe | x86_64-*-pep) targ_emul=i386pep ; targ_extra_emuls=i386pe ; - targ_extra_ofiles="deffilep.o pep-dll.o pe-dll.o" ;; + targ_extra_ofiles="deffilep.o pep-dll.o pe-dll.o" + ;; x86_64-*-cygwin) targ_emul=i386pep ; targ_extra_emuls=i386pe targ_extra_ofiles="deffilep.o pep-dll.o pe-dll.o" - test "$targ" != "$host" && LIB_PATH='${tooldir}/lib/w32api' ;; + test "$targ" != "$host" && LIB_PATH='${tooldir}/lib/w32api' + ;; x86_64-*-mingw*) targ_emul=i386pep ; targ_extra_emuls=i386pe - targ_extra_ofiles="deffilep.o pep-dll.o pe-dll.o" ;; + targ_extra_ofiles="deffilep.o pep-dll.o pe-dll.o" + ;; i[3-7]86-*-interix*) targ_emul=i386pe_posix; - targ_extra_ofiles="deffilep.o pe-dll.o" ;; -i[3-7]86-*-beospe*) targ_emul=i386beos ;; -i[3-7]86-*-beos*) targ_emul=elf_i386_be ;; -i[3-7]86-*-vxworks*) targ_emul=elf_i386_vxworks ;; + targ_extra_ofiles="deffilep.o pe-dll.o" + ;; +i[3-7]86-*-beospe*) targ_emul=i386beos + targ_extra_ofiles= + ;; +i[3-7]86-*-beos*) targ_emul=elf_i386_be + ;; +i[3-7]86-*-vxworks*) targ_emul=elf_i386_vxworks + ;; i[3-7]86-*-chaos) targ_emul=elf_i386_chaos ;; i[3-7]86-*-nacl*) targ_emul=elf_i386_nacl @@ -374,46 +494,69 @@ x86_64-*-nacl*) targ_emul=elf32_x86_64_nacl targ_extra_libpath=$targ_extra_emuls tdir_elf_i386_nacl=`echo ${targ_alias} | sed -e 's/x86_64/i386/'` ;; -ia16-*-elf*) targ_emul=elf_i386 targ_extra_emuls=i386msdos ;; -ia64-*-elf*) targ_emul=elf64_ia64 ;; +ia16-*-elf*) targ_emul=elf_i386 + targ_extra_emuls=i386msdos + ;; +ia64-*-elf*) targ_emul=elf64_ia64 + ;; ia64-*-freebsd* | ia64-*-kfreebsd*-gnu) targ_emul=elf64_ia64_fbsd - targ_extra_emuls="elf64_ia64" ;; -ia64-*-netbsd*) targ_emul=elf64_ia64 ;; -ia64-*-linux*) targ_emul=elf64_ia64 ;; -ia64-*-*vms*) targ_emul=elf64_ia64_vms ;; + targ_extra_emuls="elf64_ia64" + ;; +ia64-*-netbsd*) targ_emul=elf64_ia64 + ;; +ia64-*-linux*) targ_emul=elf64_ia64 + ;; +ia64-*-*vms*) targ_emul=elf64_ia64_vms + targ_extra_ofiles=ldelfgen.o + ;; ia64-*-aix*) targ_emul=elf64_aix ;; ip2k-*-elf) targ_emul=elf32ip2k ;; -iq2000-*-elf) targ_emul=elf32iq2000 ; targ_extra_emuls="elf32iq10" +iq2000-*-elf) targ_emul=elf32iq2000 + targ_extra_emuls="elf32iq10" + targ_extra_ofiles=ldelfgen.o ;; -lm32-*-*linux*) targ_emul=elf32lm32fd ;; -lm32-*-*) targ_emul=elf32lm32 ; targ_extra_emuls="elf32lm32fd" +lm32-*-*linux*) targ_emul=elf32lm32fd + ;; +lm32-*-*) targ_emul=elf32lm32 + targ_extra_emuls="elf32lm32fd" ;; m32c-*-elf | m32c-*-rtems*) targ_emul=elf32m32c ;; -m32r*le-*-elf*) targ_emul=m32rlelf ;; +m32r*le-*-elf*) targ_emul=m32rlelf + ;; m32r*-*-elf* | m32r*-*-rtems*) - targ_emul=m32relf ;; -m32r*le-*-linux-*) targ_emul=m32rlelf_linux ;; + targ_emul=m32relf + ;; +m32r*le-*-linux-*) targ_emul=m32rlelf_linux + ;; m32r*-*-linux-*) targ_emul=m32relf_linux ;; m68hc11-*-*|m6811-*-*) targ_emul=m68hc11elf - targ_extra_emuls="m68hc11elfb m68hc12elf m68hc12elfb" ;; + targ_extra_emuls="m68hc11elfb m68hc12elf m68hc12elfb" + ;; m68hc12-*-*|m6812-*-*) targ_emul=m68hc12elf - targ_extra_emuls="m68hc12elfb m68hc11elf m68hc11elfb" ;; -m68*-*-netbsdelf*) targ_emul=m68kelfnbsd ;; -m68*-*-*) targ_emul=m68kelf ;; + targ_extra_emuls="m68hc12elfb m68hc11elf m68hc11elfb" + ;; +m68*-*-netbsdelf*) targ_emul=m68kelfnbsd + ;; +m68*-*-*) targ_emul=m68kelf + ;; s12z-*-*) targ_emul=m9s12zelf + targ_extra_ofiles=ldelfgen.o ;; mcore-*-pe) targ_emul=mcorepe ; - targ_extra_ofiles="deffilep.o pe-dll.o" ;; + targ_extra_ofiles="deffilep.o pe-dll.o" + ;; mcore-*-elf) targ_emul=elf32mcore ;; -mep-*-elf) targ_emul=elf32mep ;; -metag-*-*) targ_emul=elf32metag ;; +mep-*-elf) targ_emul=elf32mep + ;; +metag-*-*) targ_emul=elf32metag + ;; microblazeel*-linux*) targ_emul="elf32mbel_linux" targ_extra_emuls="elf32mb_linux" ;; @@ -426,10 +569,12 @@ microblazeel*) targ_emul=elf32microblazeel microblaze*) targ_emul=elf32microblaze targ_extra_emuls=elf32microblazeel ;; -mips*-sgi-irix5*) targ_emul=elf32bsmip ;; +mips*-sgi-irix5*) targ_emul=elf32bsmip + ;; mips*-sgi-irix6*) targ_emul=elf32bmipn32 targ_extra_emuls="elf32bsmip elf64bmip" - targ_extra_libpath=$targ_extra_emuls ;; + targ_extra_libpath=$targ_extra_emuls + ;; mips*el-*-netbsd*) targ_emul=elf32ltsmip targ_extra_emuls="elf32btsmip elf64ltsmip elf64btsmip" ;; @@ -442,73 +587,101 @@ mips64el-*-openbsd*) targ_emul=elf64ltsmip mips64-*-openbsd*) targ_emul=elf64btsmip targ_extra_emuls=elf64ltsmip ;; -mips*vr4300el-*-elf*) targ_emul=elf32l4300 ;; -mips*vr4300-*-elf*) targ_emul=elf32b4300 ;; -mips*vr4100el-*-elf*) targ_emul=elf32l4300 ;; -mips*vr4100-*-elf*) targ_emul=elf32b4300 ;; -mips*vr5000el-*-elf*) targ_emul=elf32l4300 ;; -mips*vr5000-*-elf*) targ_emul=elf32b4300 ;; +mips*vr4300el-*-elf*) targ_emul=elf32l4300 + ;; +mips*vr4300-*-elf*) targ_emul=elf32b4300 + ;; +mips*vr4100el-*-elf*) targ_emul=elf32l4300 + ;; +mips*vr4100-*-elf*) targ_emul=elf32b4300 + ;; +mips*vr5000el-*-elf*) targ_emul=elf32l4300 + ;; +mips*vr5000-*-elf*) targ_emul=elf32b4300 + ;; mips*el-sde-elf* | mips*el-mti-elf* | mips*el-img-elf*) targ_emul=elf32ltsmip - targ_extra_emuls="elf32btsmip elf32ltsmipn32 elf64ltsmip elf32btsmipn32 elf64btsmip" ;; + targ_extra_emuls="elf32btsmip elf32ltsmipn32 elf64ltsmip elf32btsmipn32 elf64btsmip" + ;; mips*-sde-elf* | mips*-mti-elf* | mips*-img-elf*) targ_emul=elf32btsmip - targ_extra_emuls="elf32ltsmip elf32btsmipn32 elf64btsmip elf32ltsmipn32 elf64ltsmip" ;; + targ_extra_emuls="elf32ltsmip elf32btsmipn32 elf64btsmip elf32ltsmipn32 elf64ltsmip" + ;; mips64*el-ps2-elf*) targ_emul=elf32lr5900n32 targ_extra_emuls="elf32lr5900" - targ_extra_libpath=$targ_extra_emuls ;; + targ_extra_libpath=$targ_extra_emuls + ;; mips*el-ps2-elf*) targ_emul=elf32lr5900 targ_extra_emuls="elf32lr5900n32" - targ_extra_libpath=$targ_extra_emuls ;; -mips*el-*-elf*) targ_emul=elf32elmip ;; + targ_extra_libpath=$targ_extra_emuls + ;; +mips*el-*-elf*) targ_emul=elf32elmip + ;; mips*-*-elf* | mips*-*-rtems*) - targ_emul=elf32ebmip ;; + targ_emul=elf32ebmip + ;; mips*el-*-vxworks*) targ_emul=elf32elmipvxworks - targ_extra_emuls="elf32ebmipvxworks" ;; + targ_extra_emuls="elf32ebmipvxworks" + ;; mips*-*-vxworks*) targ_emul=elf32ebmipvxworks - targ_extra_emuls="elf32elmipvxworks" ;; -mips*-*-windiss) targ_emul=elf32mipswindiss ;; + targ_extra_emuls="elf32elmipvxworks" + ;; +mips*-*-windiss) targ_emul=elf32mipswindiss + ;; mips64*el-*-linux-*) targ_emul=elf32ltsmipn32 targ_extra_emuls="elf32btsmipn32 elf32ltsmip elf32btsmip elf64ltsmip elf64btsmip" - targ_extra_libpath=$targ_extra_emuls ;; + targ_extra_libpath=$targ_extra_emuls + ;; mips64*-*-linux-*) targ_emul=elf32btsmipn32 targ_extra_emuls="elf32ltsmipn32 elf32btsmip elf32ltsmip elf64btsmip elf64ltsmip" - targ_extra_libpath=$targ_extra_emuls ;; + targ_extra_libpath=$targ_extra_emuls + ;; mips*el-*-linux-*) targ_emul=elf32ltsmip targ_extra_emuls="elf32btsmip elf32ltsmipn32 elf64ltsmip elf32btsmipn32 elf64btsmip" - targ_extra_libpath=$targ_extra_emuls ;; + targ_extra_libpath=$targ_extra_emuls + ;; mips*-*-linux-*) targ_emul=elf32btsmip targ_extra_emuls="elf32ltsmip elf32btsmipn32 elf64btsmip elf32ltsmipn32 elf64ltsmip" - targ_extra_libpath=$targ_extra_emuls ;; + targ_extra_libpath=$targ_extra_emuls + ;; mips64*el-*-freebsd* | mips64*el-*-kfreebsd*-gnu) targ_emul=elf32ltsmipn32_fbsd targ_extra_emuls="elf32ltsmip elf32btsmip elf32ltsmipn32 elf32btsmipn32 elf64ltsmip elf64btsmip elf32ltsmip_fbsd elf32btsmip_fbsd elf32btsmipn32_fbsd elf64ltsmip_fbsd elf64btsmip_fbsd" - targ_extra_libpath=$targ_extra_emuls ;; + targ_extra_libpath=$targ_extra_emuls + ;; mips64*-*-freebsd* | mips64*-*-kfreebsd*-gnu) targ_emul=elf32btsmipn32_fbsd targ_extra_emuls="elf32ltsmip elf32btsmip elf32ltsmipn32 elf32btsmipn32 elf64ltsmip elf64btsmip elf32ltsmip_fbsd elf32btsmip_fbsd elf32ltsmipn32_fbsd elf64ltsmip_fbsd elf64btsmip_fbsd" - targ_extra_libpath=$targ_extra_emuls ;; + targ_extra_libpath=$targ_extra_emuls + ;; mips*el-*-freebsd* | mips*el-*-kfreebsd*-gnu) targ_emul=elf32ltsmip_fbsd targ_extra_emuls="elf32ltsmip elf32btsmip elf32ltsmipn32 elf32btsmipn32 elf64ltsmip elf64btsmip elf32ltsmipn32_fbsd elf32btsmip_fbsd elf32btsmipn32_fbsd elf64ltsmip_fbsd elf64btsmip_fbsd" - targ_extra_libpath=$targ_extra_emuls ;; + targ_extra_libpath=$targ_extra_emuls + ;; mips*-*-freebsd* | mips*-*-kfreebsd*-gnu) targ_emul=elf32btsmip_fbsd targ_extra_emuls="elf32ltsmip elf32btsmip elf32ltsmipn32 elf32btsmipn32 elf64ltsmip elf64btsmip elf32ltsmip_fbsd elf32btsmipn32_fbsd elf32ltsmipn32_fbsd elf64ltsmip_fbsd elf64btsmip_fbsd" - targ_extra_libpath=$targ_extra_emuls ;; + targ_extra_libpath=$targ_extra_emuls + ;; mips*-*-sysv4*) targ_emul=elf32btsmip ;; mmix-*-*) targ_emul=mmo targ_extra_emuls=elf64mmix ;; -am33_2.0-*-linux*) targ_emul=elf32am33lin ;; -mn10200-*-*) targ_emul=mn10200 ;; +am33_2.0-*-linux*) targ_emul=elf32am33lin + ;; +mn10200-*-*) targ_emul=mn10200 + targ_extra_ofiles=ldelfgen.o + ;; mn10300-*-*) targ_emul=mn10300 ;; mt-*elf) targ_emul=elf32mt + targ_extra_ofiles=ldelfgen.o ;; msp430-*-*) targ_emul=msp430elf targ_extra_emuls="msp430X" + targ_extra_ofiles=ldelfgen.o ;; nds32*le-*-elf*) targ_emul=nds32elf targ_extra_emuls="nds32elf16m nds32belf nds32belf16m" @@ -516,27 +689,40 @@ nds32*le-*-elf*) targ_emul=nds32elf nds32*be-*-elf*) targ_emul=nds32belf targ_extra_emuls="nds32elf nds32elf16m nds32belf16m" ;; -nds32*le-*-linux-gnu*) targ_emul=nds32elf_linux ;; -nds32*be-*-linux-gnu*) targ_emul=nds32belf_linux ;; -nios2*-*-linux*) targ_emul=nios2linux ;; -nios2*-*-*) targ_emul=nios2elf ;; -ns32k-pc532-mach* | ns32k-pc532-ux*) targ_emul=pc532macha ;; +nds32*le-*-linux-gnu*) targ_emul=nds32elf_linux + ;; +nds32*be-*-linux-gnu*) targ_emul=nds32belf_linux + ;; +nios2*-*-linux*) targ_emul=nios2linux + ;; +nios2*-*-*) targ_emul=nios2elf + ;; +ns32k-pc532-mach* | ns32k-pc532-ux*) targ_emul=pc532macha + targ_extra_ofiles= + ;; ns32k-*-netbsd* | ns32k-pc532-lites*) targ_emul=ns32knbsd + targ_extra_ofiles= ;; or1k-*-elf | or1knd-*-elf | or1k-*-rtems* | or1knd-*-rtems*) - targ_emul=elf32or1k ;; -or1k-*-linux* | or1knd-*-linux*) targ_emul=elf32or1k_linux ;; + targ_emul=elf32or1k + ;; +or1k-*-linux* | or1knd-*-linux*) targ_emul=elf32or1k_linux + ;; pdp11-*-*) targ_emul=pdp11 + targ_extra_ofiles= ;; pjl*-*-*) targ_emul=pjlelf - targ_extra_emuls="elf_i386 elf_iamcu" ;; + targ_extra_emuls="elf_i386 elf_iamcu" + ;; pj*-*-*) targ_emul=pjelf + targ_extra_ofiles=ldelfgen.o ;; powerpc-*-freebsd* | powerpc-*-kfreebsd*-gnu) targ_emul=elf32ppc_fbsd targ_extra_emuls="elf32ppc elf32ppcsim" targ_extra_libpath=elf32ppc; - tdir_elf32ppcsim=`echo ${targ_alias} | sed -e 's/ppc/ppcsim/'` ;; + tdir_elf32ppcsim=`echo ${targ_alias} | sed -e 's/ppc/ppcsim/'` + ;; powerpc64-*-freebsd*) targ_emul=elf64ppc_fbsd targ_extra_emuls="elf64ppc elf32ppc_fbsd elf32ppc" @@ -546,7 +732,8 @@ powerpc64-*-freebsd*) ;; powerpc-*-vxworks*) targ_emul=elf32ppcvxworks - targ_extra_emuls="elf32ppc elf32ppclinux elf32ppcsim" ;; + targ_extra_emuls="elf32ppc elf32ppclinux elf32ppcsim" + ;; powerpc*-*-elf* | powerpc*-*-eabi* | powerpc*-*-sysv* \ | powerpc*-*-linux* | powerpc*-*-netbsd* | powerpc*-*-openbsd* \ | powerpc*-*-rtems* \ @@ -621,111 +808,171 @@ powerpc*-*-elf* | powerpc*-*-eabi* | powerpc*-*-sysv* \ eval test -n \"\$${td}sim\" || eval ${td}sim="${ta32}" eval test -n \"\$${td64}\" || eval ${td64}="${ta64}" ;; -powerpc-*-nto*) targ_emul=elf32ppcnto ;; -powerpcle-*-nto*) targ_emul=elf32lppcnto ;; -powerpc-*-macos*) targ_emul=ppcmacos ;; +powerpc-*-nto*) targ_emul=elf32ppcnto + ;; +powerpcle-*-nto*) targ_emul=elf32lppcnto + ;; +powerpc-*-macos*) targ_emul=ppcmacos + targ_extra_ofiles= + ;; powerpcle-*-pe | powerpcle-*-winnt* | powerpcle-*-cygwin*) targ_emul=ppcpe - targ_extra_ofiles="deffilep.o pe-dll.o" ;; -powerpc-*-aix[5-9]*) targ_emul=aix5ppc ;; -powerpc-*-aix*) targ_emul=aixppc ;; -powerpc-*-beos*) targ_emul=aixppc ;; -powerpc-*-windiss*) targ_emul=elf32ppcwindiss ;; -powerpc-*-lynxos*) targ_emul=ppclynx ;; -pru*-*-*) targ_emul=pruelf ;; + targ_extra_ofiles="deffilep.o pe-dll.o" + ;; +powerpc-*-aix[5-9]*) targ_emul=aix5ppc + targ_extra_ofiles= + ;; +powerpc-*-aix*) targ_emul=aixppc + targ_extra_ofiles= + ;; +powerpc-*-beos*) targ_emul=aixppc + targ_extra_ofiles= + ;; +powerpc-*-windiss*) targ_emul=elf32ppcwindiss + ;; +powerpc-*-lynxos*) targ_emul=ppclynx + ;; +pru*-*-*) targ_emul=pruelf + ;; riscv32*-*-linux*) targ_emul=elf32lriscv targ_extra_emuls="elf32lriscv_ilp32f elf32lriscv_ilp32 elf64lriscv elf64lriscv_lp64f elf64lriscv_lp64" - targ_extra_libpath=$targ_extra_emuls ;; + targ_extra_libpath=$targ_extra_emuls + ;; riscv-*-* | riscv32*-*-*) targ_emul=elf32lriscv targ_extra_emuls="elf64lriscv" - targ_extra_libpath=$targ_extra_emuls ;; + targ_extra_libpath=$targ_extra_emuls + ;; riscv64*-*-linux*) targ_emul=elf64lriscv targ_extra_emuls="elf64lriscv_lp64f elf64lriscv_lp64 elf32lriscv elf32lriscv_ilp32f elf32lriscv_ilp32" - targ_extra_libpath=$targ_extra_emuls ;; + targ_extra_libpath=$targ_extra_emuls + ;; riscv64*-*-*) targ_emul=elf64lriscv targ_extra_emuls="elf32lriscv" - targ_extra_libpath=$targ_extra_emuls ;; -rs6000-*-aix[5-9]*) targ_emul=aix5rs6 ;; + targ_extra_libpath=$targ_extra_emuls + ;; +rs6000-*-aix[5-9]*) targ_emul=aix5rs6 + targ_extra_ofiles= + ;; rs6000-*-aix*) targ_emul=aixrs6 + targ_extra_ofiles= + ;; +rl78-*-*) targ_emul=elf32rl78 + ;; +rx-*-*) targ_emul=elf32rx ;; -rl78-*-*) targ_emul=elf32rl78 ;; -rx-*-*) targ_emul=elf32rx ;; s390x-*-linux*) targ_emul=elf64_s390 targ_extra_emuls=elf_s390 targ_extra_libpath=$targ_extra_emuls - tdir_elf_s390=`echo ${targ_alias} | sed -e 's/s390x/s390/'` ;; + tdir_elf_s390=`echo ${targ_alias} | sed -e 's/s390x/s390/'` + ;; s390x-*-tpf*) targ_emul=elf64_s390 - tdir_elf_s390=`echo ${targ_alias} | sed -e 's/s390x/s390/'` ;; + tdir_elf_s390=`echo ${targ_alias} | sed -e 's/s390x/s390/'` + ;; s390-*-linux*) targ_emul=elf_s390 targ64_extra_emuls=elf64_s390 targ64_extra_libpath=elf64_s390 tdir_elf64_s390=`echo ${targ_alias} | sed -e 's/s390/s390x/'` ;; score-*-elf) targ_emul=score7_elf - targ_extra_emuls=score3_elf ;; + targ_extra_emuls=score3_elf + ;; sh-*-linux*) targ_emul=shlelf_linux targ_extra_emuls="shelf_linux shlelf_fd shelf_fd" - targ_extra_libpath=shelf_linux ;; + targ_extra_libpath=shelf_linux + ;; sh*eb-*-linux*) targ_emul=shelf_linux - targ_extra_emuls="shelf_fd" ;; + targ_extra_emuls="shelf_fd" + ;; sh*-*-linux*) targ_emul=shlelf_linux - targ_extra_emuls="shlelf_fd" ;; + targ_extra_emuls="shlelf_fd" + ;; sh*l*-*-netbsdelf*) targ_emul=shlelf_nbsd - targ_extra_emuls=shelf_nbsd ;; + targ_extra_emuls=shelf_nbsd + ;; sh*-*-netbsdelf*) targ_emul=shelf_nbsd - targ_extra_emuls=shlelf_nbsd ;; + targ_extra_emuls=shlelf_nbsd + ;; shle*-*-elf* | sh[1234]*le*-*-elf | shle*-*-kaos*) targ_emul=shlelf - targ_extra_emuls="shelf shl sh" ;; + targ_extra_emuls="shelf shl sh" + ;; sh-*-elf* | sh[1234]*-*-elf | sh-*-rtems* | sh-*-kaos*) targ_emul=shelf - targ_extra_emuls="shlelf sh shl" ;; + targ_extra_emuls="shlelf sh shl" + ;; sh-*-uclinux* | sh[12]-*-uclinux*) targ_emul=shelf_uclinux - targ_extra_emuls="shelf shlelf sh shl shelf_fd shlelf_fd" ;; + targ_extra_emuls="shelf shlelf sh shl shelf_fd shlelf_fd" + ;; sh-*-vxworks) targ_emul=shelf_vxworks - targ_extra_emuls=shlelf_vxworks ;; + targ_extra_emuls=shlelf_vxworks + ;; sh-*-nto*) targ_emul=shelf_nto - targ_extra_emuls=shlelf_nto ;; + targ_extra_emuls=shlelf_nto + ;; sh-*-pe) targ_emul=shpe ; - targ_extra_ofiles="deffilep.o pe-dll.o" ;; -sh-*-*) targ_emul=sh; targ_extra_emuls=shl ;; + targ_extra_ofiles="deffilep.o pe-dll.o" + ;; +sh-*-*) targ_emul=sh; + targ_extra_emuls=shl + targ_extra_ofiles= + ;; sparc64-*-freebsd* | sparcv9-*-freebsd* | sparc64-*-kfreebsd*-gnu | sparcv9-*-kfreebsd*-gnu) targ_emul=elf64_sparc_fbsd targ_extra_emuls="elf64_sparc elf32_sparc" targ_extra_libpath=$targ_extra_emuls - tdir_elf32_sparc=`echo ${targ_alias} | sed -e 's/64//'` ;; + tdir_elf32_sparc=`echo ${targ_alias} | sed -e 's/64//'` + ;; sparc64-*-linux-*) targ_emul=elf64_sparc targ_extra_emuls="elf32_sparc" targ_extra_libpath=elf32_sparc - tdir_elf32_sparc=`echo ${targ_alias} | sed -e 's/64//'` ;; + tdir_elf32_sparc=`echo ${targ_alias} | sed -e 's/64//'` + ;; sparc64-*-*bsd*) targ_emul=elf64_sparc - targ_extra_emuls="elf32_sparc" ;; + targ_extra_emuls="elf32_sparc" + ;; sparc64-*-solaris2* | sparcv9-*-solaris2*) targ_emul=elf64_sparc_sol2 targ_extra_emuls="elf64_sparc elf32_sparc_sol2 elf32_sparc" targ_extra_libpath=$targ_extra_emuls - tdir_elf32_sparc=`echo ${targ_alias} | sed -e 's/64//'` ;; -sparc64-*-*) targ_emul=elf64_sparc ;; + tdir_elf32_sparc=`echo ${targ_alias} | sed -e 's/64//'` + ;; +sparc64-*-*) targ_emul=elf64_sparc + ;; sparc*-*-linux-*) targ_emul=elf32_sparc targ_extra_emuls="elf64_sparc" targ_extra_libpath=elf64_sparc - tdir_elf64_sparc=`echo ${targ_alias} | sed -e 's/32//'` ;; + tdir_elf64_sparc=`echo ${targ_alias} | sed -e 's/32//'` + ;; sparc-*-solaris2.[0-6] | sparc-*-solaris2.[0-6].*) targ_emul=elf32_sparc_sol2 - targ_extra_emuls=elf32_sparc ;; + targ_extra_emuls=elf32_sparc + ;; sparc-*-solaris2*) targ_emul=elf32_sparc_sol2 targ_extra_emuls="elf32_sparc elf64_sparc_sol2 elf64_sparc" targ_extra_libpath=$targ_extra_emuls - tdir_elf64_sparc=`echo ${targ_alias} | sed -e 's/32//'` ;; -sparc*-*-vxworks*) targ_emul=elf32_sparc_vxworks ;; -sparc*-*-*) targ_emul=elf32_sparc ;; -spu-*-elf*) targ_emul=elf32_spu ;; -tic30-*-*aout*) targ_emul=tic30aout ;; -tic30-*-*coff*) targ_emul=tic30coff ;; -tic4x-*-* | c4x-*-*) targ_emul=tic4xcoff ; targ_extra_emuls="tic3xcoff tic3xcoff_onchip" ;; -tic54x-*-* | c54x*-*-*) targ_emul=tic54xcoff ;; + tdir_elf64_sparc=`echo ${targ_alias} | sed -e 's/32//'` + ;; +sparc*-*-vxworks*) targ_emul=elf32_sparc_vxworks + ;; +sparc*-*-*) targ_emul=elf32_sparc + ;; +spu-*-elf*) targ_emul=elf32_spu + ;; +tic30-*-*aout*) targ_emul=tic30aout + targ_extra_ofiles= + ;; +tic30-*-*coff*) targ_emul=tic30coff + targ_extra_ofiles= + ;; +tic4x-*-* | c4x-*-*) targ_emul=tic4xcoff + targ_extra_emuls="tic3xcoff tic3xcoff_onchip" + targ_extra_ofiles= + ;; +tic54x-*-* | c54x*-*-*) targ_emul=tic54xcoff + targ_extra_ofiles= + ;; tic6x-*-elf) targ_emul=elf32_tic6x_elf_le targ_extra_emuls="elf32_tic6x_elf_be elf32_tic6x_le elf32_tic6x_be" targ_extra_libpath=$targ_extra_emuls @@ -735,24 +982,31 @@ tic6x-*-uclinux) targ_emul=elf32_tic6x_linux_le targ_extra_libpath=$targ_extra_emuls ;; tic80-*-*) targ_emul=tic80coff + targ_extra_ofiles= ;; tilegx-*-*) targ_emul=elf64tilegx targ_extra_emuls="elf64tilegx_be elf32tilegx elf32tilegx_be" - targ_extra_libpath=$targ_extra_emuls ;; + targ_extra_libpath=$targ_extra_emuls + ;; tilegxbe-*-*) targ_emul=elf64tilegx_be targ_extra_emuls="elf64tilegx elf32tilegx elf32tilegx_be" - targ_extra_libpath=$targ_extra_emuls ;; -tilepro-*-*) targ_emul=elf32tilepro ;; + targ_extra_libpath=$targ_extra_emuls + ;; +tilepro-*-*) targ_emul=elf32tilepro + ;; ft32-*-*) targ_emul=elf32ft32 + targ_extra_ofiles=ldelfgen.o ;; v850*-*-*) targ_emul=v850_rh850 targ_extra_emuls=v850 ;; vax-*-netbsdelf*) targ_emul=elf32vax - targ_extra_emuls=vaxnbsd ;; + targ_extra_emuls=vaxnbsd + ;; vax-*-netbsdaout* | vax-*-netbsd*) targ_emul=vaxnbsd - targ_extra_emuls=elf32vax ;; + targ_extra_emuls=elf32vax + ;; vax-*-linux-*) targ_emul=elf32vax ;; visium-*-elf) targ_emul=elf32visium @@ -765,12 +1019,17 @@ xstormy16-*-*) targ_emul=elf32xstormy16 xtensa*-*-*) targ_emul=elf32xtensa ;; xgate-*-*) targ_emul=xgateelf + targ_extra_ofiles=ldelfgen.o ;; z80-*-coff) targ_emul=z80 + targ_extra_ofiles= ;; -z8k-*-coff) targ_emul=z8002; targ_extra_emuls=z8001 +z8k-*-coff) targ_emul=z8002 + targ_extra_emuls=z8001 + targ_extra_ofiles= ;; *-*-ieee*) targ_emul=vanilla + targ_extra_ofiles= ;; *) echo 2>&1 "*** ld does not support target ${targ}" diff --git a/ld/emultempl/aarch64elf.em b/ld/emultempl/aarch64elf.em index 93f60a9..022de08 100644 --- a/ld/emultempl/aarch64elf.em +++ b/ld/emultempl/aarch64elf.em @@ -206,7 +206,7 @@ gldaarch64_layout_sections_again (void) /* If we have changed sizes of the stub sections, then we need to recalculate all the section offsets. This may mean we need to add even more stubs. */ - gld${EMULATION_NAME}_map_segments (TRUE); + ldelf_map_segments (TRUE); need_laying_out = -1; } @@ -275,7 +275,7 @@ gld${EMULATION_NAME}_after_allocation (void) } if (need_laying_out != -1) - gld${EMULATION_NAME}_map_segments (need_laying_out); + ldelf_map_segments (need_laying_out); } static void @@ -339,26 +339,6 @@ aarch64_elf_create_output_section_statements (void) ldlang_add_file (stub_file); } -/* Avoid processing the fake stub_file in vercheck, stat_needed and - check_needed routines. */ - -static void (*real_func) (lang_input_statement_type *); - -static void aarch64_for_each_input_file_wrapper (lang_input_statement_type *l) -{ - if (l != stub_file) - (*real_func) (l); -} - -static void -aarch64_lang_for_each_input_file (void (*func) (lang_input_statement_type *)) -{ - real_func = func; - lang_for_each_input_file (&aarch64_for_each_input_file_wrapper); -} - -#define lang_for_each_input_file aarch64_lang_for_each_input_file - EOF # Define some shell vars to insert bits of code into the standard elf diff --git a/ld/emultempl/alphaelf.em b/ld/emultempl/alphaelf.em index 55e01be..fbee01f 100644 --- a/ld/emultempl/alphaelf.em +++ b/ld/emultempl/alphaelf.em @@ -82,7 +82,7 @@ alpha_after_parse (void) exp_nameop (SIZEOF_HEADERS, NULL)), NULL); - gld${EMULATION_NAME}_after_parse (); + ldelf_after_parse (); } static void diff --git a/ld/emultempl/armelf.em b/ld/emultempl/armelf.em index 80effa4..29972f1 100644 --- a/ld/emultempl/armelf.em +++ b/ld/emultempl/armelf.em @@ -276,7 +276,7 @@ gldarm_layout_sections_again (void) /* If we have changed sizes of the stub sections, then we need to recalculate all the section offsets. This may mean we need to add even more stubs. */ - gld${EMULATION_NAME}_map_segments (TRUE); + ldelf_map_segments (TRUE); need_laying_out = -1; } @@ -413,7 +413,7 @@ gld${EMULATION_NAME}_after_allocation (void) } if (need_laying_out != -1) - gld${EMULATION_NAME}_map_segments (need_laying_out); + ldelf_map_segments (need_laying_out); } static void @@ -553,26 +553,6 @@ arm_elf_create_output_section_statements (void) bfd_elf32_arm_get_bfd_for_interworking (stub_file->the_bfd, &link_info); } -/* Avoid processing the fake stub_file in vercheck, stat_needed and - check_needed routines. */ - -static void (*real_func) (lang_input_statement_type *); - -static void arm_for_each_input_file_wrapper (lang_input_statement_type *l) -{ - if (l != stub_file) - (*real_func) (l); -} - -static void -arm_lang_for_each_input_file (void (*func) (lang_input_statement_type *)) -{ - real_func = func; - lang_for_each_input_file (&arm_for_each_input_file_wrapper); -} - -#define lang_for_each_input_file arm_lang_for_each_input_file - EOF # Define some shell vars to insert bits of code into the standard elf diff --git a/ld/emultempl/cr16elf.em b/ld/emultempl/cr16elf.em index 6fb2062..6f97d41 100644 --- a/ld/emultempl/cr16elf.em +++ b/ld/emultempl/cr16elf.em @@ -120,7 +120,7 @@ cr16elf_after_parse (void) is true the link sometimes fails. */ config.magic_demand_paged = FALSE; - gld${EMULATION_NAME}_after_parse (); + ldelf_after_parse (); } /* This is called after the sections have been attached to output diff --git a/ld/emultempl/crxelf.em b/ld/emultempl/crxelf.em index bd32173..22bacde 100644 --- a/ld/emultempl/crxelf.em +++ b/ld/emultempl/crxelf.em @@ -26,8 +26,6 @@ fragment <<EOF #include "ldctor.h" -static void crxelf_after_parse (void); - static void crxelf_after_parse (void) { @@ -42,7 +40,7 @@ crxelf_after_parse (void) is true the link sometimes fails. */ config.magic_demand_paged = FALSE; - gld${EMULATION_NAME}_after_parse (); + ldelf_after_parse (); } /* This is called after the sections have been attached to output diff --git a/ld/emultempl/cskyelf.em b/ld/emultempl/cskyelf.em index 3651bb2..aaddd9c 100644 --- a/ld/emultempl/cskyelf.em +++ b/ld/emultempl/cskyelf.em @@ -208,7 +208,7 @@ gldcsky_layout_sections_again (void) /* If we have changed sizes of the stub sections, then we need to recalculate all the section offsets. This may mean we need to add even more stubs. */ - gld${EMULATION_NAME}_map_segments (TRUE); + ldelf_map_segments (TRUE); need_laying_out = -1; } @@ -269,7 +269,7 @@ gld${EMULATION_NAME}_after_allocation (void) } if (need_laying_out != -1) - gld${EMULATION_NAME}_map_segments (need_laying_out); + ldelf_map_segments (need_laying_out); } static void @@ -283,26 +283,6 @@ gld${EMULATION_NAME}_finish (void) finish_default (); } -/* Avoid processing the fake stub_file in vercheck, stat_needed and - check_needed routines. */ - -static void (*real_func) (lang_input_statement_type *); - -static void csky_for_each_input_file_wrapper (lang_input_statement_type *l) -{ - if (l != stub_file) - (*real_func) (l); -} - -static void -csky_lang_for_each_input_file (void (*func) (lang_input_statement_type *)) -{ - real_func = func; - lang_for_each_input_file (&csky_for_each_input_file_wrapper); -} - -#define lang_for_each_input_file csky_lang_for_each_input_file - EOF # This code gets inserted into the generic elf32.sc linker script diff --git a/ld/emultempl/elf-generic.em b/ld/emultempl/elf-generic.em index ac60f99..8392cea 100644 --- a/ld/emultempl/elf-generic.em +++ b/ld/emultempl/elf-generic.em @@ -24,48 +24,4 @@ # fragment <<EOF -static void -gld${EMULATION_NAME}_map_segments (bfd_boolean need_layout) -{ - int tries = 10; - - do - { - lang_relax_sections (need_layout); - need_layout = FALSE; - - if (link_info.output_bfd->xvec->flavour == bfd_target_elf_flavour - && !bfd_link_relocatable (&link_info)) - { - bfd_size_type phdr_size; - - phdr_size = elf_program_header_size (link_info.output_bfd); - /* If we don't have user supplied phdrs, throw away any - previous linker generated program headers. */ - if (lang_phdr_list == NULL) - elf_seg_map (link_info.output_bfd) = NULL; - if (!_bfd_elf_map_sections_to_segments (link_info.output_bfd, - &link_info)) - einfo (_("%F%P: map sections to segments failed: %E\n")); - - if (phdr_size != elf_program_header_size (link_info.output_bfd)) - { - if (tries > 6) - /* The first few times we allow any change to - phdr_size . */ - need_layout = TRUE; - else if (phdr_size - < elf_program_header_size (link_info.output_bfd)) - /* After that we only allow the size to grow. */ - need_layout = TRUE; - else - elf_program_header_size (link_info.output_bfd) = phdr_size; - } - } - } - while (need_layout && --tries); - - if (tries == 0) - einfo (_("%F%P: looping in map_segments")); -} EOF diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em index 52db0fd..5a3cc2f 100644 --- a/ld/emultempl/elf32.em +++ b/ld/emultempl/elf32.em @@ -38,13 +38,8 @@ fragment <<EOF #include "sysdep.h" #include "bfd.h" #include "libiberty.h" -#include "safe-ctype.h" -#include "filenames.h" #include "getopt.h" -#include <fcntl.h> - #include "bfdlink.h" - #include "ld.h" #include "ldmain.h" #include "ldmisc.h" @@ -52,34 +47,18 @@ fragment <<EOF #include "ldlang.h" #include "ldfile.h" #include "ldemul.h" -#include "ldbuildid.h" #include <ldgram.h> -#include "elf/common.h" #include "elf-bfd.h" -#include "filenames.h" +#include "ldelf.h" +#include "ldelfgen.h" /* Declare functions used by various EXTRA_EM_FILEs. */ static void gld${EMULATION_NAME}_before_parse (void); -static void gld${EMULATION_NAME}_after_parse (void); static void gld${EMULATION_NAME}_after_open (void); static void gld${EMULATION_NAME}_before_allocation (void); static void gld${EMULATION_NAME}_after_allocation (void); -static lang_output_section_statement_type *gld${EMULATION_NAME}_place_orphan - (asection *, const char *, int); EOF -if [ "x${USE_LIBPATH}" = xyes ] ; then - case ${target} in - *-*-linux-* | *-*-k*bsd*-* | *-*-gnu*) - fragment <<EOF -#ifdef HAVE_GLOB -#include <glob.h> -#endif -EOF - ;; - esac -fi - # Import any needed special functions and/or overrides. # source_em ${srcdir}/emultempl/elf-generic.em @@ -111,2218 +90,66 @@ gld${EMULATION_NAME}_before_parse (void) EOF fi -if test x"$LDEMUL_AFTER_PARSE" != xgld"$EMULATION_NAME"_after_parse; then fragment <<EOF -static void -gld${EMULATION_NAME}_after_parse (void) -{ - if (bfd_link_pie (&link_info)) - link_info.flags_1 |= (bfd_vma) DF_1_PIE; - - if (bfd_link_executable (&link_info) - && link_info.nointerp) - { - if (link_info.dynamic_undefined_weak > 0) - einfo (_("%P: warning: -z dynamic-undefined-weak ignored\n")); - link_info.dynamic_undefined_weak = 0; - } - after_parse_default (); -} - -EOF -fi - -if test x"$LDEMUL_RECOGNIZED_FILE" != xgld"${EMULATION_NAME}"_load_symbols; then -fragment <<EOF -/* Handle the generation of DT_NEEDED tags. */ - -static bfd_boolean -gld${EMULATION_NAME}_load_symbols (lang_input_statement_type *entry) -{ - int link_class = 0; - - /* Tell the ELF linker that we don't want the output file to have a - DT_NEEDED entry for this file, unless it is used to resolve - references in a regular object. */ - if (entry->flags.add_DT_NEEDED_for_regular) - link_class = DYN_AS_NEEDED; - - /* Tell the ELF linker that we don't want the output file to have a - DT_NEEDED entry for any dynamic library in DT_NEEDED tags from - this file at all. */ - if (!entry->flags.add_DT_NEEDED_for_dynamic) - link_class |= DYN_NO_ADD_NEEDED; - - if (entry->flags.just_syms - && (bfd_get_file_flags (entry->the_bfd) & DYNAMIC) != 0) - einfo (_("%F%P: %pB: --just-symbols may not be used on DSO\n"), - entry->the_bfd); - - if (link_class == 0 - || (bfd_get_file_flags (entry->the_bfd) & DYNAMIC) == 0) - return FALSE; - - bfd_elf_set_dyn_lib_class (entry->the_bfd, - (enum dynamic_lib_link_class) link_class); - - /* Continue on with normal load_symbols processing. */ - return FALSE; -} -EOF -fi - -fragment <<EOF - -/* These variables are required to pass information back and forth - between after_open and check_needed and stat_needed and vercheck. */ - -static struct bfd_link_needed_list *global_needed; -static struct stat global_stat; -static lang_input_statement_type *global_found; -static struct bfd_link_needed_list *global_vercheck_needed; -static bfd_boolean global_vercheck_failed; - /* These variables are used to implement target options */ static char *audit; /* colon (typically) separated list of libs */ static char *depaudit; /* colon (typically) separated list of libs */ -/* Style of .note.gnu.build-id section. */ -static const char *emit_note_gnu_build_id; - -/* On Linux, it's possible to have different versions of the same - shared library linked against different versions of libc. The - dynamic linker somehow tags which libc version to use in - /etc/ld.so.cache, and, based on the libc that it sees in the - executable, chooses which version of the shared library to use. - - We try to do a similar check here by checking whether this shared - library needs any other shared libraries which may conflict with - libraries we have already included in the link. If it does, we - skip it, and try to find another shared library farther on down the - link path. - - This is called via lang_for_each_input_file. - GLOBAL_VERCHECK_NEEDED is the list of objects needed by the object - which we are checking. This sets GLOBAL_VERCHECK_FAILED if we find - a conflicting version. */ - -static void -gld${EMULATION_NAME}_vercheck (lang_input_statement_type *s) -{ - const char *soname; - struct bfd_link_needed_list *l; - - if (global_vercheck_failed) - return; - if (s->the_bfd == NULL - || (bfd_get_file_flags (s->the_bfd) & DYNAMIC) == 0) - return; - - soname = bfd_elf_get_dt_soname (s->the_bfd); - if (soname == NULL) - soname = lbasename (bfd_get_filename (s->the_bfd)); - - for (l = global_vercheck_needed; l != NULL; l = l->next) - { - const char *suffix; - - if (filename_cmp (soname, l->name) == 0) - { - /* Probably can't happen, but it's an easy check. */ - continue; - } - - if (strchr (l->name, '/') != NULL) - continue; - - suffix = strstr (l->name, ".so."); - if (suffix == NULL) - continue; - - suffix += sizeof ".so." - 1; - - if (filename_ncmp (soname, l->name, suffix - l->name) == 0) - { - /* Here we know that S is a dynamic object FOO.SO.VER1, and - the object we are considering needs a dynamic object - FOO.SO.VER2, and VER1 and VER2 are different. This - appears to be a version mismatch, so we tell the caller - to try a different version of this library. */ - global_vercheck_failed = TRUE; - return; - } - } -} - - -/* See if an input file matches a DT_NEEDED entry by running stat on - the file. */ - -static void -gld${EMULATION_NAME}_stat_needed (lang_input_statement_type *s) -{ - struct stat st; - const char *suffix; - const char *soname; - - if (global_found != NULL) - return; - if (s->the_bfd == NULL) - return; - - /* If this input file was an as-needed entry, and wasn't found to be - needed at the stage it was linked, then don't say we have loaded it. */ - if ((bfd_elf_get_dyn_lib_class (s->the_bfd) & DYN_AS_NEEDED) != 0) - return; - - if (bfd_stat (s->the_bfd, &st) != 0) - { - einfo (_("%P: %pB: bfd_stat failed: %E\n"), s->the_bfd); - return; - } - - /* Some operating systems, e.g. Windows, do not provide a meaningful - st_ino; they always set it to zero. (Windows does provide a - meaningful st_dev.) Do not indicate a duplicate library in that - case. While there is no guarantee that a system that provides - meaningful inode numbers will never set st_ino to zero, this is - merely an optimization, so we do not need to worry about false - negatives. */ - if (st.st_dev == global_stat.st_dev - && st.st_ino == global_stat.st_ino - && st.st_ino != 0) - { - global_found = s; - return; - } - - /* We issue a warning if it looks like we are including two - different versions of the same shared library. For example, - there may be a problem if -lc picks up libc.so.6 but some other - shared library has a DT_NEEDED entry of libc.so.5. This is a - heuristic test, and it will only work if the name looks like - NAME.so.VERSION. FIXME: Depending on file names is error-prone. - If we really want to issue warnings about mixing version numbers - of shared libraries, we need to find a better way. */ - - if (strchr (global_needed->name, '/') != NULL) - return; - suffix = strstr (global_needed->name, ".so."); - if (suffix == NULL) - return; - suffix += sizeof ".so." - 1; - - soname = bfd_elf_get_dt_soname (s->the_bfd); - if (soname == NULL) - soname = lbasename (s->filename); - - if (filename_ncmp (soname, global_needed->name, suffix - global_needed->name) == 0) - einfo (_("%P: warning: %s, needed by %pB, may conflict with %s\n"), - global_needed->name, global_needed->by, soname); -} - -struct dt_needed -{ - bfd *by; - const char *name; -}; - -/* This function is called for each possible name for a dynamic object - named by a DT_NEEDED entry. The FORCE parameter indicates whether - to skip the check for a conflicting version. */ - -static bfd_boolean -gld${EMULATION_NAME}_try_needed (struct dt_needed *needed, - int force) -{ - bfd *abfd; - const char *name = needed->name; - const char *soname; - int link_class; - - abfd = bfd_openr (name, bfd_get_target (link_info.output_bfd)); - if (abfd == NULL) - { - if (verbose) - info_msg (_("attempt to open %s failed\n"), name); - return FALSE; - } - - /* Linker needs to decompress sections. */ - abfd->flags |= BFD_DECOMPRESS; - - if (! bfd_check_format (abfd, bfd_object)) - { - bfd_close (abfd); - return FALSE; - } - if ((bfd_get_file_flags (abfd) & DYNAMIC) == 0) - { - bfd_close (abfd); - return FALSE; - } - - /* For DT_NEEDED, they have to match. */ - if (abfd->xvec != link_info.output_bfd->xvec) - { - bfd_close (abfd); - return FALSE; - } - - /* Check whether this object would include any conflicting library - versions. If FORCE is set, then we skip this check; we use this - the second time around, if we couldn't find any compatible - instance of the shared library. */ - - if (! force) - { - struct bfd_link_needed_list *needs; - - if (! bfd_elf_get_bfd_needed_list (abfd, &needs)) - einfo (_("%F%P: %pB: bfd_elf_get_bfd_needed_list failed: %E\n"), abfd); - - if (needs != NULL) - { - global_vercheck_needed = needs; - global_vercheck_failed = FALSE; - lang_for_each_input_file (gld${EMULATION_NAME}_vercheck); - if (global_vercheck_failed) - { - bfd_close (abfd); - /* Return FALSE to force the caller to move on to try - another file on the search path. */ - return FALSE; - } - - /* But wait! It gets much worse. On Linux, if a shared - library does not use libc at all, we are supposed to skip - it the first time around in case we encounter a shared - library later on with the same name which does use the - version of libc that we want. This is much too horrible - to use on any system other than Linux. */ - -EOF -case ${target} in - *-*-linux-* | *-*-k*bsd*-* | *-*-gnu*) - fragment <<EOF - { - struct bfd_link_needed_list *l; - - for (l = needs; l != NULL; l = l->next) - if (CONST_STRNEQ (l->name, "libc.so")) - break; - if (l == NULL) - { - bfd_close (abfd); - return FALSE; - } - } - -EOF - ;; -esac -fragment <<EOF - } - } - - /* We've found a dynamic object matching the DT_NEEDED entry. */ - - /* We have already checked that there is no other input file of the - same name. We must now check again that we are not including the - same file twice. We need to do this because on many systems - libc.so is a symlink to, e.g., libc.so.1. The SONAME entry will - reference libc.so.1. If we have already included libc.so, we - don't want to include libc.so.1 if they are the same file, and we - can only check that using stat. */ - - if (bfd_stat (abfd, &global_stat) != 0) - einfo (_("%F%P: %pB: bfd_stat failed: %E\n"), abfd); - - /* First strip off everything before the last '/'. */ - soname = lbasename (abfd->filename); - - if (verbose) - info_msg (_("found %s at %s\n"), soname, name); - - global_found = NULL; - lang_for_each_input_file (gld${EMULATION_NAME}_stat_needed); - if (global_found != NULL) - { - /* Return TRUE to indicate that we found the file, even though - we aren't going to do anything with it. */ - return TRUE; - } - - /* Specify the soname to use. */ - bfd_elf_set_dt_needed_name (abfd, soname); - - /* Tell the ELF linker that we don't want the output file to have a - DT_NEEDED entry for this file, unless it is used to resolve - references in a regular object. */ - link_class = DYN_DT_NEEDED; - - /* Tell the ELF linker that we don't want the output file to have a - DT_NEEDED entry for this file at all if the entry is from a file - with DYN_NO_ADD_NEEDED. */ - if (needed->by != NULL - && (bfd_elf_get_dyn_lib_class (needed->by) & DYN_NO_ADD_NEEDED) != 0) - link_class |= DYN_NO_NEEDED | DYN_NO_ADD_NEEDED; - - bfd_elf_set_dyn_lib_class (abfd, (enum dynamic_lib_link_class) link_class); - - /* Add this file into the symbol table. */ - if (! bfd_link_add_symbols (abfd, &link_info)) - einfo (_("%F%P: %pB: error adding symbols: %E\n"), abfd); - - return TRUE; -} - -/* Search for a needed file in a path. */ - -static bfd_boolean -gld${EMULATION_NAME}_search_needed (const char *path, - struct dt_needed *n, int force) -{ - const char *s; - const char *name = n->name; - size_t len; - struct dt_needed needed; - - if (name[0] == '/') - return gld${EMULATION_NAME}_try_needed (n, force); - - if (path == NULL || *path == '\0') - return FALSE; - - needed.by = n->by; - needed.name = n->name; - - len = strlen (name); - while (1) - { - unsigned offset = 0; - char * var; - char *filename, *sset; - - s = strchr (path, config.rpath_separator); - if (s == NULL) - s = path + strlen (path); - -#if HAVE_DOS_BASED_FILE_SYSTEM - /* Assume a match on the second char is part of drive specifier. */ - else if (config.rpath_separator == ':' - && s == path + 1 - && ISALPHA (*path)) - { - s = strchr (s + 1, config.rpath_separator); - if (s == NULL) - s = path + strlen (path); - } -#endif - filename = (char *) xmalloc (s - path + len + 2); - if (s == path) - sset = filename; - else - { - memcpy (filename, path, s - path); - filename[s - path] = '/'; - sset = filename + (s - path) + 1; - } - strcpy (sset, name); - - /* PR 20535: Support the same pseudo-environment variables that - are supported by ld.so. Namely, $ORIGIN, $LIB and $PLATFORM. - Since there can be more than one occurrence of these tokens in - the path we loop until no more are found. Since we might not - be able to substitute some of the tokens we maintain an offset - into the filename for where we should begin our scan. */ - while ((var = strchr (filename + offset, '$')) != NULL) - { - /* The ld.so manual page does not say, but I am going to assume that - these tokens are terminated by a directory separator character - (/) or the end of the string. There is also an implication that - $ORIGIN should only be used at the start of a path, but that is - not enforced here. - - The ld.so manual page also states that it allows ${ORIGIN}, - ${LIB} and ${PLATFORM}, so these are supported as well. - - FIXME: The code could be a lot cleverer about allocating space - for the processed string. */ - char * end = strchr (var, '/'); - const char *replacement = NULL; - char * v = var + 1; - char * freeme = NULL; - unsigned flen = strlen (filename); - - if (end != NULL) - /* Temporarily terminate the filename at the end of the token. */ - * end = 0; - - if (*v == '{') - ++ v; - switch (*v++) - { - case 'O': - if (strcmp (v, "RIGIN") == 0 || strcmp (v, "RIGIN}") == 0) - { - /* ORIGIN - replace with the full path to the directory - containing the program or shared object. */ - if (needed.by == NULL) - { - if (link_info.output_bfd == NULL) - { - break; - } - else - replacement = bfd_get_filename (link_info.output_bfd); - } - else - replacement = bfd_get_filename (needed.by); - - if (replacement) - { - char * slash; - - if (replacement[0] == '/') - freeme = xstrdup (replacement); - else - { - char * current_dir = getpwd (); - - freeme = xmalloc (strlen (replacement) + strlen (current_dir) + 2); - sprintf (freeme, "%s/%s", current_dir, replacement); - } - - replacement = freeme; - if ((slash = strrchr (replacement, '/')) != NULL) - * slash = 0; - } - } - break; - - case 'L': - if (strcmp (v, "IB") == 0 || strcmp (v, "IB}") == 0) - { - /* LIB - replace with "lib" in 32-bit environments - and "lib64" in 64-bit environments. */ - - /* Note - we could replace this switch statement by - conditional fragments of shell script, but that is messy. - Any compiler worth its salt is going to optimize away - all but one of these case statements anyway. */ - switch ($ELFSIZE) - { - case 32: replacement = "lib"; break; - case 64: replacement = "lib64"; break; - default: - /* $ELFSIZE is not 32 or 64 ... */ - abort (); - } - } - break; - - case 'P': - /* Supporting $PLATFORM in a cross-hosted environment is not - possible. Supporting it in a native environment involves - loading the <sys/auxv.h> header file which loads the - system <elf.h> header file, which conflicts with the - "include/elf/mips.h" header file. */ - /* Fall through. */ - default: - break; - } - - if (replacement) - { - char * filename2 = xmalloc (flen + strlen (replacement)); - - if (end) - { - sprintf (filename2, "%.*s%s/%s", - (int)(var - filename), filename, - replacement, end + 1); - offset = (var - filename) + 1 + strlen (replacement); - } - else - { - sprintf (filename2, "%.*s%s", - (int)(var - filename), filename, - replacement); - offset = var - filename + strlen (replacement); - } - - free (filename); - filename = filename2; - /* There is no need to restore the path separator (when - end != NULL) as we have replaced the entire string. */ - } - else - { - if (verbose) - /* We only issue an "unrecognised" message in verbose mode - as the $<foo> token might be a legitimate component of - a path name in the target's file system. */ - info_msg (_("unrecognised or unsupported token '%s' in search path\n"), var); - - if (end) - /* Restore the path separator. */ - * end = '/'; - - /* PR 20784: Make sure that we resume the scan *after* - the token that we could not replace. */ - offset = (var + 1) - filename; - } - - free (freeme); - } - - needed.name = filename; - - if (gld${EMULATION_NAME}_try_needed (&needed, force)) - return TRUE; - - free (filename); - - if (*s == '\0') - break; - path = s + 1; - } - - return FALSE; -} - EOF -if [ "x${USE_LIBPATH}" = xyes ] ; then - fragment <<EOF -/* Prefix the sysroot to absolute paths in PATH, a string containing - paths separated by config.rpath_separator. If running on a DOS - file system, paths containing a drive spec won't have the sysroot - prefix added, unless the sysroot also specifies the same drive. */ - -static const char * -gld${EMULATION_NAME}_add_sysroot (const char *path) -{ - size_t len, extra; - const char *p; - char *ret, *q; - int dos_drive_sysroot = HAS_DRIVE_SPEC (ld_sysroot); - - len = strlen (ld_sysroot); - for (extra = 0, p = path; ; ) - { - int dos_drive = HAS_DRIVE_SPEC (p); - - if (dos_drive) - p += 2; - if (IS_DIR_SEPARATOR (*p) - && (!dos_drive - || (dos_drive_sysroot - && ld_sysroot[0] == p[-2]))) - { - if (dos_drive && dos_drive_sysroot) - extra += len - 2; - else - extra += len; - } - p = strchr (p, config.rpath_separator); - if (!p) - break; - ++p; - } - - ret = xmalloc (strlen (path) + extra + 1); - - for (q = ret, p = path; ; ) - { - const char *end; - int dos_drive = HAS_DRIVE_SPEC (p); - - if (dos_drive) - { - *q++ = *p++; - *q++ = *p++; - } - if (IS_DIR_SEPARATOR (*p) - && (!dos_drive - || (dos_drive_sysroot - && ld_sysroot[0] == p[-2]))) - { - if (dos_drive && dos_drive_sysroot) - { - strcpy (q, ld_sysroot + 2); - q += len - 2; - } - else - { - strcpy (q, ld_sysroot); - q += len; - } - } - end = strchr (p, config.rpath_separator); - if (end) - { - size_t n = end - p + 1; - strncpy (q, p, n); - q += n; - p += n; - } - else - { - strcpy (q, p); - break; - } - } - - return ret; -} +if test x"$LDEMUL_AFTER_OPEN" != xgld"$EMULATION_NAME"_after_open; then -EOF + IS_LINUX_TARGET=FALSE + IS_FREEBSD_TARGET=FALSE case ${target} in - *-*-freebsd* | *-*-dragonfly*) - fragment <<EOF -/* Read the system search path the FreeBSD way rather than the Linux way. */ -#ifdef HAVE_ELF_HINTS_H -#include <elf-hints.h> -#else -#include "elf-hints-local.h" -#endif - -static bfd_boolean -gld${EMULATION_NAME}_check_ld_elf_hints (const struct bfd_link_needed_list *l, - int force) -{ - static bfd_boolean initialized; - static const char *ld_elf_hints; - struct dt_needed needed; - - if (!initialized) - { - FILE *f; - char *tmppath; - - tmppath = concat (ld_sysroot, _PATH_ELF_HINTS, (const char *) NULL); - f = fopen (tmppath, FOPEN_RB); - free (tmppath); - if (f != NULL) - { - struct elfhints_hdr hdr; - - if (fread (&hdr, 1, sizeof (hdr), f) == sizeof (hdr) - && hdr.magic == ELFHINTS_MAGIC - && hdr.version == 1) - { - if (fseek (f, hdr.strtab + hdr.dirlist, SEEK_SET) != -1) - { - char *b; - - b = xmalloc (hdr.dirlistlen + 1); - if (fread (b, 1, hdr.dirlistlen + 1, f) == - hdr.dirlistlen + 1) - ld_elf_hints = gld${EMULATION_NAME}_add_sysroot (b); - - free (b); - } - } - fclose (f); - } - - initialized = TRUE; - } - - if (ld_elf_hints == NULL) - return FALSE; - - needed.by = l->by; - needed.name = l->name; - return gld${EMULATION_NAME}_search_needed (ld_elf_hints, &needed, force); -} -EOF - # FreeBSD - ;; - *-*-linux-* | *-*-k*bsd*-* | *-*-gnu*) - fragment <<EOF -/* For a native linker, check the file /etc/ld.so.conf for directories - in which we may find shared libraries. /etc/ld.so.conf is really - only meaningful on Linux. */ - -struct gld${EMULATION_NAME}_ld_so_conf -{ - char *path; - size_t len, alloc; -}; - -static bfd_boolean -gld${EMULATION_NAME}_parse_ld_so_conf - (struct gld${EMULATION_NAME}_ld_so_conf *info, const char *filename); - -static void -gld${EMULATION_NAME}_parse_ld_so_conf_include - (struct gld${EMULATION_NAME}_ld_so_conf *info, const char *filename, - const char *pattern) -{ - char *newp = NULL; -#ifdef HAVE_GLOB - glob_t gl; -#endif - - if (pattern[0] != '/') - { - char *p = strrchr (filename, '/'); - size_t patlen = strlen (pattern) + 1; - - newp = xmalloc (p - filename + 1 + patlen); - memcpy (newp, filename, p - filename + 1); - memcpy (newp + (p - filename + 1), pattern, patlen); - pattern = newp; - } - -#ifdef HAVE_GLOB - if (glob (pattern, 0, NULL, &gl) == 0) - { - size_t i; - - for (i = 0; i < gl.gl_pathc; ++i) - gld${EMULATION_NAME}_parse_ld_so_conf (info, gl.gl_pathv[i]); - globfree (&gl); - } -#else - /* If we do not have glob, treat the pattern as a literal filename. */ - gld${EMULATION_NAME}_parse_ld_so_conf (info, pattern); -#endif - - if (newp) - free (newp); -} - -static bfd_boolean -gld${EMULATION_NAME}_parse_ld_so_conf - (struct gld${EMULATION_NAME}_ld_so_conf *info, const char *filename) -{ - FILE *f = fopen (filename, FOPEN_RT); - char *line; - size_t linelen; - - if (f == NULL) - return FALSE; - - linelen = 256; - line = xmalloc (linelen); - do - { - char *p = line, *q; - - /* Normally this would use getline(3), but we need to be portable. */ - while ((q = fgets (p, linelen - (p - line), f)) != NULL - && strlen (q) == linelen - (p - line) - 1 - && line[linelen - 2] != '\n') - { - line = xrealloc (line, 2 * linelen); - p = line + linelen - 1; - linelen += linelen; - } - - if (q == NULL && p == line) - break; - - p = strchr (line, '\n'); - if (p) - *p = '\0'; - - /* Because the file format does not know any form of quoting we - can search forward for the next '#' character and if found - make it terminating the line. */ - p = strchr (line, '#'); - if (p) - *p = '\0'; - - /* Remove leading whitespace. NUL is no whitespace character. */ - p = line; - while (*p == ' ' || *p == '\f' || *p == '\r' || *p == '\t' || *p == '\v') - ++p; - - /* If the line is blank it is ignored. */ - if (p[0] == '\0') - continue; - - if (CONST_STRNEQ (p, "include") && (p[7] == ' ' || p[7] == '\t')) - { - char *dir, c; - p += 8; - do - { - while (*p == ' ' || *p == '\t') - ++p; - - if (*p == '\0') - break; - - dir = p; - - while (*p != ' ' && *p != '\t' && *p) - ++p; - - c = *p; - *p++ = '\0'; - if (dir[0] != '\0') - gld${EMULATION_NAME}_parse_ld_so_conf_include (info, filename, - dir); - } - while (c != '\0'); - } - else - { - char *dir = p; - while (*p && *p != '=' && *p != ' ' && *p != '\t' && *p != '\f' - && *p != '\r' && *p != '\v') - ++p; - - while (p != dir && p[-1] == '/') - --p; - if (info->path == NULL) - { - info->alloc = p - dir + 1 + 256; - info->path = xmalloc (info->alloc); - info->len = 0; - } - else - { - if (info->len + 1 + (p - dir) >= info->alloc) - { - info->alloc += p - dir + 256; - info->path = xrealloc (info->path, info->alloc); - } - info->path[info->len++] = config.rpath_separator; - } - memcpy (info->path + info->len, dir, p - dir); - info->len += p - dir; - info->path[info->len] = '\0'; - } - } - while (! feof (f)); - free (line); - fclose (f); - return TRUE; -} - -static bfd_boolean -gld${EMULATION_NAME}_check_ld_so_conf (const struct bfd_link_needed_list *l, - int force) -{ - static bfd_boolean initialized; - static const char *ld_so_conf; - struct dt_needed needed; - - if (! initialized) - { - char *tmppath; - struct gld${EMULATION_NAME}_ld_so_conf info; - - info.path = NULL; - info.len = info.alloc = 0; - tmppath = concat (ld_sysroot, "${prefix}/etc/ld.so.conf", - (const char *) NULL); - if (!gld${EMULATION_NAME}_parse_ld_so_conf (&info, tmppath)) - { - free (tmppath); - tmppath = concat (ld_sysroot, "/etc/ld.so.conf", - (const char *) NULL); - gld${EMULATION_NAME}_parse_ld_so_conf (&info, tmppath); - } - free (tmppath); - - if (info.path) - { - ld_so_conf = gld${EMULATION_NAME}_add_sysroot (info.path); - free (info.path); - } - initialized = TRUE; - } - - if (ld_so_conf == NULL) - return FALSE; - - - needed.by = l->by; - needed.name = l->name; - return gld${EMULATION_NAME}_search_needed (ld_so_conf, &needed, force); -} - -EOF - # Linux - ;; + IS_LINUX_TARGET=TRUE ;; + *-*-freebsd* | *-*-dragonfly*) + IS_FREEBSD_TARGET=TRUE ;; esac -fi -fragment <<EOF - -/* See if an input file matches a DT_NEEDED entry by name. */ - -static void -gld${EMULATION_NAME}_check_needed (lang_input_statement_type *s) -{ - const char *soname; - - /* Stop looking if we've found a loaded lib. */ - if (global_found != NULL - && (bfd_elf_get_dyn_lib_class (global_found->the_bfd) - & DYN_AS_NEEDED) == 0) - return; - - if (s->filename == NULL || s->the_bfd == NULL) - return; - - /* Don't look for a second non-loaded as-needed lib. */ - if (global_found != NULL - && (bfd_elf_get_dyn_lib_class (s->the_bfd) & DYN_AS_NEEDED) != 0) - return; - - if (filename_cmp (s->filename, global_needed->name) == 0) - { - global_found = s; - return; - } - - if (s->flags.search_dirs) - { - const char *f = strrchr (s->filename, '/'); - if (f != NULL - && filename_cmp (f + 1, global_needed->name) == 0) - { - global_found = s; - return; - } - } - - soname = bfd_elf_get_dt_soname (s->the_bfd); - if (soname != NULL - && filename_cmp (soname, global_needed->name) == 0) - { - global_found = s; - return; - } -} - -EOF + IS_LIBPATH=FALSE + if test "x${USE_LIBPATH}" = xyes; then + IS_LIBPATH=TRUE + fi + IS_NATIVE=FALSE + if test "x${NATIVE}" = xyes; then + IS_NATIVE=TRUE + fi -if test x"$LDEMUL_AFTER_OPEN" != xgld"$EMULATION_NAME"_after_open; then fragment <<EOF -static bfd_size_type -id_note_section_size (bfd *abfd ATTRIBUTE_UNUSED) -{ - const char *style = emit_note_gnu_build_id; - bfd_size_type size; - bfd_size_type build_id_size; - - size = offsetof (Elf_External_Note, name[sizeof "GNU"]); - size = (size + 3) & -(bfd_size_type) 4; - - build_id_size = compute_build_id_size (style); - if (build_id_size) - size += build_id_size; - else - size = 0; - - return size; -} - -static bfd_boolean -write_build_id (bfd *abfd) -{ - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - struct elf_obj_tdata *t = elf_tdata (abfd); - const char *style; - asection *asec; - Elf_Internal_Shdr *i_shdr; - unsigned char *contents, *id_bits; - bfd_size_type size; - file_ptr position; - Elf_External_Note *e_note; - - style = t->o->build_id.style; - asec = t->o->build_id.sec; - if (bfd_is_abs_section (asec->output_section)) - { - einfo (_("%P: warning: .note.gnu.build-id section discarded," - " --build-id ignored\n")); - return TRUE; - } - i_shdr = &elf_section_data (asec->output_section)->this_hdr; - - if (i_shdr->contents == NULL) - { - if (asec->contents == NULL) - asec->contents = (unsigned char *) xmalloc (asec->size); - contents = asec->contents; - } - else - contents = i_shdr->contents + asec->output_offset; - - e_note = (Elf_External_Note *) contents; - size = offsetof (Elf_External_Note, name[sizeof "GNU"]); - size = (size + 3) & -(bfd_size_type) 4; - id_bits = contents + size; - size = asec->size - size; - - bfd_h_put_32 (abfd, sizeof "GNU", &e_note->namesz); - bfd_h_put_32 (abfd, size, &e_note->descsz); - bfd_h_put_32 (abfd, NT_GNU_BUILD_ID, &e_note->type); - memcpy (e_note->name, "GNU", sizeof "GNU"); - - generate_build_id (abfd, style, bed->s->checksum_contents, id_bits, size); - - position = i_shdr->sh_offset + asec->output_offset; - size = asec->size; - return (bfd_seek (abfd, position, SEEK_SET) == 0 - && bfd_bwrite (contents, size, abfd) == size); -} - -/* Make .note.gnu.build-id section, and set up elf_tdata->build_id. */ - -static bfd_boolean -setup_build_id (bfd *ibfd) -{ - asection *s; - bfd_size_type size; - flagword flags; - - size = id_note_section_size (ibfd); - if (size == 0) - { - einfo (_("%P: warning: unrecognized --build-id style ignored\n")); - return FALSE; - } - - flags = (SEC_ALLOC | SEC_LOAD | SEC_IN_MEMORY - | SEC_LINKER_CREATED | SEC_READONLY | SEC_DATA); - s = bfd_make_section_with_flags (ibfd, ".note.gnu.build-id", flags); - if (s != NULL && bfd_set_section_alignment (ibfd, s, 2)) - { - struct elf_obj_tdata *t = elf_tdata (link_info.output_bfd); - t->o->build_id.after_write_object_contents = &write_build_id; - t->o->build_id.style = emit_note_gnu_build_id; - t->o->build_id.sec = s; - elf_section_type (s) = SHT_NOTE; - s->size = size; - return TRUE; - } - - einfo (_("%P: warning: cannot create .note.gnu.build-id section," - " --build-id ignored\n")); - return FALSE; -} - /* This is called after all the input files have been opened. */ static void gld${EMULATION_NAME}_after_open (void) { - struct bfd_link_needed_list *needed, *l; - struct elf_link_hash_table *htab; - asection *s; - bfd *abfd; - - after_open_default (); - - htab = elf_hash_table (&link_info); - if (!is_elf_hash_table (htab)) - return; - - if (command_line.out_implib_filename) - { - unlink_if_ordinary (command_line.out_implib_filename); - link_info.out_implib_bfd - = bfd_openw (command_line.out_implib_filename, - bfd_get_target (link_info.output_bfd)); - - if (link_info.out_implib_bfd == NULL) - { - einfo (_("%F%P: %s: can't open for writing: %E\n"), - command_line.out_implib_filename); - } - } - - if (emit_note_gnu_build_id != NULL) - { - /* Find an ELF input. */ - for (abfd = link_info.input_bfds; - abfd != (bfd *) NULL; abfd = abfd->link.next) - if (bfd_get_flavour (abfd) == bfd_target_elf_flavour - && bfd_count_sections (abfd) != 0 - && !((lang_input_statement_type *) abfd->usrdata)->flags.just_syms) - break; - - /* PR 10555: If there are no ELF input files do not try to - create a .note.gnu-build-id section. */ - if (abfd == NULL - || !setup_build_id (abfd)) - { - free ((char *) emit_note_gnu_build_id); - emit_note_gnu_build_id = NULL; - } - } - - get_elf_backend_data (link_info.output_bfd)->setup_gnu_properties (&link_info); - - if (bfd_link_relocatable (&link_info)) - { - if (link_info.execstack == ! link_info.noexecstack) - /* PR ld/16744: If "-z [no]execstack" has been specified on the - command line and we are perfoming a relocatable link then no - PT_GNU_STACK segment will be created and so the - linkinfo.[no]execstack values set in _handle_option() will have no - effect. Instead we create a .note.GNU-stack section in much the - same way as the assembler does with its --[no]execstack option. */ - (void) bfd_make_section_with_flags (link_info.input_bfds, - ".note.GNU-stack", - SEC_READONLY | (link_info.execstack ? SEC_CODE : 0)); - - return; - } - - if (!link_info.traditional_format) - { - bfd *elfbfd = NULL; - bfd_boolean warn_eh_frame = FALSE; - int seen_type = 0; - - for (abfd = link_info.input_bfds; abfd; abfd = abfd->link.next) - { - int type = 0; - - if (((lang_input_statement_type *) abfd->usrdata)->flags.just_syms) - continue; - - for (s = abfd->sections; s && type < COMPACT_EH_HDR; s = s->next) - { - const char *name = bfd_get_section_name (abfd, s); - - if (bfd_is_abs_section (s->output_section)) - continue; - if (CONST_STRNEQ (name, ".eh_frame_entry")) - type = COMPACT_EH_HDR; - else if (strcmp (name, ".eh_frame") == 0 && s->size > 8) - type = DWARF2_EH_HDR; - } - - if (type != 0) - { - if (seen_type == 0) - { - seen_type = type; - } - else if (seen_type != type) - { - einfo (_("%F%P: compact frame descriptions incompatible with" - " DWARF2 .eh_frame from %pB\n"), - type == DWARF2_EH_HDR ? abfd : elfbfd); - break; - } - - if (!elfbfd - && (type == COMPACT_EH_HDR || link_info.eh_frame_hdr_type != 0)) - { - if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) - elfbfd = abfd; - - warn_eh_frame = TRUE; - } - } - - if (seen_type == COMPACT_EH_HDR) - link_info.eh_frame_hdr_type = COMPACT_EH_HDR; - } - if (elfbfd) - { - const struct elf_backend_data *bed; - - bed = get_elf_backend_data (elfbfd); - s = bfd_make_section_with_flags (elfbfd, ".eh_frame_hdr", - bed->dynamic_sec_flags - | SEC_READONLY); - if (s != NULL - && bfd_set_section_alignment (elfbfd, s, 2)) - { - htab->eh_info.hdr_sec = s; - warn_eh_frame = FALSE; - } - } - if (warn_eh_frame) - einfo (_("%P: warning: cannot create .eh_frame_hdr section," - " --eh-frame-hdr ignored\n")); - } - - /* Get the list of files which appear in DT_NEEDED entries in - dynamic objects included in the link (often there will be none). - For each such file, we want to track down the corresponding - library, and include the symbol table in the link. This is what - the runtime dynamic linker will do. Tracking the files down here - permits one dynamic object to include another without requiring - special action by the person doing the link. Note that the - needed list can actually grow while we are stepping through this - loop. */ - needed = bfd_elf_get_needed_list (link_info.output_bfd, &link_info); - for (l = needed; l != NULL; l = l->next) - { - struct bfd_link_needed_list *ll; - struct dt_needed n, nn; - int force; - - /* If the lib that needs this one was --as-needed and wasn't - found to be needed, then this lib isn't needed either. */ - if (l->by != NULL - && (bfd_elf_get_dyn_lib_class (l->by) & DYN_AS_NEEDED) != 0) - continue; - - /* Skip the lib if --no-copy-dt-needed-entries and - --allow-shlib-undefined is in effect. */ - if (l->by != NULL - && link_info.unresolved_syms_in_shared_libs == RM_IGNORE - && (bfd_elf_get_dyn_lib_class (l->by) & DYN_NO_ADD_NEEDED) != 0) - continue; - - /* If we've already seen this file, skip it. */ - for (ll = needed; ll != l; ll = ll->next) - if ((ll->by == NULL - || (bfd_elf_get_dyn_lib_class (ll->by) & DYN_AS_NEEDED) == 0) - && strcmp (ll->name, l->name) == 0) - break; - if (ll != l) - continue; - - /* See if this file was included in the link explicitly. */ - global_needed = l; - global_found = NULL; - lang_for_each_input_file (gld${EMULATION_NAME}_check_needed); - if (global_found != NULL - && (bfd_elf_get_dyn_lib_class (global_found->the_bfd) - & DYN_AS_NEEDED) == 0) - continue; - - n.by = l->by; - n.name = l->name; - nn.by = l->by; - if (verbose) - info_msg (_("%s needed by %pB\n"), l->name, l->by); - - /* As-needed libs specified on the command line (or linker script) - take priority over libs found in search dirs. */ - if (global_found != NULL) - { - nn.name = global_found->filename; - if (gld${EMULATION_NAME}_try_needed (&nn, TRUE)) - continue; - } - - /* We need to find this file and include the symbol table. We - want to search for the file in the same way that the dynamic - linker will search. That means that we want to use - rpath_link, rpath, then the environment variable - LD_LIBRARY_PATH (native only), then the DT_RPATH/DT_RUNPATH - entries (native only), then the linker script LIB_SEARCH_DIRS. - We do not search using the -L arguments. - - We search twice. The first time, we skip objects which may - introduce version mismatches. The second time, we force - their use. See gld${EMULATION_NAME}_vercheck comment. */ - for (force = 0; force < 2; force++) - { - size_t len; - search_dirs_type *search; -EOF -if [ "x${NATIVE}" = xyes ] || [ "x${USE_LIBPATH}" = xyes ] ; then -fragment <<EOF - const char *path; -EOF -fi -if [ "x${USE_LIBPATH}" = xyes ] ; then -fragment <<EOF - struct bfd_link_needed_list *rp; - int found; -EOF -fi -fragment <<EOF - - if (gld${EMULATION_NAME}_search_needed (command_line.rpath_link, - &n, force)) - break; -EOF -if [ "x${USE_LIBPATH}" = xyes ] ; then -fragment <<EOF - path = command_line.rpath; - if (path) - { - path = gld${EMULATION_NAME}_add_sysroot (path); - found = gld${EMULATION_NAME}_search_needed (path, &n, force); - free ((char *) path); - if (found) - break; - } -EOF -fi -if [ "x${NATIVE}" = xyes ] ; then -fragment <<EOF - if (command_line.rpath_link == NULL - && command_line.rpath == NULL) - { - path = (const char *) getenv ("LD_RUN_PATH"); - if (path - && gld${EMULATION_NAME}_search_needed (path, &n, force)) - break; - } - path = (const char *) getenv ("LD_LIBRARY_PATH"); - if (path - && gld${EMULATION_NAME}_search_needed (path, &n, force)) - break; -EOF -fi -if [ "x${USE_LIBPATH}" = xyes ] ; then -fragment <<EOF - found = 0; - rp = bfd_elf_get_runpath_list (link_info.output_bfd, &link_info); - for (; !found && rp != NULL; rp = rp->next) - { - path = gld${EMULATION_NAME}_add_sysroot (rp->name); - found = (rp->by == l->by - && gld${EMULATION_NAME}_search_needed (path, &n, - force)); - free ((char *) path); - } - if (found) - break; - -EOF -fi -if [ "x${USE_LIBPATH}" = xyes ] ; then - case ${target} in - *-*-freebsd* | *-*-dragonfly*) - fragment <<EOF - if (gld${EMULATION_NAME}_check_ld_elf_hints (l, force)) - break; -EOF - # FreeBSD - ;; - - *-*-linux-* | *-*-k*bsd*-* | *-*-gnu*) - fragment <<EOF - if (gld${EMULATION_NAME}_check_ld_so_conf (l, force)) - break; - -EOF - # Linux - ;; - esac -fi -fragment <<EOF - len = strlen (l->name); - for (search = search_head; search != NULL; search = search->next) - { - char *filename; - - if (search->cmdline) - continue; - filename = (char *) xmalloc (strlen (search->name) + len + 2); - sprintf (filename, "%s/%s", search->name, l->name); - nn.name = filename; - if (gld${EMULATION_NAME}_try_needed (&nn, force)) - break; - free (filename); - } - if (search != NULL) - break; -EOF -fragment <<EOF - } - - if (force < 2) - continue; - - einfo (_("%P: warning: %s, needed by %pB, not found " - "(try using -rpath or -rpath-link)\n"), - l->name, l->by); - } - - if (link_info.eh_frame_hdr_type == COMPACT_EH_HDR) - if (!bfd_elf_parse_eh_frame_entries (NULL, &link_info)) - einfo (_("%F%P: failed to parse EH frame entries\n")); + ldelf_after_open ($IS_LIBPATH, $IS_NATIVE, + $IS_LINUX_TARGET, $IS_FREEBSD_TARGET, $ELFSIZE); } EOF fi -fragment <<EOF - -/* Look through an expression for an assignment statement. */ - -static void -gld${EMULATION_NAME}_find_exp_assignment (etree_type *exp) -{ - bfd_boolean provide = FALSE; - - switch (exp->type.node_class) - { - case etree_provide: - case etree_provided: - provide = TRUE; - /* Fallthru */ - case etree_assign: - /* We call record_link_assignment even if the symbol is defined. - This is because if it is defined by a dynamic object, we - actually want to use the value defined by the linker script, - not the value from the dynamic object (because we are setting - symbols like etext). If the symbol is defined by a regular - object, then, as it happens, calling record_link_assignment - will do no harm. */ - if (strcmp (exp->assign.dst, ".") != 0) - { - if (!bfd_elf_record_link_assignment (link_info.output_bfd, - &link_info, - exp->assign.dst, provide, - exp->assign.hidden)) - einfo (_("%F%P: failed to record assignment to %s: %E\n"), - exp->assign.dst); - } - gld${EMULATION_NAME}_find_exp_assignment (exp->assign.src); - break; - - case etree_binary: - gld${EMULATION_NAME}_find_exp_assignment (exp->binary.lhs); - gld${EMULATION_NAME}_find_exp_assignment (exp->binary.rhs); - break; - - case etree_trinary: - gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.cond); - gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.lhs); - gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.rhs); - break; - - case etree_unary: - gld${EMULATION_NAME}_find_exp_assignment (exp->unary.child); - break; - - default: - break; - } -} - - -/* This is called by the before_allocation routine via - lang_for_each_statement. It locates any assignment statements, and - tells the ELF backend about them, in case they are assignments to - symbols which are referred to by dynamic objects. */ - -static void -gld${EMULATION_NAME}_find_statement_assignment (lang_statement_union_type *s) -{ - if (s->header.type == lang_assignment_statement_enum) - gld${EMULATION_NAME}_find_exp_assignment (s->assignment_statement.exp); -} - -EOF - if test x"$LDEMUL_BEFORE_ALLOCATION" != xgld"$EMULATION_NAME"_before_allocation; then - if test x"${ELF_INTERPRETER_NAME+set}" = xset; then - ELF_INTERPRETER_SET_DEFAULT=" - if (sinterp != NULL) - { - sinterp->contents = (unsigned char *) ${ELF_INTERPRETER_NAME}; - sinterp->size = strlen ((char *) sinterp->contents) + 1; - } - -" - else - ELF_INTERPRETER_SET_DEFAULT= + if test x"${ELF_INTERPRETER_NAME}" = x; then + ELF_INTERPRETER_NAME=NULL fi fragment <<EOF -/* used by before_allocation and handle_option. */ -static void -gld${EMULATION_NAME}_append_to_separated_string (char **to, char *op_arg) -{ - if (*to == NULL) - *to = xstrdup (op_arg); - else - { - size_t to_len = strlen (*to); - size_t op_arg_len = strlen (op_arg); - char *buf; - char *cp = *to; - - /* First see whether OPTARG is already in the path. */ - do - { - if (strncmp (op_arg, cp, op_arg_len) == 0 - && (cp[op_arg_len] == 0 - || cp[op_arg_len] == config.rpath_separator)) - /* We found it. */ - break; - - /* Not yet found. */ - cp = strchr (cp, config.rpath_separator); - if (cp != NULL) - ++cp; - } - while (cp != NULL); - - if (cp == NULL) - { - buf = xmalloc (to_len + op_arg_len + 2); - sprintf (buf, "%s%c%s", *to, - config.rpath_separator, op_arg); - free (*to); - *to = buf; - } - } -} - /* This is called after the sections have been attached to output sections, but before any sizes or addresses have been set. */ static void gld${EMULATION_NAME}_before_allocation (void) { - const char *rpath; - asection *sinterp; - bfd *abfd; - struct bfd_link_hash_entry *ehdr_start = NULL; - unsigned char ehdr_start_save_type = 0; - char ehdr_start_save_u[sizeof ehdr_start->u - - sizeof ehdr_start->u.def.next] = ""; - - if (is_elf_hash_table (link_info.hash)) - { - _bfd_elf_tls_setup (link_info.output_bfd, &link_info); - - /* Make __ehdr_start hidden if it has been referenced, to - prevent the symbol from being dynamic. */ - if (!bfd_link_relocatable (&link_info)) - { - struct elf_link_hash_table *htab = elf_hash_table (&link_info); - struct elf_link_hash_entry *h - = elf_link_hash_lookup (htab, "__ehdr_start", FALSE, FALSE, TRUE); - - /* Only adjust the export class if the symbol was referenced - and not defined, otherwise leave it alone. */ - if (h != NULL - && (h->root.type == bfd_link_hash_new - || h->root.type == bfd_link_hash_undefined - || h->root.type == bfd_link_hash_undefweak - || h->root.type == bfd_link_hash_common)) - { - const struct elf_backend_data *bed; - bed = get_elf_backend_data (link_info.output_bfd); - (*bed->elf_backend_hide_symbol) (&link_info, h, TRUE); - if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL) - h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN; - /* Don't leave the symbol undefined. Undefined hidden - symbols typically won't have dynamic relocations, but - we most likely will need dynamic relocations for - __ehdr_start if we are building a PIE or shared - library. */ - ehdr_start = &h->root; - ehdr_start_save_type = ehdr_start->type; - memcpy (ehdr_start_save_u, - (char *) &ehdr_start->u + sizeof ehdr_start->u.def.next, - sizeof ehdr_start_save_u); - ehdr_start->type = bfd_link_hash_defined; - ehdr_start->u.def.section = bfd_abs_section_ptr; - ehdr_start->u.def.value = 0; - } - } - - /* If we are going to make any variable assignments, we need to - let the ELF backend know about them in case the variables are - referred to by dynamic objects. */ - lang_for_each_statement (gld${EMULATION_NAME}_find_statement_assignment); - } - - /* Let the ELF backend work out the sizes of any sections required - by dynamic linking. */ - rpath = command_line.rpath; - if (rpath == NULL) - rpath = (const char *) getenv ("LD_RUN_PATH"); - - for (abfd = link_info.input_bfds; abfd; abfd = abfd->link.next) - if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) - { - const char *audit_libs = elf_dt_audit (abfd); - - /* If the input bfd contains an audit entry, we need to add it as - a dep audit entry. */ - if (audit_libs && *audit_libs != '\0') - { - char *cp = xstrdup (audit_libs); - do - { - int more = 0; - char *cp2 = strchr (cp, config.rpath_separator); - - if (cp2) - { - *cp2 = '\0'; - more = 1; - } - - if (cp != NULL && *cp != '\0') - gld${EMULATION_NAME}_append_to_separated_string (&depaudit, cp); - - cp = more ? ++cp2 : NULL; - } - while (cp != NULL); - } - } - - if (! (bfd_elf_size_dynamic_sections - (link_info.output_bfd, command_line.soname, rpath, - command_line.filter_shlib, audit, depaudit, - (const char * const *) command_line.auxiliary_filters, - &link_info, &sinterp))) - einfo (_("%F%P: failed to set dynamic section sizes: %E\n")); - -${ELF_INTERPRETER_SET_DEFAULT} - /* Let the user override the dynamic linker we are using. */ - if (command_line.interpreter != NULL - && sinterp != NULL) - { - sinterp->contents = (bfd_byte *) command_line.interpreter; - sinterp->size = strlen (command_line.interpreter) + 1; - } - - /* Look for any sections named .gnu.warning. As a GNU extensions, - we treat such sections as containing warning messages. We print - out the warning message, and then zero out the section size so - that it does not get copied into the output file. */ - - { - LANG_FOR_EACH_INPUT_STATEMENT (is) - { - asection *s; - bfd_size_type sz; - char *msg; - - if (is->flags.just_syms) - continue; - - s = bfd_get_section_by_name (is->the_bfd, ".gnu.warning"); - if (s == NULL) - continue; - - sz = s->size; - msg = (char *) xmalloc ((size_t) (sz + 1)); - if (! bfd_get_section_contents (is->the_bfd, s, msg, - (file_ptr) 0, sz)) - einfo (_("%F%P: %pB: can't read contents of section .gnu.warning: %E\n"), - is->the_bfd); - msg[sz] = '\0'; - (*link_info.callbacks->warning) (&link_info, msg, - (const char *) NULL, is->the_bfd, - (asection *) NULL, (bfd_vma) 0); - free (msg); - - /* Clobber the section size, so that we don't waste space - copying the warning into the output file. If we've already - sized the output section, adjust its size. The adjustment - is on rawsize because targets that size sections early will - have called lang_reset_memory_regions after sizing. */ - if (s->output_section != NULL - && s->output_section->rawsize >= s->size) - s->output_section->rawsize -= s->size; - - s->size = 0; - - /* Also set SEC_EXCLUDE, so that local symbols defined in the - warning section don't get copied to the output. */ - s->flags |= SEC_EXCLUDE | SEC_KEEP; - } - } - - before_allocation_default (); - - if (!bfd_elf_size_dynsym_hash_dynstr (link_info.output_bfd, &link_info)) - einfo (_("%F%P: failed to set dynamic section sizes: %E\n")); - - if (ehdr_start != NULL) - { - /* If we twiddled __ehdr_start to defined earlier, put it back - as it was. */ - ehdr_start->type = ehdr_start_save_type; - memcpy ((char *) &ehdr_start->u + sizeof ehdr_start->u.def.next, - ehdr_start_save_u, - sizeof ehdr_start_save_u); - } + ldelf_before_allocation (audit, depaudit, ${ELF_INTERPRETER_NAME}); } EOF fi -if test x"$LDEMUL_OPEN_DYNAMIC_ARCHIVE" != xgld"$EMULATION_NAME"_open_dynamic_archive; then -fragment <<EOF - -/* Try to open a dynamic archive. This is where we know that ELF - dynamic libraries have an extension of .so (or .sl on oddball systems - like hpux). */ - -static bfd_boolean -gld${EMULATION_NAME}_open_dynamic_archive - (const char *arch, search_dirs_type *search, lang_input_statement_type *entry) -{ - const char *filename; - char *string; - size_t len; - bfd_boolean opened = FALSE; - - if (! entry->flags.maybe_archive) - return FALSE; - - filename = entry->filename; - len = strlen (search->name) + strlen (filename); - if (entry->flags.full_name_provided) - { - len += sizeof "/"; - string = (char *) xmalloc (len); - sprintf (string, "%s/%s", search->name, filename); - } - else - { - size_t xlen = 0; - - len += strlen (arch) + sizeof "/lib.so"; -#ifdef EXTRA_SHLIB_EXTENSION - xlen = (strlen (EXTRA_SHLIB_EXTENSION) > 3 - ? strlen (EXTRA_SHLIB_EXTENSION) - 3 - : 0); -#endif - string = (char *) xmalloc (len + xlen); - sprintf (string, "%s/lib%s%s.so", search->name, filename, arch); -#ifdef EXTRA_SHLIB_EXTENSION - /* Try the .so extension first. If that fails build a new filename - using EXTRA_SHLIB_EXTENSION. */ - opened = ldfile_try_open_bfd (string, entry); - if (!opened) - strcpy (string + len - 4, EXTRA_SHLIB_EXTENSION); -#endif - } - - if (!opened && !ldfile_try_open_bfd (string, entry)) - { - free (string); - return FALSE; - } - - entry->filename = string; - - /* We have found a dynamic object to include in the link. The ELF - backend linker will create a DT_NEEDED entry in the .dynamic - section naming this file. If this file includes a DT_SONAME - entry, it will be used. Otherwise, the ELF linker will just use - the name of the file. For an archive found by searching, like - this one, the DT_NEEDED entry should consist of just the name of - the file, without the path information used to find it. Note - that we only need to do this if we have a dynamic object; an - archive will never be referenced by a DT_NEEDED entry. - - FIXME: This approach--using bfd_elf_set_dt_needed_name--is not - very pretty. I haven't been able to think of anything that is - pretty, though. */ - if (bfd_check_format (entry->the_bfd, bfd_object) - && (entry->the_bfd->flags & DYNAMIC) != 0) - { - ASSERT (entry->flags.maybe_archive && entry->flags.search_dirs); - - /* Rather than duplicating the logic above. Just use the - filename we recorded earlier. */ - - if (!entry->flags.full_name_provided) - filename = lbasename (entry->filename); - bfd_elf_set_dt_needed_name (entry->the_bfd, filename); - } - - return TRUE; -} - -EOF -fi - -if test x"$LDEMUL_PLACE_ORPHAN" != xgld"$EMULATION_NAME"_place_orphan; then -fragment <<EOF - -/* A variant of lang_output_section_find used by place_orphan. */ - -static lang_output_section_statement_type * -output_rel_find (int isdyn, int rela) -{ - lang_output_section_statement_type *lookup; - lang_output_section_statement_type *last = NULL; - lang_output_section_statement_type *last_alloc = NULL; - lang_output_section_statement_type *last_ro_alloc = NULL; - lang_output_section_statement_type *last_rel = NULL; - lang_output_section_statement_type *last_rel_alloc = NULL; - - for (lookup = &lang_os_list.head->output_section_statement; - lookup != NULL; - lookup = lookup->next) - { - if (lookup->constraint >= 0 - && CONST_STRNEQ (lookup->name, ".rel")) - { - int lookrela = lookup->name[4] == 'a'; - - /* .rel.dyn must come before all other reloc sections, to suit - GNU ld.so. */ - if (isdyn) - break; - - /* Don't place after .rel.plt as doing so results in wrong - dynamic tags. */ - if (strcmp (".plt", lookup->name + 4 + lookrela) == 0) - break; - - if (rela == lookrela || last_rel == NULL) - last_rel = lookup; - if ((rela == lookrela || last_rel_alloc == NULL) - && lookup->bfd_section != NULL - && (lookup->bfd_section->flags & SEC_ALLOC) != 0) - last_rel_alloc = lookup; - } - - last = lookup; - if (lookup->bfd_section != NULL - && (lookup->bfd_section->flags & SEC_ALLOC) != 0) - { - last_alloc = lookup; - if ((lookup->bfd_section->flags & SEC_READONLY) != 0) - last_ro_alloc = lookup; - } - } - - if (last_rel_alloc) - return last_rel_alloc; - - if (last_rel) - return last_rel; - - if (last_ro_alloc) - return last_ro_alloc; - - if (last_alloc) - return last_alloc; - - return last; -} - -/* Return whether IN is suitable to be part of OUT. */ - -static bfd_boolean -elf_orphan_compatible (asection *in, asection *out) -{ - /* Non-zero sh_info implies a section with SHF_INFO_LINK with - unknown semantics for the generic linker, or a SHT_REL/SHT_RELA - section where sh_info specifies a symbol table. (We won't see - SHT_GROUP, SHT_SYMTAB or SHT_DYNSYM sections here.) We clearly - can't merge SHT_REL/SHT_RELA using differing symbol tables, and - shouldn't merge sections with differing unknown semantics. */ - if (elf_section_data (out)->this_hdr.sh_info - != elf_section_data (in)->this_hdr.sh_info) - return FALSE; - /* We can't merge with member of output section group nor merge two - sections with differing SHF_EXCLUDE when doing a relocatable link. - */ - if (bfd_link_relocatable (&link_info) - && (elf_next_in_group (out) != NULL - || ((elf_section_flags (out) ^ elf_section_flags (in)) - & SHF_EXCLUDE) != 0)) - return FALSE; - return _bfd_elf_match_sections_by_type (link_info.output_bfd, out, - in->owner, in); -} - -/* Place an orphan section. We use this to put random SHF_ALLOC - sections in the right segment. */ - -static lang_output_section_statement_type * -gld${EMULATION_NAME}_place_orphan (asection *s, - const char *secname, - int constraint) -{ - static struct orphan_save hold[] = - { - { ".text", - SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE, - 0, 0, 0, 0 }, - { ".rodata", - SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA, - 0, 0, 0, 0 }, - { ".tdata", - SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_THREAD_LOCAL, - 0, 0, 0, 0 }, - { ".data", - SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA, - 0, 0, 0, 0 }, - { ".bss", - SEC_ALLOC, - 0, 0, 0, 0 }, - { 0, - SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA, - 0, 0, 0, 0 }, - { ".interp", - SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA, - 0, 0, 0, 0 }, - { ".sdata", - SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_SMALL_DATA, - 0, 0, 0, 0 }, - { ".comment", - SEC_HAS_CONTENTS, - 0, 0, 0, 0 }, - }; - enum orphan_save_index - { - orphan_text = 0, - orphan_rodata, - orphan_tdata, - orphan_data, - orphan_bss, - orphan_rel, - orphan_interp, - orphan_sdata, - orphan_nonalloc - }; - static int orphan_init_done = 0; - struct orphan_save *place; - lang_output_section_statement_type *after; - lang_output_section_statement_type *os; - lang_output_section_statement_type *match_by_name = NULL; - int isdyn = 0; - int elfinput = s->owner->xvec->flavour == bfd_target_elf_flavour; - int elfoutput = link_info.output_bfd->xvec->flavour == bfd_target_elf_flavour; - unsigned int sh_type = elfinput ? elf_section_type (s) : SHT_NULL; - flagword flags; - asection *nexts; - - if (!bfd_link_relocatable (&link_info) - && link_info.combreloc - && (s->flags & SEC_ALLOC)) - { - if (elfinput) - switch (sh_type) - { - case SHT_RELA: - secname = ".rela.dyn"; - isdyn = 1; - break; - case SHT_REL: - secname = ".rel.dyn"; - isdyn = 1; - break; - default: - break; - } - else if (CONST_STRNEQ (secname, ".rel")) - { - secname = secname[4] == 'a' ? ".rela.dyn" : ".rel.dyn"; - isdyn = 1; - } - } - - if (!bfd_link_relocatable (&link_info) - && elfinput - && elfoutput - && (s->flags & SEC_ALLOC) != 0 - && (elf_tdata (s->owner)->has_gnu_osabi & elf_gnu_osabi_mbind) != 0 - && (elf_section_flags (s) & SHF_GNU_MBIND) != 0) - { - /* Find the output mbind section with the same type, attributes - and sh_info field. */ - for (os = &lang_os_list.head->output_section_statement; - os != NULL; - os = os->next) - if (os->bfd_section != NULL - && !bfd_is_abs_section (os->bfd_section) - && (elf_section_flags (os->bfd_section) & SHF_GNU_MBIND) != 0 - && ((s->flags & (SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_READONLY - | SEC_CODE)) - == (os->bfd_section->flags & (SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_READONLY - | SEC_CODE))) - && (elf_section_data (os->bfd_section)->this_hdr.sh_info - == elf_section_data (s)->this_hdr.sh_info)) - { - lang_add_section (&os->children, s, NULL, os); - return os; - } - - /* Create the output mbind section with the ".mbind." prefix - in section name. */ - if ((s->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0) - secname = ".mbind.bss"; - else if ((s->flags & SEC_READONLY) == 0) - secname = ".mbind.data"; - else if ((s->flags & SEC_CODE) == 0) - secname = ".mbind.rodata"; - else - secname = ".mbind.text"; - elf_tdata (link_info.output_bfd)->has_gnu_osabi |= elf_gnu_osabi_mbind; - } - - /* Look through the script to see where to place this section. The - script includes entries added by previous lang_insert_orphan - calls, so this loop puts multiple compatible orphans of the same - name into a single output section. */ - if (constraint == 0) - for (os = lang_output_section_find (secname); - os != NULL; - os = next_matching_output_section_statement (os, 0)) - { - /* If we don't match an existing output section, tell - lang_insert_orphan to create a new output section. */ - constraint = SPECIAL; - - /* Check to see if we already have an output section statement - with this name, and its bfd section has compatible flags. - If the section already exists but does not have any flags - set, then it has been created by the linker, possibly as a - result of a --section-start command line switch. */ - if (os->bfd_section != NULL - && (os->bfd_section->flags == 0 - || (((s->flags ^ os->bfd_section->flags) - & (SEC_LOAD | SEC_ALLOC)) == 0 - && (!elfinput - || !elfoutput - || elf_orphan_compatible (s, os->bfd_section))))) - { - lang_add_section (&os->children, s, NULL, os); - return os; - } - - /* Save unused output sections in case we can match them - against orphans later. */ - if (os->bfd_section == NULL) - match_by_name = os; - } - - /* If we didn't match an active output section, see if we matched an - unused one and use that. */ - if (match_by_name) - { - lang_add_section (&match_by_name->children, s, NULL, match_by_name); - return match_by_name; - } - - if (!orphan_init_done) - { - struct orphan_save *ho; - - for (ho = hold; ho < hold + sizeof (hold) / sizeof (hold[0]); ++ho) - if (ho->name != NULL) - { - ho->os = lang_output_section_find (ho->name); - if (ho->os != NULL && ho->os->flags == 0) - ho->os->flags = ho->flags; - } - orphan_init_done = 1; - } - - /* If this is a final link, then always put .gnu.warning.SYMBOL - sections into the .text section to get them out of the way. */ - if (bfd_link_executable (&link_info) - && CONST_STRNEQ (s->name, ".gnu.warning.") - && hold[orphan_text].os != NULL) - { - os = hold[orphan_text].os; - lang_add_section (&os->children, s, NULL, os); - return os; - } - - flags = s->flags; - if (!bfd_link_relocatable (&link_info)) - { - nexts = s; - while ((nexts = bfd_get_next_section_by_name (nexts->owner, nexts)) - != NULL) - if (nexts->output_section == NULL - && (nexts->flags & SEC_EXCLUDE) == 0 - && ((nexts->flags ^ flags) & (SEC_LOAD | SEC_ALLOC)) == 0 - && (nexts->owner->flags & DYNAMIC) == 0 - && nexts->owner->usrdata != NULL - && !(((lang_input_statement_type *) nexts->owner->usrdata) - ->flags.just_syms) - && _bfd_elf_match_sections_by_type (nexts->owner, nexts, - s->owner, s)) - flags = (((flags ^ SEC_READONLY) - | (nexts->flags ^ SEC_READONLY)) - ^ SEC_READONLY); - } - - /* Decide which segment the section should go in based on the - section name and section flags. We put loadable .note sections - right after the .interp section, so that the PT_NOTE segment is - stored right after the program headers where the OS can read it - in the first page. */ - - place = NULL; - if ((flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0) - place = &hold[orphan_nonalloc]; - else if ((flags & SEC_ALLOC) == 0) - ; - else if ((flags & SEC_LOAD) != 0 - && (elfinput - ? sh_type == SHT_NOTE - : CONST_STRNEQ (secname, ".note"))) - place = &hold[orphan_interp]; - else if ((flags & (SEC_LOAD | SEC_HAS_CONTENTS | SEC_THREAD_LOCAL)) == 0) - place = &hold[orphan_bss]; - else if ((flags & SEC_SMALL_DATA) != 0) - place = &hold[orphan_sdata]; - else if ((flags & SEC_THREAD_LOCAL) != 0) - place = &hold[orphan_tdata]; - else if ((flags & SEC_READONLY) == 0) - place = &hold[orphan_data]; - else if ((flags & SEC_LOAD) != 0 - && (elfinput - ? sh_type == SHT_RELA || sh_type == SHT_REL - : CONST_STRNEQ (secname, ".rel"))) - place = &hold[orphan_rel]; - else if ((flags & SEC_CODE) == 0) - place = &hold[orphan_rodata]; - else - place = &hold[orphan_text]; - - after = NULL; - if (place != NULL) - { - if (place->os == NULL) - { - if (place->name != NULL) - place->os = lang_output_section_find (place->name); - else - { - int rela = elfinput ? sh_type == SHT_RELA : secname[4] == 'a'; - place->os = output_rel_find (isdyn, rela); - } - } - after = place->os; - if (after == NULL) - after - = lang_output_section_find_by_flags (s, flags, &place->os, - _bfd_elf_match_sections_by_type); - if (after == NULL) - /* *ABS* is always the first output section statement. */ - after = &lang_os_list.head->output_section_statement; - } - - return lang_insert_orphan (s, secname, constraint, after, place, NULL, NULL); -} -EOF -fi - if test x"$LDEMUL_AFTER_ALLOCATION" != xgld"$EMULATION_NAME"_after_allocation; then fragment <<EOF @@ -2334,7 +161,7 @@ gld${EMULATION_NAME}_after_allocation (void) if (need_layout < 0) einfo (_("%X%P: .eh_frame/.stab edit: %E\n")); else - gld${EMULATION_NAME}_map_segments (need_layout); + ldelf_map_segments (need_layout); } EOF fi @@ -2794,15 +621,15 @@ gld${EMULATION_NAME}_handle_option (int optc) return FALSE; case OPTION_BUILD_ID: - if (emit_note_gnu_build_id != NULL) + if (ldelf_emit_note_gnu_build_id != NULL) { - free ((char *) emit_note_gnu_build_id); - emit_note_gnu_build_id = NULL; + free ((char *) ldelf_emit_note_gnu_build_id); + ldelf_emit_note_gnu_build_id = NULL; } if (optarg == NULL) optarg = DEFAULT_BUILD_ID_STYLE; if (strcmp (optarg, "none")) - emit_note_gnu_build_id = xstrdup (optarg); + ldelf_emit_note_gnu_build_id = xstrdup (optarg); break; case OPTION_COMPRESS_DEBUG: @@ -2823,11 +650,11 @@ EOF if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then fragment <<EOF case OPTION_AUDIT: - gld${EMULATION_NAME}_append_to_separated_string (&audit, optarg); + ldelf_append_to_separated_string (&audit, optarg); break; case 'P': - gld${EMULATION_NAME}_append_to_separated_string (&depaudit, optarg); + ldelf_append_to_separated_string (&depaudit, optarg); break; case OPTION_DISABLE_NEW_DTAGS: @@ -3051,7 +878,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = ${LDEMUL_BEFORE_PARSE-gld${EMULATION_NAME}_before_parse}, ${LDEMUL_SYSLIB-syslib_default}, ${LDEMUL_HLL-hll_default}, - ${LDEMUL_AFTER_PARSE-gld${EMULATION_NAME}_after_parse}, + ${LDEMUL_AFTER_PARSE-ldelf_after_parse}, ${LDEMUL_AFTER_OPEN-gld${EMULATION_NAME}_after_open}, ${LDEMUL_AFTER_CHECK_RELOCS-after_check_relocs_default}, ${LDEMUL_AFTER_ALLOCATION-gld${EMULATION_NAME}_after_allocation}, @@ -3063,15 +890,15 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = "${OUTPUT_FORMAT}", ${LDEMUL_FINISH-finish_default}, ${LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS-NULL}, - ${LDEMUL_OPEN_DYNAMIC_ARCHIVE-gld${EMULATION_NAME}_open_dynamic_archive}, - ${LDEMUL_PLACE_ORPHAN-gld${EMULATION_NAME}_place_orphan}, + ${LDEMUL_OPEN_DYNAMIC_ARCHIVE-ldelf_open_dynamic_archive}, + ${LDEMUL_PLACE_ORPHAN-ldelf_place_orphan}, ${LDEMUL_SET_SYMBOLS-NULL}, ${LDEMUL_PARSE_ARGS-NULL}, gld${EMULATION_NAME}_add_options, gld${EMULATION_NAME}_handle_option, ${LDEMUL_UNRECOGNIZED_FILE-NULL}, ${LDEMUL_LIST_OPTIONS-${gld_list_options}}, - ${LDEMUL_RECOGNIZED_FILE-gld${EMULATION_NAME}_load_symbols}, + ${LDEMUL_RECOGNIZED_FILE-ldelf_load_symbols}, ${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL}, ${LDEMUL_NEW_VERS_PATTERN-NULL}, ${LDEMUL_EXTRA_MAP_FILE_TEXT-NULL} diff --git a/ld/emultempl/genelf.em b/ld/emultempl/genelf.em index 664a5b1..9c5898d 100644 --- a/ld/emultempl/genelf.em +++ b/ld/emultempl/genelf.em @@ -23,6 +23,7 @@ # fragment <<EOF #include "elf-bfd.h" +#include "ldelfgen.h" EOF source_em ${srcdir}/emultempl/elf-generic.em @@ -63,7 +64,7 @@ gld${EMULATION_NAME}_before_allocation (void) static void gld${EMULATION_NAME}_after_allocation (void) { - gld${EMULATION_NAME}_map_segments (FALSE); + ldelf_map_segments (FALSE); } EOF # Put these extra routines in ld_${EMULATION_NAME}_emulation diff --git a/ld/emultempl/hppaelf.em b/ld/emultempl/hppaelf.em index 3ae2bfd..547ab9b 100644 --- a/ld/emultempl/hppaelf.em +++ b/ld/emultempl/hppaelf.em @@ -59,7 +59,7 @@ hppaelf_after_parse (void) NULL); */ - gld${EMULATION_NAME}_after_parse (); + ldelf_after_parse (); } /* This is called before the input files are opened. We create a new @@ -215,7 +215,7 @@ hppaelf_layout_sections_again (void) /* If we have changed sizes of the stub sections, then we need to recalculate all the section offsets. This may mean we need to add even more stubs. */ - gld${EMULATION_NAME}_map_segments (TRUE); + ldelf_map_segments (TRUE); need_laying_out = -1; } @@ -289,7 +289,7 @@ gld${EMULATION_NAME}_after_allocation (void) } if (need_laying_out != -1) - gld${EMULATION_NAME}_map_segments (need_laying_out); + ldelf_map_segments (need_laying_out); if (!bfd_link_relocatable (&link_info)) { @@ -309,27 +309,6 @@ gld${EMULATION_NAME}_after_allocation (void) } } - -/* Avoid processing the fake stub_file in vercheck, stat_needed and - check_needed routines. */ - -static void (*real_func) (lang_input_statement_type *); - -static void hppa_for_each_input_file_wrapper (lang_input_statement_type *l) -{ - if (l != stub_file) - (*real_func) (l); -} - -static void -hppa_lang_for_each_input_file (void (*func) (lang_input_statement_type *)) -{ - real_func = func; - lang_for_each_input_file (&hppa_for_each_input_file_wrapper); -} - -#define lang_for_each_input_file hppa_lang_for_each_input_file - EOF # Define some shell vars to insert bits of code into the standard elf diff --git a/ld/emultempl/ia64elf.em b/ld/emultempl/ia64elf.em index f9a0604..e67a04c 100644 --- a/ld/emultempl/ia64elf.em +++ b/ld/emultempl/ia64elf.em @@ -36,7 +36,7 @@ ia64elf_after_parse (void) link_info.relax_pass = 2; bfd_elf${ELFSIZE}_ia64_after_parse (itanium); - gld${EMULATION_NAME}_after_parse (); + ldelf_after_parse (); } EOF diff --git a/ld/emultempl/m68hc1xelf.em b/ld/emultempl/m68hc1xelf.em index 0dda5dd..3fa325a 100644 --- a/ld/emultempl/m68hc1xelf.em +++ b/ld/emultempl/m68hc1xelf.em @@ -319,27 +319,6 @@ m68hc11elf_after_allocation (void) gld${EMULATION_NAME}_after_allocation (); } - -/* Avoid processing the fake stub_file in vercheck, stat_needed and - check_needed routines. */ - -static void (*real_func) (lang_input_statement_type *); - -static void m68hc11_for_each_input_file_wrapper (lang_input_statement_type *l) -{ - if (l != stub_file) - (*real_func) (l); -} - -static void -m68hc11_lang_for_each_input_file (void (*func) (lang_input_statement_type *)) -{ - real_func = func; - lang_for_each_input_file (&m68hc11_for_each_input_file_wrapper); -} - -#define lang_for_each_input_file m68hc11_lang_for_each_input_file - EOF # Define some shell vars to insert bits of code into the standard elf diff --git a/ld/emultempl/metagelf.em b/ld/emultempl/metagelf.em index e989c58..966d19c 100644 --- a/ld/emultempl/metagelf.em +++ b/ld/emultempl/metagelf.em @@ -191,7 +191,7 @@ metagelf_layout_sections_again (void) /* If we have changed sizes of the stub sections, then we need to recalculate all the section offsets. This may mean we need to add even more stubs. */ - gld${EMULATION_NAME}_map_segments (TRUE); + ldelf_map_segments (TRUE); need_laying_out = -1; } @@ -264,7 +264,7 @@ gld${EMULATION_NAME}_after_allocation (void) } if (need_laying_out != -1) - gld${EMULATION_NAME}_map_segments (need_laying_out); + ldelf_map_segments (need_laying_out); if (!bfd_link_relocatable (&link_info)) { @@ -277,27 +277,6 @@ gld${EMULATION_NAME}_after_allocation (void) } } - -/* Avoid processing the fake stub_file in vercheck, stat_needed and - check_needed routines. */ - -static void (*real_func) (lang_input_statement_type *); - -static void metag_for_each_input_file_wrapper (lang_input_statement_type *l) -{ - if (l != stub_file) - (*real_func) (l); -} - -static void -metag_lang_for_each_input_file (void (*func) (lang_input_statement_type *)) -{ - real_func = func; - lang_for_each_input_file (&metag_for_each_input_file_wrapper); -} - -#define lang_for_each_input_file metag_lang_for_each_input_file - EOF # Define some shell vars to insert bits of code into the standard elf diff --git a/ld/emultempl/mipself.em b/ld/emultempl/mipself.em index fe46e0d..108d33f 100644 --- a/ld/emultempl/mipself.em +++ b/ld/emultempl/mipself.em @@ -227,26 +227,6 @@ mips_before_allocation (void) gld${EMULATION_NAME}_before_allocation (); } -/* Avoid processing the fake stub_file in vercheck, stat_needed and - check_needed routines. */ - -static void (*real_func) (lang_input_statement_type *); - -static void mips_for_each_input_file_wrapper (lang_input_statement_type *l) -{ - if (l != stub_file) - (*real_func) (l); -} - -static void -mips_lang_for_each_input_file (void (*func) (lang_input_statement_type *)) -{ - real_func = func; - lang_for_each_input_file (&mips_for_each_input_file_wrapper); -} - -#define lang_for_each_input_file mips_lang_for_each_input_file - EOF # Define some shell vars to insert bits of code into the standard elf diff --git a/ld/emultempl/mmo.em b/ld/emultempl/mmo.em index 3e24e36..b4b4f1e 100644 --- a/ld/emultempl/mmo.em +++ b/ld/emultempl/mmo.em @@ -29,11 +29,10 @@ fragment <<EOF #define gldmmo_before_allocation before_allocation_default /* We include this header *not* because we expect to handle ELF here - but because we re-use the map_segments function in elf-generic.em, - a file which is rightly somewhat ELF-centric. But this is only to + but because we use the map_segments function. But this is only to get a weird testcase right; ld-mmix/bpo-22, forcing ELF to be output from the mmo emulation: -m mmo --oformat elf64-mmix! */ -#include "elf-bfd.h" +#include "ldelfgen.h" static void gld${EMULATION_NAME}_after_allocation (void); EOF @@ -205,7 +204,7 @@ static void gld${EMULATION_NAME}_after_allocation (void) { bfd_map_over_sections (link_info.output_bfd, mmo_wipe_sec_reloc_flag, NULL); - gld${EMULATION_NAME}_map_segments (FALSE); + ldelf_map_segments (FALSE); } /* To get on-demand global register allocation right, we need to parse the diff --git a/ld/emultempl/nds32elf.em b/ld/emultempl/nds32elf.em index cf30cbc..00e9975 100644 --- a/ld/emultempl/nds32elf.em +++ b/ld/emultempl/nds32elf.em @@ -68,7 +68,7 @@ nds32_elf_after_parse (void) if (!RELAXATION_ENABLED) relax_fp_as_gp = 0; - gld${EMULATION_NAME}_after_parse (); + ldelf_after_parse (); } static void @@ -123,7 +123,7 @@ nds32_elf_after_allocation (void) { /* Call default after allocation callback. 1. This is where relaxation is done. - 2. It calls gld${EMULATION_NAME}_map_segments to build ELF segment table. + 2. It calls ldelf_map_segments to build ELF segment table. 3. Any relaxation requires relax being done must be called after it. */ gld${EMULATION_NAME}_after_allocation (); } diff --git a/ld/emultempl/nios2elf.em b/ld/emultempl/nios2elf.em index 0f19525..676c1fb 100644 --- a/ld/emultempl/nios2elf.em +++ b/ld/emultempl/nios2elf.em @@ -208,7 +208,7 @@ nios2elf_layout_sections_again (void) /* If we have changed sizes of the stub sections, then we need to recalculate all the section offsets. This may mean we need to add even more stubs. */ - gld${EMULATION_NAME}_map_segments (TRUE); + ldelf_map_segments (TRUE); need_laying_out = -1; } @@ -282,7 +282,7 @@ gld${EMULATION_NAME}_after_allocation (void) } if (need_laying_out != -1) - gld${EMULATION_NAME}_map_segments (need_laying_out); + ldelf_map_segments (need_laying_out); if (!bfd_link_relocatable (&link_info) && RELAXATION_ENABLED) { @@ -295,27 +295,6 @@ gld${EMULATION_NAME}_after_allocation (void) } } - -/* Avoid processing the fake stub_file in vercheck, stat_needed and - check_needed routines. */ - -static void (*real_func) (lang_input_statement_type *); - -static void nios2_for_each_input_file_wrapper (lang_input_statement_type *l) -{ - if (l != stub_file) - (*real_func) (l); -} - -static void -nios2_lang_for_each_input_file (void (*func) (lang_input_statement_type *)) -{ - real_func = func; - lang_for_each_input_file (&nios2_for_each_input_file_wrapper); -} - -#define lang_for_each_input_file nios2_lang_for_each_input_file - EOF diff --git a/ld/emultempl/ppc32elf.em b/ld/emultempl/ppc32elf.em index 24a6368..eb75373 100644 --- a/ld/emultempl/ppc32elf.em +++ b/ld/emultempl/ppc32elf.em @@ -247,7 +247,6 @@ if grep -q 'ld_elf32_spu_emulation' ldemul-list.h; then fragment <<EOF /* Special handling for embedded SPU executables. */ extern bfd_boolean embedded_spu_file (lang_input_statement_type *, const char *); -static bfd_boolean gld${EMULATION_NAME}_load_symbols (lang_input_statement_type *); static bfd_boolean ppc_recognized_file (lang_input_statement_type *entry) @@ -255,7 +254,7 @@ ppc_recognized_file (lang_input_statement_type *entry) if (embedded_spu_file (entry, "-m32")) return TRUE; - return gld${EMULATION_NAME}_load_symbols (entry); + return ldelf_load_symbols (entry); } EOF diff --git a/ld/emultempl/ppc64elf.em b/ld/emultempl/ppc64elf.em index 2a354ba..ef1fd0e 100644 --- a/ld/emultempl/ppc64elf.em +++ b/ld/emultempl/ppc64elf.em @@ -456,7 +456,7 @@ ppc_layout_sections_again (void) /* If we have changed sizes of the stub sections, then we need to recalculate all the section offsets. This may mean we need to add even more stubs. */ - gld${EMULATION_NAME}_map_segments (TRUE); + ldelf_map_segments (TRUE); if (!bfd_link_relocatable (&link_info)) ppc64_elf_set_toc (&link_info, link_info.output_bfd); @@ -565,7 +565,7 @@ gld${EMULATION_NAME}_after_allocation (void) unneeded, after ppc_layout_sections_again. Another call removes these sections from the segment map. Their presence is innocuous except for confusing ELF_SECTION_IN_SEGMENT. */ - gld${EMULATION_NAME}_map_segments (need_laying_out > 0); + ldelf_map_segments (need_laying_out > 0); if (need_laying_out != -1 && !bfd_link_relocatable (&link_info)) ppc64_elf_set_toc (&link_info, link_info.output_bfd); @@ -652,34 +652,12 @@ gld${EMULATION_NAME}_new_vers_pattern (struct bfd_elf_version_expr *entry) return dot_entry; } - -/* Avoid processing the fake stub_file in vercheck, stat_needed and - check_needed routines. */ - -static void (*real_func) (lang_input_statement_type *); - -static void ppc_for_each_input_file_wrapper (lang_input_statement_type *l) -{ - if (l != stub_file) - (*real_func) (l); -} - -static void -ppc_lang_for_each_input_file (void (*func) (lang_input_statement_type *)) -{ - real_func = func; - lang_for_each_input_file (&ppc_for_each_input_file_wrapper); -} - -#define lang_for_each_input_file ppc_lang_for_each_input_file - EOF if grep -q 'ld_elf32_spu_emulation' ldemul-list.h; then fragment <<EOF /* Special handling for embedded SPU executables. */ extern bfd_boolean embedded_spu_file (lang_input_statement_type *, const char *); -static bfd_boolean gld${EMULATION_NAME}_load_symbols (lang_input_statement_type *); static bfd_boolean ppc64_recognized_file (lang_input_statement_type *entry) @@ -687,7 +665,7 @@ ppc64_recognized_file (lang_input_statement_type *entry) if (embedded_spu_file (entry, "-m64")) return TRUE; - return gld${EMULATION_NAME}_load_symbols (entry); + return ldelf_load_symbols (entry); } EOF LDEMUL_RECOGNIZED_FILE=ppc64_recognized_file diff --git a/ld/emultempl/riscvelf.em b/ld/emultempl/riscvelf.em index 32f7584..ebc07df 100644 --- a/ld/emultempl/riscvelf.em +++ b/ld/emultempl/riscvelf.em @@ -62,7 +62,7 @@ gld${EMULATION_NAME}_after_allocation (void) } } - gld${EMULATION_NAME}_map_segments (need_layout); + ldelf_map_segments (need_layout); } /* This is a convenient point to tell BFD about target specific flags. diff --git a/ld/emultempl/spuelf.em b/ld/emultempl/spuelf.em index 5ddf41c..54f9f8f 100644 --- a/ld/emultempl/spuelf.em +++ b/ld/emultempl/spuelf.em @@ -142,7 +142,7 @@ spu_place_special_section (asection *s, asection *o, const char *output_name) os = lang_output_section_find (output_name); if (os == NULL) { - os = gld${EMULATION_NAME}_place_orphan (s, output_name, 0); + os = ldelf_place_orphan (s, output_name, 0); os->addr_tree = NULL; } else if (params.ovly_flavour != ovly_soft_icache diff --git a/ld/emultempl/tic6xdsbt.em b/ld/emultempl/tic6xdsbt.em index 29b90e5..a6e2792 100644 --- a/ld/emultempl/tic6xdsbt.em +++ b/ld/emultempl/tic6xdsbt.em @@ -159,7 +159,7 @@ gld${EMULATION_NAME}_after_allocation (void) else if (ret > 0) layout_changed = 1; - gld${EMULATION_NAME}_map_segments (layout_changed); + ldelf_map_segments (layout_changed); } EOF diff --git a/ld/emultempl/vms.em b/ld/emultempl/vms.em index aadb327..c7e0b78 100644 --- a/ld/emultempl/vms.em +++ b/ld/emultempl/vms.em @@ -174,6 +174,7 @@ if test "$OUTPUT_FORMAT" = "elf64-ia64-vms"; then fragment <<EOF #include "elf-bfd.h" +#include "ldelfgen.h" EOF source_em ${srcdir}/emultempl/elf-generic.em @@ -212,7 +213,7 @@ gld${EMULATION_NAME}_after_allocation (void) if (need_layout < 0) einfo (_("%X%P: .eh_frame/.stab edit: %E\n")); else - gld${EMULATION_NAME}_map_segments (need_layout); + ldelf_map_segments (need_layout); } static void diff --git a/ld/ldelf.c b/ld/ldelf.c new file mode 100644 index 0000000..c88712f --- /dev/null +++ b/ld/ldelf.c @@ -0,0 +1,2135 @@ +/* ELF emulation code for targets using elf32.em. + Copyright (C) 1991-2019 Free Software Foundation, Inc. + + This file is part of the GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "sysdep.h" +#include "bfd.h" +#include "libiberty.h" +#include "filenames.h" +#include "ld.h" +#include "ldmain.h" +#include "ldmisc.h" +#include "ldexp.h" +#include "ldlang.h" +#include "ldfile.h" +#include "ldemul.h" +#include "ldbuildid.h" +#include <ldgram.h> +#include "elf-bfd.h" +#ifdef HAVE_GLOB +#include <glob.h> +#endif +#include "ldelf.h" + +struct dt_needed +{ + bfd *by; + const char *name; +}; + +/* Style of .note.gnu.build-id section. */ +const char *ldelf_emit_note_gnu_build_id; + +/* These variables are required to pass information back and forth + between after_open and check_needed and stat_needed and vercheck. */ + +static struct bfd_link_needed_list *global_needed; +static lang_input_statement_type *global_found; +static struct stat global_stat; +static struct bfd_link_needed_list *global_vercheck_needed; +static bfd_boolean global_vercheck_failed; + +void +ldelf_after_parse (void) +{ + if (bfd_link_pie (&link_info)) + link_info.flags_1 |= (bfd_vma) DF_1_PIE; + + if (bfd_link_executable (&link_info) + && link_info.nointerp) + { + if (link_info.dynamic_undefined_weak > 0) + einfo (_("%P: warning: -z dynamic-undefined-weak ignored\n")); + link_info.dynamic_undefined_weak = 0; + } + after_parse_default (); +} + +/* Handle the generation of DT_NEEDED tags. */ + +bfd_boolean +ldelf_load_symbols (lang_input_statement_type *entry) +{ + int link_class = 0; + + /* Tell the ELF linker that we don't want the output file to have a + DT_NEEDED entry for this file, unless it is used to resolve + references in a regular object. */ + if (entry->flags.add_DT_NEEDED_for_regular) + link_class = DYN_AS_NEEDED; + + /* Tell the ELF linker that we don't want the output file to have a + DT_NEEDED entry for any dynamic library in DT_NEEDED tags from + this file at all. */ + if (!entry->flags.add_DT_NEEDED_for_dynamic) + link_class |= DYN_NO_ADD_NEEDED; + + if (entry->flags.just_syms + && (bfd_get_file_flags (entry->the_bfd) & DYNAMIC) != 0) + einfo (_("%F%P: %pB: --just-symbols may not be used on DSO\n"), + entry->the_bfd); + + if (link_class == 0 + || (bfd_get_file_flags (entry->the_bfd) & DYNAMIC) == 0) + return FALSE; + + bfd_elf_set_dyn_lib_class (entry->the_bfd, + (enum dynamic_lib_link_class) link_class); + + /* Continue on with normal load_symbols processing. */ + return FALSE; +} + +/* On Linux, it's possible to have different versions of the same + shared library linked against different versions of libc. The + dynamic linker somehow tags which libc version to use in + /etc/ld.so.cache, and, based on the libc that it sees in the + executable, chooses which version of the shared library to use. + + We try to do a similar check here by checking whether this shared + library needs any other shared libraries which may conflict with + libraries we have already included in the link. If it does, we + skip it, and try to find another shared library farther on down the + link path. + + This is called via lang_for_each_input_file. + GLOBAL_VERCHECK_NEEDED is the list of objects needed by the object + which we are checking. This sets GLOBAL_VERCHECK_FAILED if we find + a conflicting version. */ + +static void +ldelf_vercheck (lang_input_statement_type *s) +{ + const char *soname; + struct bfd_link_needed_list *l; + + if (global_vercheck_failed) + return; + if (s->the_bfd == NULL + || (bfd_get_file_flags (s->the_bfd) & DYNAMIC) == 0) + return; + + soname = bfd_elf_get_dt_soname (s->the_bfd); + if (soname == NULL) + soname = lbasename (bfd_get_filename (s->the_bfd)); + + for (l = global_vercheck_needed; l != NULL; l = l->next) + { + const char *suffix; + + if (filename_cmp (soname, l->name) == 0) + { + /* Probably can't happen, but it's an easy check. */ + continue; + } + + if (strchr (l->name, '/') != NULL) + continue; + + suffix = strstr (l->name, ".so."); + if (suffix == NULL) + continue; + + suffix += sizeof ".so." - 1; + + if (filename_ncmp (soname, l->name, suffix - l->name) == 0) + { + /* Here we know that S is a dynamic object FOO.SO.VER1, and + the object we are considering needs a dynamic object + FOO.SO.VER2, and VER1 and VER2 are different. This + appears to be a version mismatch, so we tell the caller + to try a different version of this library. */ + global_vercheck_failed = TRUE; + return; + } + } +} + + +/* See if an input file matches a DT_NEEDED entry by running stat on + the file. */ + +static void +ldelf_stat_needed (lang_input_statement_type *s) +{ + struct stat st; + const char *suffix; + const char *soname; + + if (global_found != NULL) + return; + if (s->the_bfd == NULL) + return; + + /* If this input file was an as-needed entry, and wasn't found to be + needed at the stage it was linked, then don't say we have loaded it. */ + if ((bfd_elf_get_dyn_lib_class (s->the_bfd) & DYN_AS_NEEDED) != 0) + return; + + if (bfd_stat (s->the_bfd, &st) != 0) + { + einfo (_("%P: %pB: bfd_stat failed: %E\n"), s->the_bfd); + return; + } + + /* Some operating systems, e.g. Windows, do not provide a meaningful + st_ino; they always set it to zero. (Windows does provide a + meaningful st_dev.) Do not indicate a duplicate library in that + case. While there is no guarantee that a system that provides + meaningful inode numbers will never set st_ino to zero, this is + merely an optimization, so we do not need to worry about false + negatives. */ + if (st.st_dev == global_stat.st_dev + && st.st_ino == global_stat.st_ino + && st.st_ino != 0) + { + global_found = s; + return; + } + + /* We issue a warning if it looks like we are including two + different versions of the same shared library. For example, + there may be a problem if -lc picks up libc.so.6 but some other + shared library has a DT_NEEDED entry of libc.so.5. This is a + heuristic test, and it will only work if the name looks like + NAME.so.VERSION. FIXME: Depending on file names is error-prone. + If we really want to issue warnings about mixing version numbers + of shared libraries, we need to find a better way. */ + + if (strchr (global_needed->name, '/') != NULL) + return; + suffix = strstr (global_needed->name, ".so."); + if (suffix == NULL) + return; + suffix += sizeof ".so." - 1; + + soname = bfd_elf_get_dt_soname (s->the_bfd); + if (soname == NULL) + soname = lbasename (s->filename); + + if (filename_ncmp (soname, global_needed->name, + suffix - global_needed->name) == 0) + einfo (_("%P: warning: %s, needed by %pB, may conflict with %s\n"), + global_needed->name, global_needed->by, soname); +} + +/* This function is called for each possible name for a dynamic object + named by a DT_NEEDED entry. The FORCE parameter indicates whether + to skip the check for a conflicting version. */ + +static bfd_boolean +ldelf_try_needed (struct dt_needed *needed, int force, int is_linux) +{ + bfd *abfd; + const char *name = needed->name; + const char *soname; + int link_class; + + abfd = bfd_openr (name, bfd_get_target (link_info.output_bfd)); + if (abfd == NULL) + { + if (verbose) + info_msg (_("attempt to open %s failed\n"), name); + return FALSE; + } + + /* Linker needs to decompress sections. */ + abfd->flags |= BFD_DECOMPRESS; + + if (! bfd_check_format (abfd, bfd_object)) + { + bfd_close (abfd); + return FALSE; + } + if ((bfd_get_file_flags (abfd) & DYNAMIC) == 0) + { + bfd_close (abfd); + return FALSE; + } + + /* For DT_NEEDED, they have to match. */ + if (abfd->xvec != link_info.output_bfd->xvec) + { + bfd_close (abfd); + return FALSE; + } + + /* Check whether this object would include any conflicting library + versions. If FORCE is set, then we skip this check; we use this + the second time around, if we couldn't find any compatible + instance of the shared library. */ + + if (!force) + { + struct bfd_link_needed_list *needs; + + if (! bfd_elf_get_bfd_needed_list (abfd, &needs)) + einfo (_("%F%P: %pB: bfd_elf_get_bfd_needed_list failed: %E\n"), abfd); + + if (needs != NULL) + { + global_vercheck_needed = needs; + global_vercheck_failed = FALSE; + lang_for_each_input_file (ldelf_vercheck); + if (global_vercheck_failed) + { + bfd_close (abfd); + /* Return FALSE to force the caller to move on to try + another file on the search path. */ + return FALSE; + } + + /* But wait! It gets much worse. On Linux, if a shared + library does not use libc at all, we are supposed to skip + it the first time around in case we encounter a shared + library later on with the same name which does use the + version of libc that we want. This is much too horrible + to use on any system other than Linux. */ + if (is_linux) + { + struct bfd_link_needed_list *l; + + for (l = needs; l != NULL; l = l->next) + if (CONST_STRNEQ (l->name, "libc.so")) + break; + if (l == NULL) + { + bfd_close (abfd); + return FALSE; + } + } + } + } + + /* We've found a dynamic object matching the DT_NEEDED entry. */ + + /* We have already checked that there is no other input file of the + same name. We must now check again that we are not including the + same file twice. We need to do this because on many systems + libc.so is a symlink to, e.g., libc.so.1. The SONAME entry will + reference libc.so.1. If we have already included libc.so, we + don't want to include libc.so.1 if they are the same file, and we + can only check that using stat. */ + + if (bfd_stat (abfd, &global_stat) != 0) + einfo (_("%F%P: %pB: bfd_stat failed: %E\n"), abfd); + + /* First strip off everything before the last '/'. */ + soname = lbasename (bfd_get_filename (abfd)); + + if (verbose) + info_msg (_("found %s at %s\n"), soname, name); + + global_found = NULL; + lang_for_each_input_file (ldelf_stat_needed); + if (global_found != NULL) + { + /* Return TRUE to indicate that we found the file, even though + we aren't going to do anything with it. */ + return TRUE; + } + + /* Specify the soname to use. */ + bfd_elf_set_dt_needed_name (abfd, soname); + + /* Tell the ELF linker that we don't want the output file to have a + DT_NEEDED entry for this file, unless it is used to resolve + references in a regular object. */ + link_class = DYN_DT_NEEDED; + + /* Tell the ELF linker that we don't want the output file to have a + DT_NEEDED entry for this file at all if the entry is from a file + with DYN_NO_ADD_NEEDED. */ + if (needed->by != NULL + && (bfd_elf_get_dyn_lib_class (needed->by) & DYN_NO_ADD_NEEDED) != 0) + link_class |= DYN_NO_NEEDED | DYN_NO_ADD_NEEDED; + + bfd_elf_set_dyn_lib_class (abfd, (enum dynamic_lib_link_class) link_class); + + /* Add this file into the symbol table. */ + if (! bfd_link_add_symbols (abfd, &link_info)) + einfo (_("%F%P: %pB: error adding symbols: %E\n"), abfd); + + return TRUE; +} + +/* Search for a needed file in a path. */ + +static bfd_boolean +ldelf_search_needed (const char *path, struct dt_needed *n, int force, + int is_linux, int elfsize) +{ + const char *s; + const char *name = n->name; + size_t len; + struct dt_needed needed; + + if (name[0] == '/') + return ldelf_try_needed (n, force, is_linux); + + if (path == NULL || *path == '\0') + return FALSE; + + needed.by = n->by; + needed.name = n->name; + + len = strlen (name); + while (1) + { + unsigned offset = 0; + char * var; + char *filename, *sset; + + s = strchr (path, config.rpath_separator); + if (s == NULL) + s = path + strlen (path); + +#if HAVE_DOS_BASED_FILE_SYSTEM + /* Assume a match on the second char is part of drive specifier. */ + else if (config.rpath_separator == ':' + && s == path + 1 + && ISALPHA (*path)) + { + s = strchr (s + 1, config.rpath_separator); + if (s == NULL) + s = path + strlen (path); + } +#endif + filename = (char *) xmalloc (s - path + len + 2); + if (s == path) + sset = filename; + else + { + memcpy (filename, path, s - path); + filename[s - path] = '/'; + sset = filename + (s - path) + 1; + } + strcpy (sset, name); + + /* PR 20535: Support the same pseudo-environment variables that + are supported by ld.so. Namely, $ORIGIN, $LIB and $PLATFORM. + Since there can be more than one occurrence of these tokens in + the path we loop until no more are found. Since we might not + be able to substitute some of the tokens we maintain an offset + into the filename for where we should begin our scan. */ + while ((var = strchr (filename + offset, '$')) != NULL) + { + /* The ld.so manual page does not say, but I am going to assume that + these tokens are terminated by a directory separator character + (/) or the end of the string. There is also an implication that + $ORIGIN should only be used at the start of a path, but that is + not enforced here. + + The ld.so manual page also states that it allows ${ORIGIN}, + ${LIB} and ${PLATFORM}, so these are supported as well. + + FIXME: The code could be a lot cleverer about allocating space + for the processed string. */ + char * end = strchr (var, '/'); + const char *replacement = NULL; + char * v = var + 1; + char * freeme = NULL; + unsigned flen = strlen (filename); + + if (end != NULL) + /* Temporarily terminate the filename at the end of the token. */ + * end = 0; + + if (*v == '{') + ++ v; + switch (*v++) + { + case 'O': + if (strcmp (v, "RIGIN") == 0 || strcmp (v, "RIGIN}") == 0) + { + /* ORIGIN - replace with the full path to the directory + containing the program or shared object. */ + if (needed.by == NULL) + { + if (link_info.output_bfd == NULL) + { + break; + } + else + replacement = bfd_get_filename (link_info.output_bfd); + } + else + replacement = bfd_get_filename (needed.by); + + if (replacement) + { + char * slash; + + if (replacement[0] == '/') + freeme = xstrdup (replacement); + else + { + char * current_dir = getpwd (); + + freeme = xmalloc (strlen (replacement) + + strlen (current_dir) + 2); + sprintf (freeme, "%s/%s", current_dir, replacement); + } + + replacement = freeme; + if ((slash = strrchr (replacement, '/')) != NULL) + * slash = 0; + } + } + break; + + case 'L': + if (strcmp (v, "IB") == 0 || strcmp (v, "IB}") == 0) + { + /* LIB - replace with "lib" in 32-bit environments + and "lib64" in 64-bit environments. */ + + switch (elfsize) + { + case 32: replacement = "lib"; break; + case 64: replacement = "lib64"; break; + default: + abort (); + } + } + break; + + case 'P': + /* Supporting $PLATFORM in a cross-hosted environment is not + possible. Supporting it in a native environment involves + loading the <sys/auxv.h> header file which loads the + system <elf.h> header file, which conflicts with the + "include/elf/mips.h" header file. */ + /* Fall through. */ + default: + break; + } + + if (replacement) + { + char * filename2 = xmalloc (flen + strlen (replacement)); + + if (end) + { + sprintf (filename2, "%.*s%s/%s", + (int)(var - filename), filename, + replacement, end + 1); + offset = (var - filename) + 1 + strlen (replacement); + } + else + { + sprintf (filename2, "%.*s%s", + (int)(var - filename), filename, + replacement); + offset = var - filename + strlen (replacement); + } + + free (filename); + filename = filename2; + /* There is no need to restore the path separator (when + end != NULL) as we have replaced the entire string. */ + } + else + { + if (verbose) + /* We only issue an "unrecognised" message in verbose mode + as the $<foo> token might be a legitimate component of + a path name in the target's file system. */ + info_msg (_("unrecognised or unsupported token " + "'%s' in search path\n"), var); + if (end) + /* Restore the path separator. */ + * end = '/'; + + /* PR 20784: Make sure that we resume the scan *after* + the token that we could not replace. */ + offset = (var + 1) - filename; + } + + free (freeme); + } + + needed.name = filename; + + if (ldelf_try_needed (&needed, force, is_linux)) + return TRUE; + + free (filename); + + if (*s == '\0') + break; + path = s + 1; + } + + return FALSE; +} + +/* Prefix the sysroot to absolute paths in PATH, a string containing + paths separated by config.rpath_separator. If running on a DOS + file system, paths containing a drive spec won't have the sysroot + prefix added, unless the sysroot also specifies the same drive. */ + +static const char * +ldelf_add_sysroot (const char *path) +{ + size_t len, extra; + const char *p; + char *ret, *q; + int dos_drive_sysroot = HAS_DRIVE_SPEC (ld_sysroot); + + len = strlen (ld_sysroot); + for (extra = 0, p = path; ; ) + { + int dos_drive = HAS_DRIVE_SPEC (p); + + if (dos_drive) + p += 2; + if (IS_DIR_SEPARATOR (*p) + && (!dos_drive + || (dos_drive_sysroot + && ld_sysroot[0] == p[-2]))) + { + if (dos_drive && dos_drive_sysroot) + extra += len - 2; + else + extra += len; + } + p = strchr (p, config.rpath_separator); + if (!p) + break; + ++p; + } + + ret = xmalloc (strlen (path) + extra + 1); + + for (q = ret, p = path; ; ) + { + const char *end; + int dos_drive = HAS_DRIVE_SPEC (p); + + if (dos_drive) + { + *q++ = *p++; + *q++ = *p++; + } + if (IS_DIR_SEPARATOR (*p) + && (!dos_drive + || (dos_drive_sysroot + && ld_sysroot[0] == p[-2]))) + { + if (dos_drive && dos_drive_sysroot) + { + strcpy (q, ld_sysroot + 2); + q += len - 2; + } + else + { + strcpy (q, ld_sysroot); + q += len; + } + } + end = strchr (p, config.rpath_separator); + if (end) + { + size_t n = end - p + 1; + strncpy (q, p, n); + q += n; + p += n; + } + else + { + strcpy (q, p); + break; + } + } + + return ret; +} + +/* Read the system search path the FreeBSD way rather than the Linux way. */ +#ifdef HAVE_ELF_HINTS_H +#include <elf-hints.h> +#else +#include "elf-hints-local.h" +#endif + +static bfd_boolean +ldelf_check_ld_elf_hints (const struct bfd_link_needed_list *l, int force, + int elfsize) +{ + static bfd_boolean initialized; + static const char *ld_elf_hints; + struct dt_needed needed; + + if (!initialized) + { + FILE *f; + char *tmppath; + + tmppath = concat (ld_sysroot, _PATH_ELF_HINTS, (const char *) NULL); + f = fopen (tmppath, FOPEN_RB); + free (tmppath); + if (f != NULL) + { + struct elfhints_hdr hdr; + + if (fread (&hdr, 1, sizeof (hdr), f) == sizeof (hdr) + && hdr.magic == ELFHINTS_MAGIC + && hdr.version == 1) + { + if (fseek (f, hdr.strtab + hdr.dirlist, SEEK_SET) != -1) + { + char *b; + + b = xmalloc (hdr.dirlistlen + 1); + if (fread (b, 1, hdr.dirlistlen + 1, f) == + hdr.dirlistlen + 1) + ld_elf_hints = ldelf_add_sysroot (b); + + free (b); + } + } + fclose (f); + } + + initialized = TRUE; + } + + if (ld_elf_hints == NULL) + return FALSE; + + needed.by = l->by; + needed.name = l->name; + return ldelf_search_needed (ld_elf_hints, &needed, force, FALSE, elfsize); +} + +/* For a native linker, check the file /etc/ld.so.conf for directories + in which we may find shared libraries. /etc/ld.so.conf is really + only meaningful on Linux. */ + +struct ldelf_ld_so_conf +{ + char *path; + size_t len, alloc; +}; + +static bfd_boolean +ldelf_parse_ld_so_conf (struct ldelf_ld_so_conf *, const char *); + +static void +ldelf_parse_ld_so_conf_include (struct ldelf_ld_so_conf *info, + const char *filename, + const char *pattern) +{ + char *newp = NULL; +#ifdef HAVE_GLOB + glob_t gl; +#endif + + if (pattern[0] != '/') + { + char *p = strrchr (filename, '/'); + size_t patlen = strlen (pattern) + 1; + + newp = xmalloc (p - filename + 1 + patlen); + memcpy (newp, filename, p - filename + 1); + memcpy (newp + (p - filename + 1), pattern, patlen); + pattern = newp; + } + +#ifdef HAVE_GLOB + if (glob (pattern, 0, NULL, &gl) == 0) + { + size_t i; + + for (i = 0; i < gl.gl_pathc; ++i) + ldelf_parse_ld_so_conf (info, gl.gl_pathv[i]); + globfree (&gl); + } +#else + /* If we do not have glob, treat the pattern as a literal filename. */ + ldelf_parse_ld_so_conf (info, pattern); +#endif + + if (newp) + free (newp); +} + +static bfd_boolean +ldelf_parse_ld_so_conf (struct ldelf_ld_so_conf *info, const char *filename) +{ + FILE *f = fopen (filename, FOPEN_RT); + char *line; + size_t linelen; + + if (f == NULL) + return FALSE; + + linelen = 256; + line = xmalloc (linelen); + do + { + char *p = line, *q; + + /* Normally this would use getline(3), but we need to be portable. */ + while ((q = fgets (p, linelen - (p - line), f)) != NULL + && strlen (q) == linelen - (p - line) - 1 + && line[linelen - 2] != '\n') + { + line = xrealloc (line, 2 * linelen); + p = line + linelen - 1; + linelen += linelen; + } + + if (q == NULL && p == line) + break; + + p = strchr (line, '\n'); + if (p) + *p = '\0'; + + /* Because the file format does not know any form of quoting we + can search forward for the next '#' character and if found + make it terminating the line. */ + p = strchr (line, '#'); + if (p) + *p = '\0'; + + /* Remove leading whitespace. NUL is no whitespace character. */ + p = line; + while (*p == ' ' || *p == '\f' || *p == '\r' || *p == '\t' || *p == '\v') + ++p; + + /* If the line is blank it is ignored. */ + if (p[0] == '\0') + continue; + + if (CONST_STRNEQ (p, "include") && (p[7] == ' ' || p[7] == '\t')) + { + char *dir, c; + p += 8; + do + { + while (*p == ' ' || *p == '\t') + ++p; + + if (*p == '\0') + break; + + dir = p; + + while (*p != ' ' && *p != '\t' && *p) + ++p; + + c = *p; + *p++ = '\0'; + if (dir[0] != '\0') + ldelf_parse_ld_so_conf_include (info, filename, dir); + } + while (c != '\0'); + } + else + { + char *dir = p; + while (*p && *p != '=' && *p != ' ' && *p != '\t' && *p != '\f' + && *p != '\r' && *p != '\v') + ++p; + + while (p != dir && p[-1] == '/') + --p; + if (info->path == NULL) + { + info->alloc = p - dir + 1 + 256; + info->path = xmalloc (info->alloc); + info->len = 0; + } + else + { + if (info->len + 1 + (p - dir) >= info->alloc) + { + info->alloc += p - dir + 256; + info->path = xrealloc (info->path, info->alloc); + } + info->path[info->len++] = config.rpath_separator; + } + memcpy (info->path + info->len, dir, p - dir); + info->len += p - dir; + info->path[info->len] = '\0'; + } + } + while (! feof (f)); + free (line); + fclose (f); + return TRUE; +} + +static bfd_boolean +ldelf_check_ld_so_conf (const struct bfd_link_needed_list *l, int force, + int elfsize) +{ + static bfd_boolean initialized; + static const char *ld_so_conf; + struct dt_needed needed; + + if (! initialized) + { + char *tmppath; + struct ldelf_ld_so_conf info; + + info.path = NULL; + info.len = info.alloc = 0; + tmppath = concat (ld_sysroot, "${prefix}/etc/ld.so.conf", + (const char *) NULL); + if (!ldelf_parse_ld_so_conf (&info, tmppath)) + { + free (tmppath); + tmppath = concat (ld_sysroot, "/etc/ld.so.conf", + (const char *) NULL); + ldelf_parse_ld_so_conf (&info, tmppath); + } + free (tmppath); + + if (info.path) + { + ld_so_conf = ldelf_add_sysroot (info.path); + free (info.path); + } + initialized = TRUE; + } + + if (ld_so_conf == NULL) + return FALSE; + + + needed.by = l->by; + needed.name = l->name; + return ldelf_search_needed (ld_so_conf, &needed, force, TRUE, elfsize); +} + +/* See if an input file matches a DT_NEEDED entry by name. */ + +static void +ldelf_check_needed (lang_input_statement_type *s) +{ + const char *soname; + + /* Stop looking if we've found a loaded lib. */ + if (global_found != NULL + && (bfd_elf_get_dyn_lib_class (global_found->the_bfd) + & DYN_AS_NEEDED) == 0) + return; + + if (s->filename == NULL || s->the_bfd == NULL) + return; + + /* Don't look for a second non-loaded as-needed lib. */ + if (global_found != NULL + && (bfd_elf_get_dyn_lib_class (s->the_bfd) & DYN_AS_NEEDED) != 0) + return; + + if (filename_cmp (s->filename, global_needed->name) == 0) + { + global_found = s; + return; + } + + if (s->flags.search_dirs) + { + const char *f = strrchr (s->filename, '/'); + if (f != NULL + && filename_cmp (f + 1, global_needed->name) == 0) + { + global_found = s; + return; + } + } + + soname = bfd_elf_get_dt_soname (s->the_bfd); + if (soname != NULL + && filename_cmp (soname, global_needed->name) == 0) + { + global_found = s; + return; + } +} + +/* This is called after all the input files have been opened. */ + +void +ldelf_after_open (int use_libpath, int native, int is_linux, int is_freebsd, + int elfsize) +{ + struct bfd_link_needed_list *needed, *l; + struct elf_link_hash_table *htab; + asection *s; + bfd *abfd; + + after_open_default (); + + htab = elf_hash_table (&link_info); + if (!is_elf_hash_table (htab)) + return; + + if (command_line.out_implib_filename) + { + unlink_if_ordinary (command_line.out_implib_filename); + link_info.out_implib_bfd + = bfd_openw (command_line.out_implib_filename, + bfd_get_target (link_info.output_bfd)); + + if (link_info.out_implib_bfd == NULL) + { + einfo (_("%F%P: %s: can't open for writing: %E\n"), + command_line.out_implib_filename); + } + } + + if (ldelf_emit_note_gnu_build_id != NULL) + { + /* Find an ELF input. */ + for (abfd = link_info.input_bfds; + abfd != (bfd *) NULL; abfd = abfd->link.next) + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour + && bfd_count_sections (abfd) != 0 + && !((lang_input_statement_type *) abfd->usrdata)->flags.just_syms) + break; + + /* PR 10555: If there are no ELF input files do not try to + create a .note.gnu-build-id section. */ + if (abfd == NULL + || !ldelf_setup_build_id (abfd)) + { + free ((char *) ldelf_emit_note_gnu_build_id); + ldelf_emit_note_gnu_build_id = NULL; + } + } + + get_elf_backend_data (link_info.output_bfd)->setup_gnu_properties (&link_info); + + if (bfd_link_relocatable (&link_info)) + { + if (link_info.execstack == !link_info.noexecstack) + { + /* PR ld/16744: If "-z [no]execstack" has been specified on the + command line and we are perfoming a relocatable link then no + PT_GNU_STACK segment will be created and so the + linkinfo.[no]execstack values set in _handle_option() will have no + effect. Instead we create a .note.GNU-stack section in much the + same way as the assembler does with its --[no]execstack option. */ + flagword flags = SEC_READONLY | (link_info.execstack ? SEC_CODE : 0); + (void) bfd_make_section_with_flags (link_info.input_bfds, + ".note.GNU-stack", flags); + } + return; + } + + if (!link_info.traditional_format) + { + bfd *elfbfd = NULL; + bfd_boolean warn_eh_frame = FALSE; + int seen_type = 0; + + for (abfd = link_info.input_bfds; abfd; abfd = abfd->link.next) + { + int type = 0; + + if (((lang_input_statement_type *) abfd->usrdata)->flags.just_syms) + continue; + + for (s = abfd->sections; s && type < COMPACT_EH_HDR; s = s->next) + { + const char *name = bfd_get_section_name (abfd, s); + + if (bfd_is_abs_section (s->output_section)) + continue; + if (CONST_STRNEQ (name, ".eh_frame_entry")) + type = COMPACT_EH_HDR; + else if (strcmp (name, ".eh_frame") == 0 && s->size > 8) + type = DWARF2_EH_HDR; + } + + if (type != 0) + { + if (seen_type == 0) + { + seen_type = type; + } + else if (seen_type != type) + { + einfo (_("%F%P: compact frame descriptions incompatible with" + " DWARF2 .eh_frame from %pB\n"), + type == DWARF2_EH_HDR ? abfd : elfbfd); + break; + } + + if (!elfbfd + && (type == COMPACT_EH_HDR + || link_info.eh_frame_hdr_type != 0)) + { + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) + elfbfd = abfd; + + warn_eh_frame = TRUE; + } + } + + if (seen_type == COMPACT_EH_HDR) + link_info.eh_frame_hdr_type = COMPACT_EH_HDR; + } + if (elfbfd) + { + const struct elf_backend_data *bed; + + bed = get_elf_backend_data (elfbfd); + s = bfd_make_section_with_flags (elfbfd, ".eh_frame_hdr", + bed->dynamic_sec_flags + | SEC_READONLY); + if (s != NULL + && bfd_set_section_alignment (elfbfd, s, 2)) + { + htab->eh_info.hdr_sec = s; + warn_eh_frame = FALSE; + } + } + if (warn_eh_frame) + einfo (_("%P: warning: cannot create .eh_frame_hdr section," + " --eh-frame-hdr ignored\n")); + } + + /* Get the list of files which appear in DT_NEEDED entries in + dynamic objects included in the link (often there will be none). + For each such file, we want to track down the corresponding + library, and include the symbol table in the link. This is what + the runtime dynamic linker will do. Tracking the files down here + permits one dynamic object to include another without requiring + special action by the person doing the link. Note that the + needed list can actually grow while we are stepping through this + loop. */ + needed = bfd_elf_get_needed_list (link_info.output_bfd, &link_info); + for (l = needed; l != NULL; l = l->next) + { + struct bfd_link_needed_list *ll; + struct dt_needed n, nn; + int force; + + /* If the lib that needs this one was --as-needed and wasn't + found to be needed, then this lib isn't needed either. */ + if (l->by != NULL + && (bfd_elf_get_dyn_lib_class (l->by) & DYN_AS_NEEDED) != 0) + continue; + + /* Skip the lib if --no-copy-dt-needed-entries and + --allow-shlib-undefined is in effect. */ + if (l->by != NULL + && link_info.unresolved_syms_in_shared_libs == RM_IGNORE + && (bfd_elf_get_dyn_lib_class (l->by) & DYN_NO_ADD_NEEDED) != 0) + continue; + + /* If we've already seen this file, skip it. */ + for (ll = needed; ll != l; ll = ll->next) + if ((ll->by == NULL + || (bfd_elf_get_dyn_lib_class (ll->by) & DYN_AS_NEEDED) == 0) + && strcmp (ll->name, l->name) == 0) + break; + if (ll != l) + continue; + + /* See if this file was included in the link explicitly. */ + global_needed = l; + global_found = NULL; + lang_for_each_input_file (ldelf_check_needed); + if (global_found != NULL + && (bfd_elf_get_dyn_lib_class (global_found->the_bfd) + & DYN_AS_NEEDED) == 0) + continue; + + n.by = l->by; + n.name = l->name; + nn.by = l->by; + if (verbose) + info_msg (_("%s needed by %pB\n"), l->name, l->by); + + /* As-needed libs specified on the command line (or linker script) + take priority over libs found in search dirs. */ + if (global_found != NULL) + { + nn.name = global_found->filename; + if (ldelf_try_needed (&nn, TRUE, is_linux)) + continue; + } + + /* We need to find this file and include the symbol table. We + want to search for the file in the same way that the dynamic + linker will search. That means that we want to use + rpath_link, rpath, then the environment variable + LD_LIBRARY_PATH (native only), then the DT_RPATH/DT_RUNPATH + entries (native only), then the linker script LIB_SEARCH_DIRS. + We do not search using the -L arguments. + + We search twice. The first time, we skip objects which may + introduce version mismatches. The second time, we force + their use. See ldelf_vercheck comment. */ + for (force = 0; force < 2; force++) + { + size_t len; + search_dirs_type *search; + const char *path; + struct bfd_link_needed_list *rp; + int found; + + if (ldelf_search_needed (command_line.rpath_link, &n, force, + is_linux, elfsize)) + break; + + if (use_libpath) + { + path = command_line.rpath; + if (path) + { + path = ldelf_add_sysroot (path); + found = ldelf_search_needed (path, &n, force, + is_linux, elfsize); + free ((char *) path); + if (found) + break; + } + } + if (native) + { + if (command_line.rpath_link == NULL + && command_line.rpath == NULL) + { + path = (const char *) getenv ("LD_RUN_PATH"); + if (path + && ldelf_search_needed (path, &n, force, + is_linux, elfsize)) + break; + } + path = (const char *) getenv ("LD_LIBRARY_PATH"); + if (path + && ldelf_search_needed (path, &n, force, + is_linux, elfsize)) + break; + } + if (use_libpath) + { + found = 0; + rp = bfd_elf_get_runpath_list (link_info.output_bfd, &link_info); + for (; !found && rp != NULL; rp = rp->next) + { + path = ldelf_add_sysroot (rp->name); + found = (rp->by == l->by + && ldelf_search_needed (path, &n, force, + is_linux, elfsize)); + free ((char *) path); + } + if (found) + break; + + if (is_freebsd + && ldelf_check_ld_elf_hints (l, force, elfsize)) + break; + + if (is_linux + && ldelf_check_ld_so_conf (l, force, elfsize)) + break; + } + + len = strlen (l->name); + for (search = search_head; search != NULL; search = search->next) + { + char *filename; + + if (search->cmdline) + continue; + filename = (char *) xmalloc (strlen (search->name) + len + 2); + sprintf (filename, "%s/%s", search->name, l->name); + nn.name = filename; + if (ldelf_try_needed (&nn, force, is_linux)) + break; + free (filename); + } + if (search != NULL) + break; + } + + if (force < 2) + continue; + + einfo (_("%P: warning: %s, needed by %pB, not found " + "(try using -rpath or -rpath-link)\n"), + l->name, l->by); + } + + if (link_info.eh_frame_hdr_type == COMPACT_EH_HDR) + if (!bfd_elf_parse_eh_frame_entries (NULL, &link_info)) + einfo (_("%F%P: failed to parse EH frame entries\n")); +} + +static bfd_size_type +id_note_section_size (bfd *abfd ATTRIBUTE_UNUSED) +{ + const char *style = ldelf_emit_note_gnu_build_id; + bfd_size_type size; + bfd_size_type build_id_size; + + size = offsetof (Elf_External_Note, name[sizeof "GNU"]); + size = (size + 3) & -(bfd_size_type) 4; + + build_id_size = compute_build_id_size (style); + if (build_id_size) + size += build_id_size; + else + size = 0; + + return size; +} + +static bfd_boolean +write_build_id (bfd *abfd) +{ + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + struct elf_obj_tdata *t = elf_tdata (abfd); + const char *style; + asection *asec; + Elf_Internal_Shdr *i_shdr; + unsigned char *contents, *id_bits; + bfd_size_type size; + file_ptr position; + Elf_External_Note *e_note; + + style = t->o->build_id.style; + asec = t->o->build_id.sec; + if (bfd_is_abs_section (asec->output_section)) + { + einfo (_("%P: warning: .note.gnu.build-id section discarded," + " --build-id ignored\n")); + return TRUE; + } + i_shdr = &elf_section_data (asec->output_section)->this_hdr; + + if (i_shdr->contents == NULL) + { + if (asec->contents == NULL) + asec->contents = (unsigned char *) xmalloc (asec->size); + contents = asec->contents; + } + else + contents = i_shdr->contents + asec->output_offset; + + e_note = (Elf_External_Note *) contents; + size = offsetof (Elf_External_Note, name[sizeof "GNU"]); + size = (size + 3) & -(bfd_size_type) 4; + id_bits = contents + size; + size = asec->size - size; + + bfd_h_put_32 (abfd, sizeof "GNU", &e_note->namesz); + bfd_h_put_32 (abfd, size, &e_note->descsz); + bfd_h_put_32 (abfd, NT_GNU_BUILD_ID, &e_note->type); + memcpy (e_note->name, "GNU", sizeof "GNU"); + + generate_build_id (abfd, style, bed->s->checksum_contents, id_bits, size); + + position = i_shdr->sh_offset + asec->output_offset; + size = asec->size; + return (bfd_seek (abfd, position, SEEK_SET) == 0 + && bfd_bwrite (contents, size, abfd) == size); +} + +/* Make .note.gnu.build-id section, and set up elf_tdata->build_id. */ + +bfd_boolean +ldelf_setup_build_id (bfd *ibfd) +{ + asection *s; + bfd_size_type size; + flagword flags; + + size = id_note_section_size (ibfd); + if (size == 0) + { + einfo (_("%P: warning: unrecognized --build-id style ignored\n")); + return FALSE; + } + + flags = (SEC_ALLOC | SEC_LOAD | SEC_IN_MEMORY + | SEC_LINKER_CREATED | SEC_READONLY | SEC_DATA); + s = bfd_make_section_with_flags (ibfd, ".note.gnu.build-id", flags); + if (s != NULL && bfd_set_section_alignment (ibfd, s, 2)) + { + struct elf_obj_tdata *t = elf_tdata (link_info.output_bfd); + t->o->build_id.after_write_object_contents = &write_build_id; + t->o->build_id.style = ldelf_emit_note_gnu_build_id; + t->o->build_id.sec = s; + elf_section_type (s) = SHT_NOTE; + s->size = size; + return TRUE; + } + + einfo (_("%P: warning: cannot create .note.gnu.build-id section," + " --build-id ignored\n")); + return FALSE; +} + +/* Look through an expression for an assignment statement. */ + +static void +ldelf_find_exp_assignment (etree_type *exp) +{ + bfd_boolean provide = FALSE; + + switch (exp->type.node_class) + { + case etree_provide: + case etree_provided: + provide = TRUE; + /* Fallthru */ + case etree_assign: + /* We call record_link_assignment even if the symbol is defined. + This is because if it is defined by a dynamic object, we + actually want to use the value defined by the linker script, + not the value from the dynamic object (because we are setting + symbols like etext). If the symbol is defined by a regular + object, then, as it happens, calling record_link_assignment + will do no harm. */ + if (strcmp (exp->assign.dst, ".") != 0) + { + if (!bfd_elf_record_link_assignment (link_info.output_bfd, + &link_info, + exp->assign.dst, provide, + exp->assign.hidden)) + einfo (_("%F%P: failed to record assignment to %s: %E\n"), + exp->assign.dst); + } + ldelf_find_exp_assignment (exp->assign.src); + break; + + case etree_binary: + ldelf_find_exp_assignment (exp->binary.lhs); + ldelf_find_exp_assignment (exp->binary.rhs); + break; + + case etree_trinary: + ldelf_find_exp_assignment (exp->trinary.cond); + ldelf_find_exp_assignment (exp->trinary.lhs); + ldelf_find_exp_assignment (exp->trinary.rhs); + break; + + case etree_unary: + ldelf_find_exp_assignment (exp->unary.child); + break; + + default: + break; + } +} + +/* This is called by the before_allocation routine via + lang_for_each_statement. It locates any assignment statements, and + tells the ELF backend about them, in case they are assignments to + symbols which are referred to by dynamic objects. */ + +static void +ldelf_find_statement_assignment (lang_statement_union_type *s) +{ + if (s->header.type == lang_assignment_statement_enum) + ldelf_find_exp_assignment (s->assignment_statement.exp); +} + +/* Used by before_allocation and handle_option. */ + +void +ldelf_append_to_separated_string (char **to, char *op_arg) +{ + if (*to == NULL) + *to = xstrdup (op_arg); + else + { + size_t to_len = strlen (*to); + size_t op_arg_len = strlen (op_arg); + char *buf; + char *cp = *to; + + /* First see whether OPTARG is already in the path. */ + do + { + if (strncmp (op_arg, cp, op_arg_len) == 0 + && (cp[op_arg_len] == 0 + || cp[op_arg_len] == config.rpath_separator)) + /* We found it. */ + break; + + /* Not yet found. */ + cp = strchr (cp, config.rpath_separator); + if (cp != NULL) + ++cp; + } + while (cp != NULL); + + if (cp == NULL) + { + buf = xmalloc (to_len + op_arg_len + 2); + sprintf (buf, "%s%c%s", *to, + config.rpath_separator, op_arg); + free (*to); + *to = buf; + } + } +} + +/* This is called after the sections have been attached to output + sections, but before any sizes or addresses have been set. */ + +void +ldelf_before_allocation (char *audit, char *depaudit, + const char *default_interpreter_name) +{ + const char *rpath; + asection *sinterp; + bfd *abfd; + struct bfd_link_hash_entry *ehdr_start = NULL; + unsigned char ehdr_start_save_type = 0; + char ehdr_start_save_u[sizeof ehdr_start->u + - sizeof ehdr_start->u.def.next] = ""; + + if (is_elf_hash_table (link_info.hash)) + { + _bfd_elf_tls_setup (link_info.output_bfd, &link_info); + + /* Make __ehdr_start hidden if it has been referenced, to + prevent the symbol from being dynamic. */ + if (!bfd_link_relocatable (&link_info)) + { + struct elf_link_hash_table *htab = elf_hash_table (&link_info); + struct elf_link_hash_entry *h + = elf_link_hash_lookup (htab, "__ehdr_start", FALSE, FALSE, TRUE); + + /* Only adjust the export class if the symbol was referenced + and not defined, otherwise leave it alone. */ + if (h != NULL + && (h->root.type == bfd_link_hash_new + || h->root.type == bfd_link_hash_undefined + || h->root.type == bfd_link_hash_undefweak + || h->root.type == bfd_link_hash_common)) + { + const struct elf_backend_data *bed; + bed = get_elf_backend_data (link_info.output_bfd); + (*bed->elf_backend_hide_symbol) (&link_info, h, TRUE); + if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL) + h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN; + /* Don't leave the symbol undefined. Undefined hidden + symbols typically won't have dynamic relocations, but + we most likely will need dynamic relocations for + __ehdr_start if we are building a PIE or shared + library. */ + ehdr_start = &h->root; + ehdr_start_save_type = ehdr_start->type; + memcpy (ehdr_start_save_u, + (char *) &ehdr_start->u + sizeof ehdr_start->u.def.next, + sizeof ehdr_start_save_u); + ehdr_start->type = bfd_link_hash_defined; + ehdr_start->u.def.section = bfd_abs_section_ptr; + ehdr_start->u.def.value = 0; + } + } + + /* If we are going to make any variable assignments, we need to + let the ELF backend know about them in case the variables are + referred to by dynamic objects. */ + lang_for_each_statement (ldelf_find_statement_assignment); + } + + /* Let the ELF backend work out the sizes of any sections required + by dynamic linking. */ + rpath = command_line.rpath; + if (rpath == NULL) + rpath = (const char *) getenv ("LD_RUN_PATH"); + + for (abfd = link_info.input_bfds; abfd; abfd = abfd->link.next) + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) + { + const char *audit_libs = elf_dt_audit (abfd); + + /* If the input bfd contains an audit entry, we need to add it as + a dep audit entry. */ + if (audit_libs && *audit_libs != '\0') + { + char *cp = xstrdup (audit_libs); + do + { + int more = 0; + char *cp2 = strchr (cp, config.rpath_separator); + + if (cp2) + { + *cp2 = '\0'; + more = 1; + } + + if (cp != NULL && *cp != '\0') + ldelf_append_to_separated_string (&depaudit, cp); + + cp = more ? ++cp2 : NULL; + } + while (cp != NULL); + } + } + + if (! (bfd_elf_size_dynamic_sections + (link_info.output_bfd, command_line.soname, rpath, + command_line.filter_shlib, audit, depaudit, + (const char * const *) command_line.auxiliary_filters, + &link_info, &sinterp))) + einfo (_("%F%P: failed to set dynamic section sizes: %E\n")); + + if (sinterp != NULL) + { + /* Let the user override the dynamic linker we are using. */ + if (command_line.interpreter != NULL) + default_interpreter_name = command_line.interpreter; + if (default_interpreter_name != NULL) + { + sinterp->contents = (bfd_byte *) default_interpreter_name; + sinterp->size = strlen ((char *) sinterp->contents) + 1; + } + } + + /* Look for any sections named .gnu.warning. As a GNU extensions, + we treat such sections as containing warning messages. We print + out the warning message, and then zero out the section size so + that it does not get copied into the output file. */ + + { + LANG_FOR_EACH_INPUT_STATEMENT (is) + { + asection *s; + bfd_size_type sz; + char *msg; + + if (is->flags.just_syms) + continue; + + s = bfd_get_section_by_name (is->the_bfd, ".gnu.warning"); + if (s == NULL) + continue; + + sz = s->size; + msg = (char *) xmalloc ((size_t) (sz + 1)); + if (! bfd_get_section_contents (is->the_bfd, s, msg, + (file_ptr) 0, sz)) + einfo (_("%F%P: %pB: can't read contents of section .gnu.warning: %E\n"), + is->the_bfd); + msg[sz] = '\0'; + (*link_info.callbacks->warning) (&link_info, msg, + (const char *) NULL, is->the_bfd, + (asection *) NULL, (bfd_vma) 0); + free (msg); + + /* Clobber the section size, so that we don't waste space + copying the warning into the output file. If we've already + sized the output section, adjust its size. The adjustment + is on rawsize because targets that size sections early will + have called lang_reset_memory_regions after sizing. */ + if (s->output_section != NULL + && s->output_section->rawsize >= s->size) + s->output_section->rawsize -= s->size; + + s->size = 0; + + /* Also set SEC_EXCLUDE, so that local symbols defined in the + warning section don't get copied to the output. */ + s->flags |= SEC_EXCLUDE | SEC_KEEP; + } + } + + before_allocation_default (); + + if (!bfd_elf_size_dynsym_hash_dynstr (link_info.output_bfd, &link_info)) + einfo (_("%F%P: failed to set dynamic section sizes: %E\n")); + + if (ehdr_start != NULL) + { + /* If we twiddled __ehdr_start to defined earlier, put it back + as it was. */ + ehdr_start->type = ehdr_start_save_type; + memcpy ((char *) &ehdr_start->u + sizeof ehdr_start->u.def.next, + ehdr_start_save_u, + sizeof ehdr_start_save_u); + } +} +/* Try to open a dynamic archive. This is where we know that ELF + dynamic libraries have an extension of .so (or .sl on oddball systems + like hpux). */ + +bfd_boolean +ldelf_open_dynamic_archive (const char *arch, search_dirs_type *search, + lang_input_statement_type *entry) +{ + const char *filename; + char *string; + size_t len; + bfd_boolean opened = FALSE; + + if (! entry->flags.maybe_archive) + return FALSE; + + filename = entry->filename; + len = strlen (search->name) + strlen (filename); + if (entry->flags.full_name_provided) + { + len += sizeof "/"; + string = (char *) xmalloc (len); + sprintf (string, "%s/%s", search->name, filename); + } + else + { + size_t xlen = 0; + + len += strlen (arch) + sizeof "/lib.so"; +#ifdef EXTRA_SHLIB_EXTENSION + xlen = (strlen (EXTRA_SHLIB_EXTENSION) > 3 + ? strlen (EXTRA_SHLIB_EXTENSION) - 3 + : 0); +#endif + string = (char *) xmalloc (len + xlen); + sprintf (string, "%s/lib%s%s.so", search->name, filename, arch); +#ifdef EXTRA_SHLIB_EXTENSION + /* Try the .so extension first. If that fails build a new filename + using EXTRA_SHLIB_EXTENSION. */ + opened = ldfile_try_open_bfd (string, entry); + if (!opened) + strcpy (string + len - 4, EXTRA_SHLIB_EXTENSION); +#endif + } + + if (!opened && !ldfile_try_open_bfd (string, entry)) + { + free (string); + return FALSE; + } + + entry->filename = string; + + /* We have found a dynamic object to include in the link. The ELF + backend linker will create a DT_NEEDED entry in the .dynamic + section naming this file. If this file includes a DT_SONAME + entry, it will be used. Otherwise, the ELF linker will just use + the name of the file. For an archive found by searching, like + this one, the DT_NEEDED entry should consist of just the name of + the file, without the path information used to find it. Note + that we only need to do this if we have a dynamic object; an + archive will never be referenced by a DT_NEEDED entry. + + FIXME: This approach--using bfd_elf_set_dt_needed_name--is not + very pretty. I haven't been able to think of anything that is + pretty, though. */ + if (bfd_check_format (entry->the_bfd, bfd_object) + && (entry->the_bfd->flags & DYNAMIC) != 0) + { + ASSERT (entry->flags.maybe_archive && entry->flags.search_dirs); + + /* Rather than duplicating the logic above. Just use the + filename we recorded earlier. */ + + if (!entry->flags.full_name_provided) + filename = lbasename (entry->filename); + bfd_elf_set_dt_needed_name (entry->the_bfd, filename); + } + + return TRUE; +} + +/* A variant of lang_output_section_find used by place_orphan. */ + +static lang_output_section_statement_type * +output_rel_find (int isdyn, int rela) +{ + lang_output_section_statement_type *lookup; + lang_output_section_statement_type *last = NULL; + lang_output_section_statement_type *last_alloc = NULL; + lang_output_section_statement_type *last_ro_alloc = NULL; + lang_output_section_statement_type *last_rel = NULL; + lang_output_section_statement_type *last_rel_alloc = NULL; + + for (lookup = &lang_os_list.head->output_section_statement; + lookup != NULL; + lookup = lookup->next) + { + if (lookup->constraint >= 0 + && CONST_STRNEQ (lookup->name, ".rel")) + { + int lookrela = lookup->name[4] == 'a'; + + /* .rel.dyn must come before all other reloc sections, to suit + GNU ld.so. */ + if (isdyn) + break; + + /* Don't place after .rel.plt as doing so results in wrong + dynamic tags. */ + if (strcmp (".plt", lookup->name + 4 + lookrela) == 0) + break; + + if (rela == lookrela || last_rel == NULL) + last_rel = lookup; + if ((rela == lookrela || last_rel_alloc == NULL) + && lookup->bfd_section != NULL + && (lookup->bfd_section->flags & SEC_ALLOC) != 0) + last_rel_alloc = lookup; + } + + last = lookup; + if (lookup->bfd_section != NULL + && (lookup->bfd_section->flags & SEC_ALLOC) != 0) + { + last_alloc = lookup; + if ((lookup->bfd_section->flags & SEC_READONLY) != 0) + last_ro_alloc = lookup; + } + } + + if (last_rel_alloc) + return last_rel_alloc; + + if (last_rel) + return last_rel; + + if (last_ro_alloc) + return last_ro_alloc; + + if (last_alloc) + return last_alloc; + + return last; +} + +/* Return whether IN is suitable to be part of OUT. */ + +static bfd_boolean +elf_orphan_compatible (asection *in, asection *out) +{ + /* Non-zero sh_info implies a section with SHF_INFO_LINK with + unknown semantics for the generic linker, or a SHT_REL/SHT_RELA + section where sh_info specifies a symbol table. (We won't see + SHT_GROUP, SHT_SYMTAB or SHT_DYNSYM sections here.) We clearly + can't merge SHT_REL/SHT_RELA using differing symbol tables, and + shouldn't merge sections with differing unknown semantics. */ + if (elf_section_data (out)->this_hdr.sh_info + != elf_section_data (in)->this_hdr.sh_info) + return FALSE; + /* We can't merge with member of output section group nor merge two + sections with differing SHF_EXCLUDE when doing a relocatable link. + */ + if (bfd_link_relocatable (&link_info) + && (elf_next_in_group (out) != NULL + || ((elf_section_flags (out) ^ elf_section_flags (in)) + & SHF_EXCLUDE) != 0)) + return FALSE; + return _bfd_elf_match_sections_by_type (link_info.output_bfd, out, + in->owner, in); +} + +/* Place an orphan section. We use this to put random SHF_ALLOC + sections in the right segment. */ + +lang_output_section_statement_type * +ldelf_place_orphan (asection *s, const char *secname, int constraint) +{ + static struct orphan_save hold[] = + { + { ".text", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE, + 0, 0, 0, 0 }, + { ".rodata", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA, + 0, 0, 0, 0 }, + { ".tdata", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_THREAD_LOCAL, + 0, 0, 0, 0 }, + { ".data", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA, + 0, 0, 0, 0 }, + { ".bss", + SEC_ALLOC, + 0, 0, 0, 0 }, + { 0, + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA, + 0, 0, 0, 0 }, + { ".interp", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA, + 0, 0, 0, 0 }, + { ".sdata", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_SMALL_DATA, + 0, 0, 0, 0 }, + { ".comment", + SEC_HAS_CONTENTS, + 0, 0, 0, 0 }, + }; + enum orphan_save_index + { + orphan_text = 0, + orphan_rodata, + orphan_tdata, + orphan_data, + orphan_bss, + orphan_rel, + orphan_interp, + orphan_sdata, + orphan_nonalloc + }; + static int orphan_init_done = 0; + struct orphan_save *place; + lang_output_section_statement_type *after; + lang_output_section_statement_type *os; + lang_output_section_statement_type *match_by_name = NULL; + int isdyn = 0; + int elfinput = s->owner->xvec->flavour == bfd_target_elf_flavour; + int elfoutput = link_info.output_bfd->xvec->flavour == bfd_target_elf_flavour; + unsigned int sh_type = elfinput ? elf_section_type (s) : SHT_NULL; + flagword flags; + asection *nexts; + + if (!bfd_link_relocatable (&link_info) + && link_info.combreloc + && (s->flags & SEC_ALLOC)) + { + if (elfinput) + switch (sh_type) + { + case SHT_RELA: + secname = ".rela.dyn"; + isdyn = 1; + break; + case SHT_REL: + secname = ".rel.dyn"; + isdyn = 1; + break; + default: + break; + } + else if (CONST_STRNEQ (secname, ".rel")) + { + secname = secname[4] == 'a' ? ".rela.dyn" : ".rel.dyn"; + isdyn = 1; + } + } + + if (!bfd_link_relocatable (&link_info) + && elfinput + && elfoutput + && (s->flags & SEC_ALLOC) != 0 + && (elf_tdata (s->owner)->has_gnu_osabi & elf_gnu_osabi_mbind) != 0 + && (elf_section_flags (s) & SHF_GNU_MBIND) != 0) + { + /* Find the output mbind section with the same type, attributes + and sh_info field. */ + for (os = &lang_os_list.head->output_section_statement; + os != NULL; + os = os->next) + if (os->bfd_section != NULL + && !bfd_is_abs_section (os->bfd_section) + && (elf_section_flags (os->bfd_section) & SHF_GNU_MBIND) != 0 + && ((s->flags & (SEC_ALLOC + | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_READONLY + | SEC_CODE)) + == (os->bfd_section->flags & (SEC_ALLOC + | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_READONLY + | SEC_CODE))) + && (elf_section_data (os->bfd_section)->this_hdr.sh_info + == elf_section_data (s)->this_hdr.sh_info)) + { + lang_add_section (&os->children, s, NULL, os); + return os; + } + + /* Create the output mbind section with the ".mbind." prefix + in section name. */ + if ((s->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0) + secname = ".mbind.bss"; + else if ((s->flags & SEC_READONLY) == 0) + secname = ".mbind.data"; + else if ((s->flags & SEC_CODE) == 0) + secname = ".mbind.rodata"; + else + secname = ".mbind.text"; + elf_tdata (link_info.output_bfd)->has_gnu_osabi |= elf_gnu_osabi_mbind; + } + + /* Look through the script to see where to place this section. The + script includes entries added by previous lang_insert_orphan + calls, so this loop puts multiple compatible orphans of the same + name into a single output section. */ + if (constraint == 0) + for (os = lang_output_section_find (secname); + os != NULL; + os = next_matching_output_section_statement (os, 0)) + { + /* If we don't match an existing output section, tell + lang_insert_orphan to create a new output section. */ + constraint = SPECIAL; + + /* Check to see if we already have an output section statement + with this name, and its bfd section has compatible flags. + If the section already exists but does not have any flags + set, then it has been created by the linker, possibly as a + result of a --section-start command line switch. */ + if (os->bfd_section != NULL + && (os->bfd_section->flags == 0 + || (((s->flags ^ os->bfd_section->flags) + & (SEC_LOAD | SEC_ALLOC)) == 0 + && (!elfinput + || !elfoutput + || elf_orphan_compatible (s, os->bfd_section))))) + { + lang_add_section (&os->children, s, NULL, os); + return os; + } + + /* Save unused output sections in case we can match them + against orphans later. */ + if (os->bfd_section == NULL) + match_by_name = os; + } + + /* If we didn't match an active output section, see if we matched an + unused one and use that. */ + if (match_by_name) + { + lang_add_section (&match_by_name->children, s, NULL, match_by_name); + return match_by_name; + } + + if (!orphan_init_done) + { + struct orphan_save *ho; + + for (ho = hold; ho < hold + sizeof (hold) / sizeof (hold[0]); ++ho) + if (ho->name != NULL) + { + ho->os = lang_output_section_find (ho->name); + if (ho->os != NULL && ho->os->flags == 0) + ho->os->flags = ho->flags; + } + orphan_init_done = 1; + } + + /* If this is a final link, then always put .gnu.warning.SYMBOL + sections into the .text section to get them out of the way. */ + if (bfd_link_executable (&link_info) + && CONST_STRNEQ (s->name, ".gnu.warning.") + && hold[orphan_text].os != NULL) + { + os = hold[orphan_text].os; + lang_add_section (&os->children, s, NULL, os); + return os; + } + + flags = s->flags; + if (!bfd_link_relocatable (&link_info)) + { + nexts = s; + while ((nexts = bfd_get_next_section_by_name (nexts->owner, nexts)) + != NULL) + if (nexts->output_section == NULL + && (nexts->flags & SEC_EXCLUDE) == 0 + && ((nexts->flags ^ flags) & (SEC_LOAD | SEC_ALLOC)) == 0 + && (nexts->owner->flags & DYNAMIC) == 0 + && nexts->owner->usrdata != NULL + && !(((lang_input_statement_type *) nexts->owner->usrdata) + ->flags.just_syms) + && _bfd_elf_match_sections_by_type (nexts->owner, nexts, + s->owner, s)) + flags = (((flags ^ SEC_READONLY) + | (nexts->flags ^ SEC_READONLY)) + ^ SEC_READONLY); + } + + /* Decide which segment the section should go in based on the + section name and section flags. We put loadable .note sections + right after the .interp section, so that the PT_NOTE segment is + stored right after the program headers where the OS can read it + in the first page. */ + + place = NULL; + if ((flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0) + place = &hold[orphan_nonalloc]; + else if ((flags & SEC_ALLOC) == 0) + ; + else if ((flags & SEC_LOAD) != 0 + && (elfinput + ? sh_type == SHT_NOTE + : CONST_STRNEQ (secname, ".note"))) + place = &hold[orphan_interp]; + else if ((flags & (SEC_LOAD | SEC_HAS_CONTENTS | SEC_THREAD_LOCAL)) == 0) + place = &hold[orphan_bss]; + else if ((flags & SEC_SMALL_DATA) != 0) + place = &hold[orphan_sdata]; + else if ((flags & SEC_THREAD_LOCAL) != 0) + place = &hold[orphan_tdata]; + else if ((flags & SEC_READONLY) == 0) + place = &hold[orphan_data]; + else if ((flags & SEC_LOAD) != 0 + && (elfinput + ? sh_type == SHT_RELA || sh_type == SHT_REL + : CONST_STRNEQ (secname, ".rel"))) + place = &hold[orphan_rel]; + else if ((flags & SEC_CODE) == 0) + place = &hold[orphan_rodata]; + else + place = &hold[orphan_text]; + + after = NULL; + if (place != NULL) + { + if (place->os == NULL) + { + if (place->name != NULL) + place->os = lang_output_section_find (place->name); + else + { + int rela = elfinput ? sh_type == SHT_RELA : secname[4] == 'a'; + place->os = output_rel_find (isdyn, rela); + } + } + after = place->os; + if (after == NULL) + after + = lang_output_section_find_by_flags (s, flags, &place->os, + _bfd_elf_match_sections_by_type); + if (after == NULL) + /* *ABS* is always the first output section statement. */ + after = &lang_os_list.head->output_section_statement; + } + + return lang_insert_orphan (s, secname, constraint, after, place, NULL, NULL); +} diff --git a/ld/ldelf.h b/ld/ldelf.h new file mode 100644 index 0000000..0116629 --- /dev/null +++ b/ld/ldelf.h @@ -0,0 +1,32 @@ +/* ELF emulation code for targets using elf32.em. + Copyright (C) 1991-2019 Free Software Foundation, Inc. + + This file is part of the GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +extern const char *ldelf_emit_note_gnu_build_id; + +extern void ldelf_after_parse (void); +extern bfd_boolean ldelf_load_symbols (lang_input_statement_type *); +extern void ldelf_after_open (int, int, int, int, int); +extern bfd_boolean ldelf_setup_build_id (bfd *); +extern void ldelf_append_to_separated_string (char **, char *); +extern void ldelf_before_allocation (char *, char *, const char *); +extern bfd_boolean ldelf_open_dynamic_archive + (const char *, search_dirs_type *, lang_input_statement_type *); +extern lang_output_section_statement_type *ldelf_place_orphan + (asection *, const char *, int); diff --git a/ld/ldelfgen.c b/ld/ldelfgen.c new file mode 100644 index 0000000..98bcecd --- /dev/null +++ b/ld/ldelfgen.c @@ -0,0 +1,74 @@ +/* Emulation code used by all ELF targets. + Copyright (C) 1991-2019 Free Software Foundation, Inc. + + This file is part of the GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "sysdep.h" +#include "bfd.h" +#include "ld.h" +#include "ldmain.h" +#include "ldmisc.h" +#include "ldexp.h" +#include "ldlang.h" +#include "elf-bfd.h" +#include "ldelfgen.h" + +void +ldelf_map_segments (bfd_boolean need_layout) +{ + int tries = 10; + + do + { + lang_relax_sections (need_layout); + need_layout = FALSE; + + if (link_info.output_bfd->xvec->flavour == bfd_target_elf_flavour + && !bfd_link_relocatable (&link_info)) + { + bfd_size_type phdr_size; + + phdr_size = elf_program_header_size (link_info.output_bfd); + /* If we don't have user supplied phdrs, throw away any + previous linker generated program headers. */ + if (lang_phdr_list == NULL) + elf_seg_map (link_info.output_bfd) = NULL; + if (!_bfd_elf_map_sections_to_segments (link_info.output_bfd, + &link_info)) + einfo (_("%F%P: map sections to segments failed: %E\n")); + + if (phdr_size != elf_program_header_size (link_info.output_bfd)) + { + if (tries > 6) + /* The first few times we allow any change to + phdr_size . */ + need_layout = TRUE; + else if (phdr_size + < elf_program_header_size (link_info.output_bfd)) + /* After that we only allow the size to grow. */ + need_layout = TRUE; + else + elf_program_header_size (link_info.output_bfd) = phdr_size; + } + } + } + while (need_layout && --tries); + + if (tries == 0) + einfo (_("%F%P: looping in map_segments")); +} diff --git a/ld/ldelfgen.h b/ld/ldelfgen.h new file mode 100644 index 0000000..3284460 --- /dev/null +++ b/ld/ldelfgen.h @@ -0,0 +1,21 @@ +/* Emulation code used by all ELF targets. + Copyright (C) 1991-2019 Free Software Foundation, Inc. + + This file is part of the GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +extern void ldelf_map_segments (bfd_boolean); diff --git a/ld/ldlang.c b/ld/ldlang.c index 303aa67..d5a2b49 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -6862,8 +6862,8 @@ lang_set_flags (lang_memory_region_type *ptr, const char *flags, int invert) } } -/* Call a function on each input file. This function will be called - on an archive, but not on the elements. */ +/* Call a function on each real input file. This function will be + called on an archive, but not on the elements. */ void lang_for_each_input_file (void (*func) (lang_input_statement_type *)) @@ -6873,19 +6873,21 @@ lang_for_each_input_file (void (*func) (lang_input_statement_type *)) for (f = &input_file_chain.head->input_statement; f != NULL; f = f->next_real_file) - func (f); + if (f->flags.real) + func (f); } -/* Call a function on each file. The function will be called on all - the elements of an archive which are included in the link, but will - not be called on the archive file itself. */ +/* Call a function on each real file. The function will be called on + all the elements of an archive which are included in the link, but + will not be called on the archive file itself. */ void lang_for_each_file (void (*func) (lang_input_statement_type *)) { LANG_FOR_EACH_INPUT_STATEMENT (f) { - func (f); + if (f->flags.real) + func (f); } } diff --git a/ld/po/SRC-POTFILES.in b/ld/po/SRC-POTFILES.in index 1628826..bbadc8e 100644 --- a/ld/po/SRC-POTFILES.in +++ b/ld/po/SRC-POTFILES.in @@ -6,6 +6,10 @@ ldbuildid.h ldcref.c ldctor.c ldctor.h +ldelf.c +ldelf.h +ldelfgen.c +ldelfgen.h ldemul.c ldemul.h ldexp.c |