diff options
78 files changed, 3805 insertions, 156 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 16d81db47c6..8b5d2a24fe1 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,36 @@ +2006-09-20 Kai Tietz <Kai.Tietz@onevision.com> + + * configure.in: Added new target-vectors x86_64coff_vec, + x86_64pe_vec, and x86_64pei_vec. + * configure: Regenerate. + * config.bfd: Adjusted x86_64 target architecture detection. + * bfd.c: Add for new target "coff-x86-64" + (bfd_get_sign_extend): Add target vector idents for pe-x86-64. and pei-x86-64. + * coff-x86_64.c: Add new file for x86_64 (AMD64) coff support. + * libpei.h: Adjustments for COFF_WITH_pex64. + * coffcode.h: Add for new target machine, architecture, signature, and internal + signature handler. + * Makefile.am: Add new files to target-all and define make-rule for pex64igen.c + * Makefile.in: Regenerate. + * pe-x86_64.c: Add for new target "pe-x86-64". + * pei-x86_64.c: Add for new target "pei-x86-64". + * peicode.h: Adjusts for new targets. + (coff_swap_filehdr_out): Set for this target to + _bfd_pex64_only_swap_filehdr_out. + (SIZEOF_IDATA4): Define it as 8 byte size for this target. + (SIZEOF_IDATA5): Define it as 8 byte size for this target. + (jump_table jtab): Add for AMD64MAGIC. + (pe_ILF_build_a_bfd): Adjusts for new size of SIZEOF_IDATA4 and SIZE_IDATA5. + (pe_ILF_object_p): Add coff image-file signature to internal + signature translation. + * peXXigen.c: Adjust proper include of target coff-header and + introduced target specific code + (COFF_WITH_pex64): New macro for this target. + (pe_print_idata): New dumping method for import section of PE+ files. + * targets.c: Add new target vectors declarations for x86_64 coff targets. + * coffcode.h: Support code to support the x86_64 PE magic number. + * coff-x86_64.c: New file. + 2006-09-17 Hans-Peter Nilsson <hp@axis.com> * elf.c (special_sections_s): Revert last STRING_COMMA_LEN change diff --git a/bfd/Makefile.am b/bfd/Makefile.am index 175820e5127..df9b2a9da54 100644 --- a/bfd/Makefile.am +++ b/bfd/Makefile.am @@ -563,7 +563,11 @@ BFD64_BACKENDS = \ 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 \ @@ -586,7 +590,10 @@ BFD64_BACKENDS_CFILES = \ elf64.c \ mmo.c \ nlm32-alpha.c \ - nlm64.c + nlm64.c \ + coff-x86_64.c \ + pe-x86_64.c \ + pei-x86_64.c OPTIONAL_BACKENDS = \ aix386-core.lo \ @@ -636,7 +643,7 @@ SOURCE_CFILES = \ $(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) @@ -794,6 +801,11 @@ pepigen.c : peXXigen.c sed -e s/XX/pep/g < $(srcdir)/peXXigen.c > pepigen.new mv -f pepigen.new pepigen.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 + BFD_H_DEPS= $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h LOCAL_H_DEPS= libbfd.h sysdep.h config.h $(BFD32_LIBS) \ @@ -1861,4 +1873,7 @@ peigen.lo: peigen.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.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 +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 # IF YOU PUT ANYTHING HERE IT WILL GO AWAY diff --git a/bfd/Makefile.in b/bfd/Makefile.in index 8a15b4491a5..312b7308dee 100644 --- a/bfd/Makefile.in +++ b/bfd/Makefile.in @@ -796,7 +796,11 @@ BFD64_BACKENDS = \ 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 \ @@ -819,7 +823,10 @@ BFD64_BACKENDS_CFILES = \ elf64.c \ mmo.c \ nlm32-alpha.c \ - nlm64.c + nlm64.c \ + coff-x86_64.c \ + pe-x86_64.c \ + pei-x86_64.c OPTIONAL_BACKENDS = \ aix386-core.lo \ @@ -870,7 +877,7 @@ SOURCE_CFILES = \ $(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 = \ @@ -1372,6 +1379,11 @@ pepigen.c : peXXigen.c rm -f pepigen.c sed -e s/XX/pep/g < $(srcdir)/peXXigen.c > pepigen.new mv -f pepigen.new pepigen.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 $(BFD32_LIBS) \ $(BFD64_LIBS) \ $(ALL_MACHINES) \ @@ -2422,6 +2434,9 @@ peigen.lo: peigen.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.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 +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 # IF YOU PUT ANYTHING HERE IT WILL GO AWAY # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. diff --git a/bfd/coff-x86_64.c b/bfd/coff-x86_64.c new file mode 100644 index 00000000000..772e1ebf7c3 --- /dev/null +++ b/bfd/coff-x86_64.c @@ -0,0 +1,768 @@ +/* BFD back-end for AMD 64 COFF files. + Copyright 2006 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" +#include "libiberty.h" + +#define BADMAG(x) AMD64BADMAG(x) + +#ifdef COFF_WITH_pex64 +# undef AOUTSZ +# define AOUTSZ PEPAOUTSZ +# define PEAOUTHDR PEPAOUTHDR +#endif + +#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, + void * data, + asection *input_section ATTRIBUTE_UNUSED, + bfd *output_bfd, + char **error_message ATTRIBUTE_UNUSED) +{ + symvalue diff; + +#if !defined(COFF_WITH_PE) + if (output_bfd == NULL) + return bfd_reloc_continue; +#endif + + if (bfd_is_com_section (symbol->section)) + { +#if !defined(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. */ +#if defined(COFF_WITH_PE) + if (output_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; + } + +#if defined(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; +} + +#if defined(COFF_WITH_PE) +/* Return TRUE if this relocation should appear in the output .reloc + section. */ + +static bfd_boolean +in_reloc_p (bfd *abfd ATTRIBUTE_UNUSED, reloc_howto_type *howto) +{ + return ! howto->pc_relative && howto->type != R_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 */ + "R_X86_64_64", /* name */ + TRUE, /* partial_inplace */ + 0xffffffffffffffffll, /* src_mask */ + 0xffffffffffffffffll, /* 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 */ + "R_X86_64_32", /* 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 */ + "R_X86_64_PC32", /* 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+1", /* 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+2", /* 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+3", /* 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+4", /* 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+5", /* name */ + TRUE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + PCRELOFFSET), /* pcrel_offset */ + EMPTY_HOWTO (10), /* R_AMD64_SECTION 10 */ +#if defined(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), +#ifndef DONT_EXTEND_AMD64 + HOWTO (R_AMD64_PCRQUAD, + 0, /* rightshift */ + 4, /* size (0 = byte, 1 = short, 2 = long) */ + 64, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + coff_amd64_reloc, /* special_function */ + "R_X86_64_PC64", /* name */ + TRUE, /* partial_inplace */ + 0xffffffffffffffffll, /* src_mask */ + 0xffffffffffffffffll, /* dst_mask */ + PCRELOFFSET), /* pcrel_offset */ +#else + EMPTY_HOWTO (14), +#endif + /* 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 */ + "R_X86_64_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 */ + "R_X86_64_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 */ + "R_X86_64_32S", /* 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 */ + "R_X86_64_PC8", /* 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 */ + "R_X86_64_PC16", /* 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 */ + "R_X86_64_PC32", /* 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 < ARRAY_SIZE (howto_table)) \ + ? 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 = NULL; \ + \ + if (ptr && bfd_asymbol_bfd (ptr) != abfd) \ + coffsym = (obj_symbols (abfd) \ + + (cache_ptr->sym_ptr_ptr - symbols)); \ + else if (ptr) \ + coffsym = coff_symbol_from (abfd, ptr); \ + \ + if (coffsym != NULL \ + && coffsym->native->u.syment.n_scnum == 0) \ + cache_ptr->addend = - coffsym->native->u.syment.n_value; \ + else if (ptr && bfd_asymbol_bfd (ptr) == abfd \ + && ptr->section != 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. */ + +#if !defined(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 *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 > ARRAY_SIZE (howto_table)) + { + 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; + +#if defined(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); + +#if !defined(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 + } + +#if !defined(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 + +#if defined(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_64_PCREL: +#ifndef DONT_EXTEND_AMD64 + return howto_table + R_AMD64_PCRQUAD; +#else + /* Fall through. */ +#endif + case BFD_RELOC_32_PCREL: + return howto_table + R_AMD64_PCRLONG; + case BFD_RELOC_X86_64_32S: + return howto_table + R_RELLONG; + 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; +#if defined(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 *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. */ +#if defined(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 --git a/bfd/coffcode.h b/bfd/coffcode.h index 0c7f897453b..bc5c72e61f4 100644 --- a/bfd/coffcode.h +++ b/bfd/coffcode.h @@ -1882,11 +1882,17 @@ coff_set_arch_mach_hook (bfd *abfd, void * filehdr) #ifdef I386MAGIC case I386MAGIC: case I386PTXMAGIC: - case I386AIXMAGIC: /* Danbury PS/2 AIX C Compiler */ - case LYNXCOFFMAGIC: /* shadows the m68k Lynx number below, sigh */ + case I386AIXMAGIC: /* Danbury PS/2 AIX C Compiler. */ + case LYNXCOFFMAGIC: /* Shadows the m68k Lynx number below, sigh. */ arch = bfd_arch_i386; break; #endif +#ifdef AMD64MAGIC + case AMD64MAGIC: + arch = bfd_arch_i386; + machine = bfd_mach_x86_64; + break; +#endif #ifdef IA64MAGIC case IA64MAGIC: arch = bfd_arch_ia64; @@ -2721,13 +2727,18 @@ coff_set_flags (bfd * abfd, return TRUE; #endif -#ifdef I386MAGIC +#if defined(I386MAGIC) || defined(AMD64MAGIC) case bfd_arch_i386: +#if defined(I386MAGIC) *magicp = I386MAGIC; -#ifdef LYNXOS +#endif +#if defined LYNXOS /* Just overwrite the usual value if we're doing Lynx. */ *magicp = LYNXCOFFMAGIC; #endif +#if defined AMD64MAGIC + *magicp = AMD64MAGIC; +#endif return TRUE; #endif @@ -3759,6 +3770,7 @@ coff_write_object_contents (bfd * abfd) internal_f.f_flags |= IMAGE_FILE_LARGE_ADDRESS_AWARE; #endif +#ifndef COFF_WITH_pex64 #ifdef COFF_WITH_PE internal_f.f_flags |= IMAGE_FILE_32BIT_MACHINE; #else @@ -3767,6 +3779,7 @@ coff_write_object_contents (bfd * abfd) 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, @@ -3860,11 +3873,13 @@ coff_write_object_contents (bfd * abfd) #if defined(I386) #define __A_MAGIC_SET__ -#if defined(LYNXOS) +#if defined LYNXOS internal_a.magic = LYNXCOFFMAGIC; -#else /* LYNXOS */ +#elif defined AMD64 + internal_a.magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC; +#else internal_a.magic = ZMAGIC; -#endif /* LYNXOS */ +#endif #endif /* I386 */ #if defined(IA64) diff --git a/bfd/config.bfd b/bfd/config.bfd index 0d0212a3245..6f6a7b9168c 100644 --- a/bfd/config.bfd +++ b/bfd/config.bfd @@ -98,7 +98,7 @@ sparc*) targ_archs=bfd_sparc_arch ;; 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 ;; @@ -578,6 +578,12 @@ case "${targ}" in targ_selvecs="bfd_elf32_i386_vec i386linux_vec bfd_efi_app_ia32_vec" want64=true ;; + x86_64-*-mingw64*) + targ_defvec=x86_64pe_vec + targ_selvecs="x86_64pe_vec x86_64pei_vec x86_64coff_vec bfd_elf64_x86_64_vec" + want64=true + targ_underscore=yes + ;; #endif i[3-7]86-*-lynxos*) targ_defvec=bfd_elf32_i386_vec diff --git a/bfd/configure b/bfd/configure index ea3c3563ca9..1f17d92df31 100755 --- a/bfd/configure +++ b/bfd/configure @@ -4086,7 +4086,7 @@ ia64-*-hpux*) 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 @@ -4097,7 +4097,7 @@ x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) case "`/usr/bin/file conftest.o`" in *32-bit*) case $host in - x86_64-*linux*) + x86_64-*linux*|x86_64-*mingw64*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|powerpc64-*linux*) @@ -4113,7 +4113,7 @@ x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) ;; *64-bit*) case $host in - x86_64-*linux*) + x86_64-*linux*|x86_64-*mingw64*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) @@ -10951,6 +10951,7 @@ do 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" ;; @@ -10962,6 +10963,8 @@ do 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 ;; + 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 --git a/bfd/configure.in b/bfd/configure.in index 9af534ab5ae..339af936af3 100644 --- a/bfd/configure.in +++ b/bfd/configure.in @@ -741,6 +741,7 @@ do 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" ;; @@ -752,6 +753,8 @@ do 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 ;; + 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 --git a/bfd/libpei.h b/bfd/libpei.h index b01e222ede9..10a2a2582a4 100644 --- a/bfd/libpei.h +++ b/bfd/libpei.h @@ -204,7 +204,39 @@ #define PUT_SCNHDR_LNNOPTR H_PUT_32 #endif -#ifdef COFF_WITH_pep +#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 + +#elif defined COFF_WITH_pep #define GET_OPTHDR_IMAGE_BASE H_GET_64 #define PUT_OPTHDR_IMAGE_BASE H_PUT_64 diff --git a/bfd/pe-x86_64.c b/bfd/pe-x86_64.c new file mode 100644 index 00000000000..9eb325b8071 --- /dev/null +++ b/bfd/pe-x86_64.c @@ -0,0 +1,53 @@ +/* BFD back-end for Intel/AMD x86_64 PECOFF files. + Copyright 2006 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 --git a/bfd/peXXigen.c b/bfd/peXXigen.c index 70ad6cd71fc..5fa874ea022 100644 --- a/bfd/peXXigen.c +++ b/bfd/peXXigen.c @@ -52,8 +52,8 @@ 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 - we're compiling for straight PE or PE+. */ +/* 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 #include "bfd.h" @@ -67,7 +67,9 @@ 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_pep +#if defined COFF_WITH_pex64 +# include "coff/x86_64.h" +#elif defined COFF_WITH_pep # include "coff/ia64.h" #else # include "coff/i386.h" @@ -77,7 +79,7 @@ #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 @@ -399,7 +401,7 @@ _bfd_XXi_swap_aouthdr_in (bfd * abfd, 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); @@ -442,6 +444,7 @@ _bfd_XXi_swap_aouthdr_in (bfd * abfd, /* If data directory is empty, rva also should be 0. */ int size = H_GET_32 (abfd, src->DataDirectory[idx][1]); + a->DataDirectory[idx].Size = size; if (size) @@ -455,7 +458,7 @@ _bfd_XXi_swap_aouthdr_in (bfd * abfd, 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 } @@ -463,12 +466,12 @@ _bfd_XXi_swap_aouthdr_in (bfd * abfd, 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) { @@ -548,7 +551,7 @@ _bfd_XXi_swap_aouthdr_out (bfd * abfd, void * in, void * out) 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 } @@ -556,7 +559,7 @@ _bfd_XXi_swap_aouthdr_out (bfd * abfd, void * in, void * out) 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 } @@ -564,7 +567,7 @@ _bfd_XXi_swap_aouthdr_out (bfd * abfd, void * in, void * out) 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 } @@ -661,7 +664,7 @@ _bfd_XXi_swap_aouthdr_out (bfd * abfd, void * in, void * out) 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); @@ -1262,6 +1265,38 @@ pe_print_idata (bfd * abfd, void * vfile) } /* 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 <none>", + member_high,member, member_high & 0x7fffffff, member); + else + { + int ordinal; + char *member_name; + + ordinal = bfd_get_16 (abfd, data + member - adj); + member_name = (char *) data + member - adj + 2; + fprintf (file, "\t%04lx\t %4d %s",member, ordinal, member_name); + } + + /* If the time stamp is not zero, the import address + table holds actual addresses. */ + if (time_stamp != 0 + && first_thunk != 0 + && first_thunk != hint_addr) + 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); @@ -1294,7 +1329,7 @@ pe_print_idata (bfd * abfd, void * vfile) fprintf (file, "\n"); } - +#endif if (ft_allocated) free (ft_data); } @@ -1534,10 +1569,10 @@ pe_print_edata (bfd * abfd, void * vfile) static bfd_boolean pe_print_pdata (bfd * abfd, void * vfile) { -#ifdef COFF_WITH_pep -# define PDATA_ROW_SIZE (3*8) +#if defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64) +# define PDATA_ROW_SIZE (3 * 8) #else -# define PDATA_ROW_SIZE (5*4) +# define PDATA_ROW_SIZE (5 * 4) #endif FILE *file = (FILE *) vfile; bfd_byte *data = 0; @@ -1560,7 +1595,7 @@ pe_print_pdata (bfd * abfd, void * vfile) 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 @@ -1614,7 +1649,7 @@ pe_print_pdata (bfd * abfd, void * vfile) 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 --git a/bfd/pei-x86_64.c b/bfd/pei-x86_64.c new file mode 100644 index 00000000000..caa5db364f2 --- /dev/null +++ b/bfd/pei-x86_64.c @@ -0,0 +1,54 @@ +/* BFD back-end for Intel 386 PE IMAGE COFF files. + Copyright 2006 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 --git a/bfd/peicode.h b/bfd/peicode.h index 2061f415af6..22f1bbd4293 100644 --- a/bfd/peicode.h +++ b/bfd/peicode.h @@ -1,6 +1,6 @@ /* Support for the generic parts of PE/PEI, for BFD. Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, - 2005 Free Software Foundation, Inc. + 2005, 2006 Free Software Foundation, Inc. Written by Cygnus Solutions. This file is part of BFD, the Binary File Descriptor library. @@ -182,6 +182,10 @@ coff_swap_filehdr_in (bfd * abfd, void * src, void * dst) #ifdef COFF_IMAGE_WITH_PE # define coff_swap_filehdr_out _bfd_XXi_only_swap_filehdr_out +#elif defined COFF_WITH_pex64 +# define coff_swap_filehdr_out _bfd_pex64_only_swap_filehdr_out +#elif defined COFF_WITH_pep +# define coff_swap_filehdr_out _bfd_pep_only_swap_filehdr_out #else # define coff_swap_filehdr_out _bfd_pe_only_swap_filehdr_out #endif @@ -217,7 +221,10 @@ coff_swap_scnhdr_in (bfd * abfd, void * ext, void * in) if (scnhdr_int->s_vaddr != 0) { scnhdr_int->s_vaddr += pe_data (abfd)->pe_opthdr.ImageBase; + /* Do not cut upper 32-bits for 64-bit vma. */ +#ifndef COFF_WITH_pex64 scnhdr_int->s_vaddr &= 0xffffffff; +#endif } #ifndef COFF_NO_HACK_SCNHDR_SIZE @@ -405,8 +412,16 @@ pe_bfd_copy_private_bfd_data (bfd *ibfd, bfd *obfd) + NUM_ILF_SECTIONS * 9 \ + STRING_SIZE_SIZE) #define SIZEOF_IDATA2 (5 * 4) + +/* For PEx64 idata4 & 5 have thumb size of 8 bytes. */ +#ifdef COFF_WITH_pex64 +#define SIZEOF_IDATA4 (2 * 4) +#define SIZEOF_IDATA5 (2 * 4) +#else #define SIZEOF_IDATA4 (1 * 4) #define SIZEOF_IDATA5 (1 * 4) +#endif + #define SIZEOF_IDATA6 (2 + strlen (symbol_name) + 1 + 1) #define SIZEOF_IDATA7 (strlen (source_dll) + 1 + 1) #define SIZEOF_ILF_SECTIONS (NUM_ILF_SECTIONS * sizeof (struct coff_section_tdata)) @@ -656,9 +671,20 @@ static jump_table jtab[] = }, #endif +#ifdef AMD64MAGIC + { AMD64MAGIC, + { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x90, 0x90 }, + 8, 2 + }, +#endif + #ifdef MC68MAGIC - { MC68MAGIC, { /* XXX fill me in */ }, 0, 0 }, + { MC68MAGIC, + { /* XXX fill me in */ }, + 0, 0 + }, #endif + #ifdef MIPS_ARCH_MAGIC_WINCE { MIPS_ARCH_MAGIC_WINCE, { 0x00, 0x00, 0x08, 0x3c, 0x00, 0x00, 0x08, 0x8d, @@ -830,8 +856,15 @@ pe_ILF_build_a_bfd (bfd * abfd, /* XXX - treat as IMPORT_NAME ??? */ abort (); +#ifdef COFF_WITH_pex64 + ((unsigned int *) id4->contents)[0] = ordinal; + ((unsigned int *) id4->contents)[1] = 0x80000000; + ((unsigned int *) id5->contents)[0] = ordinal; + ((unsigned int *) id5->contents)[1] = 0x80000000; +#else * (unsigned int *) id4->contents = ordinal | 0x80000000; * (unsigned int *) id5->contents = ordinal | 0x80000000; +#endif } else { @@ -1071,6 +1104,12 @@ pe_ILF_object_p (bfd * abfd) #endif break; + case IMAGE_FILE_MACHINE_AMD64: +#ifdef AMD64MAGIC + magic = AMD64MAGIC; +#endif + break; + case IMAGE_FILE_MACHINE_M68K: #ifdef MC68AGIC magic = MC68MAGIC; diff --git a/bfd/targets.c b/bfd/targets.c index 489d0ce9ec0..117e7c6e33d 100644 --- a/bfd/targets.c +++ b/bfd/targets.c @@ -789,6 +789,9 @@ extern const bfd_target vms_alpha_vec; extern const bfd_target vms_vax_vec; extern const bfd_target w65_vec; extern const bfd_target we32kcoff_vec; +extern const bfd_target x86_64pe_vec; +extern const bfd_target x86_64pei_vec; +extern const bfd_target x86_64coff_vec; extern const bfd_target z80coff_vec; extern const bfd_target z8kcoff_vec; @@ -813,8 +816,8 @@ extern const bfd_target sco5_core_vec; extern const bfd_target trad_core_vec; extern const bfd_target bfd_elf32_am33lin_vec; -static const bfd_target * const _bfd_target_vector[] = { - +static const bfd_target * const _bfd_target_vector[] = +{ #ifdef SELECT_VECS SELECT_VECS, @@ -1054,6 +1057,11 @@ static const bfd_target * const _bfd_target_vector[] = { &i386os9k_vec, &i386pe_vec, &i386pei_vec, +#ifdef BFD64 + &x86_64coff_vec, + &x86_64pe_vec, + &x86_64pei_vec, +#endif &i860coff_vec, &icoff_big_vec, &icoff_little_vec, diff --git a/binutils/ChangeLog b/binutils/ChangeLog index cadf2b835f9..9595d929ee7 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,16 @@ +2006-09-20 Kai Tietz <Kai.Tietz@onevision.com> + + * configure.in: Add new target x86_64-pc-mingw64. + * configure: Regenerate. + * dlltool.c: Adjust include for this target. + (DLLTOOL_MX86_64): Added macro to handle target specific code. + (mname): Added default target static as "i386:x86-64". + (MX86): Added macro for target ident. + (mtable): Added target specific definitions. + (rvaafter): Add handling of MX86. + (rvabefore): Add handling of MX86. + (asmprefix): Add handling of MX86. + 2006-09-17 Mei Ligang <ligang@sunnorth.com.cn> * readelf.c: Add support for Score binaries. diff --git a/binutils/configure b/binutils/configure index 505a1e495f1..e74cb9dd13f 100755 --- a/binutils/configure +++ b/binutils/configure @@ -8445,6 +8445,12 @@ do DLLTOOL_DEFS="$DLLTOOL_DEFS -DDLLTOOL_ARM" BUILD_WINDRES='$(WINDRES_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-*-pe* | i[3-7]86-*-cygwin* | i[3-7]86-*-mingw32** | i[3-7]86-*-netbsdpe*) BUILD_DLLTOOL='$(DLLTOOL_PROG)$(EXEEXT)' DLLTOOL_DEFS="$DLLTOOL_DEFS -DDLLTOOL_I386" diff --git a/binutils/configure.in b/binutils/configure.in index 95a26cccd50..5f09e8e5bf2 100644 --- a/binutils/configure.in +++ b/binutils/configure.in @@ -257,6 +257,14 @@ changequote([,])dnl DLLTOOL_DEFS="$DLLTOOL_DEFS -DDLLTOOL_ARM" BUILD_WINDRES='$(WINDRES_PROG)$(EXEEXT)' ;; + 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 changequote(,)dnl i[3-7]86-*-pe* | i[3-7]86-*-cygwin* | i[3-7]86-*-mingw32** | i[3-7]86-*-netbsdpe*) changequote([,])dnl diff --git a/binutils/dlltool.c b/binutils/dlltool.c index b09c94ebb37..8a449a0e139 100644 --- a/binutils/dlltool.c +++ b/binutils/dlltool.c @@ -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); @@ -398,6 +401,10 @@ static const char *mname = "arm"; 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 @@ -640,6 +647,14 @@ mtable[] = arm_jtab, sizeof (arm_jtab), 8 } , + { +#define MX86 11 + "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 } }; @@ -763,6 +778,7 @@ rvaafter (int machine) { case MARM: case M386: + case MX86: case MPPC: case MTHUMB: case MARM_INTERWORK: @@ -788,6 +804,7 @@ rvabefore (int machine) { case MARM: case M386: + case MX86: case MPPC: case MTHUMB: case MARM_INTERWORK: @@ -823,6 +840,7 @@ asm_prefix (int machine, const char *name) case MARM_WINCE: break; case M386: + case MX86: /* Symbol names starting with ? do not have a leading underscore. */ if (name && *name == '?') break; @@ -1700,10 +1718,19 @@ generate_idata_ofile (FILE *filvar) for (headptr = import_list; headptr != NULL; headptr = headptr->next) { fprintf (filvar, "listone%d:\n", headindex); - for ( funcindex = 0; funcindex < headptr->nfuncs; funcindex++ ) + for (funcindex = 0; funcindex < headptr->nfuncs; funcindex++) +#ifdef DLLTOOL_MX86_64 + fprintf (filvar, "\t%sfuncptr%d_%d%s\n%s\t0\n", + ASM_RVA_BEFORE, headindex, funcindex, ASM_RVA_AFTER,ASM_LONG); +#else fprintf (filvar, "\t%sfuncptr%d_%d%s\n", ASM_RVA_BEFORE, headindex, funcindex, ASM_RVA_AFTER); - fprintf (filvar,"\t%s\t0\n", ASM_LONG); /* NULL terminating list */ +#endif +#ifdef DLLTOOL_MX86_64 + fprintf (filvar, "\t%s\t0\n\t%s\t0\n", ASM_LONG, ASM_LONG); /* NULL terminating list. */ +#else + fprintf (filvar, "\t%s\t0\n", ASM_LONG); /* NULL terminating list. */ +#endif headindex++; } @@ -1712,10 +1739,19 @@ generate_idata_ofile (FILE *filvar) for (headptr = import_list; headptr != NULL; headptr = headptr->next) { fprintf (filvar, "listtwo%d:\n", headindex); - for ( funcindex = 0; funcindex < headptr->nfuncs; funcindex++ ) + for (funcindex = 0; funcindex < headptr->nfuncs; funcindex++) +#ifdef DLLTOOL_MX86_64 + fprintf (filvar, "\t%sfuncptr%d_%d%s\n%s\t0\n", + ASM_RVA_BEFORE, headindex, funcindex, ASM_RVA_AFTER,ASM_LONG); +#else fprintf (filvar, "\t%sfuncptr%d_%d%s\n", ASM_RVA_BEFORE, headindex, funcindex, ASM_RVA_AFTER); - fprintf (filvar, "\t%s\t0\n", ASM_LONG); /* NULL terminating list */ +#endif +#ifdef DLLTOOL_MX86_64 + fprintf (filvar, "\t%s\t0\n\t%s\t0\n", ASM_LONG, ASM_LONG); /* NULL terminating list. */ +#else + fprintf (filvar, "\t%s\t0\n", ASM_LONG); /* NULL terminating list. */ +#endif headindex++; } @@ -2358,7 +2394,7 @@ make_one_lib_file (export_type *exp, int i) si->data = xmalloc (HOW_JTAB_SIZE); memcpy (si->data, HOW_JTAB, HOW_JTAB_SIZE); - /* add the reloc into idata$5 */ + /* Add the reloc into idata$5. */ rel = xmalloc (sizeof (arelent)); rpp = xmalloc (sizeof (arelent *) * 2); @@ -2388,6 +2424,36 @@ make_one_lib_file (export_type *exp, int i) /* An idata$4 or idata$5 is one word long, and has an rva to idata$6. */ +#ifdef DLLTOOL_MX86_64 + si->data = xmalloc (8); + si->size = 8; + + if (exp->noname) + { + si->data[0] = exp->ordinal ; + si->data[1] = exp->ordinal >> 8; + si->data[2] = exp->ordinal >> 16; + si->data[3] = exp->ordinal >> 24; + si->data[4] = 0; + si->data[5] = 0; + si->data[6] = 0; + si->data[7] = 0x80; + } + else + { + sec->reloc_count = 1; + memset (si->data, 0, si->size); + rel = xmalloc (sizeof (arelent)); + rpp = xmalloc (sizeof (arelent *) * 2); + rpp[0] = rel; + rpp[1] = 0; + rel->address = 0; + rel->addend = 0; + rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_RVA); + rel->sym_ptr_ptr = secdata[IDATA6].sympp; + sec->orelocation = rpp; + } +#else si->data = xmalloc (4); si->size = 4; @@ -2412,7 +2478,7 @@ make_one_lib_file (export_type *exp, int i) rel->sym_ptr_ptr = secdata[IDATA6].sympp; sec->orelocation = rpp; } - +#endif break; case IDATA6: @@ -2626,14 +2692,17 @@ make_head (void) if (!no_idata5) { fprintf (f, "\t.section\t.idata$5\n"); - fprintf (f, "\t%s\t0\n", ASM_LONG); +#ifdef DLLTOOL_MX86_64 + fprintf (f,"\t%s\t0\n\t%s\t0\n", ASM_LONG, ASM_LONG); /* NULL terminating list. */ +#else + fprintf (f,"\t%s\t0\n", ASM_LONG); /* NULL terminating list. */ +#endif fprintf (f, "fthunk:\n"); } if (!no_idata4) { fprintf (f, "\t.section\t.idata$4\n"); - fprintf (f, "\t%s\t0\n", ASM_LONG); fprintf (f, "\t.section .idata$4\n"); fprintf (f, "hname:\n"); @@ -2660,13 +2729,21 @@ make_tail (void) if (!no_idata4) { fprintf (f, "\t.section .idata$4\n"); - fprintf (f, "\t%s\t0\n", ASM_LONG); +#ifdef DLLTOOL_MX86_64 + fprintf (f,"\t%s\t0\n\t%s\t0\n", ASM_LONG, ASM_LONG); /* NULL terminating list. */ +#else + fprintf (f,"\t%s\t0\n", ASM_LONG); /* NULL terminating list. */ +#endif } if (!no_idata5) { fprintf (f, "\t.section .idata$5\n"); - fprintf (f, "\t%s\t0\n", ASM_LONG); +#ifdef DLLTOOL_MX86_64 + fprintf (f,"\t%s\t0\n\t%s\t0\n", ASM_LONG, ASM_LONG); /* NULL terminating list. */ +#else + fprintf (f,"\t%s\t0\n", ASM_LONG); /* NULL terminating list. */ +#endif } #ifdef DLLTOOL_PPC diff --git a/binutils/testsuite/ChangeLog b/binutils/testsuite/ChangeLog index a22c22f21f3..ca065c273e3 100644 --- a/binutils/testsuite/ChangeLog +++ b/binutils/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2006-09-20 Kai Tietz <Kai.Tietz@onevision.com> + + * binutils-all/copy-3.d: Add support for target x86_64-pc-mingw64. + * binutils-all/dlltool.exp: Likewise. + * binutils-all/objcopy.exp: Likewise. + * binutils-all/windres/windres.exp: Likewise. + * binutils-all/windres/lang.rc: xfail it as long as there is no windows.h. + * binutils-all/windres/strtab1.rc: Likewise. + * lib/utils-lib.exp: Adjust executable prefix detection (as .exe). + 2006-09-14 H.J. Lu <hongjiu.lu@intel.com> PR binutils/3181 diff --git a/binutils/testsuite/binutils-all/copy-3.d b/binutils/testsuite/binutils-all/copy-3.d index be3eea4e7cd..4bea36f74bd 100644 --- a/binutils/testsuite/binutils-all/copy-3.d +++ b/binutils/testsuite/binutils-all/copy-3.d @@ -3,7 +3,7 @@ #objcopy: --set-section-flags .text=alloc,data #name: copy with setting section flags 3 #source: bintest.s -#not-target: *-*-aout *-*-*pe *-*-*coff i*86-*-cygwin* i*86-*-mingw32* +#not-target: *-*-aout *-*-*pe *-*-*coff i*86-*-cygwin* i*86-*-mingw32* x86_64-*-mingw64* # The .text # section in PE/COFF has a fixed set of flags and these # cannot be changed. We skip it for them. diff --git a/binutils/testsuite/binutils-all/dlltool.exp b/binutils/testsuite/binutils-all/dlltool.exp index 6ddfcfae9b0..96b678230fb 100644 --- a/binutils/testsuite/binutils-all/dlltool.exp +++ b/binutils/testsuite/binutils-all/dlltool.exp @@ -1,4 +1,4 @@ -# Copyright 2002, 2004 Free Software Foundation, Inc. +# Copyright 2002, 2004, 2006 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -14,13 +14,14 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. -if {![istarget "i*86-*-*"]} { +if {![istarget "i*86-*-*"] && ![istarget "x86_64-*-mingw64*"] } { return } if {![istarget "i*86-*-*pe*"] \ && ![istarget "i*86-*-cygwin*"] \ - && ![istarget "i*86-*-mingw32*"] } { + && ![istarget "i*86-*-mingw32*"] \ + && ![istarget "x86_64-*-mingw64*"] } { set target_xfail "yes" } else { set target_xfail "no" diff --git a/binutils/testsuite/binutils-all/objcopy.exp b/binutils/testsuite/binutils-all/objcopy.exp index 96ae518b9ae..3ab38ec8dc6 100644 --- a/binutils/testsuite/binutils-all/objcopy.exp +++ b/binutils/testsuite/binutils-all/objcopy.exp @@ -1,5 +1,5 @@ # Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, -# 2004 +# 2004, 2006 # Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify @@ -443,7 +443,7 @@ strip_test_with_saving_a_symbol # Build a final executable. -if { [istarget *-*-cygwin] || [istarget *-*-mingw32] } { +if { [istarget *-*-cygwin] || [istarget *-*-mingw*] } { set test_prog "testprog.exe" } else { set test_prog "testprog" diff --git a/binutils/testsuite/binutils-all/windres/lang.rc b/binutils/testsuite/binutils-all/windres/lang.rc index d894315568e..f3da1057adb 100644 --- a/binutils/testsuite/binutils-all/windres/lang.rc +++ b/binutils/testsuite/binutils-all/windres/lang.rc @@ -1,3 +1,4 @@ +//#xfail *-*-mingw64 #include "windows.h" LANGUAGE 0, 0 diff --git a/binutils/testsuite/binutils-all/windres/strtab1.rc b/binutils/testsuite/binutils-all/windres/strtab1.rc index a1a246d8eb8..48fd107631b 100644 --- a/binutils/testsuite/binutils-all/windres/strtab1.rc +++ b/binutils/testsuite/binutils-all/windres/strtab1.rc @@ -1,3 +1,4 @@ +//#xfail *-*-mingw64 #include "windows.h" LANGUAGE 0, 0 diff --git a/binutils/testsuite/binutils-all/windres/windres.exp b/binutils/testsuite/binutils-all/windres/windres.exp index 4189c551a6f..2c836b8a37d 100644 --- a/binutils/testsuite/binutils-all/windres/windres.exp +++ b/binutils/testsuite/binutils-all/windres/windres.exp @@ -1,4 +1,4 @@ -# Copyright 2001, 2003, 2004 Free Software Foundation, Inc. +# Copyright 2001, 2003, 2004, 2006 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -19,13 +19,14 @@ # Written by DJ Delorie <dj@redhat.com> -if {![istarget "i*86-*-*"]} { +if {![istarget "i*86-*-*"] && ![istarget "x86_64-*-mingw64"] } { return } if {![istarget "i*86-*-*pe*"] \ && ![istarget "i*86-*-cygwin*"] \ - && ![istarget "i*86-*-mingw32*"] } { + && ![istarget "i*86-*-mingw32*"] \ + && ![istarget "x86_64-*-mingw64*"] } { set target_xfail "yes" } else { set target_xfail "no" diff --git a/binutils/testsuite/lib/utils-lib.exp b/binutils/testsuite/lib/utils-lib.exp index b9145006458..597437e6ffd 100644 --- a/binutils/testsuite/lib/utils-lib.exp +++ b/binutils/testsuite/lib/utils-lib.exp @@ -1,4 +1,4 @@ -# Copyright 1993, 1994, 1995, 1996, 1997, 2000, 2001, 2003, 2004 +# Copyright 1993, 1994, 1995, 1996, 1997, 2000, 2001, 2003, 2004, 2006 # Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify @@ -161,7 +161,7 @@ proc is_elf_format {} { # Returns target executable extension, if any. # proc exe_ext {} { - if { [istarget *-*-mingw32] || [istarget *-*-cygwin*] } { + if { [istarget *-*-mingw*] || [istarget *-*-cygwin*] } { return ".exe" } else { return "" diff --git a/gas/ChangeLog b/gas/ChangeLog index 1b939edd52c..c9b5e9077ae 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,17 @@ +2006-09-20 Kai Tietz <Kai.Tietz@onevision.com> + + * configure.in: Add new target x86_64-pc-mingw64. + * configure: Regenerate. + * configure.tgt: Add new target x86_64-pc-mingw64. + * config/obj-coff.h: Add handling for TE_PEP target specific code and definitions. + * config/tc-i386.c: Add new targets. + (md_parse_option): Add targets to OPTION_64. + (x86_64_target_format): Add new method for setup proper default target cpu mode. + * config/te-pep.h: Add new target definition header. + (TE_PEP): New macro: Identifies new target architecture. + (COFF_WITH_pex64): Set proper includes in bfd. + * NEWS: Mention new target. + 2006-09-18 Bernd Schmidt <bernd.schmidt@analog.com> * config/bfin-parse.y (binary): Change sub of const to add of negated @@ -1,4 +1,6 @@ -*- text -*- +* Add support for x86_64 PE+ target. + * Add support for Score target. * Support for the Infineon XC16X has been added by KPIT Cummins Infosystems. diff --git a/gas/config/obj-coff.h b/gas/config/obj-coff.h index 8d10b4d59b1..d2b212565ef 100644 --- a/gas/config/obj-coff.h +++ b/gas/config/obj-coff.h @@ -55,16 +55,30 @@ #endif #ifdef TC_I386 +#ifndef TE_PEP +#include "coff/x86_64.h" +#else #include "coff/i386.h" +#endif #ifdef TE_PE +#ifdef TE_PEP +extern const char * x86_64_target_format (void); +#define TARGET_FORMAT x86_64_target_format () +#define COFF_TARGET_FORMAT "pe-x86-64" +#else #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 --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index f85aed3b8fd..1e8534aea61 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -5766,9 +5766,10 @@ const char *md_shortopts = "qn"; #define OPTION_MARCH (OPTION_MD_BASE + 3) #define OPTION_MTUNE (OPTION_MD_BASE + 4) -struct option md_longopts[] = { +struct option md_longopts[] = +{ {"32", no_argument, NULL, OPTION_32}, -#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) || defined(TE_PEP) {"64", no_argument, NULL, OPTION_64}, #endif {"divide", no_argument, NULL, OPTION_DIVIDE}, @@ -5812,14 +5813,18 @@ md_parse_option (int c, char *arg) /* -s: On i386 Solaris, this tells the native assembler to use .stab instead of .stab.excl. We always use .stab anyhow. */ break; - +#endif +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) || defined(TE_PEP) case OPTION_64: { const char **list, **l; list = bfd_target_list (); for (l = list; *l != NULL; l++) - if (strncmp (*l, "elf64-x86-64", 12) == 0) + if ( strncmp (*l, "elf64-x86-64", 12) == 0 + || strcmp (*l, "coff-x86-64") == 0 + || strcmp (*l, "pe-x86-64") == 0 + || strcmp (*l, "pei-x86-64") == 0) { default_arch = "x86_64"; break; @@ -5927,6 +5932,26 @@ md_show_usage (stream) } +#if defined(TE_PEP) +const char * +x86_64_target_format (void) +{ + if (strcmp (default_arch, "x86_64") == 0) + { + set_code_flag (CODE_64BIT); + return COFF_TARGET_FORMAT; + } + else if (strcmp (default_arch, "i386") == 0) + { + set_code_flag (CODE_32BIT); + return "coff-i386"; + } + + as_fatal (_("Unknown architecture")); + return NULL; +} +#endif + #if ((defined (OBJ_MAYBE_COFF) && defined (OBJ_MAYBE_AOUT)) \ || defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) diff --git a/gas/config/te-pep.h b/gas/config/te-pep.h new file mode 100644 index 00000000000..164b22d9840 --- /dev/null +++ b/gas/config/te-pep.h @@ -0,0 +1,10 @@ +#define TE_PEP +#define COFF_WITH_pex64 + +#define TE_PE +#define LEX_AT (LEX_BEGIN_NAME | LEX_NAME) /* Can have @'s inside labels. */ + +/* The PE format supports long section names. */ +#define COFF_LONG_SECTION_NAMES + +#include "obj-format.h" diff --git a/gas/configure b/gas/configure index 166ae272b0a..e31fa35ed1a 100755 --- a/gas/configure +++ b/gas/configure @@ -3921,7 +3921,7 @@ ia64-*-hpux*) 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 @@ -3932,7 +3932,7 @@ x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) case "`/usr/bin/file conftest.o`" in *32-bit*) case $host in - x86_64-*linux*) + x86_64-*linux*|x86_64-*mingw64*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|powerpc64-*linux*) @@ -3948,7 +3948,7 @@ x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) ;; *64-bit*) case $host in - x86_64-*linux*) + x86_64-*linux*|x86_64-*mingw64*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) @@ -4895,6 +4895,19 @@ if test ${all_targets} = "yes"; then ;; 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 @@ -4958,6 +4971,11 @@ cat >>confdefs.h <<\_ACEOF #define M88KCOFF 1 _ACEOF ;; + x86_64) +cat >>confdefs.h <<\_ACEOF +#define I386COFF 1 +_ACEOF + ;; esac ;; esac diff --git a/gas/configure.in b/gas/configure.in index c306516fe6a..a0592d19957 100644 --- a/gas/configure.in +++ b/gas/configure.in @@ -417,6 +417,19 @@ if test ${all_targets} = "yes"; then ;; 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 @@ -461,6 +474,7 @@ case ${obj_format} in i386) AC_DEFINE(I386COFF, 1, [Using i386 COFF?]) ;; m68k) AC_DEFINE(M68KCOFF, 1, [Using m68k COFF?]) ;; m88k) AC_DEFINE(M88KCOFF, 1, [Using m88k COFF?]) ;; + x86_64) AC_DEFINE(I386COFF, 1, [Using i386 COFF?]) ;; esac ;; esac diff --git a/gas/configure.tgt b/gas/configure.tgt index e7c7e23e5ad..c79d2b20016 100644 --- a/gas/configure.tgt +++ b/gas/configure.tgt @@ -79,7 +79,7 @@ case ${cpu} in 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 ;; @@ -212,6 +212,7 @@ case ${generic_target} in 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 --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index 05b0f81ddd4..89892f7753d 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,3 +1,18 @@ +2006-09-20 Kai Tietz <Kai.Tietz@onevision.com> + + * gas/all/gas.exp: Add support for x86_64-*-mingw64. + * gas/i386/immed64.d: Add #pass for avoid proplems with alignment paddings. + * gas/i386/rex.d: Changed for x86_64-mingw32 target matching and padding. + * gas/i386/i386.d: Likewise. + * gas/i386/x86-64-addr32.d: Likewise. + * gas/i386/x86-64-branch.d: Likewise. + * gas/i386/x86-64-crx-suffix.d: Likewise. + * gas/i386/x86-64-crx.d: Likewise. + * gas/i386/x86-64-drx-suffix.d: Likewise. + * gas/i386/x86-64-crx-suffix.d: Likewise. + * gas/i386/x86-64-opcode.d: Likewise. + * gas/i386/x86-64-pcrel.d: Likewise. + 2006-09-19 Bernd Schmidt <bernd.schmidt@analog.com> * gas/bfin/load.s, gas/bfin/load.d: Add constant folding tests. diff --git a/gas/testsuite/gas/all/gas.exp b/gas/testsuite/gas/all/gas.exp index 928dd88348e..adaa486620f 100644 --- a/gas/testsuite/gas/all/gas.exp +++ b/gas/testsuite/gas/all/gas.exp @@ -207,6 +207,7 @@ if { ([istarget *-*-coff*] && ![istarget *arm*-*-coff] && ![istarget thumb*-*- || [istarget i*86-*-isc*] \ || [istarget i*86-*-go32*] \ || [istarget i*86-*-cygwin*] \ + || [istarget x86_64-*-mingw64*] \ || [istarget i*86-*-*nt] \ || [istarget i*86-*-interix*] \ || ([istarget i960-*-vxworks5.*] && ![istarget i960-*-vxworks5.0*]) } { diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.exp index 4158b86b5c3..096b58ae649 100644 --- a/gas/testsuite/gas/i386/i386.exp +++ b/gas/testsuite/gas/i386/i386.exp @@ -155,7 +155,9 @@ if [expr ([istarget "i*86-*-*"] || [istarget "x86_64-*-*"]) && [gas_64_check]] t run_dump_test "x86-64-rep-suffix" run_dump_test "x86-64-gidt" run_dump_test "x86-64-nops" + if ![istarget "*-*-mingw64*"] then { run_dump_test "x86-64-nops-1" + } run_dump_test "x86-64-nops-1-k8" run_dump_test "x86-64-nops-1-nocona" run_dump_test "x86-64-nops-1-merom" diff --git a/gas/testsuite/gas/i386/immed64.d b/gas/testsuite/gas/i386/immed64.d index c2ab3248b7d..667680675a5 100644 --- a/gas/testsuite/gas/i386/immed64.d +++ b/gas/testsuite/gas/i386/immed64.d @@ -57,3 +57,4 @@ Disassembly of section \.text: [ ]*[0-9a-fA-F]+:[ ]+e5 04[ ]+inl? +\$0x4,%eax [ ]*[0-9a-fA-F]+:[ ]+e5 08[ ]+inl? +\$0x8,%eax [ ]*[0-9a-fA-F]+:[ ]+e5 00[ ]+inl? +\$0x0,%eax +#pass diff --git a/gas/testsuite/gas/i386/rex.d b/gas/testsuite/gas/i386/rex.d index dab6b12580d..285e1dc6c7a 100644 --- a/gas/testsuite/gas/i386/rex.d +++ b/gas/testsuite/gas/i386/rex.d @@ -1,7 +1,7 @@ #objdump: -dw #name: x86-64 manual rex prefix use -.*: +file format elf64-x86-64 +.*: +file format .* Disassembly of section .text: diff --git a/gas/testsuite/gas/i386/x86-64-addr32.d b/gas/testsuite/gas/i386/x86-64-addr32.d index c892fb1ba1d..d22cff9c704 100644 --- a/gas/testsuite/gas/i386/x86-64-addr32.d +++ b/gas/testsuite/gas/i386/x86-64-addr32.d @@ -2,7 +2,7 @@ #objdump: -drw #name: x86-64 32-bit addressing -.*: +file format elf64-x86-64 +.*: +file format .* Disassembly of section .text: @@ -11,3 +11,4 @@ Disassembly of section .text: [ ]*8:[ ]+67 49 8d 80 00 00 00 00[ ]+addr32[ ]+lea[ ]+0x0\(%r8d?\),%rax.* [ ]*10:[ ]+67 48 8d 05 00 00 00 00[ ]+addr32[ ]+lea[ ]+0\(%[re]ip\),%rax.* [ ]*18:[ ]+67 48 8d 04 25 00 00 00 00[ ]+addr32[ ]+lea[ ]+0x0,%rax.* +#pass diff --git a/gas/testsuite/gas/i386/x86-64-branch.d b/gas/testsuite/gas/i386/x86-64-branch.d index 7ddd6fe1777..17c46a752b1 100644 --- a/gas/testsuite/gas/i386/x86-64-branch.d +++ b/gas/testsuite/gas/i386/x86-64-branch.d @@ -2,7 +2,7 @@ #objdump: -drw #name: x86-64 indirect branch -.*: +file format elf64-x86-64 +.*: +file format .* Disassembly of section .text: @@ -11,3 +11,4 @@ Disassembly of section .text: [ ]*2:[ ]+ff d0[ ]+callq[ ]+\*%rax [ ]*4:[ ]+ff e0[ ]+jmpq[ ]+\*%rax [ ]*6:[ ]+ff e0[ ]+jmpq[ ]+\*%rax +#pass diff --git a/gas/testsuite/gas/i386/x86-64-crx-suffix.d b/gas/testsuite/gas/i386/x86-64-crx-suffix.d index 1dc3584219e..6dfd47cdef6 100644 --- a/gas/testsuite/gas/i386/x86-64-crx-suffix.d +++ b/gas/testsuite/gas/i386/x86-64-crx-suffix.d @@ -2,7 +2,7 @@ #name: x86-64 control register related opcodes (with suffixes) #source: x86-64-crx.s -.*: +file format elf64-x86-64 +.*: +file format .* Disassembly of section .text: diff --git a/gas/testsuite/gas/i386/x86-64-crx.d b/gas/testsuite/gas/i386/x86-64-crx.d index 8c1333f5369..62abe70301a 100644 --- a/gas/testsuite/gas/i386/x86-64-crx.d +++ b/gas/testsuite/gas/i386/x86-64-crx.d @@ -2,7 +2,7 @@ #name: x86-64 control register related opcodes #source: x86-64-crx.s -.*: +file format elf64-x86-64 +.*: +file format .* Disassembly of section .text: diff --git a/gas/testsuite/gas/i386/x86-64-drx-suffix.d b/gas/testsuite/gas/i386/x86-64-drx-suffix.d index 1f76b8b163b..254e24defc4 100644 --- a/gas/testsuite/gas/i386/x86-64-drx-suffix.d +++ b/gas/testsuite/gas/i386/x86-64-drx-suffix.d @@ -2,7 +2,7 @@ #name: x86-64 debug register related opcodes (with suffixes) #source: x86-64-drx.s -.*: +file format elf64-x86-64 +.*: +file format .* Disassembly of section .text: diff --git a/gas/testsuite/gas/i386/x86-64-drx.d b/gas/testsuite/gas/i386/x86-64-drx.d index 879ce50a5ef..18b328f9b30 100644 --- a/gas/testsuite/gas/i386/x86-64-drx.d +++ b/gas/testsuite/gas/i386/x86-64-drx.d @@ -1,7 +1,7 @@ #objdump: -dw #name: x86-64 debug register related opcodes -.*: +file format elf64-x86-64 +.*: +file format .* Disassembly of section .text: diff --git a/gas/testsuite/gas/i386/x86-64-opcode.d b/gas/testsuite/gas/i386/x86-64-opcode.d index 669782ac40a..d3bd17f5a76 100644 --- a/gas/testsuite/gas/i386/x86-64-opcode.d +++ b/gas/testsuite/gas/i386/x86-64-opcode.d @@ -2,7 +2,7 @@ #objdump: -drw #name: x86-64 opcode -.*: +file format elf64-x86-64 +.*: +file format .* Disassembly of section .text: diff --git a/gas/testsuite/gas/i386/x86-64-pcrel.d b/gas/testsuite/gas/i386/x86-64-pcrel.d index 3be86c7c340..818ea2e6f73 100644 --- a/gas/testsuite/gas/i386/x86-64-pcrel.d +++ b/gas/testsuite/gas/i386/x86-64-pcrel.d @@ -1,7 +1,7 @@ #objdump: -drw #name: x86-64 pcrel -.*: +file format elf64-x86-64 +.*: +file format .* Disassembly of section .text: diff --git a/gas/testsuite/gas/i386/x86-64-rip.d b/gas/testsuite/gas/i386/x86-64-rip.d index 1b1d6c8a31c..a45f6bc7de6 100644 --- a/gas/testsuite/gas/i386/x86-64-rip.d +++ b/gas/testsuite/gas/i386/x86-64-rip.d @@ -2,7 +2,7 @@ #objdump: -drw #name: x86-64 rip addressing -.*: +file format elf64-x86-64 +.*: +file format .* Disassembly of section .text: @@ -11,3 +11,4 @@ Disassembly of section .text: [ ]*6:[ ]+8d 05 11 11 11 11[ ]+lea[ ]+286331153\(%rip\),%eax[ ]*(#.*)? [ ]*c:[ ]+8d 05 01 00 00 00[ ]+lea[ ]+1\(%rip\),%eax[ ]*(#.*)? [ ]*12:[ ]+8d 05 00 00 00 00[ ]+lea[ ]+0\(%rip\),%eax[ ]*(#.*)? +#pass diff --git a/gas/testsuite/gas/i386/x86-64-stack-intel.d b/gas/testsuite/gas/i386/x86-64-stack-intel.d index 0dfab4d3fbe..aaeff2ffcb3 100644 --- a/gas/testsuite/gas/i386/x86-64-stack-intel.d +++ b/gas/testsuite/gas/i386/x86-64-stack-intel.d @@ -2,7 +2,7 @@ #name: x86-64 stack-related opcodes (Intel mode) #source: x86-64-stack.s -.*: +file format elf64-x86-64 +.*: +file format .* Disassembly of section .text: diff --git a/gas/testsuite/gas/i386/x86-64-stack-suffix.d b/gas/testsuite/gas/i386/x86-64-stack-suffix.d index c5d789d8a71..75fd900feae 100644 --- a/gas/testsuite/gas/i386/x86-64-stack-suffix.d +++ b/gas/testsuite/gas/i386/x86-64-stack-suffix.d @@ -2,7 +2,7 @@ #name: x86-64 stack-related opcodes (with suffixes) #source: x86-64-stack.s -.*: +file format elf64-x86-64 +.*: +file format .* Disassembly of section .text: diff --git a/gas/testsuite/gas/i386/x86-64-stack.d b/gas/testsuite/gas/i386/x86-64-stack.d index fa010a981a1..f686a04fee8 100644 --- a/gas/testsuite/gas/i386/x86-64-stack.d +++ b/gas/testsuite/gas/i386/x86-64-stack.d @@ -1,7 +1,7 @@ #objdump: -dw #name: x86-64 stack-related opcodes -.*: +file format elf64-x86-64 +.*: +file format .* Disassembly of section .text: diff --git a/gas/testsuite/gas/i386/x86_64.d b/gas/testsuite/gas/i386/x86_64.d index 60452a51273..70ed07cdbec 100644 --- a/gas/testsuite/gas/i386/x86_64.d +++ b/gas/testsuite/gas/i386/x86_64.d @@ -6,7 +6,7 @@ Disassembly of section .text: -0+ <bar-0x1a7>: +0+ <.*>: [ ]+0: 01 ca[ ]+add[ ]+%ecx,%edx [ ]+2: 44 01 ca[ ]+add[ ]+%r9d,%edx [ ]+5: 41 01 ca[ ]+add[ ]+%ecx,%r10d diff --git a/include/coff/ChangeLog b/include/coff/ChangeLog index f41c115bdad..499d47890d9 100644 --- a/include/coff/ChangeLog +++ b/include/coff/ChangeLog @@ -1,3 +1,15 @@ +2006-09-20 Kai Tietz <Kai.Tietz@onevision.com> + + * external.h: Add proper external_aouthdr64 structure (without + data_start member). + (AOUTHDRSZ64): Set according structure size. + (AOUTHDR64): As typedef of external_aouthdr64 structure. + * internal.h: Add relocation identifiers for coff. + * pe.h: Add define IMAGE_FILE_MACHINE_AMD64 the coff signature. + (PEPAOUTHDR): Adjust structure to have proper size (using AOUTHDR64). + (PEPAOUTSZ): Calculated size of 240. + * x86_64.h: Coff information for x86_64 (AMD64). + 2006-02-05 Arnold Metselaar <arnold.metselaar@planet.nl> * internal.h: Add relocation number R_IMM24 for Z80. diff --git a/include/coff/external.h b/include/coff/external.h index 9e760bd86da..e38fb1bab4e 100644 --- a/include/coff/external.h +++ b/include/coff/external.h @@ -1,6 +1,6 @@ /* external.h -- External COFF structures - Copyright 2001 Free Software Foundation, Inc. + Copyright 2001, 2006 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -55,7 +55,21 @@ AOUTHDR; #define AOUTHDRSZ 28 #define AOUTSZ 28 -#endif + +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 /* not DO_NOT_DEFINE_AOUTHDR */ #ifndef DO_NOT_DEFINE_SCNHDR /********************** SECTION HEADER **********************/ diff --git a/include/coff/internal.h b/include/coff/internal.h index ed0918a6aea..71336ff2bfb 100644 --- a/include/coff/internal.h +++ b/include/coff/internal.h @@ -1,7 +1,7 @@ /* Internal format of COFF object file data structures, for GNU BFD. This file is part of BFD, the Binary File Descriptor library. - Copyright 1999, 2000, 2001, 2002, 2003, 2004. 2005 + Copyright 1999, 2000, 2001, 2002, 2003, 2004. 2005, 2006 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify @@ -604,6 +604,25 @@ struct internal_reloc 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_AMD64_PCRQUAD 14 /* Pseude PC64 relocation - Note: not specified by MS/AMD but need for gas pc-relative 64bit wide relocation generated by ELF. */ + +/* i386 Relocations. */ + #define R_DIR16 1 #define R_REL24 5 #define R_DIR32 6 diff --git a/include/coff/pe.h b/include/coff/pe.h index 643cea480c9..ac53a17a5ad 100644 --- a/include/coff/pe.h +++ b/include/coff/pe.h @@ -1,6 +1,6 @@ /* pe.h - PE COFF header information - Copyright 1999, 2000, 2001, 2003, 2004 Free Software Foundation, Inc. + Copyright 1999, 2000, 2001, 2003, 2004, 2006 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -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 #define IMAGE_SUBSYSTEM_UNKNOWN 0 #define IMAGE_SUBSYSTEM_NATIVE 1 @@ -259,6 +260,7 @@ typedef struct /* IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; */ char DataDirectory[16][2][4]; /* 16 entries, 2 elements/entry, 4 chars. */ } PEAOUTHDR; + #undef AOUTSZ #define AOUTSZ (AOUTHDRSZ + 196) @@ -267,8 +269,11 @@ typedef struct of just 4 bytes long. */ typedef struct { +#ifdef AOUTHDRSZ64 + AOUTHDR64 standard; +#else AOUTHDR standard; - +#endif /* NT extra fields; see internal.h for descriptions. */ char ImageBase[8]; char SectionAlignment[4]; @@ -294,7 +299,12 @@ typedef struct /* IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; */ char DataDirectory[16][2][4]; /* 16 entries, 2 elements/entry, 4 chars. */ } PEPAOUTHDR; + +#ifdef AOUTHDRSZ64 +#define PEPAOUTSZ (AOUTHDRSZ64 + 196 + 5 * 4) /* = 240 */ +#else #define PEPAOUTSZ 240 +#endif #undef E_FILNMLEN #define E_FILNMLEN 18 /* # characters in a file name. */ diff --git a/include/coff/x86_64.h b/include/coff/x86_64.h new file mode 100644 index 00000000000..b58dd2f236e --- /dev/null +++ b/include/coff/x86_64.h @@ -0,0 +1,54 @@ +/* COFF information for AMD 64. + Copyright 2006 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" + +#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 --git a/ld/ChangeLog b/ld/ChangeLog index 42895da3fe6..dd9eb5d76a7 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,20 @@ +2006-09-20 Kai Tietz <Kai.Tietz@onevision.com> + + * configure.in: Add new target x86_64-pc-mingw64. + * configure: Regenerate. + * configure.tgt: Add definition of target emulation i386pep. + * Makefile.am: Add new target files for target-all. + * Makefile.in: Regenerate. + * pe-dll.c: Adjust to be inheritable by pep_dll.c as include. + Fix memory out of bounds excess for idata relocation section data. + * pep-dll.c: Add target specific shared object handling. + * pep-dll.h: Add target specific definitions for shared object handling. + * emulparams/i386pep.sh: Add new emulation params for target x86_64 coff. + * emultempl/pep.em: Add new emulation file for target x86_64 coff. + * po/POTFILES.in: Regenerate. + * scripttempl/pep.sc: Add linker script template for target x86_64 coff. + * NEWS: Mention new target. + 2006-09-18 Thiemo Seufer <ths@networkno.de> * configure.tgt: Add mips*el-sde-elf* and mips*-sde-elf* diff --git a/ld/Makefile.am b/ld/Makefile.am index 34c56ef2fbf..26f0580a7bb 100644 --- a/ld/Makefile.am +++ b/ld/Makefile.am @@ -240,6 +240,7 @@ ALL_EMULATIONS = \ ei386nw.o \ ei386pe.o \ ei386pe_posix.o \ + ei386pep.o \ elnk960.o \ em32relf.o \ em32rlelf.o \ @@ -412,15 +413,16 @@ ALL_64_EMULATIONS = \ 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 @@ -1103,6 +1105,9 @@ ei386pe.c: $(srcdir)/emulparams/i386pe.sh \ ei386pe_posix.c: $(srcdir)/emulparams/i386pe_posix.sh \ $(srcdir)/emultempl/pe.em $(srcdir)/scripttempl/pe.sc ${GEN_DEPENDS} ${GENSCRIPTS} i386pe_posix "$(tdir_i386pe_posix)" +ei386pep.c: $(srcdir)/emulparams/i386pep.sh \ + $(srcdir)/emultempl/pep.em $(srcdir)/scripttempl/pep.sc ${GEN_DEPENDS} + ${GENSCRIPTS} i386pep "$(tdir_i386pe)" elnk960.c: $(srcdir)/emulparams/lnk960.sh \ $(srcdir)/emultempl/lnk960.em $(srcdir)/scripttempl/i960.sc ${GEN_DEPENDS} ${GENSCRIPTS} lnk960 "$(tdir_lnk960)" @@ -1970,6 +1975,12 @@ pe-dll.o: pe-dll.c ../bfd/bfd.h $(INCDIR)/ansidecl.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 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 --git a/ld/Makefile.in b/ld/Makefile.in index 1ac86614111..b754d0b89ea 100644 --- a/ld/Makefile.in +++ b/ld/Makefile.in @@ -464,6 +464,7 @@ ALL_EMULATIONS = \ ei386nw.o \ ei386pe.o \ ei386pe_posix.o \ + ei386pep.o \ elnk960.o \ em32relf.o \ em32rlelf.o \ @@ -636,15 +637,16 @@ ALL_64_EMULATIONS = \ 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 @@ -1914,6 +1916,9 @@ ei386pe.c: $(srcdir)/emulparams/i386pe.sh \ ei386pe_posix.c: $(srcdir)/emulparams/i386pe_posix.sh \ $(srcdir)/emultempl/pe.em $(srcdir)/scripttempl/pe.sc ${GEN_DEPENDS} ${GENSCRIPTS} i386pe_posix "$(tdir_i386pe_posix)" +ei386pep.c: $(srcdir)/emulparams/i386pep.sh \ + $(srcdir)/emultempl/pep.em $(srcdir)/scripttempl/pep.sc ${GEN_DEPENDS} + ${GENSCRIPTS} i386pep "$(tdir_i386pe)" elnk960.c: $(srcdir)/emulparams/lnk960.sh \ $(srcdir)/emultempl/lnk960.em $(srcdir)/scripttempl/i960.sc ${GEN_DEPENDS} ${GENSCRIPTS} lnk960 "$(tdir_lnk960)" @@ -2751,6 +2756,12 @@ pe-dll.o: pe-dll.c ../bfd/bfd.h $(INCDIR)/ansidecl.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 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 \ @@ -1,4 +1,6 @@ -*- text -*- +* Add support for x86_64 PE+ target. + * Add support for Score target. * ELF: Add --dynamic-list option to specify a list of global symbols diff --git a/ld/configure.tgt b/ld/configure.tgt index 24137fdb561..c5f3be3ab93 100644 --- a/ld/configure.tgt +++ b/ld/configure.tgt @@ -219,6 +219,8 @@ i[3-7]86-*-cygwin*) targ_emul=i386pe ; test "$targ" != "$host" && LIB_PATH='${tooldir}/lib/w32api' ;; i[3-7]86-*-mingw32*) targ_emul=i386pe ; targ_extra_ofiles="deffilep.o pe-dll.o" ;; +x86_64-*-mingw64*) targ_emul=i386pep ; + targ_extra_ofiles="deffilep.o pep-dll.o" ;; i[3-7]86-*-interix*) targ_emul=i386pe_posix; targ_extra_ofiles="deffilep.o pe-dll.o" ;; i[3-7]86-*-beospe*) targ_emul=i386beos ;; diff --git a/ld/emulparams/i386pep.sh b/ld/emulparams/i386pep.sh new file mode 100644 index 00000000000..d20f3aba5f0 --- /dev/null +++ b/ld/emulparams/i386pep.sh @@ -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 --git a/ld/emultempl/pep.em b/ld/emultempl/pep.em new file mode 100644 index 00000000000..3fa6ca4ba92 --- /dev/null +++ b/ld/emultempl/pep.em @@ -0,0 +1,1706 @@ +# 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 <<EOF +/* This file is part of GLD, the Gnu Linker. + Copyright 2006 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 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. */ + +/* For WINDOWS_XP64 and higher */ +/* Based on pe.em, but modified for 64 bit support. */ + +#define TARGET_IS_${EMULATION_NAME} + +#define COFF_IMAGE_WITH_PE +#define COFF_WITH_PE +#define COFF_WITH_pex64 + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "getopt.h" +#include "libiberty.h" +#include "ld.h" +#include "ldmain.h" +#include "ldexp.h" +#include "ldlang.h" +#include "ldfile.h" +#include "ldemul.h" +#include <ldgram.h> +#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 +#define NT_EXE_IMAGE_BASE 0x00010000 +#undef PE_DEF_SECTION_ALIGNMENT +#define PE_DEF_SUBSYSTEM 2 +#undef PE_DEF_FILE_ALIGNMENT +#define PE_DEF_FILE_ALIGNMENT 0x00000200 +#define PE_DEF_SECTION_ALIGNMENT 0x00000400 +#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 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) + lang_default_entry ("_WinMainCRTStartup"); +#else + lang_default_entry ("${ENTRY}"); +#endif +#endif +} + +/* PE format extra command line options. */ + +/* Used for setting flags in the PE header. */ +enum options +{ + OPTION_BASE_FILE = 300 + 1, + OPTION_DLL, + OPTION_FILE_ALIGNMENT, + OPTION_IMAGE_BASE, + OPTION_MAJOR_IMAGE_VERSION, + OPTION_MAJOR_OS_VERSION, + OPTION_MAJOR_SUBSYSTEM_VERSION, + OPTION_MINOR_IMAGE_VERSION, + OPTION_MINOR_OS_VERSION, + OPTION_MINOR_SUBSYSTEM_VERSION, + OPTION_SECTION_ALIGNMENT, + OPTION_STACK, + OPTION_SUBSYSTEM, + OPTION_HEAP, + OPTION_SUPPORT_OLD_CODE, + OPTION_OUT_DEF, + OPTION_EXPORT_ALL, + OPTION_EXCLUDE_SYMBOLS, + OPTION_KILL_ATS, + OPTION_STDCALL_ALIASES, + OPTION_ENABLE_STDCALL_FIXUP, + OPTION_DISABLE_STDCALL_FIXUP, + OPTION_IMPLIB_FILENAME, + OPTION_WARN_DUPLICATE_EXPORTS, + OPTION_IMP_COMPAT, + OPTION_ENABLE_AUTO_IMAGE_BASE, + OPTION_DISABLE_AUTO_IMAGE_BASE, + OPTION_DLL_SEARCH_PREFIX, + OPTION_NO_DEFAULT_EXCLUDES, + OPTION_DLL_ENABLE_AUTO_IMPORT, + OPTION_DLL_DISABLE_AUTO_IMPORT, + OPTION_ENABLE_EXTRA_PE_DEBUG, + OPTION_EXCLUDE_LIBS, + OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC, + OPTION_DLL_DISABLE_RUNTIME_PSEUDO_RELOC +}; + +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}, +#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 = 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 <basefile> Generate a base file for relocatable DLLs\n")); + fprintf (file, _(" --dll Set image base to the default for DLLs\n")); + fprintf (file, _(" --file-alignment <size> Set file alignment\n")); + fprintf (file, _(" --heap <size> Set initial size of the heap\n")); + fprintf (file, _(" --image-base <address> Set start address of the executable\n")); + fprintf (file, _(" --major-image-version <number> Set version number of the executable\n")); + fprintf (file, _(" --major-os-version <number> Set minimum required OS version\n")); + fprintf (file, _(" --major-subsystem-version <number> Set minimum required OS subsystem version\n")); + fprintf (file, _(" --minor-image-version <number> Set revision number of the executable\n")); + fprintf (file, _(" --minor-os-version <number> Set minimum required OS revision\n")); + fprintf (file, _(" --minor-subsystem-version <number> Set minimum required OS subsystem revision\n")); + fprintf (file, _(" --section-alignment <size> Set section alignment\n")); + fprintf (file, _(" --stack <size> Set size of the initial stack\n")); + fprintf (file, _(" --subsystem <name>[:<version>] Set required OS subsystem [& version]\n")); + fprintf (file, _(" --support-old-code Support interworking with old code\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 <file> Generate import library\n")); + fprintf (file, _(" --output-def <file> 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_<SYMBOL> 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=<string> When linking dynamically to a dll without\n\ + an importlib, use <string><basename>.dll\n\ + in preference to lib<basename>.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; + if (strcmp (name,"__image_base__") == 0) + set_pep_name ("__ImageBase", val); + 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; +#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 = xmalloc (symsize); + nsyms = bfd_canonicalize_symtab (b, symbols); + + for (i = 0; i < nsyms; i++) + { + if (! CONST_STRNEQ (symbols[i]->name, "__head_")) + 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: cannot perform PE operations on non PE output file '%B'.\n"), output_bfd); + + 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 /* DLL_SUPPORT */ + + { + /* 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 (CONST_STRNEQ (sec->name, ".idata\$")) + 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 = xmalloc (symsize); + symsize = bfd_canonicalize_symtab (is->the_bfd, symbols); + if (symsize < 0) + { + einfo ("%X%P: unable to process symbols: %E"); + return; + } + + relocs = 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 = 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) +{ + 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) +{ + static const struct + { + const char * format; + bfd_boolean use_prefix; + } + libname_fmt [] = + { + /* Preferred explicit import library for dll's. */ + { "lib%s.dll.a", FALSE }, + /* Alternate explicit import library for dll's. */ + { "%s.dll.a", FALSE }, + /* "libfoo.a" could be either an import lib or a static lib. + For backwards compatibility, libfoo.a needs to precede + libfoo.dll and foo.dll in the search. */ + { "lib%s.a", FALSE }, + /* The 'native' spelling of an import lib name is "foo.lib". */ + { "%s.lib", FALSE }, +#ifdef DLL_SUPPORT + /* Try "<prefix>foo.dll" (preferred dll name, if specified). */ + { "%s%s.dll", TRUE }, +#endif + /* Try "libfoo.dll" (default preferred dll name). */ + { "lib%s.dll", FALSE }, + /* Finally try 'native' dll name "foo.dll". */ + { "%s.dll", FALSE }, + /* Note: If adding more formats to this table, make sure to check to + see if their length is longer than libname_fmt[0].format, and if + so, update the call to xmalloc() below. */ + { NULL, FALSE } + }; + static unsigned int format_max_len = 0; + const char * filename; + char * full_string; + char * base_string; + unsigned int i; + + + if (! entry->is_archive) + return FALSE; + + filename = entry->filename; + + if (format_max_len == 0) + /* We need to allow space in the memory that we are going to allocate + for the characters in the format string. Since the format array is + static we only need to calculate this information once. In theory + this value could also be computed statically, but this introduces + the possibility for a discrepancy and hence a possible memory + corruption. The lengths we compute here will be too long because + they will include any formating characters (%s) in the strings, but + this will not matter. */ + for (i = 0; libname_fmt[i].format; i++) + if (format_max_len < strlen (libname_fmt[i].format)) + format_max_len = strlen (libname_fmt[i].format); + + full_string = xmalloc (strlen (search->name) + + strlen (filename) + + format_max_len +#ifdef DLL_SUPPORT + + (pep_dll_search_prefix + ? strlen (pep_dll_search_prefix) : 0) +#endif + /* Allow for the terminating NUL and for the path + separator character that is inserted between + search->name and the start of the format string. */ + + 2); + + sprintf (full_string, "%s/", search->name); + base_string = full_string + strlen (full_string); + + for (i = 0; libname_fmt[i].format; i++) + { +#ifdef DLL_SUPPORT + if (libname_fmt[i].use_prefix) + { + if (!pep_dll_search_prefix) + continue; + sprintf (base_string, libname_fmt[i].format, pep_dll_search_prefix, filename); + } + else +#endif + sprintf (base_string, libname_fmt[i].format, filename); + + if (ldfile_try_open_bfd (full_string, entry)) + break; + } + + if (!libname_fmt[i].format) + { + free (full_string); + return FALSE; + } + + entry->filename = full_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 <<EOF +{ + *isfile = 0; + + if (link_info.relocatable && config.build_constructors) + return +EOF +sed $sc ldscripts/${EMULATION_NAME}.xu >> 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 <<EOF + + +struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = +{ + gld_${EMULATION_NAME}_before_parse, + syslib_default, + hll_default, + gld_${EMULATION_NAME}_after_parse, + gld_${EMULATION_NAME}_after_open, + after_allocation_default, + set_output_arch_default, + ldemul_default_target, + gld_${EMULATION_NAME}_before_allocation, + gld_${EMULATION_NAME}_get_script, + "${EMULATION_NAME}", + "${OUTPUT_FORMAT}", + gld_${EMULATION_NAME}_finish, + NULL, /* Create output section statements. */ + gld_${EMULATION_NAME}_open_dynamic_archive, + gld_${EMULATION_NAME}_place_orphan, + gld_${EMULATION_NAME}_set_symbols, + NULL, /* parse_args */ + gld${EMULATION_NAME}_add_options, + gld${EMULATION_NAME}_handle_option, + gld_${EMULATION_NAME}_unrecognized_file, + gld_${EMULATION_NAME}_list_options, + gld_${EMULATION_NAME}_recognized_file, + gld_${EMULATION_NAME}_find_potential_libraries, + NULL /* new_vers_pattern. */ +}; +EOF diff --git a/ld/pe-dll.c b/ld/pe-dll.c index 0b783fbcba4..994af1402af 100644 --- a/ld/pe-dll.c +++ b/ld/pe-dll.c @@ -40,8 +40,30 @@ #include "coff/internal.h" #include "../bfd/libcoff.h" #include "deffile.h" + +#ifdef pe_use_x86_64 + +#define PE_IDATA4_SIZE 8 +#define PE_IDATA5_SIZE 8 +#include "pep-dll.h" +#undef AOUTSZ +#define AOUTSZ PEPAOUTSZ +#define PEAOUTHDR PEPAOUTHDR + +#else + #include "pe-dll.h" +#endif + +#ifndef PE_IDATA4_SIZE +#define PE_IDATA4_SIZE 4 +#endif + +#ifndef PE_IDATA5_SIZE +#define PE_IDATA5_SIZE 4 +#endif + /* 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 @@ -49,7 +71,7 @@ normally only called once, so static variables are used to reduce the number of parameters and return values required. - See also: ld/emultempl/pe.em. */ + See also: ld/emultempl/pe.em and ld/emultempl/pep.em. */ /* Auto-import feature by Paul Sokolovsky @@ -119,7 +141,7 @@ not, prohibiting that (detecting violation) would require more work on behalf of loader than not doing it. - See also: ld/emultempl/pe.em. */ + See also: ld/emultempl/pe.em and ld/emultempl/pep.em. */ static void add_bfd_to_link (bfd *, const char *, struct bfd_link_info *); @@ -212,9 +234,15 @@ static autofilter_entry_type autofilter_symbollist_i386[] = static pe_details_type pe_detail_list[] = { { +#ifdef pe_use_x86_64 + "pei-x86-64", + "pe-x86-64", + 3 /* R_IMAGEBASE */, +#else "pei-i386", "pe-i386", 7 /* R_IMAGEBASE */, +#endif PE_ARCH_i386, bfd_arch_i386, TRUE, @@ -480,6 +508,7 @@ auto_export (bfd *abfd, def_file *d, const char *n) it is too restrictive. Instead we have a target specific list to use: */ afptr = pe_details->autofilter_symbollist; + while (afptr->name) { if (strcmp (n, afptr->name) == 0) @@ -1214,6 +1243,12 @@ generate_reloc (bfd *abfd, struct bfd_link_info *info) switch BITS_AND_SHIFT (relocs[i]->howto->bitsize, relocs[i]->howto->rightshift) { +#ifdef pe_use_x86_64 + case BITS_AND_SHIFT (64, 0): + reloc_data[total_relocs].type = 10; + total_relocs++; + break; +#endif case BITS_AND_SHIFT (32, 0): reloc_data[total_relocs].type = 3; total_relocs++; @@ -1679,21 +1714,21 @@ make_head (bfd *parent) quick_reloc (abfd, 16, BFD_RELOC_RVA, 1); save_relocs (id2); - bfd_set_section_size (abfd, id5, 4); - d5 = xmalloc (4); + bfd_set_section_size (abfd, id5, PE_IDATA5_SIZE); + d5 = xmalloc (PE_IDATA5_SIZE); id5->contents = d5; - memset (d5, 0, 4); + memset (d5, 0, PE_IDATA5_SIZE); - bfd_set_section_size (abfd, id4, 4); - d4 = xmalloc (4); + bfd_set_section_size (abfd, id4, PE_IDATA4_SIZE); + d4 = xmalloc (PE_IDATA4_SIZE); id4->contents = d4; - memset (d4, 0, 4); + memset (d4, 0, PE_IDATA4_SIZE); bfd_set_symtab (abfd, symtab, symptr); bfd_set_section_contents (abfd, id2, d2, 0, 20); - bfd_set_section_contents (abfd, id5, d5, 0, 4); - bfd_set_section_contents (abfd, id4, d4, 0, 4); + bfd_set_section_contents (abfd, id5, d5, 0, PE_IDATA5_SIZE); + bfd_set_section_contents (abfd, id4, d4, 0, PE_IDATA4_SIZE); bfd_make_readable (abfd); return abfd; @@ -1701,8 +1736,10 @@ make_head (bfd *parent) /* .section .idata$4 .long 0 + [.long 0] for PE+ .section .idata$5 .long 0 + [.long 0] for PE+ .section idata$7 .global __my_dll_iname __my_dll_iname: @@ -1735,15 +1772,15 @@ make_tail (bfd *parent) 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, 4); - d4 = xmalloc (4); + bfd_set_section_size (abfd, id4, PE_IDATA4_SIZE); + d4 = xmalloc (PE_IDATA4_SIZE); id4->contents = d4; - memset (d4, 0, 4); + memset (d4, 0, PE_IDATA4_SIZE); - bfd_set_section_size (abfd, id5, 4); - d5 = xmalloc (4); + bfd_set_section_size (abfd, id5, PE_IDATA5_SIZE); + d5 = xmalloc (PE_IDATA5_SIZE); id5->contents = d5; - memset (d5, 0, 4); + memset (d5, 0, PE_IDATA5_SIZE); len = strlen (dll_filename) + 1; if (len & 1) @@ -1755,8 +1792,8 @@ make_tail (bfd *parent) bfd_set_symtab (abfd, symtab, symptr); - bfd_set_section_contents (abfd, id4, d4, 0, 4); - bfd_set_section_contents (abfd, id5, d5, 0, 4); + bfd_set_section_contents (abfd, id4, d4, 0, PE_IDATA4_SIZE); + bfd_set_section_contents (abfd, id5, d5, 0, PE_IDATA5_SIZE); bfd_set_section_contents (abfd, id7, d7, 0, len); bfd_make_readable (abfd); @@ -1943,16 +1980,16 @@ make_one (def_file_export *exp, bfd *parent) quick_reloc (abfd, 0, BFD_RELOC_RVA, 5); save_relocs (id7); - bfd_set_section_size (abfd, id5, 4); - d5 = xmalloc (4); + bfd_set_section_size (abfd, id5, PE_IDATA5_SIZE); + d5 = xmalloc (PE_IDATA5_SIZE); id5->contents = d5; - memset (d5, 0, 4); + memset (d5, 0, PE_IDATA5_SIZE); if (exp->flag_noname) { d5[0] = exp->ordinal; d5[1] = exp->ordinal >> 8; - d5[3] = 0x80; + d5[PE_IDATA5_SIZE - 1] = 0x80; } else { @@ -1960,16 +1997,16 @@ make_one (def_file_export *exp, bfd *parent) save_relocs (id5); } - bfd_set_section_size (abfd, id4, 4); - d4 = xmalloc (4); + bfd_set_section_size (abfd, id4, PE_IDATA4_SIZE); + d4 = xmalloc (PE_IDATA4_SIZE); id4->contents = d4; - memset (d4, 0, 4); + memset (d4, 0, PE_IDATA4_SIZE); if (exp->flag_noname) { d4[0] = exp->ordinal; d4[1] = exp->ordinal >> 8; - d4[3] = 0x80; + d4[PE_IDATA4_SIZE - 1] = 0x80; } else { @@ -2000,8 +2037,8 @@ make_one (def_file_export *exp, bfd *parent) 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, 4); - bfd_set_section_contents (abfd, id4, d4, 0, 4); + bfd_set_section_contents (abfd, id5, d5, 0, PE_IDATA5_SIZE); + bfd_set_section_contents (abfd, id4, d4, 0, PE_IDATA4_SIZE); if (!exp->flag_noname) bfd_set_section_contents (abfd, id6, d6, 0, len); @@ -2035,16 +2072,16 @@ make_singleton_name_thunk (const char *import, bfd *parent) 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 (4); + bfd_set_section_size (abfd, id4, PE_IDATA4_SIZE); + d4 = xmalloc (PE_IDATA4_SIZE); id4->contents = d4; - memset (d4, 0, 8); + memset (d4, 0, PE_IDATA4_SIZE); 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_set_section_contents (abfd, id4, d4, 0, PE_IDATA4_SIZE); bfd_make_readable (abfd); return abfd; @@ -2088,15 +2125,6 @@ make_import_fixup_mark (arelent *rel) 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; } @@ -2558,13 +2586,23 @@ pe_implied_import_dll (const char *filename) /* Get pe_header, optional header and numbers of export entries. */ pe_header_offset = pe_get32 (dll, 0x3c); opthdr_ofs = pe_header_offset + 4 + 20; +#ifdef pe_use_x86_64 + num_entries = pe_get32 (dll, opthdr_ofs + 92 + 4 * 4); /* & NumberOfRvaAndSizes. */ +#else num_entries = pe_get32 (dll, opthdr_ofs + 92); +#endif if (num_entries < 1) /* No exports. */ return FALSE; +#ifdef pe_use_x86_64 + export_rva = pe_get32 (dll, opthdr_ofs + 96 + 4 * 4); + export_size = pe_get32 (dll, opthdr_ofs + 100 + 4 * 4); +#else export_rva = pe_get32 (dll, opthdr_ofs + 96); export_size = pe_get32 (dll, opthdr_ofs + 100); +#endif + nsections = pe_get16 (dll, pe_header_offset + 4 + 2); secptr = (pe_header_offset + 4 + 20 + pe_get16 (dll, pe_header_offset + 4 + 16)); diff --git a/ld/pep-dll.c b/ld/pep-dll.c new file mode 100644 index 00000000000..27860b7d273 --- /dev/null +++ b/ld/pep-dll.c @@ -0,0 +1,57 @@ +/* Routines to help build PEPI-format DLLs (Win64 etc) + Copyright 2006 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 COFF_IMAGE_WITH_PE +#define COFF_WITH_PE +#define COFF_WITH_pex64 + +/* Local defined globals. */ +#define pe_def_file pep_def_file +#define pe_details pep_details +#define pe_dll_compat_implib pep_dll_compat_implib +#define pe_dll_extra_pe_debug pep_dll_extra_pe_debug +#define pe_dll_export_everything pep_dll_export_everything +#define pe_dll_do_default_excludes pep_dll_do_default_excludes +#define pe_dll_kill_ats pep_dll_kill_ats +#define pe_dll_stdcall_aliases pep_dll_stdcall_aliases +#define pe_dll_warn_dup_exports pep_dll_warn_dup_exports + +/* External globals. */ +#define pe_data_import_dll pep_data_import_dll + +/* Unique global name for functions to avoid double defined symbols. */ +#define pe_create_import_fixup pep_create_import_fixup +#define pe_dll_generate_def_file pep_dll_generate_def_file +#define pe_process_import_defs pep_process_import_defs +#define pe_dll_id_target pep_dll_id_target +#define pe_implied_import_dll pep_implied_import_dll +#define pe_dll_build_sections pep_dll_build_sections +#define pe_exe_build_sections pep_exe_build_sections +#define pe_dll_fill_sections pep_dll_fill_sections +#define pe_exe_fill_sections pep_exe_fill_sections +#define pe_dll_generate_implib pep_dll_generate_implib +#define pe_dll_add_excludes pep_dll_add_excludes +#define pe_walk_relocs_of_symbol pep_walk_relocs_of_symbol + +/* Uses x86_64 PE+. */ +#define pe_use_x86_64 + +#include "pe-dll.c" diff --git a/ld/pep-dll.h b/ld/pep-dll.h new file mode 100644 index 00000000000..bd1079868a0 --- /dev/null +++ b/ld/pep-dll.h @@ -0,0 +1,53 @@ +/* pep-dll.h: Header file for routines used to build Windows DLLs. + Copyright 2006 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 /* PEP_DLL_H */ diff --git a/ld/po/POTFILES.in b/ld/po/POTFILES.in index 5bb2e119c5b..3118cfa4b5f 100644 --- a/ld/po/POTFILES.in +++ b/ld/po/POTFILES.in @@ -28,3 +28,5 @@ mri.c mri.h pe-dll.c pe-dll.h +pep-dll.c +pep-dll.h diff --git a/ld/scripttempl/pep.sc b/ld/scripttempl/pep.sc new file mode 100644 index 00000000000..edad5ee8ecc --- /dev/null +++ b/ld/scripttempl/pep.sc @@ -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 <<EOF +${RELOCATING+OUTPUT_FORMAT(${OUTPUT_FORMAT})} +${RELOCATING-OUTPUT_FORMAT(${RELOCATEABLE_OUTPUT_FORMAT})} +${OUTPUT_ARCH+OUTPUT_ARCH(${OUTPUT_ARCH})} + +${LIB_SEARCH_DIRS} + +SECTIONS +{ + ${RELOCATING+/* Make the virtual address and file offset synced if the alignment is} + ${RELOCATING+ lower than the target page size. */} + ${RELOCATING+. = SIZEOF_HEADERS;} + ${RELOCATING+. = ALIGN(__section_alignment__);} + .text ${RELOCATING+ __image_base__ + ( __section_alignment__ < ${TARGET_PAGE_SIZE} ? . : __section_alignment__ )} : + { + ${RELOCATING+ *(.init)} + *(.text) + ${R_TEXT} + *(.glue_7t) + *(.glue_7) + ${CONSTRUCTING+ ___CTOR_LIST__ = .; __CTOR_LIST__ = . ; + LONG (-1);*(.ctors); *(.ctor); *(SORT(.ctors.*)); LONG (0); } + ${CONSTRUCTING+ ___DTOR_LIST__ = .; __DTOR_LIST__ = . ; + LONG (-1); *(.dtors); *(.dtor); *(SORT(.dtors.*)); LONG (0); } + ${RELOCATING+ *(.fini)} + /* ??? Why is .gcc_exc here? */ + ${RELOCATING+ *(.gcc_exc)} + ${RELOCATING+PROVIDE (etext = .);} + *(.gcc_except_table) + } + + /* The Cygwin32 library uses a section to avoid copying certain data + on fork. This used to be named ".data$nocopy". The linker used + to include this between __data_start__ and __data_end__, but that + breaks building the cygwin32 dll. Instead, we name the section + ".data_cygwin_nocopy" and explictly include it after __data_end__. */ + + .data ${RELOCATING+BLOCK(__section_alignment__)} : + { + ${RELOCATING+__data_start__ = . ;} + *(.data) + *(.data2) + ${R_DATA} + *(.jcr) + ${RELOCATING+__data_end__ = . ;} + ${RELOCATING+*(.data_cygwin_nocopy)} + } + + .rdata ${RELOCATING+BLOCK(__section_alignment__)} : + { + *(.rdata) + ${R_RDATA} + *(.eh_frame) + ${RELOCATING+___RUNTIME_PSEUDO_RELOC_LIST__ = .;} + ${RELOCATING+__RUNTIME_PSEUDO_RELOC_LIST__ = .;} + *(.rdata_runtime_pseudo_reloc) + ${RELOCATING+___RUNTIME_PSEUDO_RELOC_LIST_END__ = .;} + ${RELOCATING+__RUNTIME_PSEUDO_RELOC_LIST_END__ = .;} + } + + .pdata ${RELOCATING+BLOCK(__section_alignment__)} : + { + *(.pdata) + } + + .bss ${RELOCATING+BLOCK(__section_alignment__)} : + { + ${RELOCATING+__bss_start__ = . ;} + *(.bss) + *(COMMON) + ${RELOCATING+__bss_end__ = . ;} + } + + .edata ${RELOCATING+BLOCK(__section_alignment__)} : + { + *(.edata) + } + + /DISCARD/ : + { + *(.debug\$S) + *(.debug\$T) + *(.debug\$F) + *(.drectve) + } + + .idata ${RELOCATING+BLOCK(__section_alignment__)} : + { + /* This cannot currently be handled with grouped sections. + See pep.em:sort_sections. */ + ${R_IDATA} + } + .CRT ${RELOCATING+BLOCK(__section_alignment__)} : + { + ${RELOCATING+___crt_xc_start__ = . ;} + ${R_CRT_XC} + ${RELOCATING+___crt_xc_end__ = . ;} + ${RELOCATING+___crt_xi_start__ = . ;} + ${R_CRT_XI} + ${RELOCATING+___crt_xi_end__ = . ;} + ${RELOCATING+___crt_xl_start__ = . ;} + ${R_CRT_XL} + /* ___crt_xl_end__ is defined in the TLS Directory support code */ + ${RELOCATING+___crt_xp_start__ = . ;} + ${R_CRT_XP} + ${RELOCATING+___crt_xp_end__ = . ;} + ${RELOCATING+___crt_xt_start__ = . ;} + ${R_CRT_XT} + ${RELOCATING+___crt_xt_end__ = . ;} + } + + .tls ${RELOCATING+BLOCK(__section_alignment__)} : + { + ${RELOCATING+___tls_start__ = . ;} + ${R_TLS} + ${RELOCATING+___tls_end__ = . ;} + } + + .endjunk ${RELOCATING+BLOCK(__section_alignment__)} : + { + /* end is deprecated, don't use it */ + ${RELOCATING+PROVIDE (end = .);} + ${RELOCATING+PROVIDE ( _end = .);} + ${RELOCATING+ __end__ = .;} + } + + .rsrc ${RELOCATING+BLOCK(__section_alignment__)} : + { + *(.rsrc) + ${R_RSRC} + } + + .reloc ${RELOCATING+BLOCK(__section_alignment__)} : + { + *(.reloc) + } + + .stab ${RELOCATING+BLOCK(__section_alignment__)} ${RELOCATING+(NOLOAD)} : + { + *(.stab) + } + + .stabstr ${RELOCATING+BLOCK(__section_alignment__)} ${RELOCATING+(NOLOAD)} : + { + *(.stabstr) + } + + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section. Unlike other targets that fake this by putting the + section VMA at 0, the PE format will not allow it. */ + + /* DWARF 1.1 and DWARF 2. */ + .debug_aranges ${RELOCATING+BLOCK(__section_alignment__)} ${RELOCATING+(NOLOAD)} : + { + *(.debug_aranges) + } + + .debug_pubnames ${RELOCATING+BLOCK(__section_alignment__)} ${RELOCATING+(NOLOAD)} : + { + *(.debug_pubnames) + } + + /* DWARF 2. */ + .debug_info ${RELOCATING+BLOCK(__section_alignment__)} ${RELOCATING+(NOLOAD)} : + { + *(.debug_info) *(.gnu.linkonce.wi.*) + } + + .debug_abbrev ${RELOCATING+BLOCK(__section_alignment__)} ${RELOCATING+(NOLOAD)} : + { + *(.debug_abbrev) + } + + .debug_line ${RELOCATING+BLOCK(__section_alignment__)} ${RELOCATING+(NOLOAD)} : + { + *(.debug_line) + } + + .debug_frame ${RELOCATING+BLOCK(__section_alignment__)} ${RELOCATING+(NOLOAD)} : + { + *(.debug_frame) + } + + .debug_str ${RELOCATING+BLOCK(__section_alignment__)} ${RELOCATING+(NOLOAD)} : + { + *(.debug_str) + } + + .debug_loc ${RELOCATING+BLOCK(__section_alignment__)} ${RELOCATING+(NOLOAD)} : + { + *(.debug_loc) + } + + .debug_macinfo ${RELOCATING+BLOCK(__section_alignment__)} ${RELOCATING+(NOLOAD)} : + { + *(.debug_macinfo) + } + + /* SGI/MIPS DWARF 2 extensions. */ + .debug_weaknames ${RELOCATING+BLOCK(__section_alignment__)} ${RELOCATING+(NOLOAD)} : + { + *(.debug_weaknames) + } + + .debug_funcnames ${RELOCATING+BLOCK(__section_alignment__)} ${RELOCATING+(NOLOAD)} : + { + *(.debug_funcnames) + } + + .debug_typenames ${RELOCATING+BLOCK(__section_alignment__)} ${RELOCATING+(NOLOAD)} : + { + *(.debug_typenames) + } + + .debug_varnames ${RELOCATING+BLOCK(__section_alignment__)} ${RELOCATING+(NOLOAD)} : + { + *(.debug_varnames) + } + + /* DWARF 3. */ + .debug_ranges ${RELOCATING+BLOCK(__section_alignment__)} ${RELOCATING+(NOLOAD)} : + { + *(.debug_ranges) + } +} +EOF diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index cb0b2da3c48..6141f6718ff 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,15 @@ +2006-09-20 Kai Tietz <Kai.Tietz@onevision.com> + + * bootstrap/bootstrap.exp: Fix x86_64-mingw32 target test. + * ld-fastcall/fastcall.exp: Likewise. + * ld-scripts/align.exp: Likewise. + * ld-scripts/align2a.d: Likewise. + * ld-scripts/defined.exp: Likewise. + * ld-scripts/provide.exp: Likewise. + * ld-scripts/script.exp: Likewise. + * ld-scripts/weak.exp: Likewise. + * lib/ld-lib.exp: Detect target as pecoff file format. + 2006-09-18 Thiemo Seufer <ths@networkno.de> Maciej W. Rozycki <macro@mips.com> diff --git a/ld/testsuite/ld-bootstrap/bootstrap.exp b/ld/testsuite/ld-bootstrap/bootstrap.exp index 58cb9696513..d5ed9051150 100644 --- a/ld/testsuite/ld-bootstrap/bootstrap.exp +++ b/ld/testsuite/ld-bootstrap/bootstrap.exp @@ -1,5 +1,5 @@ # Expect script for LD Bootstrap Tests -# Copyright 1993, 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2004 +# Copyright 1993, 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2004, 2006 # Free Software Foundation, Inc. # # This file is free software; you can redistribute it and/or modify @@ -140,7 +140,7 @@ foreach flags {"" "strip" "--static" "--traditional-format" || [istarget "*-*-wince"] || [istarget "*-*-cygwin*"] || [istarget "*-*-winnt*"] - || [istarget "*-*-mingw32*"] + || [istarget "*-*-mingw*"] || [istarget "*-*-interix*"] || [istarget "*-*-beospe*"] || [istarget "*-*-netbsdpe*"]} { diff --git a/ld/testsuite/ld-fastcall/fastcall.exp b/ld/testsuite/ld-fastcall/fastcall.exp index 5f2e87e5914..30f0575cbb9 100644 --- a/ld/testsuite/ld-fastcall/fastcall.exp +++ b/ld/testsuite/ld-fastcall/fastcall.exp @@ -1,5 +1,5 @@ # Test that the linker can handle fastcall symbols correctly. -# Copyright 2002 Free Software Foundation, Inc. +# Copyright 2002, 2006 Free Software Foundation, Inc. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -17,13 +17,13 @@ set testname "ld (fastcall symbols)" -if {![istarget "i*86-*-*"]} { +if {![istarget "i*86-*-*"] && ![istarget "x86_64-*-mingw64*"] } { return } if { !([istarget "i*86-*-*pe*"] && ![istarget "i*86-*-opensd*"]) \ && ![istarget "i*86-*-cygwin*"] \ - && ![istarget "i*86-*-mingw32*"] } { + && ![istarget "i*86-*-mingw*"] } { return } diff --git a/ld/testsuite/ld-scripts/align.exp b/ld/testsuite/ld-scripts/align.exp index 43369d0b21e..25d4d3e176c 100644 --- a/ld/testsuite/ld-scripts/align.exp +++ b/ld/testsuite/ld-scripts/align.exp @@ -1,6 +1,6 @@ # Test ALIGN in a linker script. # By Nathan Sidwell, CodeSourcery LLC -# Copyright 2004, 2005 +# Copyright 2004, 2005, 2006 # Free Software Foundation, Inc. # # This file is free software; you can redistribute it and/or modify @@ -29,13 +29,20 @@ if ![ld_assemble $as $srcdir/$subdir/align.s tmpdir/align.o] { return } -# Doesn't work on PECOFF, appears to be a genuine bug -if [is_pecoff_format] { +# Doesn't work on PECOFF, appears to be a genuine bug. +# mingw64 targets need to set the image base to 0 to avoid auto image-basing. +global LDFLAGS +set saved_LDFLAGS "$LDFLAGS" +if [istarget "*-*-mingw64*"] then { + set LDFLAGS "$LDFLAGS --image-base 0" +} else { + if [is_pecoff_format] { global target_triplet setup_xfail $target_triplet + } } -if ![ld_simple_link $ld tmpdir/align "-T $srcdir/$subdir/align.t tmpdir/align.o"] { +if ![ld_simple_link $ld tmpdir/align "$LDFLAGS -T $srcdir/$subdir/align.t tmpdir/align.o"] { fail $testname } else { pass $testname @@ -50,3 +57,4 @@ if ![is_aout_format] { run_dump_test align2b } run_dump_test align2c +set LDFLAGS "$saved_LDFLAGS" diff --git a/ld/testsuite/ld-scripts/align2a.d b/ld/testsuite/ld-scripts/align2a.d index d45cf0e631b..96237dd72f7 100644 --- a/ld/testsuite/ld-scripts/align2a.d +++ b/ld/testsuite/ld-scripts/align2a.d @@ -5,8 +5,8 @@ Sections: Idx +Name +Size +VMA +LMA +File +off +Algn - +0 +\.text +[^ ]* +0+ +0+ .* - +CONTENTS, +ALLOC, +LOAD,.* CODE - +1 +\.data +[^ ]* +0+10 +0+10 .* - +CONTENTS, +ALLOC, +LOAD, +DATA +[ ]+0 +\.text +[^ ]* +0+ +0+ .* +[ ]+CONTENTS, +ALLOC, +LOAD,.* CODE +[ ]+1 +\.data +[^ ]* +0+10 +0+10 .* +[ ]+CONTENTS, +ALLOC, +LOAD, +DATA #pass diff --git a/ld/testsuite/ld-scripts/defined.exp b/ld/testsuite/ld-scripts/defined.exp index dff238b1f89..d02b9099036 100644 --- a/ld/testsuite/ld-scripts/defined.exp +++ b/ld/testsuite/ld-scripts/defined.exp @@ -1,6 +1,6 @@ # Test DEFINED in a linker script. # By Ian Lance Taylor, Cygnus Support. -# Copyright 2001, 2003 +# Copyright 2001, 2003. 2006 # Free Software Foundation, Inc. # # This file is free software; you can redistribute it and/or modify @@ -25,7 +25,13 @@ if ![ld_assemble $as $srcdir/$subdir/defined.s tmpdir/def.o] { return } -if ![ld_simple_link $ld tmpdir/def "-T $srcdir/$subdir/defined.t tmpdir/def.o"] { +global LDFLAGS +set saved_LDFLAGS "$LDFLAGS" +if [istarget "*-*-mingw64*"] then { + set LDFLAGS "$LDFLAGS --image-base 0" +} + +if ![ld_simple_link $ld tmpdir/def "$LDFLAGS -T $srcdir/$subdir/defined.t tmpdir/def.o"] { fail $testname } else { if ![ld_nm $nm "" tmpdir/def] { @@ -57,3 +63,4 @@ if ![ld_simple_link $ld tmpdir/def "-T $srcdir/$subdir/defined.t tmpdir/def.o"] set prms_id 0 run_dump_test "defined2" run_dump_test "defined3" +set LDFLAGS "$saved_LDFLAGS" diff --git a/ld/testsuite/ld-scripts/provide.exp b/ld/testsuite/ld-scripts/provide.exp index 7e2c0e7e01d..7d755a048b0 100644 --- a/ld/testsuite/ld-scripts/provide.exp +++ b/ld/testsuite/ld-scripts/provide.exp @@ -1,6 +1,6 @@ # Test PROVIDE in a linker script. # By Nathan Sidwell, CodeSourcery LLC -# Copyright 2004 +# Copyright 2004, 2006 # Free Software Foundation, Inc. # # This file is free software; you can redistribute it and/or modify @@ -29,7 +29,15 @@ if {[istarget "rs6000-*-aix*"] || [is_aout_format]} { return } +global LDFLAGS +set saved_LDFLAGS "$LDFLAGS" +if [istarget "*-*-mingw64*"] then { + set LDFLAGS "$LDFLAGS --image-base 0" +} + run_dump_test provide-1 run_dump_test provide-2 setup_xfail *-*-* run_dump_test provide-3 + +set LDFLAGS "$saved_LDFLAGS" diff --git a/ld/testsuite/ld-scripts/script.exp b/ld/testsuite/ld-scripts/script.exp index bf7b1b1dc91..6bb8c9cee27 100644 --- a/ld/testsuite/ld-scripts/script.exp +++ b/ld/testsuite/ld-scripts/script.exp @@ -1,6 +1,6 @@ # Test basic linker script functionality # By Ian Lance Taylor, Cygnus Support -# Copyright 1999, 2000, 2001, 2002, 2004 +# Copyright 1999, 2000, 2001, 2002, 2004, 2006 # Free Software Foundation, Inc. # # This file is free software; you can redistribute it and/or modify @@ -95,7 +95,7 @@ proc check_script { } { set flags "" if {[istarget "*-*-pe*"] \ || [istarget "*-*-cygwin*"] \ - || [istarget "*-*-mingw32*"] \ + || [istarget "*-*-mingw*"] \ || [istarget "*-*-winnt*"] \ || [istarget "*-*-nt"] \ || [istarget "*-*-interix*"] } then { @@ -123,5 +123,3 @@ if ![ld_simple_link $ld tmpdir/script "$flags -T $srcdir/$subdir/memory.t tmpdir } else { check_script } - - diff --git a/ld/testsuite/ld-scripts/weak.exp b/ld/testsuite/ld-scripts/weak.exp index 925c812c7e0..9ea9ff6c923 100644 --- a/ld/testsuite/ld-scripts/weak.exp +++ b/ld/testsuite/ld-scripts/weak.exp @@ -1,6 +1,6 @@ # Test weak symbols. # By Ian Lance Taylor, Cygnus Solutions. -# Copyright 1999, 2000, 2002, 2004 +# Copyright 1999, 2000, 2002, 2004, 2006 # Free Software Foundation, Inc. # # This file is free software; you can redistribute it and/or modify @@ -29,6 +29,7 @@ if {! [is_elf_format] && ! [is_pecoff_format]} { # Weak symbols are broken for non-i386 PE targets. if {! [istarget i?86-*-*]} { setup_xfail *-*-pe* + setup_xfail *-*-mingw64* } # hppa64 and or32 are incredibly broken @@ -41,6 +42,12 @@ if {! [ld_assemble $as $srcdir/$subdir/weak1.s tmpdir/weak1.o] return } +global LDFLAGS +set saved_LDFLAGS "$LDFLAGS" +if [istarget "*-*-mingw64*"] then { + set LDFLAGS "$LDFLAGS --image-base 0" +} + set weak_regexp_big \ ".*Contents of section .text:.*1000 00001008 0000200c 12121212 34343434.*Contents of section .data:.*2000 00001008 0000200c 56565656 78787878.*" @@ -52,6 +59,7 @@ if {! [ld_simple_link $ld tmpdir/weak "$flags -T $srcdir/$subdir/weak.t tmpdir/w } else { if {[which $objdump] == 0} then { unresolved $testname + set LDFLAGS "$saved_LDFLAGS" return } @@ -67,3 +75,5 @@ if {! [ld_simple_link $ld tmpdir/weak "$flags -T $srcdir/$subdir/weak.t tmpdir/w fail $testname } } + +set LDFLAGS "$saved_LDFLAGS" |