diff -rNbu binutils-2.17_org/bfd/Makefile.am binutils-2.17/bfd/Makefile.am --- binutils-2.17_org/bfd/Makefile.am 2006-06-23 20:17:17.000000000 +0200 +++ binutils-2.17/bfd/Makefile.am 2006-08-09 10:16:54.000000000 +0200 @@ -555,7 +555,11 @@ mmo.lo \ nlm32-alpha.lo \ nlm64.lo \ - pepigen.lo + coff-x86_64.lo \ + pe-x86_64.lo \ + pei-x86_64.lo \ + pepigen.lo \ + pex64igen.lo BFD64_BACKENDS_CFILES = \ aix5ppc-core.c \ @@ -578,6 +582,9 @@ elf64.c \ mmo.c \ nlm32-alpha.c \ + coff-x86_64.c \ + pe-x86_64.c \ + pei-x86_64.c \ nlm64.c OPTIONAL_BACKENDS = \ @@ -628,7 +635,7 @@ $(OPTIONAL_BACKENDS_CFILES) BUILD_CFILES = \ - elf32-ia64.c elf64-ia64.c peigen.c pepigen.c + elf32-ia64.c elf64-ia64.c peigen.c pepigen.c pex64igen.c CFILES = $(SOURCE_CFILES) $(BUILD_CFILES) @@ -781,6 +788,11 @@ sed -e s/XX/pe/g < $(srcdir)/peXXigen.c > peigen.new mv -f peigen.new peigen.c +pex64igen.c : peXXigen.c + rm -f pex64igen.c + sed -e s/XX/pex64/g < $(srcdir)/peXXigen.c > pex64igen.new + mv -f pex64igen.new pex64igen.c + pepigen.c : peXXigen.c rm -f pepigen.c sed -e s/XX/pep/g < $(srcdir)/peXXigen.c > pepigen.new @@ -1830,6 +1842,9 @@ $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(INCDIR)/opcode/ia64.h \ $(INCDIR)/elf/ia64.h $(INCDIR)/elf/reloc-macros.h $(INCDIR)/objalloc.h \ elf64-target.h +pex64igen.lo: pex64igen.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/x86_64.h $(INCDIR)/coff/external.h \ + $(INCDIR)/coff/pe.h libcoff.h $(INCDIR)/bfdlink.h libpei.h peigen.lo: peigen.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h \ $(INCDIR)/coff/internal.h $(INCDIR)/coff/i386.h $(INCDIR)/coff/external.h \ $(INCDIR)/coff/pe.h libcoff.h $(INCDIR)/bfdlink.h libpei.h diff -rNbu binutils-2.17_org/bfd/Makefile.in binutils-2.17/bfd/Makefile.in --- binutils-2.17_org/bfd/Makefile.in 2006-06-23 20:17:19.000000000 +0200 +++ binutils-2.17/bfd/Makefile.in 2006-08-09 10:17:56.000000000 +0200 @@ -793,7 +793,11 @@ mmo.lo \ nlm32-alpha.lo \ nlm64.lo \ - pepigen.lo + coff-x86_64.lo \ + pe-x86_64.lo \ + pei-x86_64.lo \ + pepigen.lo \ + pex64igen.lo BFD64_BACKENDS_CFILES = \ aix5ppc-core.c \ @@ -816,6 +820,9 @@ elf64.c \ mmo.c \ nlm32-alpha.c \ + coff-x86_64.c \ + pe-x86_64.c \ + pei-x86_64.c \ nlm64.c OPTIONAL_BACKENDS = \ @@ -867,7 +874,7 @@ $(OPTIONAL_BACKENDS_CFILES) BUILD_CFILES = \ - elf32-ia64.c elf64-ia64.c peigen.c pepigen.c + elf32-ia64.c elf64-ia64.c peigen.c pepigen.c pex64igen.c CFILES = $(SOURCE_CFILES) $(BUILD_CFILES) SOURCE_HFILES = \ @@ -1365,6 +1372,11 @@ sed -e s/XX/pe/g < $(srcdir)/peXXigen.c > peigen.new mv -f peigen.new peigen.c +pex64igen.c : peXXigen.c + rm -f pex64igen.c + sed -e s/XX/pex64/g < $(srcdir)/peXXigen.c > pex64igen.new + mv -f pex64igen.new pex64igen.c + pepigen.c : peXXigen.c rm -f pepigen.c sed -e s/XX/pep/g < $(srcdir)/peXXigen.c > pepigen.new @@ -2399,6 +2411,9 @@ peigen.lo: peigen.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h \ $(INCDIR)/coff/internal.h $(INCDIR)/coff/i386.h $(INCDIR)/coff/external.h \ $(INCDIR)/coff/pe.h libcoff.h $(INCDIR)/bfdlink.h libpei.h +pex64igen.lo: pex64igen.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/x86_64.h $(INCDIR)/coff/external.h \ + $(INCDIR)/coff/pe.h libcoff.h $(INCDIR)/bfdlink.h libpei.h pepigen.lo: pepigen.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h \ $(INCDIR)/coff/internal.h $(INCDIR)/coff/ia64.h $(INCDIR)/coff/external.h \ $(INCDIR)/coff/pe.h libcoff.h $(INCDIR)/bfdlink.h libpei.h diff -rNbu binutils-2.17_org/bfd/bfd.c binutils-2.17/bfd/bfd.c --- binutils-2.17_org/bfd/bfd.c 2006-03-16 13:20:15.000000000 +0100 +++ binutils-2.17/bfd/bfd.c 2006-08-04 11:42:38.000000000 +0200 @@ -858,7 +858,8 @@ a place will have to be found. Until then, this hack will do. */ if (strncmp (name, "coff-go32", sizeof ("coff-go32") - 1) == 0 || strcmp (name, "pe-i386") == 0 - || strcmp (name, "pei-i386") == 0) + || strcmp (name, "pei-i386") == 0 || + strcmp(name,"pe-x86-64")==0 || strcmp(name,"pei-x86-64")) return 1; bfd_set_error (bfd_error_wrong_format); diff -rNbu binutils-2.17_org/bfd/coff-x86_64.c binutils-2.17/bfd/coff-x86_64.c --- binutils-2.17_org/bfd/coff-x86_64.c 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.17/bfd/coff-x86_64.c 2006-08-17 09:06:15.000000000 +0200 @@ -0,0 +1,728 @@ +/* BFD back-end for AMD 64 COFF files. + Copyright 1995, 1996, 1999, 2001, 2002, 2004 Free Software Foundation, Inc. + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 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. + + Written by Kai Tietz, OneVision Software GmbH&CoKg. +*/ +#ifndef COFF_WITH_pex64 +#define COFF_WITH_pex64 +#endif + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +#include "coff/x86_64.h" +#include "coff/internal.h" +#include "coff/pe.h" +#include "libcoff.h" + +#define BADMAG(x) AMD64BADMAG(x) + +#ifdef COFF_WITH_pex64 +# undef AOUTSZ +# define AOUTSZ PEPAOUTSZ +# define PEAOUTHDR PEPAOUTHDR +#endif + +static bfd_reloc_status_type coff_amd64_reloc(bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **); +static reloc_howto_type *coff_amd64_rtype_to_howto(bfd *, asection *, struct internal_reloc *,struct coff_link_hash_entry *, struct internal_syment *,bfd_vma *); +static reloc_howto_type *coff_amd64_reloc_type_lookup(bfd *, bfd_reloc_code_real_type); + +#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2) +/* The page size is a guess based on ELF. */ + +#define COFF_PAGE_SIZE 0x1000 + +/* For some reason when using AMD COFF the value stored in the .text + section for a reference to a common symbol is the value itself plus + any desired offset. Ian Taylor, Cygnus Support. */ + +/* If we are producing relocatable output, we need to do some + adjustments to the object file that are not done by the + bfd_perform_relocation function. This function is called by every + reloc type to make any required adjustments. */ + +static bfd_reloc_status_type +coff_amd64_reloc(bfd *abfd,arelent *reloc_entry,asymbol *symbol,PTR data,asection *input_section ATTRIBUTE_UNUSED, + bfd *output_bfd,char **error_message ATTRIBUTE_UNUSED) +{ + symvalue diff; + +#ifndef COFF_WITH_PE + if(output_bfd == (bfd *) NULL) + return bfd_reloc_continue; +#endif + + if(bfd_is_com_section (symbol->section)) { +#ifndef COFF_WITH_PE + /* We are relocating a common symbol. The current value in the + object file is ORIG + OFFSET, where ORIG is the value of the + common symbol as seen by the object file when it was compiled + (this may be zero if the symbol was undefined) and OFFSET is + the offset into the common symbol (normally zero, but may be + non-zero when referring to a field in a common structure). + ORIG is the negative of reloc_entry->addend, which is set by + the CALC_ADDEND macro below. We want to replace the value in + the object file with NEW + OFFSET, where NEW is the value of + the common symbol which we are going to put in the final + object file. NEW is symbol->value. */ + diff = symbol->value + reloc_entry->addend; +#else + /* In PE mode, we do not offset the common symbol. */ + diff = reloc_entry->addend; +#endif + } + else + { + /* For some reason bfd_perform_relocation always effectively + ignores the addend for a COFF target when producing + relocatable output. This seems to be always wrong for 386 + COFF, so we handle the addend here instead. */ +#ifdef COFF_WITH_PE + if(output_bfd == (bfd *) NULL) + { + reloc_howto_type *howto = reloc_entry->howto; + + /* Although PC relative relocations are very similar between + PE and non-PE formats, but they are off by 1 << howto->size + bytes. For the external relocation, PE is very different + from others. See md_apply_fix3 () in gas/config/tc-amd64.c. + When we link PE and non-PE object files together to + generate a non-PE executable, we have to compensate it + here. */ + if(howto->pc_relative && howto->pcrel_offset) + diff = -(1 << howto->size); + else if(symbol->flags & BSF_WEAK) + diff = reloc_entry->addend - symbol->value; + else + diff = -reloc_entry->addend; + } + else +#endif + diff = reloc_entry->addend; + } + +#ifdef COFF_WITH_PE + /* FIXME: How should this case be handled? */ + if(reloc_entry->howto->type == R_AMD64_IMAGEBASE + && output_bfd!=NULL + && bfd_get_flavour(output_bfd) == bfd_target_coff_flavour) + diff -= pe_data (output_bfd)->pe_opthdr.ImageBase; +#endif + +#define DOIT(x) \ + x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask)) + + if(diff!=0) + { + reloc_howto_type *howto = reloc_entry->howto; + unsigned char *addr = (unsigned char *) data + reloc_entry->address; + + switch (howto->size) + { + case 0: + { + char x = bfd_get_8 (abfd, addr); + DOIT (x); + bfd_put_8 (abfd, x, addr); + } + break; + + case 1: + { + short x = bfd_get_16 (abfd, addr); + DOIT (x); + bfd_put_16 (abfd, (bfd_vma) x, addr); + } + break; + + case 2: + { + long x = bfd_get_32 (abfd, addr); + DOIT (x); + bfd_put_32 (abfd, (bfd_vma) x, addr); + } + break; + case 4: + { + long long x = bfd_get_64 (abfd, addr); + DOIT (x); + bfd_put_64 (abfd, (bfd_vma) x, addr); + } + break; + + default: + abort (); + } + } + + /* Now let bfd_perform_relocation finish everything up. */ + return bfd_reloc_continue; +} + +#ifdef COFF_WITH_PE +/* Return TRUE if this relocation should appear in the output .reloc + section. */ + +static bfd_boolean in_reloc_p(bfd *, reloc_howto_type *); + +static bfd_boolean in_reloc_p(bfd *abfd ATTRIBUTE_UNUSED,reloc_howto_type *howto) +{ + return ! howto->pc_relative && howto->type!=R_AMD64_IMAGEBASE; +} +#endif /* COFF_WITH_PE */ + +#ifndef PCRELOFFSET +#define PCRELOFFSET TRUE +#endif + +static reloc_howto_type howto_table[] = +{ + EMPTY_HOWTO (0), + HOWTO (R_AMD64_DIR64, /* type 1*/ + 0, /* rightshift */ + 4, /* size (0 = byte, 1 = short, 2 = long, 4 = long long) */ + 64, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + coff_amd64_reloc, /* special_function */ + "dir64", /* name */ + TRUE, /* partial_inplace */ + 0xffffffffffffffff, /* src_mask */ + 0xffffffffffffffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + HOWTO (R_AMD64_DIR32, /* type 2 */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + coff_amd64_reloc, /* special_function */ + "dir32", /* name */ + TRUE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + /* PE IMAGE_REL_AMD64_ADDR32NB relocation (3). */ + HOWTO (R_AMD64_IMAGEBASE, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + coff_amd64_reloc, /* special_function */ + "rva32", /* name */ + TRUE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + /* 32-bit longword PC relative relocation (4). */ + HOWTO (R_AMD64_PCRLONG, /* type 4 */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + coff_amd64_reloc, /* special_function */ + "DISP32", /* name */ + TRUE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + PCRELOFFSET), /* pcrel_offset */ + + HOWTO (R_AMD64_PCRLONG_1, /* type 5 */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + coff_amd64_reloc, /* special_function */ + "DISP32", /* name */ + TRUE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + PCRELOFFSET), /* pcrel_offset */ + HOWTO (R_AMD64_PCRLONG_2, /* type 6 */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + coff_amd64_reloc, /* special_function */ + "DISP32", /* name */ + TRUE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + PCRELOFFSET), /* pcrel_offset */ + HOWTO (R_AMD64_PCRLONG_3, /* type 7 */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + coff_amd64_reloc, /* special_function */ + "DISP32", /* name */ + TRUE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + PCRELOFFSET), /* pcrel_offset */ + HOWTO (R_AMD64_PCRLONG_4, /* type 8 */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + coff_amd64_reloc, /* special_function */ + "DISP32", /* name */ + TRUE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + PCRELOFFSET), /* pcrel_offset */ + HOWTO (R_AMD64_PCRLONG_5, /* type 9 */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + coff_amd64_reloc, /* special_function */ + "DISP32", /* name */ + TRUE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + PCRELOFFSET), /* pcrel_offset */ + EMPTY_HOWTO (10), // R_AMD64_SECTION 10 +#ifdef COFF_WITH_PE + /* 32-bit longword section relative relocation (11). */ + HOWTO (R_AMD64_SECREL, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + coff_amd64_reloc, /* special_function */ + "secrel32", /* name */ + TRUE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + TRUE), /* pcrel_offset */ +#else + EMPTY_HOWTO (11), +#endif + EMPTY_HOWTO (12), + EMPTY_HOWTO (13), + EMPTY_HOWTO (14), + /* Byte relocation (15). */ + HOWTO (R_RELBYTE, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + coff_amd64_reloc, /* special_function */ + "8", /* name */ + TRUE, /* partial_inplace */ + 0x000000ff, /* src_mask */ + 0x000000ff, /* dst_mask */ + PCRELOFFSET), /* pcrel_offset */ + /* 16-bit word relocation (16). */ + HOWTO (R_RELWORD, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + coff_amd64_reloc, /* special_function */ + "16", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + PCRELOFFSET), /* pcrel_offset */ + /* 32-bit longword relocation (17). */ + HOWTO (R_RELLONG, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + coff_amd64_reloc, /* special_function */ + "32", /* name */ + TRUE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + PCRELOFFSET), /* pcrel_offset */ + /* Byte PC relative relocation (18). */ + HOWTO (R_PCRBYTE, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + coff_amd64_reloc, /* special_function */ + "DISP8", /* name */ + TRUE, /* partial_inplace */ + 0x000000ff, /* src_mask */ + 0x000000ff, /* dst_mask */ + PCRELOFFSET), /* pcrel_offset */ + /* 16-bit word PC relative relocation (19). */ + HOWTO (R_PCRWORD, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + coff_amd64_reloc, /* special_function */ + "DISP16", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + PCRELOFFSET), /* pcrel_offset */ + /* 32-bit longword PC relative relocation (20). */ + HOWTO (R_PCRLONG, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + coff_amd64_reloc, /* special_function */ + "DISP32", /* name */ + TRUE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + PCRELOFFSET) /* pcrel_offset */ +}; + +/* Turn a howto into a reloc nunmber */ + +#define SELECT_RELOC(x,howto) { x.r_type = howto->type; } +#define I386 1 /* Customize coffcode.h */ +#define AMD64 1 +#define RTYPE2HOWTO(cache_ptr, dst) \ + ((cache_ptr)->howto = \ + ((dst)->r_type < sizeof (howto_table) / sizeof (howto_table[0]) \ + ? howto_table + (dst)->r_type \ + : NULL)) + +/* For 386 COFF a STYP_NOLOAD | STYP_BSS section is part of a shared + library. On some other COFF targets STYP_BSS is normally + STYP_NOLOAD. */ +#define BSS_NOLOAD_IS_SHARED_LIBRARY + +/* Compute the addend of a reloc. If the reloc is to a common symbol, + the object file contains the value of the common symbol. By the + time this is called, the linker may be using a different symbol + from a different object file with a different value. Therefore, we + hack wildly to locate the original symbol from this file so that we + can make the correct adjustment. This macro sets coffsym to the + symbol from the original file, and uses it to set the addend value + correctly. If this is not a common symbol, the usual addend + calculation is done, except that an additional tweak is needed for + PC relative relocs. + FIXME: This macro refers to symbols and asect; these are from the + calling function, not the macro arguments. */ + +#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr) \ + { \ + coff_symbol_type *coffsym = (coff_symbol_type *) NULL; \ + if(ptr && bfd_asymbol_bfd (ptr)!=abfd) \ + coffsym = (obj_symbols (abfd) \ + + (cache_ptr->sym_ptr_ptr - symbols)); \ + else if(ptr) \ + coffsym = coff_symbol_from (abfd, ptr); \ + if(coffsym!=(coff_symbol_type *) NULL \ + && coffsym->native->u.syment.n_scnum == 0) \ + cache_ptr->addend = - coffsym->native->u.syment.n_value; \ + else if(ptr && bfd_asymbol_bfd (ptr) == abfd \ + && ptr->section!=(asection *) NULL) \ + cache_ptr->addend = - (ptr->section->vma + ptr->value); \ + else \ + cache_ptr->addend = 0; \ + if(ptr && howto_table[reloc.r_type].pc_relative) \ + cache_ptr->addend += asect->vma; \ + } + +/* We use the special COFF backend linker. For normal AMD64 COFF, we + can use the generic relocate_section routine. For PE, we need our + own routine. */ + +#ifndef COFF_WITH_PE + +#define coff_relocate_section _bfd_coff_generic_relocate_section + +#else /* COFF_WITH_PE */ + +/* The PE relocate section routine. The only difference between this + and the regular routine is that we don't want to do anything for a + relocatable link. */ + +static bfd_boolean coff_pe_amd64_relocate_section(bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,struct internal_reloc *, struct internal_syment *, asection **); + +static bfd_boolean +coff_pe_amd64_relocate_section(bfd *output_bfd,struct bfd_link_info *info,bfd *input_bfd,asection *input_section,bfd_byte *contents,struct internal_reloc *relocs,struct internal_syment *syms,asection **sections) +{ + if(info->relocatable) + return TRUE; + + return _bfd_coff_generic_relocate_section(output_bfd, info, input_bfd,input_section, contents,relocs, syms, sections); +} + +#define coff_relocate_section coff_pe_amd64_relocate_section + +#endif /* COFF_WITH_PE */ + +/* Convert an rtype to howto for the COFF backend linker. */ + +static reloc_howto_type * +coff_amd64_rtype_to_howto(bfd *abfd ATTRIBUTE_UNUSED,asection *sec,struct internal_reloc *rel,struct coff_link_hash_entry *h,struct internal_syment *sym,bfd_vma *addendp) +{ + reloc_howto_type *howto; + + if(rel->r_type > sizeof (howto_table) / sizeof (howto_table[0])) { + bfd_set_error (bfd_error_bad_value); + return NULL; + } + if(rel->r_type>=R_AMD64_PCRLONG_1 && rel->r_type<=R_AMD64_PCRLONG_5) { + rel->r_vaddr+=(bfd_vma)(rel->r_type-R_AMD64_PCRLONG); + rel->r_type=R_AMD64_PCRLONG; + } + howto = howto_table + rel->r_type; + +#ifdef COFF_WITH_PE + /* Cancel out code in _bfd_coff_generic_relocate_section. */ + *addendp = 0; +#endif + + if(howto->pc_relative) + *addendp += sec->vma; + + if(sym!=NULL && sym->n_scnum == 0 && sym->n_value!=0) + { + /* This is a common symbol. The section contents include the + size (sym->n_value) as an addend. The relocate_section + function will be adding in the final value of the symbol. We + need to subtract out the current size in order to get the + correct result. */ + + //BFD_ASSERT (h!=NULL); + +#ifndef COFF_WITH_PE + /* I think we *do* want to bypass this. If we don't, I have + seen some data parameters get the wrong relocation address. + If I link two versions with and without this section bypassed + and then do a binary comparison, the addresses which are + different can be looked up in the map. The case in which + this section has been bypassed has addresses which correspond + to values I can find in the map. */ + *addendp -= sym->n_value; +#endif + } + +#ifndef COFF_WITH_PE + /* If the output symbol is common (in which case this must be a + relocatable link), we need to add in the final size of the + common symbol. */ + if(h!=NULL && h->root.type == bfd_link_hash_common) + *addendp += h->root.u.c.size; +#endif + +#ifdef COFF_WITH_PE + if(howto->pc_relative) + { + *addendp -= 4; + + /* If the symbol is defined, then the generic code is going to + add back the symbol value in order to cancel out an + adjustment it made to the addend. However, we set the addend + to 0 at the start of this function. We need to adjust here, + to avoid the adjustment the generic code will make. FIXME: + This is getting a bit hackish. */ + if(sym!=NULL && sym->n_scnum!=0) + *addendp -= sym->n_value; + } + + if(rel->r_type == R_AMD64_IMAGEBASE && (bfd_get_flavour(sec->output_section->owner) == bfd_target_coff_flavour)) { + *addendp -= pe_data(sec->output_section->owner)->pe_opthdr.ImageBase; + } + + if(rel->r_type == R_AMD64_SECREL) { + bfd_vma osect_vma; + + if(h && (h->type == bfd_link_hash_defined || h->type == bfd_link_hash_defweak)) + osect_vma = h->root.u.def.section->output_section->vma; + else { + asection *sec; + int i; + + /* Sigh, the only way to get the section to offset against + is to find it the hard way. */ + + for (sec = abfd->sections, i = 1; i < sym->n_scnum; i++) + sec = sec->next; + + osect_vma = sec->output_section->vma; + } + + *addendp -= osect_vma; + } +#endif + + return howto; +} + +#define coff_bfd_reloc_type_lookup coff_amd64_reloc_type_lookup + +static reloc_howto_type * +coff_amd64_reloc_type_lookup(bfd *abfd ATTRIBUTE_UNUSED,bfd_reloc_code_real_type code) +{ + switch (code) { + case BFD_RELOC_RVA: + return howto_table + R_AMD64_IMAGEBASE; + case BFD_RELOC_32: + return howto_table + R_AMD64_DIR32; + case BFD_RELOC_64: + return howto_table + R_AMD64_DIR64; + case BFD_RELOC_32_PCREL: + case BFD_RELOC_X86_64_32S: + return howto_table + R_AMD64_PCRLONG; + case BFD_RELOC_16: + return howto_table + R_RELWORD; + case BFD_RELOC_16_PCREL: + return howto_table + R_PCRWORD; + case BFD_RELOC_8: + return howto_table + R_RELBYTE; + case BFD_RELOC_8_PCREL: + return howto_table + R_PCRBYTE; +#ifdef COFF_WITH_PE + case BFD_RELOC_32_SECREL: + return howto_table + R_AMD64_SECREL; +#endif + default: + BFD_FAIL (); + return 0; + } +} + +#define coff_rtype_to_howto coff_amd64_rtype_to_howto + +#ifdef TARGET_UNDERSCORE + +/* If amd64 gcc uses underscores for symbol names, then it does not use + a leading dot for local labels, so if TARGET_UNDERSCORE is defined + we treat all symbols starting with L as local. */ + +static bfd_boolean coff_amd64_is_local_label_name(bfd *, const char *); + +static bfd_boolean coff_amd64_is_local_label_name(bfd *abfd,const char *name) +{ + if(name[0] == 'L') + return TRUE; + + return _bfd_coff_is_local_label_name (abfd, name); +} + +#define coff_bfd_is_local_label_name coff_amd64_is_local_label_name + +#endif /* TARGET_UNDERSCORE */ + +#include "coffcode.h" + +#ifdef PE +#define amd64coff_object_p pe_bfd_object_p +#else +#define amd64coff_object_p coff_object_p +#endif + +const bfd_target +#ifdef TARGET_SYM + TARGET_SYM = +#else + x86_64coff_vec = +#endif +{ +#ifdef TARGET_NAME + TARGET_NAME, +#else + "coff-x86-64", /* name */ +#endif + bfd_target_coff_flavour, + BFD_ENDIAN_LITTLE, /* data byte order is little */ + BFD_ENDIAN_LITTLE, /* header byte order is little */ + + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), + + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC /* section flags */ +#ifdef COFF_WITH_PE + | SEC_LINK_ONCE | SEC_LINK_DUPLICATES | SEC_READONLY +#endif + | SEC_CODE | SEC_DATA), + +#ifdef TARGET_UNDERSCORE + TARGET_UNDERSCORE, /* leading underscore */ +#else + 0, /* leading underscore */ +#endif + '/', /* ar_pad_char */ + 15, /* ar_max_namelen */ + + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ + +/* Note that we allow an object file to be treated as a core file as well. */ + {_bfd_dummy_target, amd64coff_object_p, /* bfd_check_format */ + bfd_generic_archive_p, amd64coff_object_p}, + {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ + bfd_false}, + {bfd_false, coff_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (coff), + BFD_JUMP_TABLE_COPY (coff), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), + BFD_JUMP_TABLE_SYMBOLS (coff), + BFD_JUMP_TABLE_RELOCS (coff), + BFD_JUMP_TABLE_WRITE (coff), + BFD_JUMP_TABLE_LINK (coff), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + NULL, + + COFF_SWAP_TABLE +}; diff -rNbu binutils-2.17_org/bfd/coffcode.h binutils-2.17/bfd/coffcode.h --- binutils-2.17_org/bfd/coffcode.h 2005-10-25 19:40:09.000000000 +0200 +++ binutils-2.17/bfd/coffcode.h 2006-08-09 12:00:50.000000000 +0200 @@ -1883,6 +1883,12 @@ arch = bfd_arch_i386; break; #endif +#ifdef AMD64MAGIC + case AMD64MAGIC: + arch=bfd_arch_i386; + machine=bfd_mach_x86_64; + break; +#endif #ifdef IA64MAGIC case IA64MAGIC: arch = bfd_arch_ia64; @@ -2713,13 +2719,18 @@ return TRUE; #endif -#ifdef I386MAGIC +#if defined(I386MAGIC) || defined(AMD64MAGIC) case bfd_arch_i386: +#ifdef I386MAGIC *magicp = I386MAGIC; +#endif #ifdef LYNXOS /* Just overwrite the usual value if we're doing Lynx. */ *magicp = LYNXCOFFMAGIC; #endif +#ifdef AMD64MAGIC + *magicp=AMD64MAGIC; +#endif return TRUE; #endif @@ -3752,13 +3763,17 @@ #endif #ifdef COFF_WITH_PE +#if !defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64) internal_f.f_flags |= IMAGE_FILE_32BIT_MACHINE; +#endif #else +#ifndef COFF_WITH_pex64 if (bfd_little_endian (abfd)) internal_f.f_flags |= F_AR32WR; else internal_f.f_flags |= F_AR32W; #endif +#endif #ifdef TI_TARGET_ID /* Target id is used in TI COFF v1 and later; COFF0 won't use this field, @@ -3855,7 +3870,11 @@ #if defined(LYNXOS) internal_a.magic = LYNXCOFFMAGIC; #else /* LYNXOS */ +#ifdef AMD64 + internal_a.magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC; +#else internal_a.magic = ZMAGIC; +#endif #endif /* LYNXOS */ #endif /* I386 */ diff -rNbu binutils-2.17_org/bfd/config.bfd binutils-2.17/bfd/config.bfd --- binutils-2.17_org/bfd/config.bfd 2006-04-05 14:41:57.000000000 +0200 +++ binutils-2.17/bfd/config.bfd 2006-07-27 10:10:35.000000000 +0200 @@ -98,7 +98,7 @@ strongarm*) targ_archs=bfd_arm_arch ;; thumb*) targ_archs=bfd_arm_arch ;; v850*) targ_archs=bfd_v850_arch ;; -x86_64) targ_archs=bfd_i386_arch ;; +x86_64*) targ_archs=bfd_i386_arch ;; xscale*) targ_archs=bfd_arm_arch ;; xtensa*) targ_archs=bfd_xtensa_arch ;; z80|r800) targ_archs=bfd_z80_arch ;; @@ -562,6 +562,11 @@ targ_defvec=bfd_elf64_x86_64_vec targ_selvecs="bfd_elf32_i386_vec i386linux_vec bfd_efi_app_ia32_vec" ;; + x86_64-*-mingw64*) + targ_defvec=x86_64pe_vec + targ_selvecs="x86_64pe_vec x86_64pei_vec x86_64coff_vec bfd_elf64_x86_64_vec" + targ_underscore=yes + ;; #endif i[3-7]86-*-lynxos*) targ_defvec=bfd_elf32_i386_vec diff -rNbu binutils-2.17_org/bfd/configure binutils-2.17/bfd/configure --- binutils-2.17_org/bfd/configure 2006-06-23 20:17:03.000000000 +0200 +++ binutils-2.17/bfd/configure 2006-08-03 16:38:04.000000000 +0200 @@ -4087,7 +4087,7 @@ rm -rf conftest* ;; -x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) +x86_64-*linux*|x86_64-*mingw64*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 @@ -4114,6 +4114,9 @@ ;; *64-bit*) case $host in + x86_64-*mingw64*) + LD="${LD-ld} -m elf_x86_64" + ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; @@ -13216,6 +13219,7 @@ i386aout_vec) tb="$tb i386aout.lo aout32.lo" ;; i386bsd_vec) tb="$tb i386bsd.lo aout32.lo" ;; i386coff_vec) tb="$tb coff-i386.lo cofflink.lo" ;; + x86_64coff_vec) tb="$tb coff-x86_64.lo cofflink.lo"; target_size=64 ;; i386dynix_vec) tb="$tb i386dynix.lo aout32.lo" ;; i386freebsd_vec) tb="$tb i386freebsd.lo aout32.lo" ;; i386linux_vec) tb="$tb i386linux.lo aout32.lo" ;; @@ -13226,7 +13230,9 @@ i386netbsd_vec) tb="$tb i386netbsd.lo aout32.lo" ;; i386os9k_vec) tb="$tb i386os9k.lo aout32.lo" ;; i386pe_vec) tb="$tb pe-i386.lo peigen.lo cofflink.lo" ;; - i386pei_vec) tb="$tb pei-i386.lo peigen.lo cofflink.lo" ;; + x86_64pe_vec) tb="$tb pe-x86_64.lo pex64igen.lo cofflink.lo"; target_size=64 ;; + i386pei_vec) tb="$tb pei-i386.lo pepigen.lo cofflink.lo" ;; + x86_64pei_vec) tb="$tb pei-x86_64.lo pex64igen.lo cofflink.lo"; target_size=64 ;; i860coff_vec) tb="$tb coff-i860.lo cofflink.lo" ;; icoff_big_vec) tb="$tb coff-i960.lo cofflink.lo" ;; icoff_little_vec) tb="$tb coff-i960.lo cofflink.lo" ;; diff -rNbu binutils-2.17_org/bfd/configure.in binutils-2.17/bfd/configure.in --- binutils-2.17_org/bfd/configure.in 2006-06-23 20:17:07.000000000 +0200 +++ binutils-2.17/bfd/configure.in 2006-08-03 16:39:09.000000000 +0200 @@ -729,6 +729,7 @@ i386aout_vec) tb="$tb i386aout.lo aout32.lo" ;; i386bsd_vec) tb="$tb i386bsd.lo aout32.lo" ;; i386coff_vec) tb="$tb coff-i386.lo cofflink.lo" ;; + x86_64coff_vec) tb="$tb coff-x86_64.lo cofflink.lo"; target_size=64 ;; i386dynix_vec) tb="$tb i386dynix.lo aout32.lo" ;; i386freebsd_vec) tb="$tb i386freebsd.lo aout32.lo" ;; i386linux_vec) tb="$tb i386linux.lo aout32.lo" ;; @@ -739,7 +740,9 @@ i386netbsd_vec) tb="$tb i386netbsd.lo aout32.lo" ;; i386os9k_vec) tb="$tb i386os9k.lo aout32.lo" ;; i386pe_vec) tb="$tb pe-i386.lo peigen.lo cofflink.lo" ;; + x86_64pe_vec) tb="$tb pe-x86_64.lo pex64igen.lo cofflink.lo"; target_size=64 ;; i386pei_vec) tb="$tb pei-i386.lo peigen.lo cofflink.lo" ;; + x86_64pei_vec) tb="$tb pei-x86_64.lo pex64igen.lo cofflink.lo"; target_size=64 ;; i860coff_vec) tb="$tb coff-i860.lo cofflink.lo" ;; icoff_big_vec) tb="$tb coff-i960.lo cofflink.lo" ;; icoff_little_vec) tb="$tb coff-i960.lo cofflink.lo" ;; diff -rNbu binutils-2.17_org/bfd/libpei.h binutils-2.17/bfd/libpei.h --- binutils-2.17_org/bfd/libpei.h 2005-05-04 17:53:35.000000000 +0200 +++ binutils-2.17/bfd/libpei.h 2006-08-09 10:42:52.000000000 +0200 @@ -204,6 +204,38 @@ #define PUT_SCNHDR_LNNOPTR H_PUT_32 #endif +#ifdef COFF_WITH_pex64 +#define GET_OPTHDR_IMAGE_BASE H_GET_64 +#define PUT_OPTHDR_IMAGE_BASE H_PUT_64 +#define GET_OPTHDR_SIZE_OF_STACK_RESERVE H_GET_64 +#define PUT_OPTHDR_SIZE_OF_STACK_RESERVE H_PUT_64 +#define GET_OPTHDR_SIZE_OF_STACK_COMMIT H_GET_64 +#define PUT_OPTHDR_SIZE_OF_STACK_COMMIT H_PUT_64 +#define GET_OPTHDR_SIZE_OF_HEAP_RESERVE H_GET_64 +#define PUT_OPTHDR_SIZE_OF_HEAP_RESERVE H_PUT_64 +#define GET_OPTHDR_SIZE_OF_HEAP_COMMIT H_GET_64 +#define PUT_OPTHDR_SIZE_OF_HEAP_COMMIT H_PUT_64 +#define GET_PDATA_ENTRY bfd_get_32 + +#define _bfd_XX_bfd_copy_private_bfd_data_common _bfd_pex64_bfd_copy_private_bfd_data_common +#define _bfd_XX_bfd_copy_private_section_data _bfd_pex64_bfd_copy_private_section_data +#define _bfd_XX_get_symbol_info _bfd_pex64_get_symbol_info +#define _bfd_XX_only_swap_filehdr_out _bfd_pex64_only_swap_filehdr_out +#define _bfd_XX_print_private_bfd_data_common _bfd_pex64_print_private_bfd_data_common +#define _bfd_XXi_final_link_postscript _bfd_pex64i_final_link_postscript +#define _bfd_XXi_final_link_postscript _bfd_pex64i_final_link_postscript +#define _bfd_XXi_only_swap_filehdr_out _bfd_pex64i_only_swap_filehdr_out +#define _bfd_XXi_swap_aouthdr_in _bfd_pex64i_swap_aouthdr_in +#define _bfd_XXi_swap_aouthdr_out _bfd_pex64i_swap_aouthdr_out +#define _bfd_XXi_swap_aux_in _bfd_pex64i_swap_aux_in +#define _bfd_XXi_swap_aux_out _bfd_pex64i_swap_aux_out +#define _bfd_XXi_swap_lineno_in _bfd_pex64i_swap_lineno_in +#define _bfd_XXi_swap_lineno_out _bfd_pex64i_swap_lineno_out +#define _bfd_XXi_swap_scnhdr_out _bfd_pex64i_swap_scnhdr_out +#define _bfd_XXi_swap_sym_in _bfd_pex64i_swap_sym_in +#define _bfd_XXi_swap_sym_out _bfd_pex64i_swap_sym_out + +#else /* !COFF_WITH_pex64 */ #ifdef COFF_WITH_pep #define GET_OPTHDR_IMAGE_BASE H_GET_64 @@ -269,6 +301,7 @@ #define _bfd_XXi_swap_sym_out _bfd_pei_swap_sym_out #endif /* !COFF_WITH_pep */ +#endif /* !COFF_WITH_pex64 */ /* Macro: Returns true if the bfd is a PE executable as opposed to a PE object file. */ #define bfd_pe_executable_p(abfd) \ diff -rNbu binutils-2.17_org/bfd/pe-x86_64.c binutils-2.17/bfd/pe-x86_64.c --- binutils-2.17_org/bfd/pe-x86_64.c 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.17/bfd/pe-x86_64.c 2006-08-17 09:06:42.000000000 +0200 @@ -0,0 +1,54 @@ +/* BFD back-end for Intel/AMD x86_64 PECOFF files. + Copyright 1995, 1996, 1999, 2001, 2002, 2004 Free Software Foundation, Inc. + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 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. + + Written by Kai Tietz, OneVision Software GmbH&CoKg. +*/ + +#include "bfd.h" +#include "sysdep.h" + +#define TARGET_SYM x86_64pe_vec +#define TARGET_NAME "pe-x86-64" +#define COFF_WITH_PE +#define COFF_WITH_pex64 +#define PCRELOFFSET TRUE +#define TARGET_UNDERSCORE '_' +#define COFF_LONG_SECTION_NAMES +#define COFF_SUPPORT_GNU_LINKONCE +#define COFF_LONG_FILENAMES + +#define COFF_SECTION_ALIGNMENT_ENTRIES \ +{ COFF_SECTION_NAME_EXACT_MATCH (".bss"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \ +{ COFF_SECTION_NAME_EXACT_MATCH (".data"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \ +{ COFF_SECTION_NAME_EXACT_MATCH (".rdata"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \ +{ COFF_SECTION_NAME_EXACT_MATCH (".text"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \ +{ COFF_SECTION_NAME_PARTIAL_MATCH (".idata"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ +{ COFF_SECTION_NAME_EXACT_MATCH (".pdata"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ +{ COFF_SECTION_NAME_PARTIAL_MATCH (".debug"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 }, \ +{ COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.wi."), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 } + +#include "coff-x86_64.c" diff -rNbu binutils-2.17_org/bfd/peXXigen.c binutils-2.17/bfd/peXXigen.c --- binutils-2.17_org/bfd/peXXigen.c 2006-01-09 16:58:42.000000000 +0100 +++ binutils-2.17/bfd/peXXigen.c 2006-08-09 11:57:35.000000000 +0200 @@ -52,7 +52,7 @@ on this code has a chance of getting something accomplished without wasting too much time. */ -/* This expands into COFF_WITH_pe or COFF_WITH_pep depending on whether +/* This expands into COFF_WITH_pe, COFF_WITH_pep, or COFF_WITH_pex64 depending on whether we're compiling for straight PE or PE+. */ #define COFF_WITH_XX @@ -67,17 +67,21 @@ within PE/PEI, so we get them from there. FIXME: The lack of variance is an assumption which may prove to be incorrect if new PE/PEI targets are created. */ +#ifdef COFF_WITH_pex64 +# include "coff/x86_64.h" +#else #ifdef COFF_WITH_pep # include "coff/ia64.h" #else # include "coff/i386.h" #endif +#endif #include "coff/pe.h" #include "libcoff.h" #include "libpei.h" -#ifdef COFF_WITH_pep +#if defined(COFF_WITH_pep) || defined(COFF_WITH_pex64) # undef AOUTSZ # define AOUTSZ PEPAOUTSZ # define PEAOUTHDR PEPAOUTHDR @@ -398,7 +402,7 @@ aouthdr_int->entry = GET_AOUTHDR_ENTRY (abfd, aouthdr_ext->entry); aouthdr_int->text_start = GET_AOUTHDR_TEXT_START (abfd, aouthdr_ext->text_start); -#ifndef COFF_WITH_pep +#if !defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64) /* PE32+ does not have data_start member! */ aouthdr_int->data_start = GET_AOUTHDR_DATA_START (abfd, aouthdr_ext->data_start); @@ -454,7 +458,7 @@ if (aouthdr_int->entry) { aouthdr_int->entry += a->ImageBase; -#ifndef COFF_WITH_pep +#if !defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64) aouthdr_int->entry &= 0xffffffff; #endif } @@ -462,12 +466,12 @@ if (aouthdr_int->tsize) { aouthdr_int->text_start += a->ImageBase; -#ifndef COFF_WITH_pep +#if !defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64) aouthdr_int->text_start &= 0xffffffff; #endif } -#ifndef COFF_WITH_pep +#if !defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64) /* PE32+ does not have data_start member! */ if (aouthdr_int->dsize) { @@ -547,7 +551,7 @@ if (aouthdr_in->tsize) { aouthdr_in->text_start -= ib; -#ifndef COFF_WITH_pep +#if !defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64) aouthdr_in->text_start &= 0xffffffff; #endif } @@ -555,7 +559,7 @@ if (aouthdr_in->dsize) { aouthdr_in->data_start -= ib; -#ifndef COFF_WITH_pep +#if !defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64) aouthdr_in->data_start &= 0xffffffff; #endif } @@ -563,7 +567,7 @@ if (aouthdr_in->entry) { aouthdr_in->entry -= ib; -#ifndef COFF_WITH_pep +#if !defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64) aouthdr_in->entry &= 0xffffffff; #endif } @@ -660,7 +664,7 @@ PUT_AOUTHDR_TEXT_START (abfd, aouthdr_in->text_start, aouthdr_out->standard.text_start); -#ifndef COFF_WITH_pep +#if !defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64) /* PE32+ does not have data_start member! */ PUT_AOUTHDR_DATA_START (abfd, aouthdr_in->data_start, aouthdr_out->standard.data_start); @@ -1261,6 +1265,35 @@ } /* Print HintName vector entries. */ +#ifdef COFF_WITH_pex64 + for (j = 0; j < datasize; j += 8) + { + unsigned long member = bfd_get_32(abfd,data+idx+j); + unsigned long member_high = bfd_get_32(abfd,data+idx+j+4); + if(!member && !member_high) break; + if (member_high & 0x80000000) + fprintf (file, "\t%lx%08lx\t %4lx%08lx ", + member_high,member, member_high & 0x7fffffff,member); + else + { + int ordinal; + char *member_name; + + ordinal = bfd_get_16 (abfd, data + member - adj); + member_name = (char *) data + member - adj + 2; + fprintf (file, "\t%04lx\t %4d %s",member, ordinal, member_name); + } + + /* If the time stamp is not zero, the import address + table holds actual addresses. */ + if (time_stamp != 0 + && first_thunk != 0 + && first_thunk != hint_addr) + fprintf (file, "\t%04lx", + (long) bfd_get_32 (abfd, ft_data + ft_idx + j)); + fprintf (file, "\n"); + } +#else for (j = 0; j < datasize; j += 4) { unsigned long member = bfd_get_32 (abfd, data + idx + j); @@ -1290,9 +1323,9 @@ && first_thunk != hint_addr) fprintf (file, "\t%04lx", (long) bfd_get_32 (abfd, ft_data + ft_idx + j)); - fprintf (file, "\n"); } +#endif if (ft_allocated) free (ft_data); @@ -1533,7 +1566,7 @@ static bfd_boolean pe_print_pdata (bfd * abfd, void * vfile) { -#ifdef COFF_WITH_pep +#if defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64) # define PDATA_ROW_SIZE (3*8) #else # define PDATA_ROW_SIZE (5*4) @@ -1559,7 +1592,7 @@ fprintf (file, _("\nThe Function Table (interpreted .pdata section contents)\n")); -#ifdef COFF_WITH_pep +#if defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64) fprintf (file, _(" vma:\t\t\tBegin Address End Address Unwind Info\n")); #else @@ -1613,7 +1646,7 @@ fprintf_vma (file, begin_addr); fputc (' ', file); fprintf_vma (file, end_addr); fputc (' ', file); fprintf_vma (file, eh_handler); -#ifndef COFF_WITH_pep +#if !defined(COFF_WITH_pep) || defined(COFF_WITH_pex64) fputc (' ', file); fprintf_vma (file, eh_data); fputc (' ', file); fprintf_vma (file, prolog_end_addr); diff -rNbu binutils-2.17_org/bfd/pei-x86_64.c binutils-2.17/bfd/pei-x86_64.c --- binutils-2.17_org/bfd/pei-x86_64.c 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.17/bfd/pei-x86_64.c 2006-08-17 09:06:59.000000000 +0200 @@ -0,0 +1,55 @@ +/* BFD back-end for Intel 386 PE IMAGE COFF files. + Copyright 1995, 1996, 1999, 2001, 2002, 2004 Free Software Foundation, Inc. + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 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. + + Written by Kai Tietz, OneVision Software GmbH&CoKg. +*/ + +#include "bfd.h" +#include "sysdep.h" + +#define TARGET_SYM x86_64pei_vec +#define TARGET_NAME "pei-x86-64" +#define COFF_IMAGE_WITH_PE +#define COFF_WITH_PE +#define COFF_WITH_pex64 +#define PCRELOFFSET TRUE +#define TARGET_UNDERSCORE '_' +#define COFF_LONG_SECTION_NAMES +#define COFF_SUPPORT_GNU_LINKONCE +#define COFF_LONG_FILENAMES + +#define COFF_SECTION_ALIGNMENT_ENTRIES \ +{ COFF_SECTION_NAME_EXACT_MATCH (".bss"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \ +{ COFF_SECTION_NAME_EXACT_MATCH (".data"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \ +{ COFF_SECTION_NAME_EXACT_MATCH (".rdata"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \ +{ COFF_SECTION_NAME_EXACT_MATCH (".text"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \ +{ COFF_SECTION_NAME_PARTIAL_MATCH (".idata"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ +{ COFF_SECTION_NAME_EXACT_MATCH (".pdata"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ +{ COFF_SECTION_NAME_PARTIAL_MATCH (".debug"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 }, \ +{ COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.wi."), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 } + +#include "coff-x86_64.c" diff -rNbu binutils-2.17_org/bfd/peicode.h binutils-2.17/bfd/peicode.h --- binutils-2.17_org/bfd/peicode.h 2005-05-04 17:53:37.000000000 +0200 +++ binutils-2.17/bfd/peicode.h 2006-08-09 10:54:39.000000000 +0200 @@ -183,8 +183,16 @@ #ifdef COFF_IMAGE_WITH_PE # define coff_swap_filehdr_out _bfd_XXi_only_swap_filehdr_out #else +#ifdef COFF_WITH_pex64 +#define coff_swap_filehdr_out _bfd_pex64_only_swap_filehdr_out +#else +#ifdef COFF_WITH_pep +#define coff_swap_filehdr_out _bfd_pep_only_swap_filehdr_out +#else # define coff_swap_filehdr_out _bfd_pe_only_swap_filehdr_out #endif +#endif +#endif static void coff_swap_scnhdr_in (bfd * abfd, void * ext, void * in) @@ -363,7 +371,6 @@ #define coff_get_symbol_info _bfd_XX_get_symbol_info #ifdef COFF_IMAGE_WITH_PE - /* Code to handle Microsoft's Image Library Format. Also known as LINK6 format. Documentation about this format can be found at: @@ -405,8 +412,13 @@ + NUM_ILF_SECTIONS * 9 \ + STRING_SIZE_SIZE) #define SIZEOF_IDATA2 (5 * 4) +#ifndef COFF_WITH_pex64 #define SIZEOF_IDATA4 (1 * 4) #define SIZEOF_IDATA5 (1 * 4) +#else +#define SIZEOF_IDATA4 (2 * 4) +#define SIZEOF_IDATA5 (2 * 4) +#endif #define SIZEOF_IDATA6 (2 + strlen (symbol_name) + 1 + 1) #define SIZEOF_IDATA7 (strlen (source_dll) + 1 + 1) #define SIZEOF_ILF_SECTIONS (NUM_ILF_SECTIONS * sizeof (struct coff_section_tdata)) @@ -655,6 +667,12 @@ 8, 2 }, #endif +#ifdef AMD64MAGIC + { AMD64MAGIC, + { 0xff,0x25,0x00,0x00,0x00,0x00,0x90,0x90 }, + 8,2 + }, +#endif #ifdef MC68MAGIC { MC68MAGIC, { /* XXX fill me in */ }, 0, 0 }, @@ -830,8 +848,15 @@ /* XXX - treat as IMPORT_NAME ??? */ abort (); +#ifndef COFF_WITH_pex64 * (unsigned int *) id4->contents = ordinal | 0x80000000; * (unsigned int *) id5->contents = ordinal | 0x80000000; +#else + * (unsigned int *) id4->contents = ordinal; + ((unsigned int *) id4->contents)[1] = 0x80000000; + * (unsigned int *) id5->contents = ordinal; + ((unsigned int *) id5->contents)[1] = 0x80000000; +#endif } else { @@ -1070,7 +1095,11 @@ magic = I386MAGIC; #endif break; - + case IMAGE_FILE_MACHINE_AMD64: +#ifdef AMD64MAGIC + magic=AMD64MAGIC; +#endif + break; case IMAGE_FILE_MACHINE_M68K: #ifdef MC68AGIC magic = MC68MAGIC; @@ -1255,7 +1284,6 @@ bfd_set_error (bfd_error_wrong_format); return NULL; } - /* Here is the hack. coff_object_p wants to read filhsz bytes to pick up the COFF header for PE, see "struct external_PEI_filehdr" in include/coff/pe.h. We adjust so that that will work. */ @@ -1265,7 +1293,6 @@ bfd_set_error (bfd_error_wrong_format); return NULL; } - return coff_object_p (abfd); } diff -rNbu binutils-2.17_org/bfd/targets.c binutils-2.17/bfd/targets.c --- binutils-2.17_org/bfd/targets.c 2006-04-05 14:41:57.000000000 +0200 +++ binutils-2.17/bfd/targets.c 2006-08-04 11:57:01.000000000 +0200 @@ -782,6 +782,9 @@ extern const bfd_target we32kcoff_vec; extern const bfd_target z80coff_vec; extern const bfd_target z8kcoff_vec; +extern const bfd_target x86_64pe_vec; +extern const bfd_target x86_64pei_vec; +extern const bfd_target x86_64coff_vec; /* These are always included. */ extern const bfd_target srec_vec; @@ -1019,6 +1022,11 @@ #if 0 &i386dynix_vec, #endif +#ifdef BFD64 + &x86_64coff_vec, + &x86_64pe_vec, + &x86_64pei_vec, +#endif &i386freebsd_vec, #if 0 /* Since a.out files lack decent magic numbers, no way to recognize diff -rNbu binutils-2.17_org/binutils/configure binutils-2.17/binutils/configure --- binutils-2.17_org/binutils/configure 2006-04-06 23:49:29.000000000 +0200 +++ binutils-2.17/binutils/configure 2006-08-08 15:57:53.000000000 +0200 @@ -10722,6 +10722,12 @@ BUILD_WINDRES='$(WINDRES_PROG)$(EXEEXT)' BUILD_DLLWRAP='$(DLLWRAP_PROG)$(EXEEXT)' ;; + x86_64-*-mingw64*) + BUILD_DLLTOOL='$(DLLTOOL_PROG)$(EXEEXT)' + DLLTOOL_DEFS="$DLLTOOL_DEFS -DDLLTOOL_MX86_64" + BUILD_WINDRES='$(WINDRES_PROG)$(EXEEXT)' + BUILD_DLLWRAP='$(DLLWRAP_PROG)$(EXEEXT)' + ;; i[3-7]86-*-interix) BUILD_DLLTOOL='$(DLLTOOL_PROG)' DLLTOOL_DEFS="$DLLTOOL_DEFS -DDLLTOOL_I386" diff -rNbu binutils-2.17_org/binutils/configure.in binutils-2.17/binutils/configure.in --- binutils-2.17_org/binutils/configure.in 2006-04-06 23:49:29.000000000 +0200 +++ binutils-2.17/binutils/configure.in 2006-08-08 15:56:56.000000000 +0200 @@ -260,6 +260,14 @@ BUILD_DLLWRAP='$(DLLWRAP_PROG)$(EXEEXT)' ;; changequote(,)dnl + x86_64-*-mingw64*) +changequote([,])dnl + BUILD_DLLTOOL='$(DLLTOOL_PROG)$(EXEEXT)' + DLLTOOL_DEFS="$DLLTOOL_DEFS -DDLLTOOL_MX86_64" + BUILD_WINDRES='$(WINDRES_PROG)$(EXEEXT)' + BUILD_DLLWRAP='$(DLLWRAP_PROG)$(EXEEXT)' + ;; +changequote(,)dnl i[3-7]86-*-interix) changequote([,])dnl BUILD_DLLTOOL='$(DLLTOOL_PROG)' diff -rNbu binutils-2.17_org/binutils/dlltool.c binutils-2.17/binutils/dlltool.c --- binutils-2.17_org/binutils/dlltool.c 2006-03-09 22:50:53.000000000 +0100 +++ binutils-2.17/binutils/dlltool.c 2006-08-17 09:09:15.000000000 +0200 @@ -261,6 +261,9 @@ #include "coff/arm.h" #include "coff/internal.h" #endif +#ifdef DLLTOOL_MX86_64 +#include "coff/x86_64.h" +#endif /* Forward references. */ static char *look_for_prog (const char *, const char *, int); @@ -396,6 +399,10 @@ static const char *mname = "i386"; #endif +#ifdef DLLTOOL_MX86_64 +static const char *mname = "i386:x86-64"; +#endif + #ifdef DLLTOOL_PPC static const char *mname = "ppc"; #endif @@ -629,6 +636,14 @@ arm_jtab, sizeof (arm_jtab), 8 } , + { +#define MX86 10 + "i386:x86-64", ".byte", ".short", ".long", ".asciz", "#", + "jmp *", ".global", ".space", ".align\t2",".align\t4", "", + "pe-x86-64",bfd_arch_i386, + i386_jtab, sizeof (i386_jtab), 2 + } + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; @@ -752,6 +767,7 @@ { case MARM: case M386: + case MX86: case MPPC: case MTHUMB: case MARM_INTERWORK: @@ -776,6 +792,7 @@ { case MARM: case M386: + case MX86: case MPPC: case MTHUMB: case MARM_INTERWORK: @@ -809,6 +826,7 @@ case MARM_EPOC: break; case M386: + case MX86: /* Symbol names starting with ? do not have a leading underscore. */ if (name && *name == '?') break; diff -rNbu binutils-2.17_org/config.guess binutils-2.17/config.guess --- binutils-2.17_org/config.guess 2006-01-16 18:34:37.000000000 +0100 +++ binutils-2.17/config.guess 2006-07-26 15:22:53.000000000 +0200 @@ -777,6 +777,9 @@ i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; + i*:MINGW64*:*) + echo ${UNAME_MACHINE}-pc-mingw64 + exit ;; i*:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; diff -rNbu binutils-2.17_org/config.sub binutils-2.17/config.sub --- binutils-2.17_org/config.sub 2006-01-16 18:34:37.000000000 +0100 +++ binutils-2.17/config.sub 2006-07-26 15:25:35.000000000 +0200 @@ -683,6 +683,10 @@ basic_machine=i386-pc os=-mingw32 ;; + mingw64) + basic_machine=x86_64-pc + os=-mingw64 + ;; miniframe) basic_machine=m68000-convergent ;; @@ -1207,7 +1211,7 @@ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -mingw32* | -mingw64* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ diff -rNbu binutils-2.17_org/configure binutils-2.17/configure --- binutils-2.17_org/configure 2006-04-06 23:49:25.000000000 +0200 +++ binutils-2.17/configure 2006-07-26 15:29:08.000000000 +0200 @@ -1771,6 +1771,8 @@ ;; *-mingw32*) ;; + *-mingw64*) + ;; *-interix*) host_makefile_frag="config/mh-interix" ;; diff -rNbu binutils-2.17_org/gas/config/obj-coff.h binutils-2.17/gas/config/obj-coff.h --- binutils-2.17_org/gas/config/obj-coff.h 2006-08-03 15:18:32.000000000 +0200 +++ binutils-2.17/gas/config/obj-coff.h 2006-08-04 09:42:45.000000000 +0200 @@ -57,24 +57,28 @@ #endif #ifdef TC_I386 -#ifdef TE_PEP -#include "coff/x86_64.h" -#else +#ifndef TE_PEP #include "coff/i386.h" +#else +#include "coff/x86_64.h" #endif #ifdef TE_PE -#ifndef TE_PEP -#define TARGET_FORMAT "pe-i386" +#ifdef TE_PEP +#define TARGET_FORMAT "coff-x86-64" #else -#define TARGET_FORMAT "pe-x86-64" +#define TARGET_FORMAT "pe-i386" #endif #endif #ifndef TARGET_FORMAT +#ifdef TE_PEP +#define TARGET_FORMAT "coff-x86-64" +#else #define TARGET_FORMAT "coff-i386" #endif #endif +#endif #ifdef TC_M68K #include "coff/m68k.h" diff -rNbu binutils-2.17_org/gas/config/tc-i386.c binutils-2.17/gas/config/tc-i386.c --- binutils-2.17_org/gas/config/tc-i386.c 2006-04-07 08:40:57.000000000 +0200 +++ binutils-2.17/gas/config/tc-i386.c 2006-08-14 10:32:38.000000000 +0200 @@ -5469,7 +5469,8 @@ list = bfd_target_list (); for (l = list; *l != NULL; l++) - if (strcmp (*l, "elf64-x86-64") == 0) + if (strcmp (*l, "elf64-x86-64") == 0 || strcmp(*l,"coff-x86-64")==0 || strcmp(*l,"pe-x86-64")==0 || + strcmp(*l,"pei-x86-64")==0) { default_arch = "x86_64"; break; diff -rNbu binutils-2.17_org/gas/config/te-pep.h binutils-2.17/gas/config/te-pep.h --- binutils-2.17_org/gas/config/te-pep.h 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.17/gas/config/te-pep.h 2006-08-17 09:11:31.000000000 +0200 @@ -0,0 +1,6 @@ +#define TE_PEP +#define COFF_IMAGE_WITH_PE +#define COFF_WITH_PE +#define COFF_WITH_pex64 + +#include "te-pe.h" diff -rNbu binutils-2.17_org/gas/configure binutils-2.17/gas/configure --- binutils-2.17_org/gas/configure 2006-04-06 23:49:31.000000000 +0200 +++ binutils-2.17/gas/configure 2006-07-20 16:12:04.000000000 +0200 @@ -3922,7 +3922,7 @@ rm -rf conftest* ;; -x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) +x86_64-*linux*|x86_64-*mingw64*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 @@ -3936,6 +3936,9 @@ x86_64-*linux*) LD="${LD-ld} -m elf_i386" ;; + x86_64-*mingw64*) + LD="${LD-ld} -m elf_i386" + ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; @@ -3952,6 +3955,9 @@ x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; + x86_64-*mingw64*) + LD="${LD-ld} -m elf_x86_64" + ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; diff -rNbu binutils-2.17_org/gas/configure.in binutils-2.17/gas/configure.in --- binutils-2.17_org/gas/configure.in 2006-04-06 23:49:33.000000000 +0200 +++ binutils-2.17/gas/configure.in 2006-07-20 15:17:11.000000000 +0200 @@ -417,6 +417,19 @@ ;; esac ;; + x86_64) + case ${obj_format} in + aout) + emulations="$emulations i386coff i386elf" + ;; + coff) + emulations="$emulations i386aout i386elf" + ;; + elf) + emulations="$emulations i386aout i386coff" + ;; + esac + ;; esac fi diff -rNbu binutils-2.17_org/gas/configure.tgt binutils-2.17/gas/configure.tgt --- binutils-2.17_org/gas/configure.tgt 2006-04-05 14:41:57.000000000 +0200 +++ binutils-2.17/gas/configure.tgt 2006-08-03 14:15:58.000000000 +0200 @@ -77,7 +77,7 @@ strongarm*b) cpu_type=arm endian=big ;; strongarm*) cpu_type=arm endian=little ;; v850*) cpu_type=v850 ;; - x86_64) cpu_type=i386 arch=x86_64;; + x86_64*) cpu_type=i386 arch=x86_64;; xscale*be|xscale*b) cpu_type=arm endian=big ;; xscale*) cpu_type=arm endian=little ;; xtensa*) cpu_type=xtensa arch=xtensa ;; @@ -87,6 +87,8 @@ # Assign object format. Set fmt, em, and bfd_gas. generic_target=${cpu_type}-$vendor-$os +echo "$$$$: info: GAS want support target CPU ${generic_target}" >&2; + # Note: This table is alpha-sorted, please try to keep it that way. case ${generic_target} in alpha-*-*vms*) fmt=evax ;; @@ -210,6 +212,7 @@ i386-*-cygwin*) fmt=coff em=pe ;; i386-*-interix*) fmt=coff em=interix ;; i386-*-mingw32*) fmt=coff em=pe ;; + i386-*-mingw64*) fmt=coff em=pep ;; i386-*-nto-qnx*) fmt=elf ;; i386-*-*nt*) fmt=coff em=pe ;; i386-*-chaos) fmt=elf ;; diff -rNbu binutils-2.17_org/include/coff/external.h binutils-2.17/include/coff/external.h --- binutils-2.17_org/include/coff/external.h 2005-05-10 12:21:09.000000000 +0200 +++ binutils-2.17/include/coff/external.h 2006-08-07 13:08:59.000000000 +0200 @@ -55,6 +55,20 @@ #define AOUTHDRSZ 28 #define AOUTSZ 28 + +typedef struct external_aouthdr64 + { + char magic[2]; /* type of file */ + char vstamp[2]; /* version stamp */ + char tsize[4]; /* text size in bytes, padded to FW bdry*/ + char dsize[4]; /* initialized data " " */ + char bsize[4]; /* uninitialized data " " */ + char entry[4]; /* entry pt. */ + char text_start[4]; /* base of text used for this file */ + } +AOUTHDR64; +#define AOUTHDRSZ64 24 + #endif #ifndef DO_NOT_DEFINE_SCNHDR diff -rNbu binutils-2.17_org/include/coff/internal.h binutils-2.17/include/coff/internal.h --- binutils-2.17_org/include/coff/internal.h 2006-02-05 12:57:34.000000000 +0100 +++ binutils-2.17/include/coff/internal.h 2006-08-07 12:36:01.000000000 +0200 @@ -604,6 +604,22 @@ unsigned long r_offset; /* Used by Alpha ECOFF, SPARC, others */ }; +/* X86-64 relocations */ +#define R_AMD64_ABS 0 /* Reference is absolute, no relocation is necessary */ +#define R_AMD64_DIR64 1 /* 64-bit address (VA) */ +#define R_AMD64_DIR32 2 /* 32-bit address (VA) R_DIR32 */ +#define R_AMD64_IMAGEBASE 3 /* 32-bit absolute ref w/o base R_IMAGEBASE */ +#define R_AMD64_PCRLONG 4 /* 32-bit relative address from byte following reloc R_PCRLONG */ +#define R_AMD64_PCRLONG_1 5 /* 32-bit relative address from byte distance 1 from reloc */ +#define R_AMD64_PCRLONG_2 6 /* 32-bit relative address from byte distance 2 from reloc */ +#define R_AMD64_PCRLONG_3 7 /* 32-bit relative address from byte distance 3 from reloc */ +#define R_AMD64_PCRLONG_4 8 /* 32-bit relative address from byte distance 4 from reloc */ +#define R_AMD64_PCRLONG_5 9 /* 32-bit relative address from byte distance 5 from reloc */ +#define R_AMD64_SECTION 10 /* Section index */ +#define R_AMD64_SECREL 11 /* 32 bit offset from base of section containing target R_SECREL*/ +#define R_AMD64_SECREL7 12 /* 7 bit unsigned offset from base of section containing target */ +#define R_AMD64_TOKEN 13 /* 32 bit metadata token */ + #define R_DIR16 1 #define R_REL24 5 #define R_DIR32 6 diff -rNbu binutils-2.17_org/include/coff/pe.h binutils-2.17/include/coff/pe.h --- binutils-2.17_org/include/coff/pe.h 2005-05-10 12:21:09.000000000 +0200 +++ binutils-2.17/include/coff/pe.h 2006-08-07 13:08:12.000000000 +0200 @@ -119,6 +119,7 @@ #define IMAGE_FILE_MACHINE_THUMB 0x01c2 #define IMAGE_FILE_MACHINE_TRICORE 0x0520 #define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 +#define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8) #define IMAGE_SUBSYSTEM_UNKNOWN 0 #define IMAGE_SUBSYSTEM_NATIVE 1 @@ -233,7 +234,6 @@ typedef struct { AOUTHDR standard; - /* NT extra fields; see internal.h for descriptions. */ char ImageBase[4]; char SectionAlignment[4]; @@ -267,7 +267,7 @@ of just 4 bytes long. */ typedef struct { - AOUTHDR standard; + AOUTHDR64 standard; /* NT extra fields; see internal.h for descriptions. */ char ImageBase[8]; @@ -294,7 +294,7 @@ /* IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; */ char DataDirectory[16][2][4]; /* 16 entries, 2 elements/entry, 4 chars. */ } PEPAOUTHDR; -#define PEPAOUTSZ 240 +#define PEPAOUTSZ (AOUTHDRSZ64+196+5*4) /* 240 */ #undef E_FILNMLEN #define E_FILNMLEN 18 /* # characters in a file name. */ diff -rNbu binutils-2.17_org/include/coff/x86_64.h binutils-2.17/include/coff/x86_64.h --- binutils-2.17_org/include/coff/x86_64.h 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.17/include/coff/x86_64.h 2006-08-17 09:12:23.000000000 +0200 @@ -0,0 +1,67 @@ +/* coff information for AMD 64. + Copyright 1995, 1996, 1999, 2001, 2002, 2004 Free Software Foundation, Inc. + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 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. + + Written by Kai Tietz, OneVision Software GmbH&CoKg. +*/ + +#define L_LNNO_SIZE 2 +#define INCLUDE_COMDAT_FIELDS_IN_AUXENT +#include "coff/external.h" + +/* Bits for f_flags: + F_RELFLG relocation info stripped from file + F_EXEC file is executable (no unresolved external references) + F_LNNO line numbers stripped from file + F_LSYMS local symbols stripped from file + F_AR32WR file has byte ordering of an AR32WR machine (e.g. vax). */ + +#define F_RELFLG (0x0001) +#define F_EXEC (0x0002) +#define F_LNNO (0x0004) +#define F_LSYMS (0x0008) + +#define AMD64MAGIC 0x8664 + +#define AMD64BADMAG(x) ( (x).f_magic != AMD64MAGIC) +#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b + +#define OMAGIC 0404 /* object files, eg as output */ +#define ZMAGIC IMAGE_NT_OPTIONAL_HDR64_MAGIC /* demand load format, eg normal ld output 0x10b */ +#define STMAGIC 0401 /* target shlib */ +#define SHMAGIC 0443 /* host shlib */ + +/* define some NT default values */ +/* #define NT_IMAGE_BASE 0x400000 moved to internal.h */ +#define NT_SECTION_ALIGNMENT 0x1000 +#define NT_FILE_ALIGNMENT 0x200 +#define NT_DEF_RESERVE 0x100000 +#define NT_DEF_COMMIT 0x1000 + +/********************** RELOCATION DIRECTIVES **********************/ + +struct external_reloc +{ + char r_vaddr[4]; + char r_symndx[4]; + char r_type[2]; +}; + +#define RELOC struct external_reloc +#define RELSZ 10 + diff -rNbu binutils-2.17_org/ld/Makefile.am binutils-2.17/ld/Makefile.am --- binutils-2.17_org/ld/Makefile.am 2006-06-03 06:45:50.000000000 +0200 +++ binutils-2.17/ld/Makefile.am 2006-08-02 10:30:06.000000000 +0200 @@ -240,6 +240,7 @@ ei386nto.o \ ei386nw.o \ ei386pe.o \ + ei386pep.o \ ei386pe_posix.o \ elnk960.o \ em32relf.o \ @@ -410,15 +411,16 @@ ALL_EMUL_EXTRA_OFILES = \ deffilep.o \ - pe-dll.o + pe-dll.o \ + pep-dll.o 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 + mri.c ldcref.c pe-dll.c pep-dll.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 elf-hints-local.h + ldwrite.h mri.h deffile.h pe-dll.h pep-dll.h elf-hints-local.h GENERATED_CFILES = ldgram.c ldlex.c deffilep.c GENERATED_HFILES = ldgram.h ldemul-list.h deffilep.h @@ -1069,6 +1071,9 @@ ei386pe.c: $(srcdir)/emulparams/i386pe.sh \ $(srcdir)/emultempl/pe.em $(srcdir)/scripttempl/pe.sc ${GEN_DEPENDS} ${GENSCRIPTS} i386pe "$(tdir_i386pe)" +ei386pep.c: $(srcdir)/emulparams/i386pep.sh \ + $(srcdir)/emultempl/pep.em $(srcdir)/scripttempl/pep.sc ${GEN_DEPENDS} + ${GENSCRIPTS} i386pep "$(tdir_i386pe)" ei386pe_posix.c: $(srcdir)/emulparams/i386pe_posix.sh \ $(srcdir)/emultempl/pe.em $(srcdir)/scripttempl/pe.sc ${GEN_DEPENDS} ${GENSCRIPTS} i386pe_posix "$(tdir_i386pe_posix)" @@ -1937,6 +1942,12 @@ ld.h $(INCDIR)/bin-bugs.h ldexp.h ldlang.h ldwrite.h \ ldmisc.h ldgram.h ldmain.h ldfile.h ldemul.h $(INCDIR)/coff/internal.h \ $(BFDDIR)/libcoff.h deffile.h pe-dll.h +pep-dll.o: pep-dll.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \ + $(INCDIR)/symcat.h sysdep.h config.h $(INCDIR)/fopen-same.h \ + $(INCDIR)/bfdlink.h $(INCDIR)/libiberty.h $(INCDIR)/safe-ctype.h \ + ld.h $(INCDIR)/bin-bugs.h ldexp.h ldlang.h ldwrite.h \ + ldmisc.h ldgram.h ldmain.h ldfile.h ldemul.h $(INCDIR)/coff/internal.h \ + $(BFDDIR)/libcoff.h deffile.h pep-dll.h ldgram.o: ldgram.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \ $(INCDIR)/symcat.h sysdep.h config.h $(INCDIR)/fopen-same.h \ $(INCDIR)/bfdlink.h ld.h $(INCDIR)/bin-bugs.h ldexp.h \ diff -rNbu binutils-2.17_org/ld/Makefile.in binutils-2.17/ld/Makefile.in --- binutils-2.17_org/ld/Makefile.in 2006-06-03 06:45:50.000000000 +0200 +++ binutils-2.17/ld/Makefile.in 2006-08-02 10:31:07.000000000 +0200 @@ -464,6 +464,7 @@ ei386nto.o \ ei386nw.o \ ei386pe.o \ + ei386pep.o \ ei386pe_posix.o \ elnk960.o \ em32relf.o \ @@ -634,15 +635,16 @@ ALL_EMUL_EXTRA_OFILES = \ deffilep.o \ - pe-dll.o + pe-dll.o \ + pep-dll.o 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 + mri.c ldcref.c pe-dll.c pep-dll.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 elf-hints-local.h + ldwrite.h mri.h deffile.h pe-dll.h pep-dll.h elf-hints-local.h GENERATED_CFILES = ldgram.c ldlex.c deffilep.c GENERATED_HFILES = ldgram.h ldemul-list.h deffilep.h @@ -1880,6 +1882,9 @@ ei386pe.c: $(srcdir)/emulparams/i386pe.sh \ $(srcdir)/emultempl/pe.em $(srcdir)/scripttempl/pe.sc ${GEN_DEPENDS} ${GENSCRIPTS} i386pe "$(tdir_i386pe)" +ei386pep.c: $(srcdir)/emulparams/i386pep.sh \ + $(srcdir)/emultempl/pep.em $(srcdir)/scripttempl/pep.sc ${GEN_DEPENDS} + ${GENSCRIPTS} i386pep "$(tdir_i386pe)" ei386pe_posix.c: $(srcdir)/emulparams/i386pe_posix.sh \ $(srcdir)/emultempl/pe.em $(srcdir)/scripttempl/pe.sc ${GEN_DEPENDS} ${GENSCRIPTS} i386pe_posix "$(tdir_i386pe_posix)" @@ -2718,6 +2723,12 @@ ld.h $(INCDIR)/bin-bugs.h ldexp.h ldlang.h ldwrite.h \ ldmisc.h ldgram.h ldmain.h ldfile.h ldemul.h $(INCDIR)/coff/internal.h \ $(BFDDIR)/libcoff.h deffile.h pe-dll.h +pep-dll.o: pep-dll.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \ + $(INCDIR)/symcat.h sysdep.h config.h $(INCDIR)/fopen-same.h \ + $(INCDIR)/bfdlink.h $(INCDIR)/libiberty.h $(INCDIR)/safe-ctype.h \ + ld.h $(INCDIR)/bin-bugs.h ldexp.h ldlang.h ldwrite.h \ + ldmisc.h ldgram.h ldmain.h ldfile.h ldemul.h $(INCDIR)/coff/internal.h \ + $(BFDDIR)/libcoff.h deffile.h pep-dll.h ldgram.o: ldgram.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \ $(INCDIR)/symcat.h sysdep.h config.h $(INCDIR)/fopen-same.h \ $(INCDIR)/bfdlink.h ld.h $(INCDIR)/bin-bugs.h ldexp.h \ diff -rNbu binutils-2.17_org/ld/configure binutils-2.17/ld/configure --- binutils-2.17_org/ld/configure 2006-04-11 12:36:26.000000000 +0200 +++ binutils-2.17/ld/configure 2006-07-27 10:58:43.000000000 +0200 @@ -3924,7 +3924,7 @@ rm -rf conftest* ;; -x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) +x86_64-*linux*|x86_64-*mingw64*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 @@ -3951,6 +3951,9 @@ ;; *64-bit*) case $host in + x86_64-*mingw64*) + LD="${LD-ld} -m elf_x86_64" + ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; diff -rNbu binutils-2.17_org/ld/configure.tgt binutils-2.17/ld/configure.tgt --- binutils-2.17_org/ld/configure.tgt 2006-04-05 14:41:57.000000000 +0200 +++ binutils-2.17/ld/configure.tgt 2006-08-02 10:27:25.000000000 +0200 @@ -155,6 +155,8 @@ targ_extra_emuls="$targ_extra_emuls elf_x86_64" fi tdir_i386linux=${targ_alias}aout ;; +x86_64-*-mingw64*) targ_emul=i386pep ; + targ_extra_ofiles="deffilep.o pep-dll.o" ;; x86_64-*-linux-*) targ_emul=elf_x86_64 targ_extra_emuls="elf_i386 i386linux" targ_extra_libpath=elf_i386 diff -rNbu binutils-2.17_org/ld/emulparams/i386pep.sh binutils-2.17/ld/emulparams/i386pep.sh --- binutils-2.17_org/ld/emulparams/i386pep.sh 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.17/ld/emulparams/i386pep.sh 2006-07-28 12:43:22.000000000 +0200 @@ -0,0 +1,9 @@ +ARCH="i386:x86-64" +SCRIPT_NAME=pep +OUTPUT_FORMAT="pei-x86-64" +RELOCATEABLE_OUTPUT_FORMAT="pe-x86-64" +TEMPLATE_NAME=pep +ENTRY="_mainCRTStartup" +SUBSYSTEM=PE_DEF_SUBSYSTEM +INITIAL_SYMBOL_CHAR=\"_\" +TARGET_PAGE_SIZE=0x1000 diff -rNbu binutils-2.17_org/ld/emultempl/pep.em binutils-2.17/ld/emultempl/pep.em --- binutils-2.17_org/ld/emultempl/pep.em 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.17/ld/emultempl/pep.em 2006-08-17 09:16:43.000000000 +0200 @@ -0,0 +1,1748 @@ +# This shell script emits a C file. -*- C -*- +# It does some substitutions. +test -z "${ENTRY}" && ENTRY="_mainCRTStartup" +if [ -z "$MACHINE" ]; then + OUTPUT_ARCH=${ARCH} +else + OUTPUT_ARCH=${ARCH}:${MACHINE} +fi +rm -f e${EMULATION_NAME}.c +(echo;echo;echo;echo;echo)>e${EMULATION_NAME}.c # there, now line numbers match ;-) +cat >>e${EMULATION_NAME}.c < +#include "ldlex.h" +#include "ldmisc.h" +#include "ldctor.h" +#include "coff/internal.h" + +/* FIXME: See bfd/peXXigen.c for why we include an architecture specific + header in generic PE code. */ +#include "coff/x86_64.h" +#include "coff/pe.h" + +/* FIXME: This is a BFD internal header file, and we should not be + using it here. */ +#include "../bfd/libcoff.h" + +#undef AOUTSZ +#define AOUTSZ PEPAOUTSZ +#define PEAOUTHDR PEPAOUTHDR + +#include "deffile.h" +#include "pep-dll.h" +#include "safe-ctype.h" + +/* Permit the emulation parameters to override the default section + alignment by setting OVERRIDE_SECTION_ALIGNMENT. FIXME: This makes + it seem that include/coff/internal.h should not define + PE_DEF_SECTION_ALIGNMENT. */ +#if PE_DEF_SECTION_ALIGNMENT != ${OVERRIDE_SECTION_ALIGNMENT:-PE_DEF_SECTION_ALIGNMENT} +#undef PE_DEF_SECTION_ALIGNMENT +#define PE_DEF_SECTION_ALIGNMENT ${OVERRIDE_SECTION_ALIGNMENT} +#endif + +#ifdef TARGET_IS_i386pep +#define DLL_SUPPORT +#endif + +#if defined(TARGET_IS_i386pep) || ! defined(DLL_SUPPORT) +#define PE_DEF_SUBSYSTEM 3 +#else +#undef NT_EXE_IMAGE_BASE +#undef PE_DEF_SECTION_ALIGNMENT +#undef PE_DEF_FILE_ALIGNMENT +#define NT_EXE_IMAGE_BASE 0x00010000 +#define PE_DEF_SECTION_ALIGNMENT 0x00000400 +#define PE_DEF_SUBSYSTEM 2 +#define PE_DEF_FILE_ALIGNMENT 0x00000200 +#endif + + +static struct internal_extra_pe_aouthdr pep; +static int dll; +static flagword real_flags = IMAGE_FILE_LARGE_ADDRESS_AWARE; +static int support_old_code = 0; +static char * thumb_entry_symbol = NULL; +static lang_assignment_statement_type *image_base_statement = 0; + +#ifdef DLL_SUPPORT +static int pep_enable_stdcall_fixup = -1; /* 0=disable 1=enable. */ +static char *pep_out_def_filename = NULL; +static char *pep_implib_filename = NULL; +static int pep_enable_auto_image_base = 0; +static char *pep_dll_search_prefix = NULL; +#endif + +extern const char *output_filename; + +static void +gld_${EMULATION_NAME}_before_parse (void) +{ + ldfile_set_output_arch ("${OUTPUT_ARCH}", bfd_arch_`echo ${ARCH} | sed -e 's/:.*//'`); + output_filename = "${EXECUTABLE_NAME:-a.exe}"; +#ifdef DLL_SUPPORT + config.dynamic_link = TRUE; + config.has_shared = 1; + link_info.pei386_auto_import = -1; + link_info.pei386_runtime_pseudo_reloc = -1; + +#if (PE_DEF_SUBSYSTEM == 9) || (PE_DEF_SUBSYSTEM == 2) +#if defined TARGET_IS_mipspe || defined TARGET_IS_armpe + lang_default_entry ("WinMainCRTStartup"); +#else + lang_default_entry ("_WinMainCRTStartup"); +#endif +#else + lang_default_entry ("${ENTRY}"); +#endif +#endif +} + +/* PE format extra command line options. */ + +/* Used for setting flags in the PE header. */ +#define OPTION_BASE_FILE (300 + 1) +#define OPTION_DLL (OPTION_BASE_FILE + 1) +#define OPTION_FILE_ALIGNMENT (OPTION_DLL + 1) +#define OPTION_IMAGE_BASE (OPTION_FILE_ALIGNMENT + 1) +#define OPTION_MAJOR_IMAGE_VERSION (OPTION_IMAGE_BASE + 1) +#define OPTION_MAJOR_OS_VERSION (OPTION_MAJOR_IMAGE_VERSION + 1) +#define OPTION_MAJOR_SUBSYSTEM_VERSION (OPTION_MAJOR_OS_VERSION + 1) +#define OPTION_MINOR_IMAGE_VERSION (OPTION_MAJOR_SUBSYSTEM_VERSION + 1) +#define OPTION_MINOR_OS_VERSION (OPTION_MINOR_IMAGE_VERSION + 1) +#define OPTION_MINOR_SUBSYSTEM_VERSION (OPTION_MINOR_OS_VERSION + 1) +#define OPTION_SECTION_ALIGNMENT (OPTION_MINOR_SUBSYSTEM_VERSION + 1) +#define OPTION_STACK (OPTION_SECTION_ALIGNMENT + 1) +#define OPTION_SUBSYSTEM (OPTION_STACK + 1) +#define OPTION_HEAP (OPTION_SUBSYSTEM + 1) +#define OPTION_SUPPORT_OLD_CODE (OPTION_HEAP + 1) +#define OPTION_OUT_DEF (OPTION_SUPPORT_OLD_CODE + 1) +#define OPTION_EXPORT_ALL (OPTION_OUT_DEF + 1) +#define OPTION_EXCLUDE_SYMBOLS (OPTION_EXPORT_ALL + 1) +#define OPTION_KILL_ATS (OPTION_EXCLUDE_SYMBOLS + 1) +#define OPTION_STDCALL_ALIASES (OPTION_KILL_ATS + 1) +#define OPTION_ENABLE_STDCALL_FIXUP (OPTION_STDCALL_ALIASES + 1) +#define OPTION_DISABLE_STDCALL_FIXUP (OPTION_ENABLE_STDCALL_FIXUP + 1) +#define OPTION_IMPLIB_FILENAME (OPTION_DISABLE_STDCALL_FIXUP + 1) +#define OPTION_THUMB_ENTRY (OPTION_IMPLIB_FILENAME + 1) +#define OPTION_WARN_DUPLICATE_EXPORTS (OPTION_THUMB_ENTRY + 1) +#define OPTION_IMP_COMPAT (OPTION_WARN_DUPLICATE_EXPORTS + 1) +#define OPTION_ENABLE_AUTO_IMAGE_BASE (OPTION_IMP_COMPAT + 1) +#define OPTION_DISABLE_AUTO_IMAGE_BASE (OPTION_ENABLE_AUTO_IMAGE_BASE + 1) +#define OPTION_DLL_SEARCH_PREFIX (OPTION_DISABLE_AUTO_IMAGE_BASE + 1) +#define OPTION_NO_DEFAULT_EXCLUDES (OPTION_DLL_SEARCH_PREFIX + 1) +#define OPTION_DLL_ENABLE_AUTO_IMPORT (OPTION_NO_DEFAULT_EXCLUDES + 1) +#define OPTION_DLL_DISABLE_AUTO_IMPORT (OPTION_DLL_ENABLE_AUTO_IMPORT + 1) +#define OPTION_ENABLE_EXTRA_PE_DEBUG (OPTION_DLL_DISABLE_AUTO_IMPORT + 1) +#define OPTION_EXCLUDE_LIBS (OPTION_ENABLE_EXTRA_PE_DEBUG + 1) +#define OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC \ + (OPTION_EXCLUDE_LIBS + 1) +#define OPTION_DLL_DISABLE_RUNTIME_PSEUDO_RELOC \ + (OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC + 1) + +static void +gld${EMULATION_NAME}_add_options + (int ns ATTRIBUTE_UNUSED, char **shortopts ATTRIBUTE_UNUSED, int nl, + struct option **longopts, int nrl ATTRIBUTE_UNUSED, + struct option **really_longopts ATTRIBUTE_UNUSED) +{ + static const struct option xtra_long[] = { + /* PE options */ + {"base-file", required_argument, NULL, OPTION_BASE_FILE}, + {"dll", no_argument, NULL, OPTION_DLL}, + {"file-alignment", required_argument, NULL, OPTION_FILE_ALIGNMENT}, + {"heap", required_argument, NULL, OPTION_HEAP}, + {"image-base", required_argument, NULL, OPTION_IMAGE_BASE}, + {"major-image-version", required_argument, NULL, OPTION_MAJOR_IMAGE_VERSION}, + {"major-os-version", required_argument, NULL, OPTION_MAJOR_OS_VERSION}, + {"major-subsystem-version", required_argument, NULL, OPTION_MAJOR_SUBSYSTEM_VERSION}, + {"minor-image-version", required_argument, NULL, OPTION_MINOR_IMAGE_VERSION}, + {"minor-os-version", required_argument, NULL, OPTION_MINOR_OS_VERSION}, + {"minor-subsystem-version", required_argument, NULL, OPTION_MINOR_SUBSYSTEM_VERSION}, + {"section-alignment", required_argument, NULL, OPTION_SECTION_ALIGNMENT}, + {"stack", required_argument, NULL, OPTION_STACK}, + {"subsystem", required_argument, NULL, OPTION_SUBSYSTEM}, + {"support-old-code", no_argument, NULL, OPTION_SUPPORT_OLD_CODE}, + {"thumb-entry", required_argument, NULL, OPTION_THUMB_ENTRY}, +#ifdef DLL_SUPPORT + /* getopt allows abbreviations, so we do this to stop it from treating -o + as an abbreviation for this option */ + {"output-def", required_argument, NULL, OPTION_OUT_DEF}, + {"output-def", required_argument, NULL, OPTION_OUT_DEF}, + {"export-all-symbols", no_argument, NULL, OPTION_EXPORT_ALL}, + {"exclude-symbols", required_argument, NULL, OPTION_EXCLUDE_SYMBOLS}, + {"exclude-libs", required_argument, NULL, OPTION_EXCLUDE_LIBS}, + {"kill-at", no_argument, NULL, OPTION_KILL_ATS}, + {"add-stdcall-alias", no_argument, NULL, OPTION_STDCALL_ALIASES}, + {"enable-stdcall-fixup", no_argument, NULL, OPTION_ENABLE_STDCALL_FIXUP}, + {"disable-stdcall-fixup", no_argument, NULL, OPTION_DISABLE_STDCALL_FIXUP}, + {"out-implib", required_argument, NULL, OPTION_IMPLIB_FILENAME}, + {"warn-duplicate-exports", no_argument, NULL, OPTION_WARN_DUPLICATE_EXPORTS}, + /* getopt() allows abbreviations, so we do this to stop it from + treating -c as an abbreviation for these --compat-implib. */ + {"compat-implib", no_argument, NULL, OPTION_IMP_COMPAT}, + {"compat-implib", no_argument, NULL, OPTION_IMP_COMPAT}, + {"enable-auto-image-base", no_argument, NULL, OPTION_ENABLE_AUTO_IMAGE_BASE}, + {"disable-auto-image-base", no_argument, NULL, OPTION_DISABLE_AUTO_IMAGE_BASE}, + {"dll-search-prefix", required_argument, NULL, OPTION_DLL_SEARCH_PREFIX}, + {"no-default-excludes", no_argument, NULL, OPTION_NO_DEFAULT_EXCLUDES}, + {"enable-auto-import", no_argument, NULL, OPTION_DLL_ENABLE_AUTO_IMPORT}, + {"disable-auto-import", no_argument, NULL, OPTION_DLL_DISABLE_AUTO_IMPORT}, + {"enable-extra-pep-debug", no_argument, NULL, OPTION_ENABLE_EXTRA_PE_DEBUG}, + {"enable-runtime-pseudo-reloc", no_argument, NULL, OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC}, + {"disable-runtime-pseudo-reloc", no_argument, NULL, OPTION_DLL_DISABLE_RUNTIME_PSEUDO_RELOC}, +#endif + {NULL, no_argument, NULL, 0} + }; + + *longopts = (struct option *) + xrealloc (*longopts, nl * sizeof (struct option) + sizeof (xtra_long)); + memcpy (*longopts + nl, &xtra_long, sizeof (xtra_long)); +} + +/* PE/WIN32; added routines to get the subsystem type, heap and/or stack + parameters which may be input from the command line. */ + +typedef struct +{ + void *ptr; + int size; + int value; + char *symbol; + int inited; +} definfo; + +#define D(field,symbol,def) {&pep.field,sizeof(pep.field), def, symbol,0} + +static definfo init[] = +{ + /* imagebase must be first */ +#define IMAGEBASEOFF 0 + D(ImageBase,"__image_base__", NT_EXE_IMAGE_BASE), +#define DLLOFF 1 + {&dll, sizeof(dll), 0, "__dll__", 0}, +#define MSIMAGEBASEOFF 2 + D(ImageBase,"__ImageBase", NT_EXE_IMAGE_BASE), + D(SectionAlignment,"__section_alignment__", PE_DEF_SECTION_ALIGNMENT), + D(FileAlignment,"__file_alignment__", PE_DEF_FILE_ALIGNMENT), + D(MajorOperatingSystemVersion,"__major_os_version__", 4), + D(MinorOperatingSystemVersion,"__minor_os_version__", 0), + D(MajorImageVersion,"__major_image_version__", 0), + D(MinorImageVersion,"__minor_image_version__", 0), + D(MajorSubsystemVersion,"__major_subsystem_version__", 5), + D(MinorSubsystemVersion,"__minor_subsystem_version__", 2), + D(Subsystem,"__subsystem__", ${SUBSYSTEM}), + D(SizeOfStackReserve,"__size_of_stack_reserve__", 0x200000), + D(SizeOfStackCommit,"__size_of_stack_commit__", 0x1000), + D(SizeOfHeapReserve,"__size_of_heap_reserve__", 0x100000), + D(SizeOfHeapCommit,"__size_of_heap_commit__", 0x1000), + D(LoaderFlags,"__loader_flags__", 0x0), + { NULL, 0, 0, NULL, 0 } +}; + + +static void +gld_${EMULATION_NAME}_list_options (FILE *file) +{ + fprintf (file, _(" --base_file Generate a base file for relocatable DLLs\n")); + fprintf (file, _(" --dll Set image base to the default for DLLs\n")); + fprintf (file, _(" --file-alignment Set file alignment\n")); + fprintf (file, _(" --heap Set initial size of the heap\n")); + fprintf (file, _(" --image-base
Set start address of the executable\n")); + fprintf (file, _(" --major-image-version Set version number of the executable\n")); + fprintf (file, _(" --major-os-version Set minimum required OS version\n")); + fprintf (file, _(" --major-subsystem-version Set minimum required OS subsystem version\n")); + fprintf (file, _(" --minor-image-version Set revision number of the executable\n")); + fprintf (file, _(" --minor-os-version Set minimum required OS revision\n")); + fprintf (file, _(" --minor-subsystem-version Set minimum required OS subsystem revision\n")); + fprintf (file, _(" --section-alignment Set section alignment\n")); + fprintf (file, _(" --stack Set size of the initial stack\n")); + fprintf (file, _(" --subsystem [:] Set required OS subsystem [& version]\n")); + fprintf (file, _(" --support-old-code Support interworking with old code\n")); + fprintf (file, _(" --thumb-entry= Set the entry point to be Thumb \n")); +#ifdef DLL_SUPPORT + fprintf (file, _(" --add-stdcall-alias Export symbols with and without @nn\n")); + fprintf (file, _(" --disable-stdcall-fixup Don't link _sym to _sym@nn\n")); + fprintf (file, _(" --enable-stdcall-fixup Link _sym to _sym@nn without warnings\n")); + fprintf (file, _(" --exclude-symbols sym,sym,... Exclude symbols from automatic export\n")); + fprintf (file, _(" --exclude-libs lib,lib,... Exclude libraries from automatic export\n")); + fprintf (file, _(" --export-all-symbols Automatically export all globals to DLL\n")); + fprintf (file, _(" --kill-at Remove @nn from exported symbols\n")); + fprintf (file, _(" --out-implib Generate import library\n")); + fprintf (file, _(" --output-def Generate a .DEF file for the built DLL\n")); + fprintf (file, _(" --warn-duplicate-exports Warn about duplicate exports.\n")); + fprintf (file, _(" --compat-implib Create backward compatible import libs;\n\ + create __imp_ as well.\n")); + fprintf (file, _(" --enable-auto-image-base Automatically choose image base for DLLs\n\ + unless user specifies one\n")); + fprintf (file, _(" --disable-auto-image-base Do not auto-choose image base. (default)\n")); + fprintf (file, _(" --dll-search-prefix= When linking dynamically to a dll without\n\ + an importlib, use .dll\n\ + in preference to lib.dll \n")); + fprintf (file, _(" --enable-auto-import Do sophistcated linking of _sym to\n\ + __imp_sym for DATA references\n")); + fprintf (file, _(" --disable-auto-import Do not auto-import DATA items from DLLs\n")); + fprintf (file, _(" --enable-runtime-pseudo-reloc Work around auto-import limitations by\n\ + adding pseudo-relocations resolved at\n\ + runtime.\n")); + fprintf (file, _(" --disable-runtime-pseudo-reloc Do not add runtime pseudo-relocations for\n\ + auto-imported DATA.\n")); + fprintf (file, _(" --enable-extra-pep-debug Enable verbose debug output when building\n\ + or linking to DLLs (esp. auto-import)\n")); +#endif +} + + +static void +set_pep_name (char *name, long val) +{ + int i; + + /* Find the name and set it. */ + for (i = 0; init[i].ptr; i++) + { + if (strcmp (name, init[i].symbol) == 0) + { + init[i].value = val; + init[i].inited = 1; + return; + } + } + abort (); +} + + +static void +set_pep_subsystem (void) +{ + const char *sver; + const char *entry; + const char *initial_symbol_char; + char *end; + int len; + int i; + int subsystem; + unsigned long temp_subsystem; + static const struct + { + const char *name; + const int value; + const char *entry; + } + v[] = + { + { "native", 1, "NtProcessStartup" }, + { "windows", 2, "WinMainCRTStartup" }, + { "console", 3, "mainCRTStartup" }, + { "posix", 7, "__PosixProcessStartup"}, + { "wince", 9, "_WinMainCRTStartup" }, + { "xbox", 14, "mainCRTStartup" }, + { NULL, 0, NULL } + }; + /* Entry point name for arbitrary subsystem numbers. */ + static const char default_entry[] = "mainCRTStartup"; + + /* Check for the presence of a version number. */ + sver = strchr (optarg, ':'); + if (sver == NULL) + len = strlen (optarg); + else + { + len = sver - optarg; + set_pep_name ("__major_subsystem_version__", + strtoul (sver + 1, &end, 0)); + if (*end == '.') + set_pep_name ("__minor_subsystem_version__", + strtoul (end + 1, &end, 0)); + if (*end != '\0') + einfo (_("%P: warning: bad version number in -subsystem option\n")); + } + + /* Check for numeric subsystem. */ + temp_subsystem = strtoul (optarg, & end, 0); + if ((*end == ':' || *end == '\0') && (temp_subsystem < 65536)) + { + /* Search list for a numeric match to use its entry point. */ + for (i = 0; v[i].name; i++) + if (v[i].value == (int) temp_subsystem) + break; + + /* If no match, use the default. */ + if (v[i].name != NULL) + entry = v[i].entry; + else + entry = default_entry; + + /* Use this subsystem. */ + subsystem = (int) temp_subsystem; + } + else + { + /* Search for subsystem by name. */ + for (i = 0; v[i].name; i++) + if (strncmp (optarg, v[i].name, len) == 0 + && v[i].name[len] == '\0') + break; + + if (v[i].name == NULL) + { + einfo (_("%P%F: invalid subsystem type %s\n"), optarg); + return; + } + + entry = v[i].entry; + subsystem = v[i].value; + } + + set_pep_name ("__subsystem__", subsystem); + + initial_symbol_char = ${INITIAL_SYMBOL_CHAR}; + if (*initial_symbol_char != '\0') + { + char *alc_entry; + + /* lang_default_entry expects its argument to be permanently + allocated, so we don't free this string. */ + alc_entry = xmalloc (strlen (initial_symbol_char) + + strlen (entry) + + 1); + strcpy (alc_entry, initial_symbol_char); + strcat (alc_entry, entry); + entry = alc_entry; + } + + lang_default_entry (entry); + + return; +} + + +static void +set_pep_value (char *name) +{ + char *end; + + set_pep_name (name, strtoul (optarg, &end, 0)); + + if (end == optarg) + einfo (_("%P%F: invalid hex number for PE parameter '%s'\n"), optarg); + + optarg = end; +} + + +static void +set_pep_stack_heap (char *resname, char *comname) +{ + set_pep_value (resname); + + if (*optarg == ',') + { + optarg++; + set_pep_value (comname); + } + else if (*optarg) + einfo (_("%P%F: strange hex info for PE parameter '%s'\n"), optarg); +} + + +static bfd_boolean +gld${EMULATION_NAME}_handle_option (int optc) +{ + switch (optc) + { + default: + return FALSE; + + case OPTION_BASE_FILE: + link_info.base_file = fopen (optarg, FOPEN_WB); + if (link_info.base_file == NULL) + { + /* xgettext:c-format */ + fprintf (stderr, _("%s: Can't open base file %s\n"), + program_name, optarg); + xexit (1); + } + break; + + /* PE options. */ + case OPTION_HEAP: + set_pep_stack_heap ("__size_of_heap_reserve__", "__size_of_heap_commit__"); + break; + case OPTION_STACK: + set_pep_stack_heap ("__size_of_stack_reserve__", "__size_of_stack_commit__"); + break; + case OPTION_SUBSYSTEM: + set_pep_subsystem (); + break; + case OPTION_MAJOR_OS_VERSION: + set_pep_value ("__major_os_version__"); + break; + case OPTION_MINOR_OS_VERSION: + set_pep_value ("__minor_os_version__"); + break; + case OPTION_MAJOR_SUBSYSTEM_VERSION: + set_pep_value ("__major_subsystem_version__"); + break; + case OPTION_MINOR_SUBSYSTEM_VERSION: + set_pep_value ("__minor_subsystem_version__"); + break; + case OPTION_MAJOR_IMAGE_VERSION: + set_pep_value ("__major_image_version__"); + break; + case OPTION_MINOR_IMAGE_VERSION: + set_pep_value ("__minor_image_version__"); + break; + case OPTION_FILE_ALIGNMENT: + set_pep_value ("__file_alignment__"); + break; + case OPTION_SECTION_ALIGNMENT: + set_pep_value ("__section_alignment__"); + break; + case OPTION_DLL: + set_pep_name ("__dll__", 1); + break; + case OPTION_IMAGE_BASE: + set_pep_value ("__image_base__"); + break; + case OPTION_SUPPORT_OLD_CODE: + support_old_code = 1; + break; + case OPTION_THUMB_ENTRY: + thumb_entry_symbol = optarg; + break; +#ifdef DLL_SUPPORT + case OPTION_OUT_DEF: + pep_out_def_filename = xstrdup (optarg); + break; + case OPTION_EXPORT_ALL: + pep_dll_export_everything = 1; + break; + case OPTION_EXCLUDE_SYMBOLS: + pep_dll_add_excludes (optarg, 0); + break; + case OPTION_EXCLUDE_LIBS: + pep_dll_add_excludes (optarg, 1); + break; + case OPTION_KILL_ATS: + pep_dll_kill_ats = 1; + break; + case OPTION_STDCALL_ALIASES: + pep_dll_stdcall_aliases = 1; + break; + case OPTION_ENABLE_STDCALL_FIXUP: + pep_enable_stdcall_fixup = 1; + break; + case OPTION_DISABLE_STDCALL_FIXUP: + pep_enable_stdcall_fixup = 0; + break; + case OPTION_IMPLIB_FILENAME: + pep_implib_filename = xstrdup (optarg); + break; + case OPTION_WARN_DUPLICATE_EXPORTS: + pep_dll_warn_dup_exports = 1; + break; + case OPTION_IMP_COMPAT: + pep_dll_compat_implib = 1; + break; + case OPTION_ENABLE_AUTO_IMAGE_BASE: + pep_enable_auto_image_base = 1; + break; + case OPTION_DISABLE_AUTO_IMAGE_BASE: + pep_enable_auto_image_base = 0; + break; + case OPTION_DLL_SEARCH_PREFIX: + pep_dll_search_prefix = xstrdup (optarg); + break; + case OPTION_NO_DEFAULT_EXCLUDES: + pep_dll_do_default_excludes = 0; + break; + case OPTION_DLL_ENABLE_AUTO_IMPORT: + link_info.pei386_auto_import = 1; + break; + case OPTION_DLL_DISABLE_AUTO_IMPORT: + link_info.pei386_auto_import = 0; + break; + case OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC: + link_info.pei386_runtime_pseudo_reloc = 1; + break; + case OPTION_DLL_DISABLE_RUNTIME_PSEUDO_RELOC: + link_info.pei386_runtime_pseudo_reloc = 0; + break; + case OPTION_ENABLE_EXTRA_PE_DEBUG: + pep_dll_extra_pe_debug = 1; + break; +#endif + } + return TRUE; +} + + +#ifdef DLL_SUPPORT +static unsigned long +strhash (const char *str) +{ + const unsigned char *s; + unsigned long hash; + unsigned int c; + unsigned int len; + + hash = 0; + len = 0; + s = (const unsigned char *) str; + while ((c = *s++) != '\0') + { + hash += c + (c << 17); + hash ^= hash >> 2; + ++len; + } + hash += len + (len << 17); + hash ^= hash >> 2; + + return hash; +} + +/* Use the output file to create a image base for relocatable DLLs. */ + +static unsigned long +compute_dll_image_base (const char *ofile) +{ + unsigned long hash = strhash (ofile); + return 0x61300000 + ((hash << 16) & 0x0FFC0000); +} +#endif + +/* Assign values to the special symbols before the linker script is + read. */ + +static void +gld_${EMULATION_NAME}_set_symbols (void) +{ + /* Run through and invent symbols for all the + names and insert the defaults. */ + int j; + lang_statement_list_type *save; + + if (!init[IMAGEBASEOFF].inited) + { + if (link_info.relocatable) + init[IMAGEBASEOFF].value = 0; + else if (init[DLLOFF].value || (link_info.shared && !link_info.pie)) +#ifdef DLL_SUPPORT + init[IMAGEBASEOFF].value = (pep_enable_auto_image_base) ? + compute_dll_image_base (output_filename) : NT_DLL_IMAGE_BASE; +#else + init[IMAGEBASEOFF].value = NT_DLL_IMAGE_BASE; +#endif + else + init[IMAGEBASEOFF].value = NT_EXE_IMAGE_BASE; + init[MSIMAGEBASEOFF].value=init[IMAGEBASEOFF].value; + } + + /* Don't do any symbol assignments if this is a relocatable link. */ + if (link_info.relocatable) + return; + + /* Glue the assignments into the abs section. */ + save = stat_ptr; + + stat_ptr = &(abs_output_section->children); + + for (j = 0; init[j].ptr; j++) + { + long val = init[j].value; + lang_assignment_statement_type *rv; + rv = lang_add_assignment (exp_assop ('=', init[j].symbol, + exp_intop (val))); + if (init[j].size == sizeof (short)) + *(short *) init[j].ptr = val; + else if (init[j].size == sizeof (int)) + *(int *) init[j].ptr = val; + else if (init[j].size == sizeof (long)) + *(long *) init[j].ptr = val; + /* This might be a long long or other special type. */ + else if (init[j].size == sizeof (bfd_vma)) + *(bfd_vma *) init[j].ptr = val; + else abort (); + if (j == IMAGEBASEOFF) + image_base_statement = rv; + } + /* Restore the pointer. */ + stat_ptr = save; + + if (pep.FileAlignment > + pep.SectionAlignment) + { + einfo (_("%P: warning, file alignment > section alignment.\n")); + } +} + +/* This is called after the linker script and the command line options + have been read. */ + +static void +gld_${EMULATION_NAME}_after_parse (void) +{ + /* The Windows libraries are designed for the linker to treat the + entry point as an undefined symbol. Otherwise, the .obj that + defines mainCRTStartup is brought in because it is the first + encountered in libc.lib and it has other symbols in it which will + be pulled in by the link process. To avoid this, we act as + though the user specified -u with the entry point symbol. + + This function is called after the linker script and command line + options have been read, so at this point we know the right entry + point. This function is called before the input files are + opened, so registering the symbol as undefined will make a + difference. */ + + if (! link_info.relocatable && entry_symbol.name != NULL) + ldlang_add_undef (entry_symbol.name); +} + +/* pep-dll.c directly accesses pep_data_import_dll, + so it must be defined outside of #ifdef DLL_SUPPORT. + Note - this variable is deliberately not initialised. + This allows it to be treated as a common varaible, and only + exist in one incarnation in a multiple target enabled linker. */ +char * pep_data_import_dll; + +#ifdef DLL_SUPPORT +static struct bfd_link_hash_entry *pep_undef_found_sym; + +static bfd_boolean +pep_undef_cdecl_match (struct bfd_link_hash_entry *h, void *inf) +{ + int sl; + char *string = inf; + + sl = strlen (string); + if (h->type == bfd_link_hash_defined + && strncmp (h->root.string, string, sl) == 0 + && h->root.string[sl] == '@') + { + pep_undef_found_sym = h; + return FALSE; + } + return TRUE; +} + +static void +pep_fixup_stdcalls (void) +{ + static int gave_warning_message = 0; + struct bfd_link_hash_entry *undef, *sym; + + if (pep_dll_extra_pe_debug) + printf ("%s\n", __FUNCTION__); + + for (undef = link_info.hash->undefs; undef; undef=undef->u.undef.next) + if (undef->type == bfd_link_hash_undefined) + { + char* at = strchr (undef->root.string, '@'); + int lead_at = (*undef->root.string == '@'); + /* For now, don't try to fixup fastcall symbols. */ + + if (at && !lead_at) + { + /* The symbol is a stdcall symbol, so let's look for a + cdecl symbol with the same name and resolve to that. */ + char *cname = xstrdup (undef->root.string /* + lead_at */); + at = strchr (cname, '@'); + *at = 0; + sym = bfd_link_hash_lookup (link_info.hash, cname, 0, 0, 1); + + if (sym && sym->type == bfd_link_hash_defined) + { + undef->type = bfd_link_hash_defined; + undef->u.def.value = sym->u.def.value; + undef->u.def.section = sym->u.def.section; + + if (pep_enable_stdcall_fixup == -1) + { + einfo (_("Warning: resolving %s by linking to %s\n"), + undef->root.string, cname); + if (! gave_warning_message) + { + gave_warning_message = 1; + einfo (_("Use --enable-stdcall-fixup to disable these warnings\n")); + einfo (_("Use --disable-stdcall-fixup to disable these fixups\n")); + } + } + } + } + else + { + /* The symbol is a cdecl symbol, so we look for stdcall + symbols - which means scanning the whole symbol table. */ + pep_undef_found_sym = 0; + bfd_link_hash_traverse (link_info.hash, pep_undef_cdecl_match, + (char *) undef->root.string); + sym = pep_undef_found_sym; + if (sym) + { + undef->type = bfd_link_hash_defined; + undef->u.def.value = sym->u.def.value; + undef->u.def.section = sym->u.def.section; + + if (pep_enable_stdcall_fixup == -1) + { + einfo (_("Warning: resolving %s by linking to %s\n"), + undef->root.string, sym->root.string); + if (! gave_warning_message) + { + gave_warning_message = 1; + einfo (_("Use --enable-stdcall-fixup to disable these warnings\n")); + einfo (_("Use --disable-stdcall-fixup to disable these fixups\n")); + } + } + } + } + } +} + +static int +make_import_fixup (arelent *rel, asection *s) +{ + struct bfd_symbol *sym = *rel->sym_ptr_ptr; + char addend[4]; + + if (pep_dll_extra_pe_debug) + printf ("arelent: %s@%#lx: add=%li\n", sym->name, + (long) rel->address, (long) rel->addend); + + if (! bfd_get_section_contents (s->owner, s, addend, rel->address, sizeof (addend))) + einfo (_("%C: Cannot get section contents - auto-import exception\n"), + s->owner, s, rel->address); + + pep_create_import_fixup (rel, s, bfd_get_32 (s->owner, addend)); + + return 1; +} + +static void +pep_find_data_imports (void) +{ + struct bfd_link_hash_entry *undef, *sym; + + if (link_info.pei386_auto_import == 0) + return; + + for (undef = link_info.hash->undefs; undef; undef=undef->u.undef.next) + { + if (undef->type == bfd_link_hash_undefined) + { + /* C++ symbols are *long*. */ + char buf[4096]; + + if (pep_dll_extra_pe_debug) + printf ("%s:%s\n", __FUNCTION__, undef->root.string); + + sprintf (buf, "__imp_%s", undef->root.string); + + sym = bfd_link_hash_lookup (link_info.hash, buf, 0, 0, 1); + + if (sym && sym->type == bfd_link_hash_defined) + { + bfd *b = sym->u.def.section->owner; + asymbol **symbols; + int nsyms, symsize, i; + + if (link_info.pei386_auto_import == -1) + info_msg (_("Info: resolving %s by linking to %s (auto-import)\n"), + undef->root.string, buf); + + symsize = bfd_get_symtab_upper_bound (b); + symbols = (asymbol **) xmalloc (symsize); + nsyms = bfd_canonicalize_symtab (b, symbols); + + for (i = 0; i < nsyms; i++) + { + if (memcmp (symbols[i]->name, "__head_", + sizeof ("__head_") - 1)) + continue; + + if (pep_dll_extra_pe_debug) + printf ("->%s\n", symbols[i]->name); + + pep_data_import_dll = (char*) (symbols[i]->name + + sizeof ("__head_") - 1); + break; + } + + pep_walk_relocs_of_symbol (&link_info, undef->root.string, + make_import_fixup); + + /* Let's differentiate it somehow from defined. */ + undef->type = bfd_link_hash_defweak; + /* We replace original name with __imp_ prefixed, this + 1) may trash memory 2) leads to duplicate symbol generation. + Still, IMHO it's better than having name poluted. */ + undef->root.string = sym->root.string; + undef->u.def.value = sym->u.def.value; + undef->u.def.section = sym->u.def.section; + } + } + } +} + +static bfd_boolean +pr_sym (struct bfd_hash_entry *h, void *inf ATTRIBUTE_UNUSED) +{ + if (pep_dll_extra_pe_debug) + printf ("+%s\n", h->string); + + return TRUE; +} +#endif /* DLL_SUPPORT */ + + +static void +gld_${EMULATION_NAME}_after_open (void) +{ +#ifdef DLL_SUPPORT + if (pep_dll_extra_pe_debug) + { + bfd *a; + struct bfd_link_hash_entry *sym; + + printf ("%s()\n", __FUNCTION__); + + for (sym = link_info.hash->undefs; sym; sym=sym->u.undef.next) + printf ("-%s\n", sym->root.string); + bfd_hash_traverse (&link_info.hash->table, pr_sym, NULL); + + for (a = link_info.input_bfds; a; a = a->link_next) + printf ("*%s\n",a->filename); + } +#endif + + /* Pass the wacky PE command line options into the output bfd. + FIXME: This should be done via a function, rather than by + including an internal BFD header. */ + + if (coff_data (output_bfd) == NULL || coff_data (output_bfd)->pe == 0) + einfo (_("%F%P: PE operations on non PE file.\n")); + + pe_data (output_bfd)->pe_opthdr = pep; + pe_data (output_bfd)->dll = init[DLLOFF].value; + pe_data (output_bfd)->real_flags |= real_flags; + +#ifdef DLL_SUPPORT + if (pep_enable_stdcall_fixup) /* -1=warn or 1=disable */ + pep_fixup_stdcalls (); + + pep_process_import_defs (output_bfd, & link_info); + + pep_find_data_imports (); + +#ifndef TARGET_IS_i386pep + if (link_info.shared) +#else + if (!link_info.relocatable) +#endif + pep_dll_build_sections (output_bfd, &link_info); + +#ifndef TARGET_IS_i386pep + else + pep_exe_build_sections (output_bfd, &link_info); +#endif +#endif + + { + /* This next chunk of code tries to detect the case where you have + two import libraries for the same DLL (specifically, + symbolically linking libm.a and libc.a in cygwin to + libcygwin.a). In those cases, it's possible for function + thunks from the second implib to be used but without the + head/tail objects, causing an improper import table. We detect + those cases and rename the "other" import libraries to match + the one the head/tail come from, so that the linker will sort + things nicely and produce a valid import table. */ + + LANG_FOR_EACH_INPUT_STATEMENT (is) + { + if (is->the_bfd->my_archive) + { + int idata2 = 0, reloc_count=0, is_imp = 0; + asection *sec; + + /* See if this is an import library thunk. */ + for (sec = is->the_bfd->sections; sec; sec = sec->next) + { + if (strcmp (sec->name, ".idata\$2") == 0) + idata2 = 1; + if (strncmp (sec->name, ".idata\$", 7) == 0) + is_imp = 1; + reloc_count += sec->reloc_count; + } + + if (is_imp && !idata2 && reloc_count) + { + /* It is, look for the reference to head and see if it's + from our own library. */ + for (sec = is->the_bfd->sections; sec; sec = sec->next) + { + int i; + long symsize; + long relsize; + asymbol **symbols; + arelent **relocs; + int nrelocs; + + symsize = bfd_get_symtab_upper_bound (is->the_bfd); + if (symsize < 1) + break; + relsize = bfd_get_reloc_upper_bound (is->the_bfd, sec); + if (relsize < 1) + break; + + symbols = (asymbol **) xmalloc (symsize); + symsize = bfd_canonicalize_symtab (is->the_bfd, symbols); + if (symsize < 0) + { + einfo ("%X%P: unable to process symbols: %E"); + return; + } + + relocs = (arelent **) xmalloc ((size_t) relsize); + nrelocs = bfd_canonicalize_reloc (is->the_bfd, sec, + relocs, symbols); + if (nrelocs < 0) + { + free (relocs); + einfo ("%X%P: unable to process relocs: %E"); + return; + } + + for (i = 0; i < nrelocs; i++) + { + struct bfd_symbol *s; + struct bfd_link_hash_entry * blhe; + char *other_bfd_filename; + char *n; + + s = (relocs[i]->sym_ptr_ptr)[0]; + + if (s->flags & BSF_LOCAL) + continue; + + /* Thunk section with reloc to another bfd. */ + blhe = bfd_link_hash_lookup (link_info.hash, + s->name, + FALSE, FALSE, TRUE); + + if (blhe == NULL + || blhe->type != bfd_link_hash_defined) + continue; + + other_bfd_filename + = blhe->u.def.section->owner->my_archive + ? bfd_get_filename (blhe->u.def.section->owner->my_archive) + : bfd_get_filename (blhe->u.def.section->owner); + + if (strcmp (bfd_get_filename (is->the_bfd->my_archive), + other_bfd_filename) == 0) + continue; + + /* Rename this implib to match the other one. */ + n = xmalloc (strlen (other_bfd_filename) + 1); + strcpy (n, other_bfd_filename); + is->the_bfd->my_archive->filename = n; + } + + free (relocs); + /* Note - we do not free the symbols, + they are now cached in the BFD. */ + } + } + } + } + } + + { + int is_ms_arch = 0; + bfd *cur_arch = 0; + lang_input_statement_type *is2; + lang_input_statement_type *is3; + + /* Careful - this is a shell script. Watch those dollar signs! */ + /* Microsoft import libraries have every member named the same, + and not in the right order for us to link them correctly. We + must detect these and rename the members so that they'll link + correctly. There are three types of objects: the head, the + thunks, and the sentinel(s). The head is easy; it's the one + with idata2. We assume that the sentinels won't have relocs, + and the thunks will. It's easier than checking the symbol + table for external references. */ + LANG_FOR_EACH_INPUT_STATEMENT (is) + { + if (is->the_bfd->my_archive) + { + char *pnt; + bfd *arch = is->the_bfd->my_archive; + + if (cur_arch != arch) + { + cur_arch = arch; + is_ms_arch = 1; + + for (is3 = is; + is3 && is3->the_bfd->my_archive == arch; + is3 = (lang_input_statement_type *) is3->next) + { + /* A MS dynamic import library can also contain static + members, so look for the first element with a .dll + extension, and use that for the remainder of the + comparisons. */ + pnt = strrchr (is3->the_bfd->filename, '.'); + if (pnt != NULL && strcmp (pnt, ".dll") == 0) + break; + } + + if (is3 == NULL) + is_ms_arch = 0; + else + { + /* OK, found one. Now look to see if the remaining + (dynamic import) members use the same name. */ + for (is2 = is; + is2 && is2->the_bfd->my_archive == arch; + is2 = (lang_input_statement_type *) is2->next) + { + /* Skip static members, ie anything with a .obj + extension. */ + pnt = strrchr (is2->the_bfd->filename, '.'); + if (pnt != NULL && strcmp (pnt, ".obj") == 0) + continue; + + if (strcmp (is3->the_bfd->filename, + is2->the_bfd->filename)) + { + is_ms_arch = 0; + break; + } + } + } + } + + /* This fragment might have come from an .obj file in a Microsoft + import, and not an actual import record. If this is the case, + then leave the filename alone. */ + pnt = strrchr (is->the_bfd->filename, '.'); + + if (is_ms_arch && (strcmp (pnt, ".dll") == 0)) + { + int idata2 = 0, reloc_count=0; + asection *sec; + char *new_name, seq; + + for (sec = is->the_bfd->sections; sec; sec = sec->next) + { + if (strcmp (sec->name, ".idata\$2") == 0) + idata2 = 1; + reloc_count += sec->reloc_count; + } + + if (idata2) /* .idata2 is the TOC */ + seq = 'a'; + else if (reloc_count > 0) /* thunks */ + seq = 'b'; + else /* sentinel */ + seq = 'c'; + + new_name = xmalloc (strlen (is->the_bfd->filename) + 3); + sprintf (new_name, "%s.%c", is->the_bfd->filename, seq); + is->the_bfd->filename = new_name; + + new_name = xmalloc (strlen (is->filename) + 3); + sprintf (new_name, "%s.%c", is->filename, seq); + is->filename = new_name; + } + } + } + } +} + +static void +gld_${EMULATION_NAME}_before_allocation (void) +{ + before_allocation_default (); +} + +#ifdef DLL_SUPPORT +/* This is called when an input file isn't recognized as a BFD. We + check here for .DEF files and pull them in automatically. */ + +static int +saw_option (char *option) +{ + int i; + + for (i = 0; init[i].ptr; i++) + if (strcmp (init[i].symbol, option) == 0) + return init[i].inited; + return 0; +} +#endif /* DLL_SUPPORT */ + +static bfd_boolean +gld_${EMULATION_NAME}_unrecognized_file (lang_input_statement_type *entry ATTRIBUTE_UNUSED) +{ +#ifdef DLL_SUPPORT + const char *ext = entry->filename + strlen (entry->filename) - 4; + + if (strcmp (ext, ".def") == 0 || strcmp (ext, ".DEF") == 0) + { + pep_def_file = def_file_parse (entry->filename, pep_def_file); + + if (pep_def_file) + { + int i, buflen=0, len; + char *buf; + + for (i = 0; i < pep_def_file->num_exports; i++) + { + len = strlen (pep_def_file->exports[i].internal_name); + if (buflen < len + 2) + buflen = len + 2; + } + + buf = (char *) xmalloc (buflen); + + for (i = 0; i < pep_def_file->num_exports; i++) + { + struct bfd_link_hash_entry *h; + + sprintf (buf, "_%s", pep_def_file->exports[i].internal_name); + + h = bfd_link_hash_lookup (link_info.hash, buf, TRUE, TRUE, TRUE); + if (h == (struct bfd_link_hash_entry *) NULL) + einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n")); + if (h->type == bfd_link_hash_new) + { + h->type = bfd_link_hash_undefined; + h->u.undef.abfd = NULL; + bfd_link_add_undef (link_info.hash, h); + } + } + free (buf); + + /* def_file_print (stdout, pep_def_file); */ + if (pep_def_file->is_dll == 1) + link_info.shared = 1; + + if (pep_def_file->base_address != (bfd_vma)(-1)) + { + pep.ImageBase = + pe_data (output_bfd)->pe_opthdr.ImageBase = + init[IMAGEBASEOFF].value = pep_def_file->base_address; + init[IMAGEBASEOFF].inited = 1; + if (image_base_statement) + image_base_statement->exp = + exp_assop ('=', "__image_base__", exp_intop (pep.ImageBase)); + } + + if (pep_def_file->stack_reserve != -1 + && ! saw_option ("__size_of_stack_reserve__")) + { + pep.SizeOfStackReserve = pep_def_file->stack_reserve; + if (pep_def_file->stack_commit != -1) + pep.SizeOfStackCommit = pep_def_file->stack_commit; + } + if (pep_def_file->heap_reserve != -1 + && ! saw_option ("__size_of_heap_reserve__")) + { + pep.SizeOfHeapReserve = pep_def_file->heap_reserve; + if (pep_def_file->heap_commit != -1) + pep.SizeOfHeapCommit = pep_def_file->heap_commit; + } + return TRUE; + } + } +#endif + return FALSE; +} + +static bfd_boolean +gld_${EMULATION_NAME}_recognized_file (lang_input_statement_type *entry ATTRIBUTE_UNUSED) +{ +#ifdef DLL_SUPPORT +#ifdef TARGET_IS_i386pep + pep_dll_id_target ("pei-x86-64"); +#endif + if (bfd_get_format (entry->the_bfd) == bfd_object) + { + char fbuf[LD_PATHMAX + 1]; + const char *ext; + + if (REALPATH (entry->filename, fbuf) == NULL) + strncpy (fbuf, entry->filename, sizeof (fbuf)); + + ext = fbuf + strlen (fbuf) - 4; + + if (strcmp (ext, ".dll") == 0 || strcmp (ext, ".DLL") == 0) + return pep_implied_import_dll (fbuf); + } +#endif + return FALSE; +} + +static void +gld_${EMULATION_NAME}_finish (void) +{ +#if defined(TARGET_IS_armpe) || defined(TARGET_IS_arm_epoc_pe) + struct bfd_link_hash_entry * h; + + if (thumb_entry_symbol != NULL) + { + h = bfd_link_hash_lookup (link_info.hash, thumb_entry_symbol, + FALSE, FALSE, TRUE); + + if (h != (struct bfd_link_hash_entry *) NULL + && (h->type == bfd_link_hash_defined + || h->type == bfd_link_hash_defweak) + && h->u.def.section->output_section != NULL) + { + static char buffer[32]; + bfd_vma val; + + /* Special procesing is required for a Thumb entry symbol. The + bottom bit of its address must be set. */ + val = (h->u.def.value + + bfd_get_section_vma (output_bfd, + h->u.def.section->output_section) + + h->u.def.section->output_offset); + + val |= 1; + + /* Now convert this value into a string and store it in entry_symbol + where the lang_finish() function will pick it up. */ + buffer[0] = '0'; + buffer[1] = 'x'; + + sprintf_vma (buffer + 2, val); + + if (entry_symbol.name != NULL && entry_from_cmdline) + einfo (_("%P: warning: '--thumb-entry %s' is overriding '-e %s'\n"), + thumb_entry_symbol, entry_symbol.name); + entry_symbol.name = buffer; + } + else + einfo (_("%P: warning: connot find thumb start symbol %s\n"), thumb_entry_symbol); + } +#endif /* defined(TARGET_IS_armpe) || defined(TARGET_IS_arm_epoc_pe) */ + + finish_default (); + +#ifdef DLL_SUPPORT + if (link_info.shared + || (!link_info.relocatable && pep_def_file->num_exports != 0) + ) + { + pep_dll_fill_sections (output_bfd, &link_info); + if (pep_implib_filename) + pep_dll_generate_implib (pep_def_file, pep_implib_filename); + } + + if (pep_out_def_filename) + pep_dll_generate_def_file (pep_out_def_filename); +#endif /* DLL_SUPPORT */ + + /* I don't know where .idata gets set as code, but it shouldn't be. */ + { + asection *asec = bfd_get_section_by_name (output_bfd, ".idata"); + + if (asec) + { + asec->flags &= ~SEC_CODE; + asec->flags |= SEC_DATA; + } + } +} + + +/* Place an orphan section. + + We use this to put sections in a reasonable place in the file, and + to ensure that they are aligned as required. + + We handle grouped sections here as well. A section named .foo$nn + goes into the output section .foo. All grouped sections are sorted + by name. + + Grouped sections for the default sections are handled by the + default linker script using wildcards, and are sorted by + sort_sections. */ + +static bfd_boolean +gld_${EMULATION_NAME}_place_orphan (asection *s) +{ + const char *secname; + const char *orig_secname; + char *dollar = NULL; + lang_output_section_statement_type *os; + lang_statement_list_type add_child; + + secname = bfd_get_section_name (s->owner, s); + + /* Look through the script to see where to place this section. */ + orig_secname = secname; + if (!link_info.relocatable + && (dollar = strchr (secname, '$')) != NULL) + { + size_t len = dollar - orig_secname; + char *newname = xmalloc (len + 1); + memcpy (newname, orig_secname, len); + newname[len] = '\0'; + secname = newname; + } + + os = lang_output_section_find (secname); + + lang_list_init (&add_child); + + if (os != NULL + && (os->bfd_section == NULL + || os->bfd_section->flags == 0 + || ((s->flags ^ os->bfd_section->flags) + & (SEC_LOAD | SEC_ALLOC)) == 0)) + { + /* We already have an output section statement with this + name, and its bfd section, if any, has compatible flags. + If the section already exists but does not have any flags set, + then it has been created by the linker, probably as a result of + a --section-start command line switch. */ + lang_add_section (&add_child, s, os); + } + else + { + static struct orphan_save hold[] = + { + { ".text", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE, + 0, 0, 0, 0 }, + { ".rdata", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA, + 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 } + }; + enum orphan_save_index + { + orphan_text = 0, + orphan_rodata, + orphan_data, + orphan_bss + }; + static int orphan_init_done = 0; + struct orphan_save *place; + lang_output_section_statement_type *after; + etree_type *address; + + 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; + } + + /* Try to put the new output section in a reasonable place based + on the section name and section flags. */ + + place = NULL; + if ((s->flags & SEC_ALLOC) == 0) + ; + else if ((s->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0) + place = &hold[orphan_bss]; + else if ((s->flags & SEC_READONLY) == 0) + place = &hold[orphan_data]; + else if ((s->flags & SEC_CODE) == 0) + place = &hold[orphan_rodata]; + else + place = &hold[orphan_text]; + + after = NULL; + if (place != NULL) + { + if (place->os == NULL) + place->os = lang_output_section_find (place->name); + after = place->os; + if (after == NULL) + after = lang_output_section_find_by_flags (s, &place->os, NULL); + if (after == NULL) + /* *ABS* is always the first output section statement. */ + after = (&lang_output_section_statement.head + ->output_section_statement); + } + + /* Choose a unique name for the section. This will be needed if the + same section name appears in the input file with different + loadable or allocatable characteristics. */ + if (bfd_get_section_by_name (output_bfd, secname) != NULL) + { + static int count = 1; + secname = bfd_get_unique_section_name (output_bfd, secname, &count); + if (secname == NULL) + einfo ("%F%P: place_orphan failed: %E\n"); + } + + /* All sections in an executable must be aligned to a page boundary. */ + address = exp_unop (ALIGN_K, exp_nameop (NAME, "__section_alignment__")); + os = lang_insert_orphan (s, secname, after, place, address, &add_child); + } + + { + lang_statement_union_type **pl = &os->children.head; + + if (dollar != NULL) + { + bfd_boolean found_dollar; + + /* The section name has a '$'. Sort it with the other '$' + sections. */ + found_dollar = FALSE; + for ( ; *pl != NULL; pl = &(*pl)->header.next) + { + lang_input_section_type *ls; + const char *lname; + + if ((*pl)->header.type != lang_input_section_enum) + continue; + + ls = &(*pl)->input_section; + + lname = bfd_get_section_name (ls->section->owner, ls->section); + if (strchr (lname, '$') == NULL) + { + if (found_dollar) + break; + } + else + { + found_dollar = TRUE; + if (strcmp (orig_secname, lname) < 0) + break; + } + } + } + + if (add_child.head != NULL) + { + add_child.head->header.next = *pl; + *pl = add_child.head; + } + } + + return TRUE; +} + +static bfd_boolean +gld_${EMULATION_NAME}_open_dynamic_archive + (const char *arch ATTRIBUTE_UNUSED, search_dirs_type *search, + lang_input_statement_type *entry) +{ + const char * filename; + char * string; + + if (! entry->is_archive) + return FALSE; + + filename = entry->filename; + + string = (char *) xmalloc (strlen (search->name) + + strlen (filename) + + sizeof "/lib.a.dll" +#ifdef DLL_SUPPORT + + (pep_dll_search_prefix ? strlen (pep_dll_search_prefix) : 0) +#endif + + 1); + + /* Try "libfoo.dll.a" first (preferred explicit import library for dll's. */ + sprintf (string, "%s/lib%s.dll.a", search->name, filename); + + if (! ldfile_try_open_bfd (string, entry)) + { + /* Try "foo.dll.a" next (alternate explicit import library for dll's. */ + sprintf (string, "%s/%s.dll.a", search->name, filename); + if (! ldfile_try_open_bfd (string, entry)) + { + /* Try libfoo.a next. Normally, this would be interpreted as a static + library, but it *could* be an import library. For backwards compatibility, + libfoo.a needs to ==precede== libfoo.dll and foo.dll in the search, + or sometimes errors occur when building legacy packages. + + Putting libfoo.a here means that in a failure case (i.e. the library + -lfoo is not found) we will search for libfoo.a twice before + giving up -- once here, and once when searching for a "static" lib. + for a "static" lib. */ + /* Try "libfoo.a" (import lib, or static lib, but must + take precedence over dll's). */ + sprintf (string, "%s/lib%s.a", search->name, filename); + if (! ldfile_try_open_bfd (string, entry)) + { +#ifdef DLL_SUPPORT + if (pep_dll_search_prefix) + { + /* Try "foo.dll" (preferred dll name, if specified). */ + sprintf (string, "%s/%s%s.dll", search->name, pep_dll_search_prefix, filename); + if (! ldfile_try_open_bfd (string, entry)) + { + /* Try "libfoo.dll" (default preferred dll name). */ + sprintf (string, "%s/lib%s.dll", search->name, filename); + if (! ldfile_try_open_bfd (string, entry)) + { + /* Finally, try "foo.dll" (alternate dll name). */ + sprintf (string, "%s/%s.dll", search->name, filename); + if (! ldfile_try_open_bfd (string, entry)) + { + free (string); + return FALSE; + } + } + } + } + else /* pep_dll_search_prefix not specified. */ +#endif + { + /* Try "libfoo.dll" (preferred dll name). */ + sprintf (string, "%s/lib%s.dll", search->name, filename); + if (! ldfile_try_open_bfd (string, entry)) + { + /* Finally, try "foo.dll" (alternate dll name). */ + sprintf (string, "%s/%s.dll", search->name, filename); + if (! ldfile_try_open_bfd (string, entry)) + { + free (string); + return FALSE; + } + } + } + } + } + } + + entry->filename = string; + + return TRUE; +} + +static int +gld_${EMULATION_NAME}_find_potential_libraries + (char *name, lang_input_statement_type *entry) +{ + return ldfile_open_file_search (name, entry, "", ".lib"); +} + +static char * +gld_${EMULATION_NAME}_get_script (int *isfile) +EOF +# Scripts compiled in. +# sed commands to quote an ld script as a C string. +sc="-f stringify.sed" + +cat >>e${EMULATION_NAME}.c <> e${EMULATION_NAME}.c +echo ' ; else if (link_info.relocatable) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c +echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c +echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c +echo ' ; else return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c +echo '; }' >> e${EMULATION_NAME}.c + +cat >>e${EMULATION_NAME}.c < + +#include "ld.h" +#include "ldexp.h" +#include "ldlang.h" +#include "ldwrite.h" +#include "ldmisc.h" +#include +#include "ldmain.h" +#include "ldfile.h" +#include "ldemul.h" +#include "coff/internal.h" +#include "../bfd/libcoff.h" +#include "deffile.h" +#include "pep-dll.h" + +#undef AOUTSZ +#define AOUTSZ PEPAOUTSZ +#define PEAOUTHDR PEPAOUTHDR + +/* This file turns a regular Windows PE image into a DLL. Because of + the complexity of this operation, it has been broken down into a + number of separate modules which are all called by the main function + at the end of this file. This function is not re-entrant and is + normally only called once, so static variables are used to reduce + the number of parameters and return values required. + + See also: ld/emultempl/pep.em. */ + +/* Auto-import feature by Paul Sokolovsky + + Quick facts: + + 1. With this feature on, DLL clients can import variables from DLL + without any concern from their side (for example, without any source + code modifications). + + 2. This is done completely in bounds of the PE specification (to be fair, + there's a place where it pokes nose out of, but in practice it works). + So, resulting module can be used with any other PE compiler/linker. + + 3. Auto-import is fully compatible with standard import method and they + can be mixed together. + + 4. Overheads: space: 8 bytes per imported symbol, plus 20 for each + reference to it; load time: negligible; virtual/physical memory: should be + less than effect of DLL relocation, and I sincerely hope it doesn't affect + DLL sharability (too much). + + Idea + + The obvious and only way to get rid of dllimport insanity is to make client + access variable directly in the DLL, bypassing extra dereference. I.e., + whenever client contains something like + + mov dll_var,%eax, + + address of dll_var in the command should be relocated to point into loaded + DLL. The aim is to make OS loader do so, and than make ld help with that. + Import section of PE made following way: there's a vector of structures + each describing imports from particular DLL. Each such structure points + to two other parallel vectors: one holding imported names, and one which + will hold address of corresponding imported name. So, the solution is + de-vectorize these structures, making import locations be sparse and + pointing directly into code. Before continuing, it is worth a note that, + while authors strives to make PE act ELF-like, there're some other people + make ELF act PE-like: elfvector, ;-) . + + Implementation + + For each reference of data symbol to be imported from DLL (to set of which + belong symbols with name , if __imp_ is found in implib), the + import fixup entry is generated. That entry is of type + IMAGE_IMPORT_DESCRIPTOR and stored in .idata$3 subsection. Each + fixup entry contains pointer to symbol's address within .text section + (marked with __fuN_ symbol, where N is integer), pointer to DLL name + (so, DLL name is referenced by multiple entries), and pointer to symbol + name thunk. Symbol name thunk is singleton vector (__nm_th_) + pointing to IMAGE_IMPORT_BY_NAME structure (__nm_) directly + containing imported name. Here comes that "om the edge" problem mentioned + above: PE specification rambles that name vector (OriginalFirstThunk) + should run in parallel with addresses vector (FirstThunk), i.e. that they + should have same number of elements and terminated with zero. We violate + this, since FirstThunk points directly into machine code. But in practice, + OS loader implemented the sane way: it goes thru OriginalFirstThunk and + puts addresses to FirstThunk, not something else. It once again should be + noted that dll and symbol name structures are reused across fixup entries + and should be there anyway to support standard import stuff, so sustained + overhead is 20 bytes per reference. Other question is whether having several + IMAGE_IMPORT_DESCRIPTORS for the same DLL is possible. Answer is yes, it is + done even by native compiler/linker (libth32's functions are in fact reside + in windows9x kernel32.dll, so if you use it, you have two + IMAGE_IMPORT_DESCRIPTORS for kernel32.dll). Yet other question is whether + referencing the same PE structures several times is valid. The answer is why + not, prohibiting that (detecting violation) would require more work on + behalf of loader than not doing it. + + See also: ld/emultempl/pe.em. */ + +static void add_bfd_to_link (bfd *, const char *, struct bfd_link_info *); + +/* For emultempl/pe.em. */ + +def_file * pep_def_file = 0; +int pep_dll_export_everything = 0; +int pep_dll_do_default_excludes = 1; +int pep_dll_kill_ats = 0; +int pep_dll_stdcall_aliases = 0; +int pep_dll_warn_dup_exports = 0; +int pep_dll_compat_implib = 0; +int pep_dll_extra_pe_debug = 0; + +/* Static variables and types. */ + +static bfd_vma image_base; +static bfd *filler_bfd; +static struct bfd_section *edata_s, *reloc_s; +static unsigned char *edata_d, *reloc_d; +static size_t edata_sz, reloc_sz; +static int runtime_pseudo_relocs_created = 0; + +typedef struct + { + char *target_name; + char *object_target; + unsigned int imagebase_reloc; + int pep_arch; + int bfd_arch; + int underscored; + } +pep_details_type; + +typedef struct + { + char *name; + int len; + } +autofilter_entry_type; + +#define PE_ARCH_i386 1 +#define PE_ARCH_sh 2 +#define PE_ARCH_mips 3 +#define PE_ARCH_arm 4 +#define PE_ARCH_arm_epoc 5 + +static pep_details_type pep_detail_list[] = +{ + { + "pei-x86-64", + "pe-x86-64", + 3 /* R_IMAGEBASE */, + PE_ARCH_i386, + bfd_arch_i386, + 1 + }, + { NULL, NULL, 0, 0, 0, 0 } +}; + +static pep_details_type *pep_details; + +static autofilter_entry_type autofilter_symbollist[] = +{ + { "DllMain@12", 10 }, + { "DllEntryPoint@0", 15 }, + { "DllMainCRTStartup@12", 20 }, + { "_cygwin_dll_entry@12", 20 }, + { "_cygwin_crt0_common@8", 21 }, + { "_cygwin_noncygwin_dll_entry@12", 30 }, + { "impure_ptr", 10 }, + { "_pei386_runtime_relocator", 25 }, + { "do_pseudo_reloc", 15 }, + { "cygwin_crt0", 11 }, + { NULL, 0 } +}; + +/* Do not specify library suffix explicitly, to allow for dllized versions. */ +static autofilter_entry_type autofilter_liblist[] = +{ + { "libcygwin", 9 }, + { "libgcc", 6 }, + { "libstdc++", 9 }, + { "libmingw32", 10 }, + { "libmingwex", 10 }, + { "libg2c", 6 }, + { "libsupc++", 9 }, + { "libobjc", 7 }, + { "libgcj", 6 }, + { NULL, 0 } +}; + +static autofilter_entry_type autofilter_objlist[] = +{ + { "crt0.o", 6 }, + { "crt1.o", 6 }, + { "crt2.o", 6 }, + { "dllcrt1.o", 9 }, + { "dllcrt2.o", 9 }, + { "gcrt0.o", 7 }, + { "gcrt1.o", 7 }, + { "gcrt2.o", 7 }, + { "crtbegin.o", 10 }, + { "crtend.o", 8 }, + { NULL, 0 } +}; + +static autofilter_entry_type autofilter_symbolprefixlist[] = +{ + /* { "__imp_", 6 }, */ + /* Do __imp_ explicitly to save time. */ + { "__rtti_", 7 }, + /* Don't re-export auto-imported symbols. */ + { "_nm_", 4 }, + { "__builtin_", 10 }, + /* Don't export symbols specifying internal DLL layout. */ + { "_head_", 6 }, + { "_fmode", 6 }, + { "_impure_ptr", 11 }, + { "cygwin_attach_dll", 17 }, + { "cygwin_premain0", 15 }, + { "cygwin_premain1", 15 }, + { "cygwin_premain2", 15 }, + { "cygwin_premain3", 15 }, + { "environ", 7 }, + { NULL, 0 } +}; + +static autofilter_entry_type autofilter_symbolsuffixlist[] = +{ + { "_iname", 6 }, + { NULL, 0 } +}; + +#define U(str) (pep_details->underscored ? "_" str : str) + +void +pep_dll_id_target (const char *target) +{ + int i; + + for (i = 0; pep_detail_list[i].target_name; i++) + if (strcmp (pep_detail_list[i].target_name, target) == 0 + || strcmp (pep_detail_list[i].object_target, target) == 0) + { + pep_details = pep_detail_list + i; + return; + } + einfo (_("%XUnsupported PEI architecture: %s\n"), target); + exit (1); +} + +/* Helper functions for qsort. Relocs must be sorted so that we can write + them out by pages. */ + +typedef struct + { + bfd_vma vma; + char type; + short extra; + } +reloc_data_type; + +static int +reloc_sort (const void *va, const void *vb) +{ + bfd_vma a = ((const reloc_data_type *) va)->vma; + bfd_vma b = ((const reloc_data_type *) vb)->vma; + + return (a > b) ? 1 : ((a < b) ? -1 : 0); +} + +static int +pep_export_sort (const void *va, const void *vb) +{ + const def_file_export *a = va; + const def_file_export *b = vb; + + return strcmp (a->name, b->name); +} + +/* Read and process the .DEF file. */ + +/* These correspond to the entries in pep_def_file->exports[]. I use + exported_symbol_sections[i] to tag whether or not the symbol was + defined, since we can't export symbols we don't have. */ + +static bfd_vma *exported_symbol_offsets; +static struct bfd_section **exported_symbol_sections; +static int export_table_size; +static int count_exported; +static int count_exported_byname; +static int count_with_ordinals; +static const char *dll_name; +static int min_ordinal, max_ordinal; +static int *exported_symbols; + +typedef struct exclude_list_struct + { + char *string; + struct exclude_list_struct *next; + int type; + } +exclude_list_struct; + +static struct exclude_list_struct *excludes = 0; + +void +pep_dll_add_excludes (const char *new_excludes, const int type) +{ + char *local_copy; + char *exclude_string; + + local_copy = xstrdup (new_excludes); + + exclude_string = strtok (local_copy, ",:"); + for (; exclude_string; exclude_string = strtok (NULL, ",:")) + { + struct exclude_list_struct *new_exclude; + + new_exclude = xmalloc (sizeof (struct exclude_list_struct)); + new_exclude->string = xmalloc (strlen (exclude_string) + 1); + strcpy (new_exclude->string, exclude_string); + new_exclude->type = type; + new_exclude->next = excludes; + excludes = new_exclude; + } + + free (local_copy); +} + + +/* abfd is a bfd containing n (or NULL) + It can be used for contextual checks. */ + +static int +auto_export (bfd *abfd, def_file *d, const char *n) +{ + int i; + struct exclude_list_struct *ex; + autofilter_entry_type *afptr; + const char * libname = 0; + if (abfd && abfd->my_archive) + libname = lbasename (abfd->my_archive->filename); + + /* We should not re-export imported stuff. */ + if (strncmp (n, "_imp_", 5) == 0) + return 0; + + for (i = 0; i < d->num_exports; i++) + if (strcmp (d->exports[i].name, n) == 0) + return 0; + + if (pep_dll_do_default_excludes) + { + const char * p; + int len; + + if (pep_dll_extra_pe_debug) + printf ("considering exporting: %s, abfd=%p, abfd->my_arc=%p\n", + n, abfd, abfd->my_archive); + + /* First of all, make context checks: + Don't export anything from standard libs. */ + if (libname) + { + afptr = autofilter_liblist; + + while (afptr->name) + { + if (strncmp (libname, afptr->name, afptr->len) == 0 ) + return 0; + afptr++; + } + } + + /* Next, exclude symbols from certain startup objects. */ + + if (abfd && (p = lbasename (abfd->filename))) + { + afptr = autofilter_objlist; + while (afptr->name) + { + if (strcmp (p, afptr->name) == 0) + return 0; + afptr++; + } + } + + /* Don't try to blindly exclude all symbols + that begin with '__'; this was tried and + it is too restrictive. */ + + /* Then, exclude specific symbols. */ + afptr = autofilter_symbollist; + while (afptr->name) + { + if (strcmp (n, afptr->name) == 0) + return 0; + + afptr++; + } + + /* Next, exclude symbols starting with ... */ + afptr = autofilter_symbolprefixlist; + while (afptr->name) + { + if (strncmp (n, afptr->name, afptr->len) == 0) + return 0; + + afptr++; + } + + /* Finally, exclude symbols ending with ... */ + len = strlen (n); + afptr = autofilter_symbolsuffixlist; + while (afptr->name) + { + if ((len >= afptr->len) + /* Add 1 to insure match with trailing '\0'. */ + && strncmp (n + len - afptr->len, afptr->name, + afptr->len + 1) == 0) + return 0; + + afptr++; + } + } + + for (ex = excludes; ex; ex = ex->next) + { + if (ex->type == 1) /* exclude-libs */ + { + if (libname + && ((strcmp (libname, ex->string) == 0) + || (strcasecmp ("ALL", ex->string) == 0))) + return 0; + } + else if (strcmp (n, ex->string) == 0) + return 0; + } + + return 1; +} + +static void +process_def_file (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) +{ + int i, j; + struct bfd_link_hash_entry *blhe; + bfd *b; + struct bfd_section *s; + def_file_export *e = 0; + + if (!pep_def_file) + pep_def_file = def_file_empty (); + + /* First, run around to all the objects looking for the .drectve + sections, and push those into the def file too. */ + for (b = info->input_bfds; b; b = b->link_next) + { + s = bfd_get_section_by_name (b, ".drectve"); + if (s) + { + long size = s->size; + char *buf = xmalloc (size); + + bfd_get_section_contents (b, s, buf, 0, size); + def_file_add_directive (pep_def_file, buf, size); + free (buf); + } + } + + /* If we are not building a DLL, when there are no exports + we do not build an export table at all. */ + if (!pep_dll_export_everything && pep_def_file->num_exports == 0 + && info->executable) + return; + + /* Now, maybe export everything else the default way. */ + if (pep_dll_export_everything || pep_def_file->num_exports == 0) + { + for (b = info->input_bfds; b; b = b->link_next) + { + asymbol **symbols; + int nsyms, symsize; + + symsize = bfd_get_symtab_upper_bound (b); + symbols = xmalloc (symsize); + nsyms = bfd_canonicalize_symtab (b, symbols); + + for (j = 0; j < nsyms; j++) + { + /* We should export symbols which are either global or not + anything at all. (.bss data is the latter) + We should not export undefined symbols. */ + if (symbols[j]->section != &bfd_und_section + && ((symbols[j]->flags & BSF_GLOBAL) + || (symbols[j]->flags == BFD_FORT_COMM_DEFAULT_VALUE))) + { + const char *sn = symbols[j]->name; + + /* We should not re-export imported stuff. */ + { + char *name = xmalloc (strlen (sn) + 2 + 6); + sprintf (name, "%s%s", U("_imp_"), sn); + printf("*** Export Sym:%s\n",name); + blhe = bfd_link_hash_lookup (info->hash, name, + FALSE, FALSE, FALSE); + free (name); + + if (blhe && blhe->type == bfd_link_hash_defined) + continue; + } + + if (*sn == '_') + sn++; + + if (auto_export (b, pep_def_file, sn)) + { + def_file_export *p; + p=def_file_add_export (pep_def_file, sn, 0, -1); + /* Fill data flag properly, from dlltool.c. */ + p->flag_data = !(symbols[j]->flags & BSF_FUNCTION); + } + } + } + } + } + +#undef NE +#define NE pep_def_file->num_exports + + /* Canonicalize the export list. */ + if (pep_dll_kill_ats) + { + for (i = 0; i < NE; i++) + { + if (strchr (pep_def_file->exports[i].name, '@')) + { + /* This will preserve internal_name, which may have been + pointing to the same memory as name, or might not + have. */ + int lead_at = (*pep_def_file->exports[i].name == '@'); + char *tmp = xstrdup (pep_def_file->exports[i].name + lead_at); + char *tmp_at = strchr (tmp, '@'); + + if (tmp_at) + *tmp_at = 0; + else + einfo (_("%XCannot export %s: invalid export name\n"), + pep_def_file->exports[i].name); + pep_def_file->exports[i].name = tmp; + } + } + } + + if (pep_dll_stdcall_aliases) + { + for (i = 0; i < NE; i++) + { + if (strchr (pep_def_file->exports[i].name, '@')) + { + int lead_at = (*pep_def_file->exports[i].name == '@'); + char *tmp = xstrdup (pep_def_file->exports[i].name + lead_at); + + *(strchr (tmp, '@')) = 0; + if (auto_export (NULL, pep_def_file, tmp)) + def_file_add_export (pep_def_file, tmp, + pep_def_file->exports[i].internal_name, + -1); + else + free (tmp); + } + } + } + + /* Convenience, but watch out for it changing. */ + e = pep_def_file->exports; + + exported_symbol_offsets = xmalloc (NE * sizeof (bfd_vma)); + exported_symbol_sections = xmalloc (NE * sizeof (struct bfd_section *)); + + memset (exported_symbol_sections, 0, NE * sizeof (struct bfd_section *)); + max_ordinal = 0; + min_ordinal = 65536; + count_exported = 0; + count_exported_byname = 0; + count_with_ordinals = 0; + + qsort (pep_def_file->exports, NE, sizeof (pep_def_file->exports[0]), + pep_export_sort); + for (i = 0, j = 0; i < NE; i++) + { + if (i > 0 && strcmp (e[i].name, e[i - 1].name) == 0) + { + /* This is a duplicate. */ + if (e[j - 1].ordinal != -1 + && e[i].ordinal != -1 + && e[j - 1].ordinal != e[i].ordinal) + { + if (pep_dll_warn_dup_exports) + /* xgettext:c-format */ + einfo (_("%XError, duplicate EXPORT with ordinals: %s (%d vs %d)\n"), + e[j - 1].name, e[j - 1].ordinal, e[i].ordinal); + } + else + { + if (pep_dll_warn_dup_exports) + /* xgettext:c-format */ + einfo (_("Warning, duplicate EXPORT: %s\n"), + e[j - 1].name); + } + + if (e[i].ordinal != -1) + e[j - 1].ordinal = e[i].ordinal; + e[j - 1].flag_private |= e[i].flag_private; + e[j - 1].flag_constant |= e[i].flag_constant; + e[j - 1].flag_noname |= e[i].flag_noname; + e[j - 1].flag_data |= e[i].flag_data; + } + else + { + if (i != j) + e[j] = e[i]; + j++; + } + } + pep_def_file->num_exports = j; /* == NE */ + + for (i = 0; i < NE; i++) + { + char *name; + + /* Check for forward exports */ + if (strchr (pep_def_file->exports[i].internal_name, '.')) + { + count_exported++; + if (!pep_def_file->exports[i].flag_noname) + count_exported_byname++; + + pep_def_file->exports[i].flag_forward = 1; + + if (pep_def_file->exports[i].ordinal != -1) + { + if (max_ordinal < pep_def_file->exports[i].ordinal) + max_ordinal = pep_def_file->exports[i].ordinal; + if (min_ordinal > pep_def_file->exports[i].ordinal) + min_ordinal = pep_def_file->exports[i].ordinal; + count_with_ordinals++; + } + + continue; + } + + name = xmalloc (strlen (pep_def_file->exports[i].internal_name) + 2); + if (pep_details->underscored + && (*pep_def_file->exports[i].internal_name != '@')) + { + *name = '_'; + strcpy (name + 1, pep_def_file->exports[i].internal_name); + } + else + strcpy (name, pep_def_file->exports[i].internal_name); + + blhe = bfd_link_hash_lookup (info->hash, + name, + FALSE, FALSE, TRUE); + + if (blhe + && (blhe->type == bfd_link_hash_defined + || (blhe->type == bfd_link_hash_common))) + { + count_exported++; + if (!pep_def_file->exports[i].flag_noname) + count_exported_byname++; + + /* Only fill in the sections. The actual offsets are computed + in fill_exported_offsets() after common symbols are laid + out. */ + if (blhe->type == bfd_link_hash_defined) + exported_symbol_sections[i] = blhe->u.def.section; + else + exported_symbol_sections[i] = blhe->u.c.p->section; + + if (pep_def_file->exports[i].ordinal != -1) + { + if (max_ordinal < pep_def_file->exports[i].ordinal) + max_ordinal = pep_def_file->exports[i].ordinal; + if (min_ordinal > pep_def_file->exports[i].ordinal) + min_ordinal = pep_def_file->exports[i].ordinal; + count_with_ordinals++; + } + } + else if (blhe && blhe->type == bfd_link_hash_undefined) + { + /* xgettext:c-format */ + einfo (_("%XCannot export %s: symbol not defined\n"), + pep_def_file->exports[i].internal_name); + } + else if (blhe) + { + /* xgettext:c-format */ + einfo (_("%XCannot export %s: symbol wrong type (%d vs %d)\n"), + pep_def_file->exports[i].internal_name, + blhe->type, bfd_link_hash_defined); + } + else + { + /* xgettext:c-format */ + einfo (_("%XCannot export %s: symbol not found\n"), + pep_def_file->exports[i].internal_name); + } + free (name); + } +} + +/* Build the bfd that will contain .edata and .reloc sections. */ + +static void +build_filler_bfd (int include_edata) +{ + lang_input_statement_type *filler_file; + filler_file = lang_add_input_file ("dll stuff", + lang_input_file_is_fake_enum, + NULL); + filler_file->the_bfd = filler_bfd = bfd_create ("dll stuff", output_bfd); + if (filler_bfd == NULL + || !bfd_set_arch_mach (filler_bfd, + bfd_get_arch (output_bfd), + bfd_get_mach (output_bfd))) + { + einfo ("%X%P: can not create BFD: %E\n"); + return; + } + + if (include_edata) + { + edata_s = bfd_make_section_old_way (filler_bfd, ".edata"); + if (edata_s == NULL + || !bfd_set_section_flags (filler_bfd, edata_s, + (SEC_HAS_CONTENTS + | SEC_ALLOC + | SEC_LOAD + | SEC_KEEP + | SEC_IN_MEMORY))) + { + einfo ("%X%P: can not create .edata section: %E\n"); + return; + } + bfd_set_section_size (filler_bfd, edata_s, edata_sz); + } + + reloc_s = bfd_make_section_old_way (filler_bfd, ".reloc"); + if (reloc_s == NULL + || !bfd_set_section_flags (filler_bfd, reloc_s, + (SEC_HAS_CONTENTS + | SEC_ALLOC + | SEC_LOAD + | SEC_KEEP + | SEC_IN_MEMORY))) + { + einfo ("%X%P: can not create .reloc section: %E\n"); + return; + } + + bfd_set_section_size (filler_bfd, reloc_s, 0); + + ldlang_add_file (filler_file); +} + +/* Gather all the exported symbols and build the .edata section. */ + +static void +generate_edata (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED) +{ + int i, next_ordinal; + int name_table_size = 0; + const char *dlnp; + + /* First, we need to know how many exported symbols there are, + and what the range of ordinals is. */ + if (pep_def_file->name) + dll_name = pep_def_file->name; + else + { + dll_name = abfd->filename; + + for (dlnp = dll_name; *dlnp; dlnp++) + if (*dlnp == '\\' || *dlnp == '/' || *dlnp == ':') + dll_name = dlnp + 1; + } + + if (count_with_ordinals && max_ordinal > count_exported) + { + if (min_ordinal > max_ordinal - count_exported + 1) + min_ordinal = max_ordinal - count_exported + 1; + } + else + { + min_ordinal = 1; + max_ordinal = count_exported; + } + + export_table_size = max_ordinal - min_ordinal + 1; + exported_symbols = xmalloc (export_table_size * sizeof (int)); + for (i = 0; i < export_table_size; i++) + exported_symbols[i] = -1; + + /* Now we need to assign ordinals to those that don't have them. */ + for (i = 0; i < NE; i++) + { + if (exported_symbol_sections[i] || + pep_def_file->exports[i].flag_forward) + { + if (pep_def_file->exports[i].ordinal != -1) + { + int ei = pep_def_file->exports[i].ordinal - min_ordinal; + int pi = exported_symbols[ei]; + + if (pi != -1) + { + /* xgettext:c-format */ + einfo (_("%XError, ordinal used twice: %d (%s vs %s)\n"), + pep_def_file->exports[i].ordinal, + pep_def_file->exports[i].name, + pep_def_file->exports[pi].name); + } + exported_symbols[ei] = i; + } + name_table_size += strlen (pep_def_file->exports[i].name) + 1; + } + + /* Reserve space for the forward name. */ + if (pep_def_file->exports[i].flag_forward) + { + name_table_size += strlen (pep_def_file->exports[i].internal_name) + 1; + } + } + + next_ordinal = min_ordinal; + for (i = 0; i < NE; i++) + if ((exported_symbol_sections[i] || + pep_def_file->exports[i].flag_forward) && + pep_def_file->exports[i].ordinal == -1) + { + while (exported_symbols[next_ordinal - min_ordinal] != -1) + next_ordinal++; + + exported_symbols[next_ordinal - min_ordinal] = i; + pep_def_file->exports[i].ordinal = next_ordinal; + } + + /* OK, now we can allocate some memory. */ + edata_sz = (40 /* directory */ + + 4 * export_table_size /* addresses */ + + 4 * count_exported_byname /* name ptrs */ + + 2 * count_exported_byname /* ordinals */ + + name_table_size + strlen (dll_name) + 1); +} + +/* Fill the exported symbol offsets. The preliminary work has already + been done in process_def_file(). */ + +static void +fill_exported_offsets (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) +{ + int i; + struct bfd_link_hash_entry *blhe; + + for (i = 0; i < pep_def_file->num_exports; i++) + { + char *name; + + name = xmalloc (strlen (pep_def_file->exports[i].internal_name) + 2); + if (pep_details->underscored + && *pep_def_file->exports[i].internal_name != '@') + { + *name = '_'; + strcpy (name + 1, pep_def_file->exports[i].internal_name); + } + else + strcpy (name, pep_def_file->exports[i].internal_name); + + blhe = bfd_link_hash_lookup (info->hash, + name, + FALSE, FALSE, TRUE); + + if (blhe && blhe->type == bfd_link_hash_defined) + exported_symbol_offsets[i] = blhe->u.def.value; + + free (name); + } +} + +static void +fill_edata (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED) +{ + int s, hint; + unsigned char *edirectory; + unsigned char *eaddresses; + unsigned char *enameptrs; + unsigned char *eordinals; + char *enamestr; + time_t now; + + time (&now); + + edata_d = xmalloc (edata_sz); + + /* Note use of array pointer math here. */ + edirectory = edata_d; + eaddresses = edata_d + 40; + enameptrs = eaddresses + 4 * export_table_size; + eordinals = enameptrs + 4 * count_exported_byname; + enamestr = (char *) eordinals + 2 * count_exported_byname; + +#define ERVA(ptr) (((unsigned char *)(ptr) - edata_d) \ + + edata_s->output_section->vma - image_base) + + memset (edata_d, 0, edata_sz); + bfd_put_32 (abfd, now, edata_d + 4); + if (pep_def_file->version_major != -1) + { + bfd_put_16 (abfd, pep_def_file->version_major, edata_d + 8); + bfd_put_16 (abfd, pep_def_file->version_minor, edata_d + 10); + } + + bfd_put_32 (abfd, ERVA (enamestr), edata_d + 12); + strcpy (enamestr, dll_name); + enamestr += strlen (enamestr) + 1; + bfd_put_32 (abfd, min_ordinal, edata_d + 16); + bfd_put_32 (abfd, export_table_size, edata_d + 20); + bfd_put_32 (abfd, count_exported_byname, edata_d + 24); + bfd_put_32 (abfd, ERVA (eaddresses), edata_d + 28); + bfd_put_32 (abfd, ERVA (enameptrs), edata_d + 32); + bfd_put_32 (abfd, ERVA (eordinals), edata_d + 36); + + fill_exported_offsets (abfd, info); + + /* Ok, now for the filling in part. + Scan alphabetically - ie the ordering in the exports[] table, + rather than by ordinal - the ordering in the exported_symbol[] + table. See dlltool.c and: + http://sources.redhat.com/ml/binutils/2003-04/msg00379.html + for more information. */ + hint = 0; + for (s = 0; s < NE; s++) + { + struct bfd_section *ssec = exported_symbol_sections[s]; + if (pep_def_file->exports[s].ordinal != -1 && + (pep_def_file->exports[s].flag_forward || ssec != NULL)) + { + int ord = pep_def_file->exports[s].ordinal; + + if (pep_def_file->exports[s].flag_forward) + { + bfd_put_32 (abfd, ERVA (enamestr), + eaddresses + 4 * (ord - min_ordinal)); + + strcpy (enamestr, pep_def_file->exports[s].internal_name); + enamestr += strlen (pep_def_file->exports[s].internal_name) + 1; + } + else + { + unsigned long srva = (exported_symbol_offsets[s] + + ssec->output_section->vma + + ssec->output_offset); + + bfd_put_32 (abfd, srva - image_base, + eaddresses + 4 * (ord - min_ordinal)); + } + + if (!pep_def_file->exports[s].flag_noname) + { + char *ename = pep_def_file->exports[s].name; + + bfd_put_32 (abfd, ERVA (enamestr), enameptrs); + enameptrs += 4; + strcpy (enamestr, ename); + enamestr += strlen (enamestr) + 1; + bfd_put_16 (abfd, ord - min_ordinal, eordinals); + eordinals += 2; + pep_def_file->exports[s].hint = hint++; + } + } + } +} + + +static struct bfd_section *current_sec; + +void +pep_walk_relocs_of_symbol (struct bfd_link_info *info, + const char *name, + int (*cb) (arelent *, asection *)) +{ + bfd *b; + asection *s; + + for (b = info->input_bfds; b; b = b->link_next) + { + asymbol **symbols; + int nsyms, symsize; + + symsize = bfd_get_symtab_upper_bound (b); + symbols = xmalloc (symsize); + nsyms = bfd_canonicalize_symtab (b, symbols); + + for (s = b->sections; s; s = s->next) + { + arelent **relocs; + int relsize, nrelocs, i; + int flags = bfd_get_section_flags (b, s); + + /* Skip discarded linkonce sections. */ + if (flags & SEC_LINK_ONCE + && s->output_section == bfd_abs_section_ptr) + continue; + + current_sec = s; + + relsize = bfd_get_reloc_upper_bound (b, s); + relocs = xmalloc (relsize); + nrelocs = bfd_canonicalize_reloc (b, s, relocs, symbols); + + for (i = 0; i < nrelocs; i++) + { + struct bfd_symbol *sym = *relocs[i]->sym_ptr_ptr; + + if (!strcmp (name, sym->name)) + cb (relocs[i], s); + } + + free (relocs); + + /* Warning: the allocated symbols are remembered in BFD and reused + later, so don't free them! */ + /* free (symbols); */ + } + } +} + +/* Gather all the relocations and build the .reloc section. */ + +static void +generate_reloc (bfd *abfd, struct bfd_link_info *info) +{ + + /* For .reloc stuff. */ + reloc_data_type *reloc_data; + int total_relocs = 0; + int i; + unsigned long sec_page = (unsigned long) -1; + unsigned long page_ptr, page_count; + int bi; + bfd *b; + struct bfd_section *s; + + total_relocs = 0; + for (b = info->input_bfds; b; b = b->link_next) + for (s = b->sections; s; s = s->next) + total_relocs += s->reloc_count; + + reloc_data = xmalloc (total_relocs * sizeof (reloc_data_type)); + + total_relocs = 0; + bi = 0; + for (bi = 0, b = info->input_bfds; b; bi++, b = b->link_next) + { + arelent **relocs; + int relsize, nrelocs, i; + + for (s = b->sections; s; s = s->next) + { + unsigned long sec_vma = s->output_section->vma + s->output_offset; + asymbol **symbols; + int nsyms, symsize; + + /* If it's not loaded, we don't need to relocate it this way. */ + if (!(s->output_section->flags & SEC_LOAD)) + continue; + + /* I don't know why there would be a reloc for these, but I've + seen it happen - DJ */ + if (s->output_section == &bfd_abs_section) + continue; + + if (s->output_section->vma == 0) + { + /* Huh? Shouldn't happen, but punt if it does. */ + einfo ("DJ: zero vma section reloc detected: `%s' #%d f=%d\n", + s->output_section->name, s->output_section->index, + s->output_section->flags); + continue; + } + + symsize = bfd_get_symtab_upper_bound (b); + symbols = xmalloc (symsize); + nsyms = bfd_canonicalize_symtab (b, symbols); + + relsize = bfd_get_reloc_upper_bound (b, s); + relocs = xmalloc (relsize); + nrelocs = bfd_canonicalize_reloc (b, s, relocs, symbols); + + for (i = 0; i < nrelocs; i++) + { + if (pep_dll_extra_pe_debug) + { + struct bfd_symbol *sym = *relocs[i]->sym_ptr_ptr; + printf ("rel: %s\n", sym->name); + } + if (!relocs[i]->howto->pc_relative + && relocs[i]->howto->type != pep_details->imagebase_reloc) + { + bfd_vma sym_vma; + struct bfd_symbol *sym = *relocs[i]->sym_ptr_ptr; + + sym_vma = (relocs[i]->addend + + sym->value + + sym->section->vma + + sym->section->output_offset + + sym->section->output_section->vma); + reloc_data[total_relocs].vma = sec_vma + relocs[i]->address; + +#define BITS_AND_SHIFT(bits, shift) (bits * 1000 | shift) + + switch BITS_AND_SHIFT (relocs[i]->howto->bitsize, + relocs[i]->howto->rightshift) + { + case BITS_AND_SHIFT (32, 0): + reloc_data[total_relocs].type = 3; + total_relocs++; + break; + case BITS_AND_SHIFT (16, 0): + reloc_data[total_relocs].type = 2; + total_relocs++; + break; + case BITS_AND_SHIFT (16, 16): + reloc_data[total_relocs].type = 4; + /* FIXME: we can't know the symbol's right value + yet, but we probably can safely assume that + CE will relocate us in 64k blocks, so leaving + it zero is safe. */ + reloc_data[total_relocs].extra = 0; + total_relocs++; + break; + case BITS_AND_SHIFT (26, 2): + reloc_data[total_relocs].type = 5; + total_relocs++; + break; + case BITS_AND_SHIFT (24, 2): + /* FIXME: 0 is ARM_26D, it is defined in bfd/coff-arm.c + Those ARM_xxx definitions should go in proper + header someday. */ + if (relocs[i]->howto->type == 0 + /* Older GNU linkers used 5 instead of 0 for this reloc. */ + || relocs[i]->howto->type == 5) + /* This is an ARM_26D reloc, which is an ARM_26 reloc + that has already been fully processed during a + previous link stage, so ignore it here. */ + break; + /* Fall through. */ + default: + /* xgettext:c-format */ + einfo (_("%XError: %d-bit reloc in dll\n"), + relocs[i]->howto->bitsize); + break; + } + } + } + free (relocs); + /* Warning: the allocated symbols are remembered in BFD and + reused later, so don't free them! */ + } + } + + /* At this point, we have total_relocs relocation addresses in + reloc_addresses, which are all suitable for the .reloc section. + We must now create the new sections. */ + qsort (reloc_data, total_relocs, sizeof (*reloc_data), reloc_sort); + + for (i = 0; i < total_relocs; i++) + { + unsigned long this_page = (reloc_data[i].vma >> 12); + + if (this_page != sec_page) + { + reloc_sz = (reloc_sz + 3) & ~3; /* 4-byte align. */ + reloc_sz += 8; + sec_page = this_page; + } + + reloc_sz += 2; + + if (reloc_data[i].type == 4) + reloc_sz += 2; + } + + reloc_sz = (reloc_sz + 3) & ~3; /* 4-byte align. */ + reloc_d = xmalloc (reloc_sz); + sec_page = (unsigned long) -1; + reloc_sz = 0; + page_ptr = (unsigned long) -1; + page_count = 0; + + for (i = 0; i < total_relocs; i++) + { + unsigned long rva = reloc_data[i].vma - image_base; + unsigned long this_page = (rva & ~0xfff); + + if (this_page != sec_page) + { + while (reloc_sz & 3) + reloc_d[reloc_sz++] = 0; + + if (page_ptr != (unsigned long) -1) + bfd_put_32 (abfd, reloc_sz - page_ptr, reloc_d + page_ptr + 4); + + bfd_put_32 (abfd, this_page, reloc_d + reloc_sz); + page_ptr = reloc_sz; + reloc_sz += 8; + sec_page = this_page; + page_count = 0; + } + + bfd_put_16 (abfd, (rva & 0xfff) + (reloc_data[i].type << 12), + reloc_d + reloc_sz); + reloc_sz += 2; + + if (reloc_data[i].type == 4) + { + bfd_put_16 (abfd, reloc_data[i].extra, reloc_d + reloc_sz); + reloc_sz += 2; + } + + page_count++; + } + + while (reloc_sz & 3) + reloc_d[reloc_sz++] = 0; + + if (page_ptr != (unsigned long) -1) + bfd_put_32 (abfd, reloc_sz - page_ptr, reloc_d + page_ptr + 4); + + while (reloc_sz < reloc_s->size) + reloc_d[reloc_sz++] = 0; +} + +/* Given the exiting def_file structure, print out a .DEF file that + corresponds to it. */ + +static void +quoteput (char *s, FILE *f, int needs_quotes) +{ + char *cp; + + for (cp = s; *cp; cp++) + if (*cp == '\'' + || *cp == '"' + || *cp == '\\' + || ISSPACE (*cp) + || *cp == ',' + || *cp == ';') + needs_quotes = 1; + + if (needs_quotes) + { + putc ('"', f); + + while (*s) + { + if (*s == '"' || *s == '\\') + putc ('\\', f); + + putc (*s, f); + s++; + } + + putc ('"', f); + } + else + fputs (s, f); +} + +void +pep_dll_generate_def_file (const char *pep_out_def_filename) +{ + int i; + FILE *out = fopen (pep_out_def_filename, "w"); + + if (out == NULL) + /* xgettext:c-format */ + einfo (_("%s: Can't open output def file %s\n"), + program_name, pep_out_def_filename); + + if (pep_def_file) + { + if (pep_def_file->name) + { + if (pep_def_file->is_dll) + fprintf (out, "LIBRARY "); + else + fprintf (out, "NAME "); + + quoteput (pep_def_file->name, out, 1); + + if (pe_data (output_bfd)->pe_opthdr.ImageBase) + fprintf (out, " BASE=0x%lx", + (unsigned long) pe_data (output_bfd)->pe_opthdr.ImageBase); + fprintf (out, "\n"); + } + + if (pep_def_file->description) + { + fprintf (out, "DESCRIPTION "); + quoteput (pep_def_file->description, out, 1); + fprintf (out, "\n"); + } + + if (pep_def_file->version_minor != -1) + fprintf (out, "VERSION %d.%d\n", pep_def_file->version_major, + pep_def_file->version_minor); + else if (pep_def_file->version_major != -1) + fprintf (out, "VERSION %d\n", pep_def_file->version_major); + + if (pep_def_file->stack_reserve != -1 || pep_def_file->heap_reserve != -1) + fprintf (out, "\n"); + + if (pep_def_file->stack_commit != -1) + fprintf (out, "STACKSIZE 0x%x,0x%x\n", + pep_def_file->stack_reserve, pep_def_file->stack_commit); + else if (pep_def_file->stack_reserve != -1) + fprintf (out, "STACKSIZE 0x%x\n", pep_def_file->stack_reserve); + + if (pep_def_file->heap_commit != -1) + fprintf (out, "HEAPSIZE 0x%x,0x%x\n", + pep_def_file->heap_reserve, pep_def_file->heap_commit); + else if (pep_def_file->heap_reserve != -1) + fprintf (out, "HEAPSIZE 0x%x\n", pep_def_file->heap_reserve); + + if (pep_def_file->num_section_defs > 0) + { + fprintf (out, "\nSECTIONS\n\n"); + + for (i = 0; i < pep_def_file->num_section_defs; i++) + { + fprintf (out, " "); + quoteput (pep_def_file->section_defs[i].name, out, 0); + + if (pep_def_file->section_defs[i].class) + { + fprintf (out, " CLASS "); + quoteput (pep_def_file->section_defs[i].class, out, 0); + } + + if (pep_def_file->section_defs[i].flag_read) + fprintf (out, " READ"); + + if (pep_def_file->section_defs[i].flag_write) + fprintf (out, " WRITE"); + + if (pep_def_file->section_defs[i].flag_execute) + fprintf (out, " EXECUTE"); + + if (pep_def_file->section_defs[i].flag_shared) + fprintf (out, " SHARED"); + + fprintf (out, "\n"); + } + } + + if (pep_def_file->num_exports > 0) + { + fprintf (out, "EXPORTS\n"); + + for (i = 0; i < pep_def_file->num_exports; i++) + { + def_file_export *e = pep_def_file->exports + i; + fprintf (out, " "); + quoteput (e->name, out, 0); + + if (e->internal_name && strcmp (e->internal_name, e->name)) + { + fprintf (out, " = "); + quoteput (e->internal_name, out, 0); + } + + if (e->ordinal != -1) + fprintf (out, " @%d", e->ordinal); + + if (e->flag_private) + fprintf (out, " PRIVATE"); + + if (e->flag_constant) + fprintf (out, " CONSTANT"); + + if (e->flag_noname) + fprintf (out, " NONAME"); + + if (e->flag_data) + fprintf (out, " DATA"); + + fprintf (out, "\n"); + } + } + + if (pep_def_file->num_imports > 0) + { + fprintf (out, "\nIMPORTS\n\n"); + + for (i = 0; i < pep_def_file->num_imports; i++) + { + def_file_import *im = pep_def_file->imports + i; + fprintf (out, " "); + + if (im->internal_name + && (!im->name || strcmp (im->internal_name, im->name))) + { + quoteput (im->internal_name, out, 0); + fprintf (out, " = "); + } + + quoteput (im->module->name, out, 0); + fprintf (out, "."); + + if (im->name) + quoteput (im->name, out, 0); + else + fprintf (out, "%d", im->ordinal); + + fprintf (out, "\n"); + } + } + } + else + fprintf (out, _("; no contents available\n")); + + if (fclose (out) == EOF) + /* xgettext:c-format */ + einfo (_("%P: Error closing file `%s'\n"), pep_out_def_filename); +} + +/* Generate the import library. */ + +static asymbol **symtab; +static int symptr; +static int tmp_seq; +static const char *dll_filename; +static char *dll_symname; + +#define UNDSEC (asection *) &bfd_und_section + +static asection * +quick_section (bfd *abfd, const char *name, int flags, int align) +{ + asection *sec; + asymbol *sym; + + sec = bfd_make_section_old_way (abfd, name); + bfd_set_section_flags (abfd, sec, flags | SEC_ALLOC | SEC_LOAD | SEC_KEEP); + bfd_set_section_alignment (abfd, sec, align); + /* Remember to undo this before trying to link internally! */ + sec->output_section = sec; + + sym = bfd_make_empty_symbol (abfd); + symtab[symptr++] = sym; + sym->name = sec->name; + sym->section = sec; + sym->flags = BSF_LOCAL; + sym->value = 0; + + return sec; +} + +static void +quick_symbol (bfd *abfd, + const char *n1, + const char *n2, + const char *n3, + asection *sec, + int flags, + int addr) +{ + asymbol *sym; + char *name = xmalloc (strlen (n1) + strlen (n2) + strlen (n3) + 1); + + strcpy (name, n1); + strcat (name, n2); + strcat (name, n3); + printf("*** Quick Sym:%s sec:%p addr:%d\n",name,sec,addr); + sym = bfd_make_empty_symbol (abfd); + sym->name = name; + sym->section = sec; + sym->flags = flags; + sym->value = addr; + symtab[symptr++] = sym; +} + +static arelent *reltab = 0; +static int relcount = 0, relsize = 0; + +static void +quick_reloc (bfd *abfd, int address, int which_howto, int symidx) +{ + if (relcount >= relsize - 1) + { + relsize += 10; + if (reltab) + reltab = xrealloc (reltab, relsize * sizeof (arelent)); + else + reltab = xmalloc (relsize * sizeof (arelent)); + } + reltab[relcount].address = address; + reltab[relcount].addend = 0; + reltab[relcount].howto = bfd_reloc_type_lookup (abfd, which_howto); + reltab[relcount].sym_ptr_ptr = symtab + symidx; + relcount++; +} + +static void +save_relocs (asection *sec) +{ + int i; + + sec->relocation = reltab; + sec->reloc_count = relcount; + sec->orelocation = xmalloc ((relcount + 1) * sizeof (arelent *)); + for (i = 0; i < relcount; i++) + sec->orelocation[i] = sec->relocation + i; + sec->orelocation[relcount] = 0; + sec->flags |= SEC_RELOC; + reltab = 0; + relcount = relsize = 0; +} + +/* .section .idata$2 + .global __head_my_dll + __head_my_dll: + .rva hname + .long 0 + .long 0 + .rva __my_dll_iname + .rva fthunk + + .section .idata$5 + .long 0 + .long 0 + fthunk: + + .section .idata$4 + .long 0 + .long 0 + hname: */ + +static bfd * +make_head (bfd *parent) +{ + asection *id2, *id5, *id4; + unsigned char *d2, *d5, *d4; + char *oname; + bfd *abfd; + + oname = xmalloc (20); + sprintf (oname, "d%06d.o", tmp_seq); + tmp_seq++; + + abfd = bfd_create (oname, parent); + bfd_find_target (pep_details->object_target, abfd); + bfd_make_writable (abfd); + + bfd_set_format (abfd, bfd_object); + bfd_set_arch_mach (abfd, pep_details->bfd_arch, 0); + + symptr = 0; + symtab = xmalloc (6 * sizeof (asymbol *)); + id2 = quick_section (abfd, ".idata$2", SEC_HAS_CONTENTS, 2); + id5 = quick_section (abfd, ".idata$5", SEC_HAS_CONTENTS, 2); + id4 = quick_section (abfd, ".idata$4", SEC_HAS_CONTENTS, 2); + quick_symbol (abfd, U ("_head_"), dll_symname, "", id2, BSF_GLOBAL, 0); + quick_symbol (abfd, U (""), dll_symname, "_iname", UNDSEC, BSF_GLOBAL, 0); + + /* OK, pay attention here. I got confused myself looking back at + it. We create a four-byte section to mark the beginning of the + list, and we include an offset of 4 in the section, so that the + pointer to the list points to the *end* of this section, which is + the start of the list of sections from other objects. */ + + bfd_set_section_size (abfd, id2, 20); + d2 = xmalloc (20); + id2->contents = d2; + memset (d2, 0, 20); + d2[0] = d2[16] = 4; /* Reloc addend. */ + quick_reloc (abfd, 0, BFD_RELOC_RVA, 2); + quick_reloc (abfd, 12, BFD_RELOC_RVA, 4); + quick_reloc (abfd, 16, BFD_RELOC_RVA, 1); + save_relocs (id2); + + bfd_set_section_size (abfd, id5, 8); + d5 = xmalloc (8); + id5->contents = d5; + memset (d5, 0, 8); + + bfd_set_section_size (abfd, id4, 8); + d4 = xmalloc (8); + id4->contents = d4; + memset (d4, 0, 8); + + bfd_set_symtab (abfd, symtab, symptr); + + bfd_set_section_contents (abfd, id2, d2, 0, 20); + bfd_set_section_contents (abfd, id5, d5, 0, 8); + bfd_set_section_contents (abfd, id4, d4, 0, 8); + + bfd_make_readable (abfd); + return abfd; +} + +/* .section .idata$4 + .long 0 + .long 0 + .section .idata$5 + .long 0 + .long 0 + .section idata$7 + .global __my_dll_iname + __my_dll_iname: + .asciz "my.dll" */ + +static bfd * +make_tail (bfd *parent) +{ + asection *id4, *id5, *id7; + unsigned char *d4, *d5, *d7; + int len; + char *oname; + bfd *abfd; + + oname = xmalloc (20); + sprintf (oname, "d%06d.o", tmp_seq); + tmp_seq++; + + abfd = bfd_create (oname, parent); + bfd_find_target (pep_details->object_target, abfd); + bfd_make_writable (abfd); + + bfd_set_format (abfd, bfd_object); + bfd_set_arch_mach (abfd, pep_details->bfd_arch, 0); + + symptr = 0; + symtab = xmalloc (5 * sizeof (asymbol *)); + id4 = quick_section (abfd, ".idata$4", SEC_HAS_CONTENTS, 2); + id5 = quick_section (abfd, ".idata$5", SEC_HAS_CONTENTS, 2); + id7 = quick_section (abfd, ".idata$7", SEC_HAS_CONTENTS, 2); + quick_symbol (abfd, U (""), dll_symname, "_iname", id7, BSF_GLOBAL, 0); + + bfd_set_section_size (abfd, id4, 8); + d4 = xmalloc (8); + id4->contents = d4; + memset (d4, 0, 8); + + bfd_set_section_size (abfd, id5, 8); + d5 = xmalloc (8); + id5->contents = d5; + memset (d5, 0, 8); + + len = strlen (dll_filename) + 1; + if (len & 1) + len++; + bfd_set_section_size (abfd, id7, len); + d7 = xmalloc (len); + id7->contents = d7; + strcpy ((char *) d7, dll_filename); + + bfd_set_symtab (abfd, symtab, symptr); + + bfd_set_section_contents (abfd, id4, d4, 0, 8); + bfd_set_section_contents (abfd, id5, d5, 0, 8); + bfd_set_section_contents (abfd, id7, d7, 0, len); + + bfd_make_readable (abfd); + return abfd; +} + +/* .text + .global _function + .global ___imp_function + .global __imp__function + _function: + jmp *__imp__function: + + .section idata$7 + .long __head_my_dll + + .section .idata$5 + ___imp_function: + __imp__function: + iat? + .section .idata$4 + iat? + .section .idata$6 + ID: + .short + .asciz "function" xlate? (add underscore, kill at) */ + +static unsigned char jmp_ix86_bytes[] = +{ + 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x90, 0x90 +}; + +static bfd * +make_one (def_file_export *exp, bfd *parent) +{ + asection *tx, *id7, *id5, *id4, *id6; + unsigned char *td = NULL, *d7, *d5, *d4, *d6 = NULL; + int len; + char *oname; + bfd *abfd; + unsigned char *jmp_bytes = NULL; + int jmp_byte_count = 0; + + switch (pep_details->pep_arch) + { + case PE_ARCH_i386: + jmp_bytes = jmp_ix86_bytes; + jmp_byte_count = sizeof (jmp_ix86_bytes); + break; + default: + abort (); + } + + oname = xmalloc (20); + sprintf (oname, "d%06d.o", tmp_seq); + tmp_seq++; + + abfd = bfd_create (oname, parent); + bfd_find_target (pep_details->object_target, abfd); + bfd_make_writable (abfd); + + bfd_set_format (abfd, bfd_object); + bfd_set_arch_mach (abfd, pep_details->bfd_arch, 0); + + symptr = 0; + symtab = xmalloc (11 * sizeof (asymbol *)); + tx = quick_section (abfd, ".text", SEC_CODE|SEC_HAS_CONTENTS, 2); + id7 = quick_section (abfd, ".idata$7", SEC_HAS_CONTENTS, 2); + id5 = quick_section (abfd, ".idata$5", SEC_HAS_CONTENTS, 2); + id4 = quick_section (abfd, ".idata$4", SEC_HAS_CONTENTS, 2); + id6 = quick_section (abfd, ".idata$6", SEC_HAS_CONTENTS, 2); + + if (*exp->internal_name == '@') + { + quick_symbol (abfd, U ("_head_"), dll_symname, "", UNDSEC, + BSF_GLOBAL, 0); + if (! exp->flag_data) + quick_symbol (abfd, "", exp->internal_name, "", tx, BSF_GLOBAL, 0); + quick_symbol (abfd, U ("_imp_"), exp->internal_name, "", id5, + BSF_GLOBAL, 0); + /* Fastcall applies only to functions, + so no need for auto-import symbol. */ + } + else + { + quick_symbol (abfd, U ("_head_"), dll_symname, "", UNDSEC, + BSF_GLOBAL, 0); + if (! exp->flag_data) + quick_symbol (abfd, U (""), exp->internal_name, "", tx, + BSF_GLOBAL, 0); + quick_symbol (abfd, U ("_imp__"), exp->internal_name, "", id5, + BSF_GLOBAL, 0); + /* Symbol to reference ord/name of imported + data symbol, used to implement auto-import. */ + if (exp->flag_data) + quick_symbol (abfd, U("_nm__"), exp->internal_name, "", id6, + BSF_GLOBAL,0); + } + if (pep_dll_compat_implib) + quick_symbol (abfd, U ("__imp_"), exp->internal_name, "", id5, + BSF_GLOBAL, 0); + //quick_symbol (abfd, U ("_imp"), exp->internal_name, "", id5, + // BSF_GLOBAL, 0); $$$$ + + if (! exp->flag_data) + { + bfd_set_section_size (abfd, tx, jmp_byte_count); + td = xmalloc (jmp_byte_count); + tx->contents = td; + memcpy (td, jmp_bytes, jmp_byte_count); + + switch (pep_details->pep_arch) + { + case PE_ARCH_i386: + quick_reloc (abfd, 2, BFD_RELOC_32, 2); + break; + case PE_ARCH_sh: + quick_reloc (abfd, 8, BFD_RELOC_32, 2); + break; + case PE_ARCH_mips: + quick_reloc (abfd, 0, BFD_RELOC_HI16_S, 2); + quick_reloc (abfd, 0, BFD_RELOC_LO16, 0); /* MIPS_R_PAIR */ + quick_reloc (abfd, 4, BFD_RELOC_LO16, 2); + break; + default: + abort (); + } + save_relocs (tx); + } + + bfd_set_section_size (abfd, id7, 4); + d7 = xmalloc (4); + id7->contents = d7; + memset (d7, 0, 4); + quick_reloc (abfd, 0, BFD_RELOC_RVA, 5); + save_relocs (id7); + + bfd_set_section_size (abfd, id5, 8); + d5 = xmalloc (8); + id5->contents = d5; + memset (d5, 0, 8); + + if (exp->flag_noname) + { + d5[0] = exp->ordinal; + d5[1] = exp->ordinal >> 8; + d5[7] = 0x80; + } + else + { + quick_reloc (abfd, 0, BFD_RELOC_RVA, 4); + save_relocs (id5); + } + + bfd_set_section_size (abfd, id4, 8); + d4 = xmalloc (8); + id4->contents = d4; + memset (d4, 0, 8); + + if (exp->flag_noname) + { + d4[0] = exp->ordinal; + d4[1] = exp->ordinal >> 8; + d4[7] = 0x80; + } + else + { + quick_reloc (abfd, 0, BFD_RELOC_RVA, 4); + save_relocs (id4); + } + + if (exp->flag_noname) + { + len = 0; + bfd_set_section_size (abfd, id6, 0); + } + else + { + len = strlen (exp->name) + 3; + if (len & 1) + len++; + bfd_set_section_size (abfd, id6, len); + d6 = xmalloc (len); + id6->contents = d6; + memset (d6, 0, len); + d6[0] = exp->hint & 0xff; + d6[1] = exp->hint >> 8; + strcpy ((char *) d6 + 2, exp->name); + } + + bfd_set_symtab (abfd, symtab, symptr); + + bfd_set_section_contents (abfd, tx, td, 0, jmp_byte_count); + bfd_set_section_contents (abfd, id7, d7, 0, 4); + bfd_set_section_contents (abfd, id5, d5, 0, 8); + bfd_set_section_contents (abfd, id4, d4, 0, 8); + if (!exp->flag_noname) + bfd_set_section_contents (abfd, id6, d6, 0, len); + + bfd_make_readable (abfd); + return abfd; +} + +static bfd * +make_singleton_name_thunk (const char *import, bfd *parent) +{ + /* Name thunks go to idata$4. */ + asection *id4; + unsigned char *d4; + char *oname; + bfd *abfd; + + oname = xmalloc (20); + sprintf (oname, "nmth%06d.o", tmp_seq); + tmp_seq++; + + abfd = bfd_create (oname, parent); + bfd_find_target (pep_details->object_target, abfd); + bfd_make_writable (abfd); + + bfd_set_format (abfd, bfd_object); + bfd_set_arch_mach (abfd, pep_details->bfd_arch, 0); + + symptr = 0; + symtab = xmalloc (3 * sizeof (asymbol *)); + id4 = quick_section (abfd, ".idata$4", SEC_HAS_CONTENTS, 2); + quick_symbol (abfd, U ("_nm_thnk_"), import, "", id4, BSF_GLOBAL, 0); + quick_symbol (abfd, U ("_nm_"), import, "", UNDSEC, BSF_GLOBAL, 0); + + bfd_set_section_size (abfd, id4, 8); + d4 = xmalloc (8); + id4->contents = d4; + memset (d4, 0, 8); + quick_reloc (abfd, 0, BFD_RELOC_RVA, 2); + save_relocs (id4); + + bfd_set_symtab (abfd, symtab, symptr); + + bfd_set_section_contents (abfd, id4, d4, 0, 8); + + bfd_make_readable (abfd); + return abfd; +} + +static char * +make_import_fixup_mark (arelent *rel) +{ + /* We convert reloc to symbol, for later reference. */ + static int counter; + static char *fixup_name = NULL; + static size_t buffer_len = 0; + + struct bfd_symbol *sym = *rel->sym_ptr_ptr; + + bfd *abfd = bfd_asymbol_bfd (sym); + struct bfd_link_hash_entry *bh; + + if (!fixup_name) + { + fixup_name = xmalloc (384); + buffer_len = 384; + } + + if (strlen (sym->name) + 25 > buffer_len) + /* Assume 25 chars for "__fu" + counter + "_". If counter is + bigger than 20 digits long, we've got worse problems than + overflowing this buffer... */ + { + free (fixup_name); + /* New buffer size is length of symbol, plus 25, but + then rounded up to the nearest multiple of 128. */ + buffer_len = ((strlen (sym->name) + 25) + 127) & ~127; + fixup_name = xmalloc (buffer_len); + } + + sprintf (fixup_name, "__fu%d_%s", counter++, sym->name); + + bh = NULL; + bfd_coff_link_add_one_symbol (&link_info, abfd, fixup_name, BSF_GLOBAL, + current_sec, /* sym->section, */ + rel->address, NULL, TRUE, FALSE, &bh); + + if (0) + { + struct coff_link_hash_entry *myh; + + myh = (struct coff_link_hash_entry *) bh; + printf ("type:%d\n", myh->type); + printf ("%s\n", myh->root.u.def.section->name); + } + + return fixup_name; +} + +/* .section .idata$3 + .rva __nm_thnk_SYM (singleton thunk with name of func) + .long 0 + .long 0 + .rva __my_dll_iname (name of dll) + .rva __fuNN_SYM (pointer to reference (address) in text) */ + +static bfd * +make_import_fixup_entry (const char *name, + const char *fixup_name, + const char *dll_symname, + bfd *parent) +{ + asection *id3; + unsigned char *d3; + char *oname; + bfd *abfd; + + oname = xmalloc (20); + sprintf (oname, "fu%06d.o", tmp_seq); + tmp_seq++; + + abfd = bfd_create (oname, parent); + bfd_find_target (pep_details->object_target, abfd); + bfd_make_writable (abfd); + + bfd_set_format (abfd, bfd_object); + bfd_set_arch_mach (abfd, pep_details->bfd_arch, 0); + + symptr = 0; + symtab = xmalloc (6 * sizeof (asymbol *)); + id3 = quick_section (abfd, ".idata$3", SEC_HAS_CONTENTS, 2); + + quick_symbol (abfd, U ("_nm_thnk_"), name, "", UNDSEC, BSF_GLOBAL, 0); + quick_symbol (abfd, U (""), dll_symname, "_iname", UNDSEC, BSF_GLOBAL, 0); + quick_symbol (abfd, "", fixup_name, "", UNDSEC, BSF_GLOBAL, 0); + + bfd_set_section_size (abfd, id3, 20); + d3 = xmalloc (20); + id3->contents = d3; + memset (d3, 0, 20); + + quick_reloc (abfd, 0, BFD_RELOC_RVA, 1); + quick_reloc (abfd, 12, BFD_RELOC_RVA, 2); + quick_reloc (abfd, 16, BFD_RELOC_RVA, 3); + save_relocs (id3); + + bfd_set_symtab (abfd, symtab, symptr); + + bfd_set_section_contents (abfd, id3, d3, 0, 20); + + bfd_make_readable (abfd); + return abfd; +} + +/* .section .rdata_runtime_pseudo_reloc + .long addend + .rva __fuNN_SYM (pointer to reference (address) in text) */ + +static bfd * +make_runtime_pseudo_reloc (const char *name ATTRIBUTE_UNUSED, + const char *fixup_name, + int addend, + bfd *parent) +{ + asection *rt_rel; + unsigned char *rt_rel_d; + char *oname; + bfd *abfd; + + oname = xmalloc (20); + sprintf (oname, "rtr%06d.o", tmp_seq); + tmp_seq++; + + abfd = bfd_create (oname, parent); + bfd_find_target (pep_details->object_target, abfd); + bfd_make_writable (abfd); + + bfd_set_format (abfd, bfd_object); + bfd_set_arch_mach (abfd, pep_details->bfd_arch, 0); + + symptr = 0; + symtab = xmalloc (2 * sizeof (asymbol *)); + rt_rel = quick_section (abfd, ".rdata_runtime_pseudo_reloc", + SEC_HAS_CONTENTS, 2); + + quick_symbol (abfd, "", fixup_name, "", UNDSEC, BSF_GLOBAL, 0); + + bfd_set_section_size (abfd, rt_rel, 8); + rt_rel_d = xmalloc (8); + rt_rel->contents = rt_rel_d; + memset (rt_rel_d, 0, 8); + bfd_put_32 (abfd, addend, rt_rel_d); + + quick_reloc (abfd, 4, BFD_RELOC_RVA, 1); + save_relocs (rt_rel); + + bfd_set_symtab (abfd, symtab, symptr); + + bfd_set_section_contents (abfd, rt_rel, rt_rel_d, 0, 8); + + bfd_make_readable (abfd); + return abfd; +} + +/* .section .rdata + .rva __pei386_runtime_relocator */ + +static bfd * +pep_create_runtime_relocator_reference (bfd *parent) +{ + asection *extern_rt_rel; + unsigned char *extern_rt_rel_d; + char *oname; + bfd *abfd; + + oname = xmalloc (20); + sprintf (oname, "ertr%06d.o", tmp_seq); + tmp_seq++; + + abfd = bfd_create (oname, parent); + bfd_find_target (pep_details->object_target, abfd); + bfd_make_writable (abfd); + + bfd_set_format (abfd, bfd_object); + bfd_set_arch_mach (abfd, pep_details->bfd_arch, 0); + + symptr = 0; + symtab = xmalloc (2 * sizeof (asymbol *)); + extern_rt_rel = quick_section (abfd, ".rdata", SEC_HAS_CONTENTS, 2); + + quick_symbol (abfd, "", "__pei386_runtime_relocator", "", UNDSEC, + BSF_NO_FLAGS, 0); + + bfd_set_section_size (abfd, extern_rt_rel, 4); + extern_rt_rel_d = xmalloc (4); + extern_rt_rel->contents = extern_rt_rel_d; + + quick_reloc (abfd, 0, BFD_RELOC_RVA, 1); + save_relocs (extern_rt_rel); + + bfd_set_symtab (abfd, symtab, symptr); + + bfd_set_section_contents (abfd, extern_rt_rel, extern_rt_rel_d, 0, 4); + + bfd_make_readable (abfd); + return abfd; +} + +void +pep_create_import_fixup (arelent *rel, asection *s, int addend) +{ + char buf[300]; + struct bfd_symbol *sym = *rel->sym_ptr_ptr; + struct bfd_link_hash_entry *name_thunk_sym; + const char *name = sym->name; + char *fixup_name = make_import_fixup_mark (rel); + bfd *b; + + sprintf (buf, U ("_nm_thnk_%s"), name); + + name_thunk_sym = bfd_link_hash_lookup (link_info.hash, buf, 0, 0, 1); + + if (!name_thunk_sym || name_thunk_sym->type != bfd_link_hash_defined) + { + bfd *b = make_singleton_name_thunk (name, output_bfd); + add_bfd_to_link (b, b->filename, &link_info); + + /* If we ever use autoimport, we have to cast text section writable. */ + config.text_read_only = FALSE; + output_bfd->flags &= ~WP_TEXT; + } + + if (addend == 0 || link_info.pei386_runtime_pseudo_reloc) + { + extern char * pep_data_import_dll; + char * dll_symname = pep_data_import_dll ? pep_data_import_dll : "unknown"; + + b = make_import_fixup_entry (name, fixup_name, dll_symname, output_bfd); + add_bfd_to_link (b, b->filename, &link_info); + } + + if (addend != 0) + { + if (link_info.pei386_runtime_pseudo_reloc) + { + if (pep_dll_extra_pe_debug) + printf ("creating runtime pseudo-reloc entry for %s (addend=%d)\n", + fixup_name, addend); + b = make_runtime_pseudo_reloc (name, fixup_name, addend, output_bfd); + add_bfd_to_link (b, b->filename, &link_info); + + if (runtime_pseudo_relocs_created == 0) + { + b = pep_create_runtime_relocator_reference (output_bfd); + add_bfd_to_link (b, b->filename, &link_info); + } + runtime_pseudo_relocs_created++; + } + else + { + einfo (_("%C: variable '%T' can't be auto-imported. Please read the documentation for ld's --enable-auto-import for details.\n"), + s->owner, s, rel->address, sym->name); + einfo ("%X"); + } + } +} + + +void +pep_dll_generate_implib (def_file *def, const char *impfilename) +{ + int i; + bfd *ar_head; + bfd *ar_tail; + bfd *outarch; + bfd *head = 0; + + dll_filename = (def->name) ? def->name : dll_name; + dll_symname = xstrdup (dll_filename); + for (i = 0; dll_symname[i]; i++) + if (!ISALNUM (dll_symname[i])) + dll_symname[i] = '_'; + + unlink_if_ordinary (impfilename); + + outarch = bfd_openw (impfilename, 0); + + if (!outarch) + { + /* xgettext:c-format */ + einfo (_("%XCan't open .lib file: %s\n"), impfilename); + return; + } + + /* xgettext:c-format */ + info_msg (_("Creating library file: %s\n"), impfilename); + + bfd_set_format (outarch, bfd_archive); + outarch->has_armap = 1; + + /* Work out a reasonable size of things to put onto one line. */ + ar_head = make_head (outarch); + + for (i = 0; i < def->num_exports; i++) + { + /* The import library doesn't know about the internal name. */ + char *internal = def->exports[i].internal_name; + bfd *n; + + /* Don't add PRIVATE entries to import lib. */ + if (pep_def_file->exports[i].flag_private) + continue; + def->exports[i].internal_name = def->exports[i].name; + n = make_one (def->exports + i, outarch); + n->next = head; + head = n; + def->exports[i].internal_name = internal; + } + + ar_tail = make_tail (outarch); + + if (ar_head == NULL || ar_tail == NULL) + return; + + /* Now stick them all into the archive. */ + ar_head->next = head; + ar_tail->next = ar_head; + head = ar_tail; + + if (! bfd_set_archive_head (outarch, head)) + einfo ("%Xbfd_set_archive_head: %E\n"); + + if (! bfd_close (outarch)) + einfo ("%Xbfd_close %s: %E\n", impfilename); + + while (head != NULL) + { + bfd *n = head->next; + bfd_close (head); + head = n; + } +} + +static void +add_bfd_to_link (bfd *abfd, const char *name, struct bfd_link_info *link_info) +{ + lang_input_statement_type *fake_file; + + fake_file = lang_add_input_file (name, + lang_input_file_is_fake_enum, + NULL); + fake_file->the_bfd = abfd; + ldlang_add_file (fake_file); + + if (!bfd_link_add_symbols (abfd, link_info)) + einfo ("%Xaddsym %s: %E\n", name); +} + +void +pep_process_import_defs (bfd *output_bfd, struct bfd_link_info *link_info) +{ + def_file_module *module; + + pep_dll_id_target (bfd_get_target (output_bfd)); + + if (!pep_def_file) + return; + + for (module = pep_def_file->modules; module; module = module->next) + { + int i, do_this_dll; + + dll_filename = module->name; + dll_symname = xstrdup (module->name); + for (i = 0; dll_symname[i]; i++) + if (!ISALNUM (dll_symname[i])) + dll_symname[i] = '_'; + + do_this_dll = 0; + + for (i = 0; i < pep_def_file->num_imports; i++) + if (pep_def_file->imports[i].module == module) + { + def_file_export exp; + struct bfd_link_hash_entry *blhe; + int lead_at = (*pep_def_file->imports[i].internal_name == '@'); + /* See if we need this import. */ + size_t len = strlen (pep_def_file->imports[i].internal_name); + char *name = xmalloc (len + 2 + 6); + + if (lead_at) + sprintf (name, "%s%s", "", + pep_def_file->imports[i].internal_name); + else + sprintf (name, "%s%s",U (""), + pep_def_file->imports[i].internal_name); + + blhe = bfd_link_hash_lookup (link_info->hash, name, + FALSE, FALSE, FALSE); + + if (!blhe || (blhe && blhe->type != bfd_link_hash_undefined)) + { + if (lead_at) + sprintf (name, "%s%s", U ("_imp_"), + pep_def_file->imports[i].internal_name); + else + sprintf (name, "%s%s", U ("_imp__"), + pep_def_file->imports[i].internal_name); + + blhe = bfd_link_hash_lookup (link_info->hash, name, + FALSE, FALSE, FALSE); + } + free (name); + + if (blhe && blhe->type == bfd_link_hash_undefined) + { + bfd *one; + /* We do. */ + if (!do_this_dll) + { + bfd *ar_head = make_head (output_bfd); + add_bfd_to_link (ar_head, ar_head->filename, link_info); + do_this_dll = 1; + } + exp.internal_name = pep_def_file->imports[i].internal_name; + exp.name = pep_def_file->imports[i].name; + exp.ordinal = pep_def_file->imports[i].ordinal; + exp.hint = exp.ordinal >= 0 ? exp.ordinal : 0; + exp.flag_private = 0; + exp.flag_constant = 0; + exp.flag_data = pep_def_file->imports[i].data; + exp.flag_noname = exp.name ? 0 : 1; + one = make_one (&exp, output_bfd); + add_bfd_to_link (one, one->filename, link_info); + } + } + if (do_this_dll) + { + bfd *ar_tail = make_tail (output_bfd); + add_bfd_to_link (ar_tail, ar_tail->filename, link_info); + } + + free (dll_symname); + } +} + +/* We were handed a *.DLL file. Parse it and turn it into a set of + IMPORTS directives in the def file. Return TRUE if the file was + handled, FALSE if not. */ + +static unsigned int +pep_get16 (bfd *abfd, int where) +{ + unsigned char b[2]; + + bfd_seek (abfd, (file_ptr) where, SEEK_SET); + bfd_bread (b, (bfd_size_type) 2, abfd); + return b[0] + (b[1] << 8); +} + +static unsigned int +pep_get32 (bfd *abfd, int where) +{ + unsigned char b[4]; + + bfd_seek (abfd, (file_ptr) where, SEEK_SET); + bfd_bread (b, (bfd_size_type) 4, abfd); + return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24); +} + +static unsigned int +pep_as32 (void *ptr) +{ + unsigned char *b = ptr; + + return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24); +} + +bfd_boolean +pep_implied_import_dll (const char *filename) +{ + bfd *dll; + unsigned long pep_header_offset, opthdr_ofs, num_entries, i; + unsigned long export_rva, export_size, nsections, secptr, expptr; + unsigned long exp_funcbase; + unsigned char *expdata; + char *erva; + unsigned long name_rvas, ordinals, nexp, ordbase; + const char *dll_name; + /* Initialization with start > end guarantees that is_data + will not be set by mistake, and avoids compiler warning. */ + unsigned long data_start = 1; + unsigned long data_end = 0; + unsigned long rdata_start = 1; + unsigned long rdata_end = 0; + unsigned long bss_start = 1; + unsigned long bss_end = 0; + + /* No, I can't use bfd here. kernel32.dll puts its export table in + the middle of the .rdata section. */ + dll = bfd_openr (filename, pep_details->target_name); + if (!dll) + { + einfo ("%Xopen %s: %E\n", filename); + return FALSE; + } + + /* PEI dlls seem to be bfd_objects. */ + if (!bfd_check_format (dll, bfd_object)) + { + einfo ("%X%s: this doesn't appear to be a DLL\n", filename); + return FALSE; + } + + /* Get pe_header, optional header and numbers of export entries. */ + pep_header_offset = pep_get32 (dll, 0x3c); + opthdr_ofs = pep_header_offset + 4 + 20; // Magic of opt header + num_entries = pep_get32 (dll, opthdr_ofs + 92 +4*4); // &NumberOfRvaAndSizes + + if (pep_dll_extra_pe_debug) + printf ("%s: Export num_entries %ld\n", __FUNCTION__,num_entries); + + if (num_entries < 1) /* No exports. */ + return FALSE; + + export_rva = pep_get32 (dll, opthdr_ofs + 96+4*4); + export_size = pep_get32 (dll, opthdr_ofs + 100+4*4); + nsections = pep_get16 (dll, pep_header_offset + 4 + 2); + secptr = (pep_header_offset + 4 + 20 + + pep_get16 (dll, pep_header_offset + 4 + 16)); + expptr = 0; + + /* Get the rva and size of the export section. */ + for (i = 0; i < nsections; i++) + { + char sname[8]; + unsigned long secptr1 = secptr + 40 * i; + unsigned long vaddr = pep_get32 (dll, secptr1 + 12); + unsigned long vsize = pep_get32 (dll, secptr1 + 16); + unsigned long fptr = pep_get32 (dll, secptr1 + 20); + + bfd_seek (dll, (file_ptr) secptr1, SEEK_SET); + bfd_bread (sname, (bfd_size_type) 8, dll); + + if (vaddr <= export_rva && vaddr + vsize > export_rva) + { + expptr = fptr + (export_rva - vaddr); + if (export_rva + export_size > vaddr + vsize) + export_size = vsize - (export_rva - vaddr); + break; + } + } + + /* Scan sections and store the base and size of the + data and bss segments in data/base_start/end. */ + for (i = 0; i < nsections; i++) + { + unsigned long secptr1 = secptr + 40 * i; + unsigned long vsize = pep_get32 (dll, secptr1 + 8); + unsigned long vaddr = pep_get32 (dll, secptr1 + 12); + unsigned long flags = pep_get32 (dll, secptr1 + 36); + char sec_name[9]; + + sec_name[8] = '\0'; + bfd_seek (dll, (file_ptr) secptr1 + 0, SEEK_SET); + bfd_bread (sec_name, (bfd_size_type) 8, dll); + + if (strcmp(sec_name,".data") == 0) + { + data_start = vaddr; + data_end = vaddr + vsize; + + if (pep_dll_extra_pe_debug) + printf ("%s %s: 0x%08lx-0x%08lx (0x%08lx)\n", + __FUNCTION__, sec_name, vaddr, vaddr + vsize, flags); + } + else if (strcmp(sec_name,".rdata") == 0) + { + rdata_start = vaddr; + rdata_end = vaddr + vsize; + + if (pep_dll_extra_pe_debug) + printf ("%s %s: 0x%08lx-0x%08lx (0x%08lx)\n", + __FUNCTION__, sec_name, vaddr, vaddr + vsize, flags); + } + else if (strcmp (sec_name,".bss") == 0) + { + bss_start = vaddr; + bss_end = vaddr + vsize; + + if (pep_dll_extra_pe_debug) + printf ("%s %s: 0x%08lx-0x%08lx (0x%08lx)\n", + __FUNCTION__, sec_name, vaddr, vaddr + vsize, flags); + } + } + + if (pep_dll_extra_pe_debug) + printf ("%s: Export size:%lu offset:0x%lx\n", + __FUNCTION__,export_size,(file_ptr)expptr); + expdata = xmalloc (export_size); + bfd_seek (dll, (file_ptr) expptr, SEEK_SET); + bfd_bread (expdata, (bfd_size_type) export_size, dll); + erva = (char *) expdata - export_rva; + + if (pep_def_file == 0) + pep_def_file = def_file_empty (); + + nexp = pep_as32 (expdata + 24); + name_rvas = pep_as32 (expdata + 32); + ordinals = pep_as32 (expdata + 36); + ordbase = pep_as32 (expdata + 16); + exp_funcbase = pep_as32 (expdata + 28); + if (pep_dll_extra_pe_debug) + printf ("%s: nexp:%lu namerva:0x%lx ord:%lu ordbase:%lu fb=0x%lx\n", + __FUNCTION__,nexp,name_rvas,ordinals,ordbase,exp_funcbase); + + /* Use internal dll name instead of filename + to enable symbolic dll linking. */ + dll_name = erva + pep_as32 (expdata + 12); + + /* Check to see if the dll has already been added to + the definition list and if so return without error. + This avoids multiple symbol definitions. */ + if (def_get_module (pep_def_file, dll_name)) + { + if (pep_dll_extra_pe_debug) + printf ("%s is already loaded\n", dll_name); + return TRUE; + } + + /* Iterate through the list of symbols. */ + for (i = 0; i < nexp; i++) + { + /* Pointer to the names vector. */ + unsigned long name_rva = pep_as32 (erva + name_rvas + i * 4); + def_file_import *imp; + /* Pointer to the function address vector. */ + unsigned long func_rva = pep_as32 (erva + exp_funcbase + i * 4); + int is_data = 0; + + /* Skip unwanted symbols, which are + exported in buggy auto-import releases. */ + if (strncmp (erva + name_rva, "_nm_", 4) != 0) + { + /* is_data is true if the address is in the data, rdata or bss + segment. */ + is_data = + (func_rva >= data_start && func_rva < data_end) + || (func_rva >= rdata_start && func_rva < rdata_end) + || (func_rva >= bss_start && func_rva < bss_end); + + imp = def_file_add_import (pep_def_file, erva + name_rva, + dll_name, i, 0); + /* Mark symbol type. */ + imp->data = is_data; + + if (pep_dll_extra_pe_debug) + printf ("%s dll-name: %s sym: %s addr: 0x%lx %s\n", + __FUNCTION__, dll_name, erva + name_rva, + func_rva, is_data ? "(data)" : ""); + } + } + + return TRUE; +} + +/* These are the main functions, called from the emulation. The first + is called after the bfds are read, so we can guess at how much space + we need. The second is called after everything is placed, so we + can put the right values in place. */ + +void +pep_dll_build_sections (bfd *abfd, struct bfd_link_info *info) +{ + pep_dll_id_target (bfd_get_target (abfd)); + process_def_file (abfd, info); + + if (pep_def_file->num_exports == 0 && !info->shared) + return; + + generate_edata (abfd, info); + build_filler_bfd (1); +} + +void +pep_exe_build_sections (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED) +{ + pep_dll_id_target (bfd_get_target (abfd)); + build_filler_bfd (0); +} + +void +pep_dll_fill_sections (bfd *abfd, struct bfd_link_info *info) +{ + pep_dll_id_target (bfd_get_target (abfd)); + image_base = pe_data (abfd)->pe_opthdr.ImageBase; + + generate_reloc (abfd, info); + if (reloc_sz > 0) + { + bfd_set_section_size (filler_bfd, reloc_s, reloc_sz); + + /* Resize the sections. */ + lang_reset_memory_regions (); + lang_size_sections (NULL, TRUE); + + /* Redo special stuff. */ + ldemul_after_allocation (); + + /* Do the assignments again. */ + lang_do_assignments (); + } + + fill_edata (abfd, info); + + if (info->shared && !info->pie) + pe_data (abfd)->dll = 1; + + edata_s->contents = edata_d; + reloc_s->contents = reloc_d; +} + +void +pep_exe_fill_sections (bfd *abfd, struct bfd_link_info *info) +{ + pep_dll_id_target (bfd_get_target (abfd)); + image_base = pe_data (abfd)->pe_opthdr.ImageBase; + + generate_reloc (abfd, info); + if (reloc_sz > 0) + { + bfd_set_section_size (filler_bfd, reloc_s, reloc_sz); + + /* Resize the sections. */ + lang_reset_memory_regions (); + lang_size_sections (NULL, TRUE); + + /* Redo special stuff. */ + ldemul_after_allocation (); + + /* Do the assignments again. */ + lang_do_assignments (); + } + reloc_s->contents = reloc_d; +} diff -rNbu binutils-2.17_org/ld/pep-dll.h binutils-2.17/ld/pep-dll.h --- binutils-2.17_org/ld/pep-dll.h 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.17/ld/pep-dll.h 2006-08-17 09:13:35.000000000 +0200 @@ -0,0 +1,64 @@ +/* pep-dll.h: Header file for routines used to build Windows DLLs. + Copyright 1995, 1996, 1999, 2001, 2002, 2004 Free Software Foundation, Inc. + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 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. + + Written by Kai Tietz, OneVision Software GmbH&CoKg. +*/ + +#ifndef PEP_DLL_H +#define PEP_DLL_H + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "deffile.h" + +extern def_file *pep_def_file; +extern int pep_dll_export_everything; +extern int pep_dll_do_default_excludes; +extern int pep_dll_kill_ats; +extern int pep_dll_stdcall_aliases; +extern int pep_dll_warn_dup_exports; +extern int pep_dll_compat_implib; +extern int pep_dll_extra_pe_debug; + +extern void pep_dll_id_target + (const char *); +extern void pep_dll_add_excludes + (const char *, const int); +extern void pep_dll_generate_def_file + (const char *); +extern void pep_dll_generate_implib + (def_file *, const char *); +extern void pep_process_import_defs + (bfd *, struct bfd_link_info *); +extern bfd_boolean pep_implied_import_dll + (const char *); +extern void pep_dll_build_sections + (bfd *, struct bfd_link_info *); +extern void pep_exe_build_sections + (bfd *, struct bfd_link_info *); +extern void pep_dll_fill_sections + (bfd *, struct bfd_link_info *); +extern void pep_exe_fill_sections + (bfd *, struct bfd_link_info *); +extern void pep_walk_relocs_of_symbol + (struct bfd_link_info *, const char *, int (*) (arelent *, asection *)); +extern void pep_create_import_fixup + (arelent * rel, asection *, int); +#endif /* PE_DLL_H */ diff -rNbu binutils-2.17_org/ld/po/POTFILES.in binutils-2.17/ld/po/POTFILES.in --- binutils-2.17_org/ld/po/POTFILES.in 2006-04-16 20:21:51.000000000 +0200 +++ binutils-2.17/ld/po/POTFILES.in 2006-08-02 13:44:47.000000000 +0200 @@ -28,3 +28,5 @@ mri.h pe-dll.c pe-dll.h +pep-dll.c +pep-dll.h diff -rNbu binutils-2.17_org/ld/scripttempl/pep.sc binutils-2.17/ld/scripttempl/pep.sc --- binutils-2.17_org/ld/scripttempl/pep.sc 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.17/ld/scripttempl/pep.sc 2006-07-28 14:12:22.000000000 +0200 @@ -0,0 +1,272 @@ +# Linker script for PE. + +if test -z "${RELOCATEABLE_OUTPUT_FORMAT}"; then + RELOCATEABLE_OUTPUT_FORMAT=${OUTPUT_FORMAT} +fi + +# We can't easily and portably get an unquoted $ in a shell +# substitution, so we do this instead. +# Sorting of the .foo$* sections is required by the definition of +# grouped sections in PE. +# Sorting of the file names in R_IDATA is required by the +# current implementation of dlltool (this could probably be changed to +# use grouped sections instead). +if test "${RELOCATING}"; then + R_TEXT='*(SORT(.text$*))' + R_DATA='*(SORT(.data$*))' + R_RDATA='*(SORT(.rdata$*))' + R_IDATA=' + SORT(*)(.idata$2) + SORT(*)(.idata$3) + /* These zeroes mark the end of the import list. */ + LONG (0); LONG (0); LONG (0); LONG (0); LONG (0); + SORT(*)(.idata$4) + SORT(*)(.idata$5) + SORT(*)(.idata$6) + SORT(*)(.idata$7)' + R_CRT_XC='*(SORT(.CRT$XC*)) /* C initialization */' + R_CRT_XI='*(SORT(.CRT$XI*)) /* C++ initialization */' + R_CRT_XL='*(SORT(.CRT$XL*)) /* TLS callbacks */' + R_CRT_XP='*(SORT(.CRT$XP*)) /* Pre-termination */' + R_CRT_XT='*(SORT(.CRT$XT*)) /* Termination */' + R_TLS=' + *(.tls) + *(.tls$) + *(SORT(.tls$*))' + R_RSRC='*(SORT(.rsrc$*))' +else + R_TEXT= + R_DATA= + R_RDATA= + R_IDATA= + R_CRT= + R_RSRC= +fi + +cat <