Discussion:
[edk2] [RFC PATCH 1/4] BaseTools: AArch64: conditionally allow page-based PC relative relocations
Ard Biesheuvel
2015-06-23 15:30:52 UTC
Permalink
This updates GenFw's ELF conversion for AArch64 so that relocation pairs
that operate on ADRP/ADD, ADRP/LDR or ADRP/STR instruction combinations
are allowed under the following conditions:
- the relative alignment to the nearest 4 KB boundary of the target of the
relocation must be identical between the ELF and the PE/COFF versions of
the binary;
- the offset between the relocation target and the symbol it refers to is
identical between the ELF and the PE/COFF versions, even if the symbol
lives in another section.

These two conditions can be met by using a carefully crafted GNU ld script
that reflects the placement logic of GenFw. Note that such binaries need
to be loaded at a 4 KB aligned load address.

This is a preliminary step towards allowing AArch64 binaries to be built
with the standard 'small' C model.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ard Biesheuvel <***@linaro.org>
---
BaseTools/Source/C/GenFw/Elf64Convert.c | 51 +++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 41 insertions(+), 10 deletions(-)

diff --git a/BaseTools/Source/C/GenFw/Elf64Convert.c b/BaseTools/Source/C/GenFw/Elf64Convert.c
index 25b90e2f7b51..2266e487cec7 100644
--- a/BaseTools/Source/C/GenFw/Elf64Convert.c
+++ b/BaseTools/Source/C/GenFw/Elf64Convert.c
@@ -734,13 +734,33 @@ WriteSections64 (
break;

case R_AARCH64_ADR_PREL_PG_HI21:
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADR_PREL_PG_HI21.", mInImageName);
- break;
-
case R_AARCH64_ADD_ABS_LO12_NC:
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADD_ABS_LO12_NC.", mInImageName);
+ case R_AARCH64_LDST8_ABS_LO12_NC:
+ case R_AARCH64_LDST16_ABS_LO12_NC:
+ case R_AARCH64_LDST32_ABS_LO12_NC:
+ case R_AARCH64_LDST64_ABS_LO12_NC:
+ case R_AARCH64_LDST128_ABS_LO12_NC:
+ //
+ // These are static PC relative relocation pairs that will already have been resolved
+ // during static linking of the ELF shared object. So no need to do anything here if
+ // a) the original ELF .text section and the derived PE/COFF .text section are placed at
+ // the same relative alignment with respect to the nearest 4K aligned boundary;
+ // b) the section containing the symbol that the relocation pair refers to is at
+ // the same relative offset in both binaries;
+ // c) it is guaranteed that the load time alignment of the PE/COFF binary is
+ // at least 4 KB.
+ //
+ // While conditions a) and b) could be met by recalculating the immediates based on
+ // the actual placement of the PE/COFF sections if their offsets and/or alignments
+ // deviate, condition c) is a necessary condition that applies universally when
+ // ADRP based symbol references are used. It thus requires the appropriate 'Align=4K'
+ // declarations in the platform .FDF.
+ //
+ if ((SecOffset % 4096) != (SecShdr->sh_addr % 4096) ||
+ (mCoffSectionsOffset[Sym->st_shndx] - SecOffset) != (SymShdr->sh_addr - SecShdr->sh_addr)) {
+ // TODO: recalculate the two immediates based on the actual placement
+ Error (NULL, 0, 3000, "Invalid", "AArch64: ADRP/ADD and ADRP/LDR pairs must retain relative sym offset and relative alignment to 4 KB!.");
+ }
break;

// Absolute relocations.
@@ -825,13 +845,24 @@ WriteRelocations64 (
break;

case R_AARCH64_ADR_PREL_PG_HI21:
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADR_PREL_PG_HI21.", mInImageName);
break;

case R_AARCH64_ADD_ABS_LO12_NC:
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADD_ABS_LO12_NC.", mInImageName);
+ break;
+
+ case R_AARCH64_LDST8_ABS_LO12_NC:
+ break;
+
+ case R_AARCH64_LDST16_ABS_LO12_NC:
+ break;
+
+ case R_AARCH64_LDST32_ABS_LO12_NC:
+ break;
+
+ case R_AARCH64_LDST64_ABS_LO12_NC:
+ break;
+
+ case R_AARCH64_LDST128_ABS_LO12_NC:
break;

case R_AARCH64_ABS64:
--
1.9.1
Ard Biesheuvel
2015-06-23 15:30:53 UTC
Permalink
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 <***@linaro.org>
---
BaseTools/Conf/tools_def.template | 23 +++++++++++++----------
BaseTools/Scripts/gcc-aarch64-ld-script | 33 +++++++++++++++++++++++++++++++++
2 files changed, 46 insertions(+), 10 deletions(-)

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)
+ }
+}
--
1.9.1
Cohen, Eugene
2015-06-24 15:21:27 UTC
Permalink
Post by Ard Biesheuvel
+ * 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).

-----Original Message-----
From: Ard Biesheuvel [mailto:***@linaro.org]
Sent: Tuesday, June 23, 2015 9:31 AM
To: edk2-***@lists.sourceforge.net; ***@arm.com; ***@linaro.org
Subject: [edk2] [RFC PATCH 2/4] BaseTools: AArch64: use an explicit linker script

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 <***@linaro.org>
---
BaseTools/Conf/tools_def.template | 23 +++++++++++++----------
BaseTools/Scripts/gcc-aarch64-ld-script | 33 +++++++++++++++++++++++++++++++++
2 files changed, 46 insertions(+), 10 deletions(-)

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)
+ }
+}
--
1.9.1


------------------------------------------------------------------------------
Monitor 25 network devices or servers for free with OpManager!
OpManager is web-based network management software that monitors
network devices and physical & virtual servers, alerts via email & sms
for fault. Monitor 25 devices for free with no restriction. Download now
http://ad.doubleclick.net/ddm/clk/292181274;119417398;o
_______________________________________________
edk2-devel mailing list
edk2-***@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel
Ard Biesheuvel
2015-06-24 15:27:34 UTC
Permalink
Post by Cohen, Eugene
Post by Ard Biesheuvel
+ * 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.
--
Ard.
Post by Cohen, Eugene
-----Original Message-----
Sent: Tuesday, June 23, 2015 9:31 AM
Subject: [edk2] [RFC PATCH 2/4] BaseTools: AArch64: use an explicit linker script
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
---
BaseTools/Conf/tools_def.template | 23 +++++++++++++----------
BaseTools/Scripts/gcc-aarch64-ld-script | 33 +++++++++++++++++++++++++++++++++
2 files changed, 46 insertions(+), 10 deletions(-)
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)
+ }
+}
--
1.9.1
------------------------------------------------------------------------------
Monitor 25 network devices or servers for free with OpManager!
OpManager is web-based network management software that monitors
network devices and physical & virtual servers, alerts via email & sms
for fault. Monitor 25 devices for free with no restriction. Download now
http://ad.doubleclick.net/ddm/clk/292181274;119417398;o
_______________________________________________
edk2-devel mailing list
https://lists.sourceforge.net/lists/listinfo/edk2-devel
------------------------------------------------------------------------------
Monitor 25 network devices or servers for free with OpManager!
OpManager is web-based network management software that monitors
network devices and physical & virtual servers, alerts via email & sms
for fault. Monitor 25 devices for free with no restriction. Download now
http://ad.doubleclick.net/ddm/clk/292181274;119417398;o
_______________________________________________
edk2-devel mailing list
https://lists.sourceforge.net/lists/listinfo/edk2-devel
Ard Biesheuvel
2015-06-23 15:30:54 UTC
Permalink
GCC allows options supplied on the command line to be overridden by
passing the same option again with a different value. This is useful
for platforms to override default options, so move $(PLATFORM_FLAGS)
and $(ARCHCC_FLAGS) to the end of the GCC command line.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ard Biesheuvel <***@linaro.org>
---
BaseTools/Conf/tools_def.template | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/BaseTools/Conf/tools_def.template b/BaseTools/Conf/tools_def.template
index 9ba8d38a1791..d8d9f9e150e1 100644
--- a/BaseTools/Conf/tools_def.template
+++ b/BaseTools/Conf/tools_def.template
@@ -3882,7 +3882,7 @@ DEFINE GCC47_ASM_FLAGS = DEF(GCC46_ASM_FLAGS)
DEFINE GCC47_ARM_ASM_FLAGS = DEF(GCC46_ARM_ASM_FLAGS)
DEFINE GCC47_AARCH64_ASM_FLAGS = $(ARCHASM_FLAGS) $(PLATFORM_FLAGS) DEF(GCC_ASM_FLAGS) -mlittle-endian
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_AARCH64_CC_FLAGS = DEF(GCC44_ALL_CC_FLAGS) DEF(GCC_AARCH64_CC_FLAGS) $(ARCHCC_FLAGS) $(PLATFORM_FLAGS)
DEFINE GCC47_ARM_DLINK_FLAGS = DEF(GCC46_ARM_DLINK_FLAGS)
DEFINE GCC47_AARCH64_DLINK_FLAGS = DEF(GCC_AARCH64_DLINK_FLAGS)
DEFINE GCC47_ARM_ASLDLINK_FLAGS = DEF(GCC46_ARM_ASLDLINK_FLAGS)
--
1.9.1
Ard Biesheuvel
2015-06-23 15:30:55 UTC
Permalink
Use GCC's 'small' C model when building ArmVirtQemu for AArch64.
This model uses PC relative references for globals instead of
absolute references, which is assumed to be beneficial since it
means fewer runtime relocations to fix up, and less indirect
addressing via literals that are accessed via the D-cache.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ard Biesheuvel <***@linaro.org>
---
ArmVirtPkg/ArmVirtQemu.dsc | 2 +-
ArmVirtPkg/ArmVirtQemu.fdf | 24 +++++++++++++++++++++---
2 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc
index 374cf7a9ee02..b6a6a44c7216 100644
--- a/ArmVirtPkg/ArmVirtQemu.dsc
+++ b/ArmVirtPkg/ArmVirtQemu.dsc
@@ -76,7 +76,7 @@ [LibraryClasses.ARM.SEC]
[BuildOptions]
RVCT:*_*_ARM_PLATFORM_FLAGS == --cpu Cortex-A15 -I$(WORKSPACE)/ArmVirtPkg/Include
GCC:*_*_ARM_PLATFORM_FLAGS == -mcpu=cortex-a15 -I$(WORKSPACE)/ArmVirtPkg/Include
- *_*_AARCH64_PLATFORM_FLAGS == -I$(WORKSPACE)/ArmVirtPkg/Include
+ *_*_AARCH64_PLATFORM_FLAGS == -I$(WORKSPACE)/ArmVirtPkg/Include -mcmodel=small


################################################################################
diff --git a/ArmVirtPkg/ArmVirtQemu.fdf b/ArmVirtPkg/ArmVirtQemu.fdf
index 73d088a3bbdb..617b786798ca 100644
--- a/ArmVirtPkg/ArmVirtQemu.fdf
+++ b/ArmVirtPkg/ArmVirtQemu.fdf
@@ -306,24 +306,42 @@ [FV.FVMAIN_COMPACT]
#
############################################################################

-[Rule.Common.SEC]
+[Rule.ARM.SEC]
FILE SEC = $(NAMED_GUID) RELOCS_STRIPPED {
TE TE Align = 128 $(INF_OUTPUT)/$(MODULE_NAME).efi
}

-[Rule.Common.PEI_CORE]
+[Rule.AARCH64.SEC]
+ FILE SEC = $(NAMED_GUID) RELOCS_STRIPPED {
+ TE TE Align = 4K $(INF_OUTPUT)/$(MODULE_NAME).efi
+ }
+
+[Rule.ARM.PEI_CORE]
FILE PEI_CORE = $(NAMED_GUID) {
TE TE Align = 8 $(INF_OUTPUT)/$(MODULE_NAME).efi
UI STRING ="$(MODULE_NAME)" Optional
}

-[Rule.Common.PEIM]
+[Rule.AARCH64.PEI_CORE]
+ FILE PEI_CORE = $(NAMED_GUID) {
+ TE TE Align = 4K $(INF_OUTPUT)/$(MODULE_NAME).efi
+ UI STRING ="$(MODULE_NAME)" Optional
+ }
+
+[Rule.ARM.PEIM]
FILE PEIM = $(NAMED_GUID) {
PEI_DEPEX PEI_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
TE TE Align = 8 $(INF_OUTPUT)/$(MODULE_NAME).efi
UI STRING="$(MODULE_NAME)" Optional
}

+[Rule.AARCH64.PEIM]
+ FILE PEIM = $(NAMED_GUID) {
+ PEI_DEPEX PEI_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
+ TE TE Align = 4K $(INF_OUTPUT)/$(MODULE_NAME).efi
+ UI STRING="$(MODULE_NAME)" Optional
+ }
+
[Rule.Common.PEIM.TIANOCOMPRESSED]
FILE PEIM = $(NAMED_GUID) DEBUG_MYTOOLS_IA32 {
PEI_DEPEX PEI_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
--
1.9.1
Laszlo Ersek
2015-06-23 20:31:57 UTC
Permalink
Post by Ard Biesheuvel
Use GCC's 'small' C model when building ArmVirtQemu for AArch64.
This model uses PC relative references for globals instead of
absolute references, which is assumed to be beneficial since it
means fewer runtime relocations to fix up, and less indirect
addressing via literals that are accessed via the D-cache.
Contributed-under: TianoCore Contribution Agreement 1.0
---
ArmVirtPkg/ArmVirtQemu.dsc | 2 +-
ArmVirtPkg/ArmVirtQemu.fdf | 24 +++++++++++++++++++++---
2 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc
index 374cf7a9ee02..b6a6a44c7216 100644
--- a/ArmVirtPkg/ArmVirtQemu.dsc
+++ b/ArmVirtPkg/ArmVirtQemu.dsc
@@ -76,7 +76,7 @@ [LibraryClasses.ARM.SEC]
[BuildOptions]
RVCT:*_*_ARM_PLATFORM_FLAGS == --cpu Cortex-A15 -I$(WORKSPACE)/ArmVirtPkg/Include
GCC:*_*_ARM_PLATFORM_FLAGS == -mcpu=cortex-a15 -I$(WORKSPACE)/ArmVirtPkg/Include
- *_*_AARCH64_PLATFORM_FLAGS == -I$(WORKSPACE)/ArmVirtPkg/Include
+ *_*_AARCH64_PLATFORM_FLAGS == -I$(WORKSPACE)/ArmVirtPkg/Include -mcmodel=small
According to the gcc documentation, "-mcmodel=small" is actually the
default setting (... for hosted -- not freestanding -- compilation at
least).

https://gcc.gnu.org/onlinedocs/gcc/AArch64-Options.html

-mcmodel=small
Generate code for the small code model. The program and its
statically defined symbols must be within 4GB of each other.
Pointers are 64 bits. Programs can be statically or dynamically
linked. This is the default code model.

Seems fine, I just wish there was a way to avoid duplicating the
-mcmodel option (cue the previous patch in the series). If I remember
correctly, "==" replaces, "=" appends... but yes, here only
PLATFORM_FLAGS are replaced, and they are fused with a bunch of others
in the previous patch.

I wonder if -mcmodel=large could be removed fom GCC_AARCH64_CC_FLAGS,
and pushed to all the more specific flag variables that include
GCC_AARCH64_CC_FLAGS. Could be a big churn though.
Post by Ard Biesheuvel
################################################################################
diff --git a/ArmVirtPkg/ArmVirtQemu.fdf b/ArmVirtPkg/ArmVirtQemu.fdf
index 73d088a3bbdb..617b786798ca 100644
--- a/ArmVirtPkg/ArmVirtQemu.fdf
+++ b/ArmVirtPkg/ArmVirtQemu.fdf
@@ -306,24 +306,42 @@ [FV.FVMAIN_COMPACT]
#
############################################################################
-[Rule.Common.SEC]
+[Rule.ARM.SEC]
FILE SEC = $(NAMED_GUID) RELOCS_STRIPPED {
TE TE Align = 128 $(INF_OUTPUT)/$(MODULE_NAME).efi
}
-[Rule.Common.PEI_CORE]
+[Rule.AARCH64.SEC]
+ FILE SEC = $(NAMED_GUID) RELOCS_STRIPPED {
+ TE TE Align = 4K $(INF_OUTPUT)/$(MODULE_NAME).efi
+ }
+
+[Rule.ARM.PEI_CORE]
FILE PEI_CORE = $(NAMED_GUID) {
TE TE Align = 8 $(INF_OUTPUT)/$(MODULE_NAME).efi
UI STRING ="$(MODULE_NAME)" Optional
}
-[Rule.Common.PEIM]
+[Rule.AARCH64.PEI_CORE]
+ FILE PEI_CORE = $(NAMED_GUID) {
+ TE TE Align = 4K $(INF_OUTPUT)/$(MODULE_NAME).efi
+ UI STRING ="$(MODULE_NAME)" Optional
+ }
+
+[Rule.ARM.PEIM]
FILE PEIM = $(NAMED_GUID) {
PEI_DEPEX PEI_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
TE TE Align = 8 $(INF_OUTPUT)/$(MODULE_NAME).efi
UI STRING="$(MODULE_NAME)" Optional
}
+[Rule.AARCH64.PEIM]
+ FILE PEIM = $(NAMED_GUID) {
+ PEI_DEPEX PEI_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
+ TE TE Align = 4K $(INF_OUTPUT)/$(MODULE_NAME).efi
+ UI STRING="$(MODULE_NAME)" Optional
+ }
+
[Rule.Common.PEIM.TIANOCOMPRESSED]
FILE PEIM = $(NAMED_GUID) DEBUG_MYTOOLS_IA32 {
PEI_DEPEX PEI_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
Looks reasonable to me. This seems to handle all the TE binary rules.

Reviewed-by: Laszlo Ersek <***@redhat.com>
Ard Biesheuvel
2015-06-24 07:33:37 UTC
Permalink
Hello all,
This is an RFC series to elicit discussion regarding the use of linker script,
and the fact that we use the somewhat obscure 'large' C model for building
EDK2 for AArch64.
- the -Ttext=0x0 LD command line option appears to have no beneficial effect
- the builtin LD script that we have been using so far prevents .text and .data
from sharing any 64 KB page frames; this is intentional since .text and .data
are typically mapped with different permissions when executing under an OS,
and the maximum page size on AArch64 is 64 KB;
- we have been using the 'large' C model, which may be suboptimal
- the Property Table support in UEFI 2.5 requires the use of an explicit linker
script so that sections are 4 KB aligned, and .text and .data are guaranteed
not to share a 4 KB page frame, again for allowing them to be mapped with
different permissions. This maps poorly onto AArch64, again due to its maximum
page size of 64 KB.
These patches propose a linker script to be used with AArch64 that preserves the
layout between ELF and PE/COFF, i.e., the placement of .text and .data is the
same for both binaries. It also places .text such that ADRP based PC relative
symbol references can be supported, provided that the PE/COFF binaries are
always loaded at a 4 KB aligned offset.
A quick survey with the .efi binaries generated during the ArmVirtQemu
build shows that these changes eliminate 80% of the runtime
relocations. Total size savings are only 68 KB, but I suppose there is
a runtime benefit as well to not having to do the fixups.

It would indeed be quite useful to be able to specify different build
options per module type, so that we can have different linker scripts
and C models for XIP, normal and runtime modules.
--
Ard.
Cohen, Eugene
2015-06-24 15:29:19 UTC
Permalink
the Property Table support in UEFI 2.5 requires the use of an explicit linker
script so that sections are 4 KB aligned, and .text and .data are guaranteed
not to share a 4 KB page frame, again for allowing them to be mapped with
different permissions. This maps poorly onto AArch64, again due to its maximum
page size of 64 KB.
I see changes associated with SEC and PEI (in ArmVirtQemu) to implement the 4KB requirement which seems strange to me. You mentioned the reason for this is to enable mapping with different permissions but what is the scope of this - DXE and OS runtime only, or does it really have to be all phases of boot including SEC and PEI? In practice we don't specify different MMU permissions in edk2 for our earlier boot phases so, at least for now, I don't think this is bringing an advantage and the code size increase for uncompressed/XIP images could be significant. Have you been able to characterize the size change on an uncompressed firmware volume with this change?

Eugene

-----Original Message-----
From: Ard Biesheuvel [mailto:***@linaro.org]
Sent: Tuesday, June 23, 2015 9:31 AM
To: edk2-***@lists.sourceforge.net; ***@arm.com; ***@linaro.org
Subject: [edk2] [RFC PATCH 0/4] AArch64 linker script and small C model

Hello all,

This is an RFC series to elicit discussion regarding the use of linker script, and the fact that we use the somewhat obscure 'large' C model for building
EDK2 for AArch64.

Some observations that brought about this series:
- the -Ttext=0x0 LD command line option appears to have no beneficial effect
- the builtin LD script that we have been using so far prevents .text and .data
from sharing any 64 KB page frames; this is intentional since .text and .data
are typically mapped with different permissions when executing under an OS,
and the maximum page size on AArch64 is 64 KB;
- we have been using the 'large' C model, which may be suboptimal
- the Property Table support in UEFI 2.5 requires the use of an explicit linker
script so that sections are 4 KB aligned, and .text and .data are guaranteed
not to share a 4 KB page frame, again for allowing them to be mapped with
different permissions. This maps poorly onto AArch64, again due to its maximum
page size of 64 KB.

These patches propose a linker script to be used with AArch64 that preserves the layout between ELF and PE/COFF, i.e., the placement of .text and .data is the same for both binaries. It also places .text such that ADRP based PC relative symbol references can be supported, provided that the PE/COFF binaries are always loaded at a 4 KB aligned offset.

As said, this is meant to elicit discussion, so fire away ...

Ard Biesheuvel (4):
BaseTools: AArch64: conditionally allow page-based PC relative
relocations
BaseTools: AArch64: use an explicit linker script
BaseTools: move ARCHCC_ and PLATFORM_FLAGS to end of GCC command line
ArmVirtPkg: ArmVirtQemu: use GCC 'small' C model on AArch64

ArmVirtPkg/ArmVirtQemu.dsc | 2 +-
ArmVirtPkg/ArmVirtQemu.fdf | 24 +++++++++++++++++++++---
BaseTools/Conf/tools_def.template | 25 ++++++++++++++-----------
BaseTools/Scripts/gcc-aarch64-ld-script | 33 +++++++++++++++++++++++++++++++++ BaseTools/Source/C/GenFw/Elf64Convert.c | 51 +++++++++++++++++++++++++++++++++++++++++----------
5 files changed, 110 insertions(+), 25 deletions(-) create mode 100644 BaseTools/Scripts/gcc-aarch64-ld-script

--
1.9.1


------------------------------------------------------------------------------
Monitor 25 network devices or servers for free with OpManager!
OpManager is web-based network management software that monitors
network devices and physical & virtual servers, alerts via email & sms
for fault. Monitor 25 devices for free with no restriction. Download now
http://ad.doubleclick.net/ddm/clk/292181274;119417398;o
_______________________________________________
edk2-devel mailing list
edk2-***@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel
Andrew Fish
2015-06-24 16:05:11 UTC
Permalink
This is an RFC series to elicit discussion regarding the use of linker script,
and the fact that we use the somewhat obscure 'large' C model for building
EDK2 for AArch64.
Sorry I missed why the `large C` module is being used?

Also what impact does it have on the ABI? For example does it impact size_t definition? I assume it does not change the definition of long?

Thanks,

Andrew Fish
Ard Biesheuvel
2015-06-24 16:28:16 UTC
Permalink
This is an RFC series to elicit discussion regarding the use of linker script,
and the fact that we use the somewhat obscure 'large' C model for building
EDK2 for AArch64.
Sorry I missed why the `large C` module is being used?
Also what impact does it have on the ABI? For example does it impact size_t
definition? I assume it does not change the definition of long?
The 'small' C model, which is the default, uses ADRP/ADD pairs to
compose PC relative symbol references using two instructions, where
the first gets the page address of the symbol, and the second the
offset into the page. This avoids having lots of literals containing
absolute addresses (that need to be relocated at runtime) but it does
require the link time and load time addresses of the instructions to
be at the same offset relative to the nearest 4 K boundary. Since EDK2
does not guarantee such alignment, the large C model is used instead.

However, when looking into the issue Eugene reported (which is related
to differences in memory layout between ELF and PE/COFF versions of
the binaries), and agreeing that we should not rely on the linker's
builtin linker script but use an explicit one instead (like we do for
GCC/X64 as well), I realized that it is an opportunity for proposing
some changes that allow the small C model to be used.
--
Ard.
Loading...