aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlivier Deprez <olivier.deprez@arm.com>2020-03-06 17:17:56 +0100
committerOlivier Deprez <olivier.deprez@arm.com>2020-03-23 10:19:59 +0100
commit1d2b88d430aa98961865f8be296a1b61b9ce0813 (patch)
treec3586961194fd2b0334787f6eed4abe997935c65
parent231115da2736e7e36627a02497815f33f022cc57 (diff)
downloadtf-a-tests-1d2b88d430aa98961865f8be296a1b61b9ce0813.tar.gz
cactus: add symbols relocation fixup
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com> Change-Id: Ibde8aadecf6ae6c320d01ee2acab9c3c8db3859d
-rw-r--r--lib/aarch64/misc_helpers.S115
-rw-r--r--spm/cactus/aarch64/cactus_entrypoint.S10
-rw-r--r--spm/cactus/cactus.ld.S25
3 files changed, 147 insertions, 3 deletions
diff --git a/lib/aarch64/misc_helpers.S b/lib/aarch64/misc_helpers.S
index 7c9da92af..b67772152 100644
--- a/lib/aarch64/misc_helpers.S
+++ b/lib/aarch64/misc_helpers.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,6 +7,7 @@
#include <arch.h>
#include <asm_macros.S>
#include <assert_macros.S>
+#include <lib/xlat_tables/xlat_tables_defs.h>
.globl smc
@@ -110,3 +111,115 @@ endfunc disable_mmu_icache
/* Need this label for asm_read/write_sctlr_el1_or_el2 */
dead:
b dead
+
+/* ---------------------------------------------------------------------------
+ * Helper to fixup Global Offset table (GOT) and dynamic relocations
+ * (.rela.dyn) at runtime.
+ *
+ * This function is meant to be used when the firmware is compiled with -fpie
+ * and linked with -pie options. We rely on the linker script exporting
+ * appropriate markers for start and end of the section. For GOT, we
+ * expect __GOT_START__ and __GOT_END__. Similarly for .rela.dyn, we expect
+ * __RELA_START__ and __RELA_END__.
+ *
+ * The function takes the limits of the memory to apply fixups to as
+ * arguments (which is usually the limits of the relocable BL image).
+ * x0 - the start of the fixup region
+ * x1 - the limit of the fixup region
+ * These addresses have to be page (4KB aligned).
+ * ---------------------------------------------------------------------------
+ */
+.globl fixup_gdt_reloc
+func fixup_gdt_reloc
+ mov x6, x0
+ mov x7, x1
+
+ /* Test if the limits are 4K aligned */
+#if ENABLE_ASSERTIONS
+ orr x0, x0, x1
+ tst x0, #(PAGE_SIZE - 1)
+ ASM_ASSERT(eq)
+#endif
+ /*
+ * Calculate the offset based on return address in x30.
+ * Assume that this function is called within a page at the start of
+ * fixup region.
+ */
+ and x2, x30, #~(PAGE_SIZE - 1)
+ sub x0, x2, x6 /* Diff(S) = Current Address - Compiled Address */
+
+ adrp x1, __GOT_START__
+ add x1, x1, :lo12:__GOT_START__
+ adrp x2, __GOT_END__
+ add x2, x2, :lo12:__GOT_END__
+
+ /*
+ * GOT is an array of 64_bit addresses which must be fixed up as
+ * new_addr = old_addr + Diff(S).
+ * The new_addr is the address currently the binary is executing from
+ * and old_addr is the address at compile time.
+ */
+1:
+ ldr x3, [x1]
+ /* Skip adding offset if address is < lower limit */
+ cmp x3, x6
+ b.lo 2f
+ /* Skip adding offset if address is >= upper limit */
+ cmp x3, x7
+ b.ge 2f
+ add x3, x3, x0
+ str x3, [x1]
+2:
+ add x1, x1, #8
+ cmp x1, x2
+ b.lo 1b
+
+ /* Starting dynamic relocations. Use adrp/adr to get RELA_START and END */
+ adrp x1, __RELA_START__
+ add x1, x1, :lo12:__RELA_START__
+ adrp x2, __RELA_END__
+ add x2, x2, :lo12:__RELA_END__
+ /*
+ * According to ELF-64 specification, the RELA data structure is as
+ * follows:
+ * typedef struct
+ * {
+ * Elf64_Addr r_offset;
+ * Elf64_Xword r_info;
+ * Elf64_Sxword r_addend;
+ * } Elf64_Rela;
+ *
+ * r_offset is address of reference
+ * r_info is symbol index and type of relocation (in this case
+ * 0x403 which corresponds to R_AARCH64_RELATIVE).
+ * r_addend is constant part of expression.
+ *
+ * Size of Elf64_Rela structure is 24 bytes.
+ */
+1:
+ /* Assert that the relocation type is R_AARCH64_RELATIVE */
+#if ENABLE_ASSERTIONS
+ ldr x3, [x1, #8]
+ cmp x3, #0x403
+ ASM_ASSERT(eq)
+#endif
+ ldr x3, [x1] /* r_offset */
+ add x3, x0, x3
+ ldr x4, [x1, #16] /* r_addend */
+
+ /* Skip adding offset if r_addend is < lower limit */
+ cmp x4, x6
+ b.lo 2f
+ /* Skip adding offset if r_addend entry is >= upper limit */
+ cmp x4, x7
+ b.ge 2f
+
+ add x4, x0, x4 /* Diff(S) + r_addend */
+ str x4, [x3]
+
+2: add x1, x1, #24
+ cmp x1, x2
+ b.lo 1b
+
+ ret
+endfunc fixup_gdt_reloc
diff --git a/spm/cactus/aarch64/cactus_entrypoint.S b/spm/cactus/aarch64/cactus_entrypoint.S
index 7d6b6b26e..4fe17e343 100644
--- a/spm/cactus/aarch64/cactus_entrypoint.S
+++ b/spm/cactus/aarch64/cactus_entrypoint.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2017-2020, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -27,6 +27,14 @@ func cactus_entrypoint
msr sctlr_el1, x0
isb
+ /* Relocate symbols */
+pie_fixup:
+ ldr x0, =pie_fixup
+ and x0, x0, #~(0x1000 - 1)
+ mov x1, #CACTUS_IMAGE_SIZE
+ add x1, x1, x0
+ bl fixup_gdt_reloc
+
/* And jump to the C entrypoint. */
b cactus_main
diff --git a/spm/cactus/cactus.ld.S b/spm/cactus/cactus.ld.S
index a3d8e65d0..30ad0da7b 100644
--- a/spm/cactus/cactus.ld.S
+++ b/spm/cactus/cactus.ld.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2017-2020, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -32,8 +32,20 @@ SECTIONS
. = ALIGN(PAGE_SIZE);
__RODATA_START__ = .;
*(.rodata*)
+
+ /*
+ * Keep the .got section in the RO section as it is patched
+ * prior to enabling the MMU and having the .got in RO is better for
+ * security. GOT is a table of addresses so ensure 8-byte alignment.
+ */
+ . = ALIGN(8);
+ __GOT_START__ = .;
+ *(.got)
+ __GOT_END__ = .;
+
. = NEXT(PAGE_SIZE);
__RODATA_END__ = .;
+
}
.data : {
@@ -44,6 +56,17 @@ SECTIONS
__DATA_END__ = .;
}
+ /*
+ * .rela.dyn needs to come after .data for the read-elf utility to parse
+ * this section correctly. Ensure 8-byte alignment so that the fields of
+ * RELA data structure are aligned.
+ */
+ . = ALIGN(8);
+ __RELA_START__ = .;
+ .rela.dyn . : {
+ }
+ __RELA_END__ = .;
+
.bss (NOLOAD) : {
. = ALIGN(PAGE_SIZE);
__BSS_START__ = .;