[edk2,RFC,2/4] BaseTools: AArch64: use an explicit linker script

Message ID 1435073455-3268-3-git-send-email-ard.biesheuvel@linaro.org
State New
Headers show

Commit Message

Ard Biesheuvel June 23, 2015, 3:30 p.m.
Instead of relying on the builtin linker script of GNU ld, which
may vary based on binutils version (which is not tightly coupled to
the GCC version) and linker command line options, introduce a linker
script for AArch64 to be used by all GCC/binutils versions.

The script is laid out such that both the file and memory layout
are identical between the ELF intermediate file and the final
PE/COFF file. This should prevent problems with debuggers and other
tooling that are ELF based.
It also places the .text section such that, provided that the entire
image is loaded at a 4 KB aligned offset, the build time and runtime
relative alignment with respect to the nearest 4 KB boundary is the
same. This allows the 'small' GCC C model to be used.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 BaseTools/Conf/tools_def.template       | 23 +++++++++++++----------
 BaseTools/Scripts/gcc-aarch64-ld-script | 33 +++++++++++++++++++++++++++++++++
 2 files changed, 46 insertions(+), 10 deletions(-)

Comments

Ard Biesheuvel June 24, 2015, 3:27 p.m. | #1
On 24 June 2015 at 17:21, Cohen, Eugene <eugene@hp.com> wrote:
>> +   * Since some AArch64 code is aligned to 0x800 (i.e., the vector table), we
>> +   * need to use at least this alignment for .text.
>
> >From what I can see the vector table code uses .align directives to increase the alignment size which is propagated into the resulting ELF.  The PE-COFF conversion respects this so I don't believe it is necessary to impose this alignment requirement.
>
> We are very sensitive to code size in SEC and PEI which are typically uncompressed and XIP so I would ask that we keep the alignment padding to a minimum (see Andrew's email about this topic).
>

Indeed. If we end up agreeing that using the small C model has its
merits, we would ideally implement it in the following way:
- use 'large' C model for SEC and PEI, with the smallest alignment
that we can support
- use 'small' C model for boot time modules, using the linker script
in this patch
- use 'small' C model and 64 KB alignment (with an alternative linker
script) for runtime modules, so that we can benefit from the
Properties Table feature, which allows code regions to be mapped R-X
and data regions to be mapped RW-

I know this is a it of a jumble of related but not entirely similar
issues. I was just triggered by your patch, and decided to experiment
and come up with something that addresses all these issues.

Patch hide | download patch | download mbox

diff --git a/BaseTools/Conf/tools_def.template b/BaseTools/Conf/tools_def.template
index fd7b4b55e8ba..9ba8d38a1791 100644
--- a/BaseTools/Conf/tools_def.template
+++ b/BaseTools/Conf/tools_def.template
@@ -3821,9 +3821,12 @@  DEFINE GCC_ARM_CC_FLAGS            = DEF(GCC_ALL_CC_FLAGS) -mword-relocations -m
 DEFINE GCC_AARCH64_CC_FLAGS        = DEF(GCC_ALL_CC_FLAGS) -mcmodel=large -mlittle-endian -fno-short-enums -save-temps -fverbose-asm -fsigned-char  -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-builtin -Wno-address
 DEFINE GCC_DLINK_FLAGS_COMMON      = -nostdlib --pie
 DEFINE GCC_IA32_X64_DLINK_COMMON   = DEF(GCC_DLINK_FLAGS_COMMON) --gc-sections
-DEFINE GCC_ARM_AARCH64_DLINK_COMMON= -Ttext=0x0 --emit-relocs -nostdlib --gc-sections -u $(IMAGE_ENTRY_POINT) -e $(IMAGE_ENTRY_POINT) -Map $(DEST_DIR_DEBUG)/$(BASE_NAME).map
+DEFINE GCC_ARM_AARCH64_DLINK_COMMON= --emit-relocs -nostdlib --gc-sections -u $(IMAGE_ENTRY_POINT) -e $(IMAGE_ENTRY_POINT) -Map $(DEST_DIR_DEBUG)/$(BASE_NAME).map
+DEFINE GCC_ARM_DLINK_FLAGS         = DEF(GCC_ARM_AARCH64_DLINK_COMMON) -Ttext=0x0
+DEFINE GCC_AARCH64_DLINK_FLAGS     = DEF(GCC_ARM_AARCH64_DLINK_COMMON) --script=$(EDK_TOOLS_PATH)/Scripts/gcc-aarch64-ld-script
 DEFINE GCC_IA32_X64_ASLDLINK_FLAGS = DEF(GCC_IA32_X64_DLINK_COMMON) --entry _ReferenceAcpiTable -u $(IMAGE_ENTRY_POINT)
-DEFINE GCC_ARM_AARCH64_ASLDLINK_FLAGS = DEF(GCC_ARM_AARCH64_DLINK_COMMON) --entry ReferenceAcpiTable -u $(IMAGE_ENTRY_POINT)
+DEFINE GCC_ARM_ASLDLINK_FLAGS      = DEF(GCC_ARM_DLINK_FLAGS) --entry ReferenceAcpiTable -u $(IMAGE_ENTRY_POINT)
+DEFINE GCC_AARCH64_ASLDLINK_FLAGS  = DEF(GCC_AARCH64_DLINK_FLAGS) --entry ReferenceAcpiTable -u $(IMAGE_ENTRY_POINT)
 DEFINE GCC_IA32_X64_DLINK_FLAGS    = DEF(GCC_IA32_X64_DLINK_COMMON) --entry _$(IMAGE_ENTRY_POINT) --file-alignment 0x20 --section-alignment 0x20 -Map $(DEST_DIR_DEBUG)/$(BASE_NAME).map
 DEFINE GCC_IPF_DLINK_FLAGS         = -nostdlib -O2 --gc-sections --dll -static --entry $(IMAGE_ENTRY_POINT) --undefined $(IMAGE_ENTRY_POINT) -Map $(DEST_DIR_DEBUG)/$(BASE_NAME).map
 DEFINE GCC_IPF_OBJCOPY_FLAGS       = -I elf64-ia64-little -O efi-bsdrv-ia64
@@ -3866,8 +3869,8 @@  DEFINE GCC46_X64_DLINK_FLAGS         = DEF(GCC45_X64_DLINK_FLAGS)
 DEFINE GCC46_ASM_FLAGS               = DEF(GCC45_ASM_FLAGS)
 DEFINE GCC46_ARM_ASM_FLAGS           = $(ARCHASM_FLAGS) $(PLATFORM_FLAGS) DEF(GCC_ASM_FLAGS) -mlittle-endian
 DEFINE GCC46_ARM_CC_FLAGS            = $(ARCHCC_FLAGS) $(PLATFORM_FLAGS) DEF(GCC44_ALL_CC_FLAGS) DEF(GCC_ARM_CC_FLAGS) -fstack-protector
-DEFINE GCC46_ARM_DLINK_FLAGS         = DEF(GCC_ARM_AARCH64_DLINK_COMMON) --oformat=elf32-littlearm
-DEFINE GCC46_ARM_ASLDLINK_FLAGS      = DEF(GCC_ARM_AARCH64_ASLDLINK_FLAGS) --oformat=elf32-littlearm
+DEFINE GCC46_ARM_DLINK_FLAGS         = DEF(GCC_ARM_DLINK_FLAGS) --oformat=elf32-littlearm
+DEFINE GCC46_ARM_ASLDLINK_FLAGS      = DEF(GCC_ARM_ASLDLINK_FLAGS) --oformat=elf32-littlearm
 
 DEFINE GCC47_IA32_CC_FLAGS           = DEF(GCC46_IA32_CC_FLAGS)
 DEFINE GCC47_X64_CC_FLAGS            = DEF(GCC46_X64_CC_FLAGS)
@@ -3881,9 +3884,9 @@  DEFINE GCC47_AARCH64_ASM_FLAGS       = $(ARCHASM_FLAGS) $(PLATFORM_FLAGS) DEF(GC
 DEFINE GCC47_ARM_CC_FLAGS            = DEF(GCC46_ARM_CC_FLAGS) -mno-unaligned-access
 DEFINE GCC47_AARCH64_CC_FLAGS        = $(ARCHCC_FLAGS) $(PLATFORM_FLAGS) DEF(GCC44_ALL_CC_FLAGS) DEF(GCC_AARCH64_CC_FLAGS)
 DEFINE GCC47_ARM_DLINK_FLAGS         = DEF(GCC46_ARM_DLINK_FLAGS)
-DEFINE GCC47_AARCH64_DLINK_FLAGS     = DEF(GCC_ARM_AARCH64_DLINK_COMMON)
+DEFINE GCC47_AARCH64_DLINK_FLAGS     = DEF(GCC_AARCH64_DLINK_FLAGS)
 DEFINE GCC47_ARM_ASLDLINK_FLAGS      = DEF(GCC46_ARM_ASLDLINK_FLAGS)
-DEFINE GCC47_AARCH64_ASLDLINK_FLAGS  = DEF(GCC_ARM_AARCH64_ASLDLINK_FLAGS)
+DEFINE GCC47_AARCH64_ASLDLINK_FLAGS  = DEF(GCC_AARCH64_ASLDLINK_FLAGS)
 
 DEFINE GCC48_IA32_CC_FLAGS           = DEF(GCC47_IA32_CC_FLAGS)
 DEFINE GCC48_X64_CC_FLAGS            = DEF(GCC47_X64_CC_FLAGS)
@@ -3897,9 +3900,9 @@  DEFINE GCC48_AARCH64_ASM_FLAGS       = DEF(GCC47_AARCH64_ASM_FLAGS)
 DEFINE GCC48_ARM_CC_FLAGS            = DEF(GCC47_ARM_CC_FLAGS)
 DEFINE GCC48_AARCH64_CC_FLAGS        = DEF(GCC47_AARCH64_CC_FLAGS)
 DEFINE GCC48_ARM_DLINK_FLAGS         = DEF(GCC47_ARM_DLINK_FLAGS)
-DEFINE GCC48_AARCH64_DLINK_FLAGS     = DEF(GCC_ARM_AARCH64_DLINK_COMMON)
+DEFINE GCC48_AARCH64_DLINK_FLAGS     = DEF(GCC47_AARCH64_DLINK_FLAGS)
 DEFINE GCC48_ARM_ASLDLINK_FLAGS      = DEF(GCC47_ARM_ASLDLINK_FLAGS)
-DEFINE GCC48_AARCH64_ASLDLINK_FLAGS  = DEF(GCC_ARM_AARCH64_ASLDLINK_FLAGS)
+DEFINE GCC48_AARCH64_ASLDLINK_FLAGS  = DEF(GCC47_AARCH64_ASLDLINK_FLAGS)
 
 DEFINE GCC49_IA32_CC_FLAGS           = DEF(GCC48_IA32_CC_FLAGS)
 DEFINE GCC49_X64_CC_FLAGS            = DEF(GCC48_X64_CC_FLAGS)
@@ -3913,9 +3916,9 @@  DEFINE GCC49_AARCH64_ASM_FLAGS       = DEF(GCC48_AARCH64_ASM_FLAGS)
 DEFINE GCC49_ARM_CC_FLAGS            = DEF(GCC48_ARM_CC_FLAGS)
 DEFINE GCC49_AARCH64_CC_FLAGS        = DEF(GCC48_AARCH64_CC_FLAGS)
 DEFINE GCC49_ARM_DLINK_FLAGS         = DEF(GCC48_ARM_DLINK_FLAGS)
-DEFINE GCC49_AARCH64_DLINK_FLAGS     = DEF(GCC_ARM_AARCH64_DLINK_COMMON)
+DEFINE GCC49_AARCH64_DLINK_FLAGS     = DEF(GCC48_AARCH64_DLINK_FLAGS)
 DEFINE GCC49_ARM_ASLDLINK_FLAGS      = DEF(GCC48_ARM_ASLDLINK_FLAGS)
-DEFINE GCC49_AARCH64_ASLDLINK_FLAGS  = DEF(GCC_ARM_AARCH64_ASLDLINK_FLAGS)
+DEFINE GCC49_AARCH64_ASLDLINK_FLAGS  = DEF(GCC48_AARCH64_ASLDLINK_FLAGS)
 
 ####################################################################################
 #
diff --git a/BaseTools/Scripts/gcc-aarch64-ld-script b/BaseTools/Scripts/gcc-aarch64-ld-script
new file mode 100644
index 000000000000..cf09b63d916f
--- /dev/null
+++ b/BaseTools/Scripts/gcc-aarch64-ld-script
@@ -0,0 +1,33 @@ 
+SECTIONS {
+
+  /*
+   * By positioning the .text section at 0x800, and aligning it at 0x800, it
+   * is guaranteed to end up at 0x800 offset in the resulting PE/COFF image as
+   * well. This allows us to use GCC's 'small' C model, which uses PC relative
+   * ADRP/ADD and ADRP/LDR pairs to reference global symbols, instead of 64-bit
+   * absolute addresses.
+   * Since some AArch64 code is aligned to 0x800 (i.e., the vector table), we
+   * need to use at least this alignment for .text. The actual PE/COFF headers
+   * are only around 0x260 bytes in size, so we are wasting around 1.5 KB here.
+   */
+  .text 0x800 : ALIGN(0x800) {
+    *(.text .text.* .rodata .rodata.*)
+  }
+  .data : ALIGN(0x40) {
+    *(.data .data.*)
+    *(.bss .bss.* *COM*)
+  }
+  .rela ALIGN(0x20) : {
+    *(.rela .rela.*)
+  }
+
+  /DISCARD/ : {
+    *(.note.GNU-stack)
+    *(.interp)
+    *(.dynsym)
+    *(.dynstr)
+    *(.dynamic)
+    *(.hash)
+    *(.comment)
+  }
+}