From c60b3806799abf1d7f6cf5108a1b0e733a950b13 Mon Sep 17 00:00:00 2001 From: Jedidiah Thompson Date: Wed, 19 Oct 2022 10:57:12 +0200 Subject: aarch64-pe support for LD, GAS and BFD Allows aarch64-pe to be targeted natively, not having to use objcopy to convert it from ELF to PE. Based on initial work by Jedidiah Thompson Co-authored-by: Jedidiah Thompson Co-authored-by: Zac Walker --- ld/Makefile.am | 1 + ld/Makefile.in | 1 + ld/configure.tgt | 6 +++++- ld/emulparams/aarch64pe.sh | 9 +++++++++ ld/emultempl/pep.em | 10 +++++++++- ld/pe-dll.c | 44 ++++++++++++++++++++++++++++++++--------- ld/pep-dll-aarch64.c | 23 +++++++++++++++++++++ ld/pep-dll-x86_64.c | 22 +++++++++++++++++++++ ld/pep-dll.c | 5 ++--- ld/testsuite/ld-pe/pe-aarch64.d | 16 +++++++++++++++ ld/testsuite/ld-pe/pe-aarch64.s | 11 +++++++++++ ld/testsuite/ld-pe/pe.exp | 5 +++++ 12 files changed, 139 insertions(+), 14 deletions(-) create mode 100644 ld/emulparams/aarch64pe.sh create mode 100644 ld/pep-dll-aarch64.c create mode 100644 ld/pep-dll-x86_64.c create mode 100644 ld/testsuite/ld-pe/pe-aarch64.d create mode 100644 ld/testsuite/ld-pe/pe-aarch64.s (limited to 'ld') diff --git a/ld/Makefile.am b/ld/Makefile.am index bbe25f3..b4ec47a 100644 --- a/ld/Makefile.am +++ b/ld/Makefile.am @@ -377,6 +377,7 @@ ALL_EMULATIONS = $(ALL_EMULATION_SOURCES:.c=.@OBJEXT@) ALL_64_EMULATION_SOURCES = \ eaarch64cloudabi.c \ eaarch64cloudabib.c \ + eaarch64pe.c \ eaarch64elf.c \ eaarch64elf32.c \ eaarch64elf32b.c \ diff --git a/ld/Makefile.in b/ld/Makefile.in index 400eed2..21d7edb 100644 --- a/ld/Makefile.in +++ b/ld/Makefile.in @@ -887,6 +887,7 @@ ALL_64_EMULATION_SOURCES = \ eaarch64linux32.c \ eaarch64linux32b.c \ eaarch64linuxb.c \ + eaarch64pe.c \ eelf32_x86_64.c \ eelf32b4300.c \ eelf32bmip.c \ diff --git a/ld/configure.tgt b/ld/configure.tgt index 2bae909..9763988 100644 --- a/ld/configure.tgt +++ b/ld/configure.tgt @@ -117,6 +117,10 @@ aarch64-*-linux*) targ_emul=aarch64linux aarch64-*-haiku*) targ_emul=aarch64haiku targ_extra_emuls="aarch64elf aarch64elf32 aarch64elf32b aarch64elfb armelf armelfb armelf_haiku $targ_extra_libpath" ;; +aarch64-*-pe*) + targ_emul=aarch64pe + targ_extra_ofiles="deffilep.o pep-dll-aarch64.o" + ;; alpha*-*-freebsd* | alpha*-*-kfreebsd*-gnu) targ_emul=elf64alpha_fbsd targ_extra_emuls="elf64alpha alpha" @@ -1042,7 +1046,7 @@ x86_64-*-freebsd* | x86_64-*-kfreebsd*-gnu) ;; x86_64-*-pe | x86_64-*-pep) targ_emul=i386pep ; targ_extra_emuls=i386pe ; - targ_extra_ofiles="deffilep.o pep-dll.o pe-dll.o" + targ_extra_ofiles="deffilep.o pep-dll-x86_64.o pe-dll.o" ;; x86_64-*-cygwin) targ_emul=i386pep ; targ_extra_emuls=i386pe diff --git a/ld/emulparams/aarch64pe.sh b/ld/emulparams/aarch64pe.sh new file mode 100644 index 0000000..02bf02c --- /dev/null +++ b/ld/emulparams/aarch64pe.sh @@ -0,0 +1,9 @@ +ARCH="aarch64" +SCRIPT_NAME=pep +OUTPUT_FORMAT="pei-aarch64-little" +RELOCATEABLE_OUTPUT_FORMAT="pe-aarch64-little" +TEMPLATE_NAME=pep +SUBSYSTEM=PE_DEF_SUBSYSTEM +INITIAL_SYMBOL_CHAR=\"_\" +TARGET_PAGE_SIZE=0x1000 +GENERATE_AUTO_IMPORT_SCRIPT=1 diff --git a/ld/emultempl/pep.em b/ld/emultempl/pep.em index d94f18b..7a390e7 100644 --- a/ld/emultempl/pep.em +++ b/ld/emultempl/pep.em @@ -48,7 +48,11 @@ fragment <howto->bitsize, relocs[i]->howto->rightshift) { -#ifdef pe_use_x86_64 +#ifdef pe_use_plus case BITS_AND_SHIFT (64, 0): reloc_data[total_relocs].type = IMAGE_REL_BASED_DIR64; total_relocs++; @@ -2248,6 +2258,15 @@ static const unsigned char jmp_ix86_bytes[] = }; /* _function: + b <__imp_function> + nop */ +static const unsigned char jmp_aarch64_bytes[] = +{ + 0x00, 0x00, 0x00, 0x14, + 0x1f, 0x20, 0x03, 0xD5 +}; + +/* _function: mov.l ip+8,r0 mov.l @r0,r0 jmp @r0 @@ -2317,6 +2336,10 @@ make_one (def_file_export *exp, bfd *parent, bool include_jmp_stub) jmp_bytes = jmp_arm_bytes; jmp_byte_count = sizeof (jmp_arm_bytes); break; + case PE_ARCH_aarch64: + jmp_bytes = jmp_aarch64_bytes; + jmp_byte_count = sizeof (jmp_aarch64_bytes); + break; default: abort (); } @@ -2386,7 +2409,7 @@ make_one (def_file_export *exp, bfd *parent, bool include_jmp_stub) switch (pe_details->pe_arch) { case PE_ARCH_i386: -#ifdef pe_use_x86_64 +#ifdef pe_use_plus quick_reloc (abfd, 2, BFD_RELOC_32_PCREL, 2); #else /* Mark this object as SAFESEH compatible. */ @@ -2407,6 +2430,9 @@ make_one (def_file_export *exp, bfd *parent, bool include_jmp_stub) case PE_ARCH_arm_wince: quick_reloc (abfd, 8, BFD_RELOC_32, 2); break; + case PE_ARCH_aarch64: + quick_reloc (abfd, 0, BFD_RELOC_AARCH64_JUMP26, 2); + break; default: abort (); } @@ -3406,7 +3432,7 @@ pe_implied_import_dll (const char *filename) /* Get pe_header, optional header and numbers of directory entries. */ pe_header_offset = pe_get32 (dll, 0x3c); opthdr_ofs = pe_header_offset + 4 + 20; -#ifdef pe_use_x86_64 +#ifdef pe_use_plus num_entries = pe_get32 (dll, opthdr_ofs + 92 + 4 * 4); /* & NumberOfRvaAndSizes. */ #else num_entries = pe_get32 (dll, opthdr_ofs + 92); @@ -3416,7 +3442,7 @@ pe_implied_import_dll (const char *filename) if (num_entries < 1) return false; -#ifdef pe_use_x86_64 +#ifdef pe_use_plus export_rva = pe_get32 (dll, opthdr_ofs + 96 + 4 * 4); export_size = pe_get32 (dll, opthdr_ofs + 100 + 4 * 4); #else diff --git a/ld/pep-dll-aarch64.c b/ld/pep-dll-aarch64.c new file mode 100644 index 0000000..61c9a2a --- /dev/null +++ b/ld/pep-dll-aarch64.c @@ -0,0 +1,23 @@ +/* Tiny wrapper over pep-dll.c + Copyright (C) 2006-2022 Free Software Foundation, Inc. + + This file is part of the GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#define COFF_WITH_peAArch64 + +#include "pep-dll.c" diff --git a/ld/pep-dll-x86_64.c b/ld/pep-dll-x86_64.c new file mode 100644 index 0000000..0be1898 --- /dev/null +++ b/ld/pep-dll-x86_64.c @@ -0,0 +1,22 @@ +/* Tiny wrapper over pep-dll.c + Copyright (C) 2006-2022 Free Software Foundation, Inc. + This file is part of the GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#define COFF_WITH_pex64 + +#include "pep-dll.c" diff --git a/ld/pep-dll.c b/ld/pep-dll.c index 3049a02..1cfed49 100644 --- a/ld/pep-dll.c +++ b/ld/pep-dll.c @@ -21,7 +21,6 @@ #define COFF_IMAGE_WITH_PE #define COFF_WITH_PE -#define COFF_WITH_pex64 /* Local defined globals. */ #define pe_def_file pep_def_file @@ -58,7 +57,7 @@ #define pe_output_file_set_long_section_names \ pep_output_file_set_long_section_names -/* Uses x86_64 PE+. */ -#define pe_use_x86_64 +/* Uses PE+. */ +#define pe_use_plus #include "pe-dll.c" diff --git a/ld/testsuite/ld-pe/pe-aarch64.d b/ld/testsuite/ld-pe/pe-aarch64.d new file mode 100644 index 0000000..fac02b5 --- /dev/null +++ b/ld/testsuite/ld-pe/pe-aarch64.d @@ -0,0 +1,16 @@ +#ld: +#objdump: -d + +.*: file format pei-aarch64-little + + +Disassembly of section .text: + +0000000140001000 <__rt_psrelocs_end>: + 140001000: d2800281 mov x1, #0x14 // #20 + 140001004: 14000001 b 140001008 + +0000000140001008 : + 140001008: d65f03c0 ret + 14000100c: 00000000 udf #0 +#... diff --git a/ld/testsuite/ld-pe/pe-aarch64.s b/ld/testsuite/ld-pe/pe-aarch64.s new file mode 100644 index 0000000..5d49350 --- /dev/null +++ b/ld/testsuite/ld-pe/pe-aarch64.s @@ -0,0 +1,11 @@ +# A little test to ensure pe-aarch64 is working in LD. +# Currently, the poor pe-aarch64 implementation in binutils +# couldn't do anything useful, hence, this test is rather short + +.section .text + +_start: + mov x1, 20 + b foo +foo: + ret diff --git a/ld/testsuite/ld-pe/pe.exp b/ld/testsuite/ld-pe/pe.exp index 22819e0..d8595ee 100644 --- a/ld/testsuite/ld-pe/pe.exp +++ b/ld/testsuite/ld-pe/pe.exp @@ -78,6 +78,11 @@ if {[istarget i*86-*-cygwin*] run_ld_link_tests $pe_tests } +if {[istarget "aarch64-*-pe*"]} { + run_dump_test "pe-aarch64" +} + + run_dump_test "image_size" run_dump_test "export_dynamic_warning" -- cgit v1.1