[U-Boot] [RFC] [PATCH V2] arm: arm926ejs: use ELF relocations

Albert Aribaud albert.aribaud at free.fr
Tue Oct 5 08:31:27 CEST 2010


HISTORY:

V1	Initial patch
V2	Rebased on latest mainline master

This patch is *not* a submission for master!

It is a proof of concept of ELF relocations for ARM, hastily done
in a day's work time for people on the list to try and to comment.
All comments are welcome, as several suggestions have been made
today on the list that I did not have time to incorporate, such as
rewriting the elf table fixup code in C.

The basic idea of this patch is to replace the -fPIC compile-time
option with the -pie link-time option. This removes the GOT but adds
the .rel.dyn and .dynsym tables, which together allow fixing up code
more completely than with -fPIC and the GOT; for instance, all pointers
inside structures are fixed up with -pie, whereas they are not with GOT.

Note that references to linker-file-generated symbols were also made
relative to _start rather than absolute. This is not needed as such,
but it will be useful when optimizing the relocation tables. Actually
I should have separated this from the ELF relocation support per se.

The edminiv2.h config file is there for reference only; this is the
one I used for tests. Latest numbers are:

With GOT relocs:

   text	   data	    bss	    dec	    hex	filename	.bin size
 141376	   4388	  16640	 162404	  27a64	./u-boot	145764
 
With ELF relocs:

   text	   data	    bss	    dec	    hex	filename	.bin size
 149677	   3727	  16636	 170040	  29838	./u-boot	153408

The size difference is essentially due to .rel.dyn not being optimal.
As discussed, an added build step should allow reducing it by half and
making ELF sizes roughly similar to GOT ones.

Tests and comments not only welcome but also heartily called for.

Amicalement,
Albert.

---
 arch/arm/config.mk                |    3 +-
 arch/arm/cpu/arm926ejs/start.S    |  172 +++++++++++++++++++++----------------
 arch/arm/cpu/arm926ejs/u-boot.lds |    9 ++
 arch/arm/include/asm/u-boot-arm.h |   14 ++--
 arch/arm/lib/board.c              |    8 +-
 include/configs/edminiv2.h        |    7 ++
 6 files changed, 126 insertions(+), 87 deletions(-)

diff --git a/arch/arm/config.mk b/arch/arm/config.mk
index 6923f6d..e9e02da 100644
--- a/arch/arm/config.mk
+++ b/arch/arm/config.mk
@@ -35,7 +35,7 @@ endif
 
 ifndef CONFIG_SYS_ARM_WITHOUT_RELOC
 # needed for relocation
-PLATFORM_RELFLAGS += -fPIC
+#PLATFORM_RELFLAGS += -fPIC
 endif
 
 ifdef CONFIG_SYS_ARM_WITHOUT_RELOC
@@ -72,3 +72,4 @@ PLATFORM_LIBS += $(OBJTREE)/arch/arm/lib/eabi_compat.o
 endif
 endif
 LDSCRIPT := $(SRCTREE)/$(CPUDIR)/u-boot.lds
+PLATFORM_LDFLAGS += -pie
\ No newline at end of file
diff --git a/arch/arm/cpu/arm926ejs/start.S b/arch/arm/cpu/arm926ejs/start.S
index 16ee972..5a7ae7e 100644
--- a/arch/arm/cpu/arm926ejs/start.S
+++ b/arch/arm/cpu/arm926ejs/start.S
@@ -10,6 +10,7 @@
  *  Copyright (c) 2002	Gary Jennejohn <garyj at denx.de>
  *  Copyright (c) 2003	Richard Woodruff <r-woodruff2 at ti.com>
  *  Copyright (c) 2003	Kshitij <kshitij at ti.com>
+ *  Copyright (c) 2010	Albert Aribaud <albert.aribaud at free.fr>
  *
  * See file CREDITS for list of people who contributed to this
  * project.
@@ -118,22 +119,19 @@ _fiq:
 _TEXT_BASE:
 	.word	TEXT_BASE
 
-#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
-.globl _armboot_start
-_armboot_start:
-	.word _start
-#endif
-
 /*
  * These are defined in the board-specific linker script.
+ * Subtracting _start from them lets the linker put their
+ * relative position in the executable instead of leaving
+ * them null.
  */
-.globl _bss_start
-_bss_start:
-	.word __bss_start
+.globl _bss_start_ofs
+_bss_start_ofs:
+	.word __bss_start - _start
 
-.globl _bss_end
-_bss_end:
-	.word _end
+.globl _bss_end_ofs
+_bss_end_ofs:
+	.word _end - _start
 
 #ifdef CONFIG_USE_IRQ
 /* IRQ stack memory (calculated at run-time) */
@@ -153,29 +151,21 @@ FIQ_STACK_START:
 IRQ_STACK_START_IN:
 	.word	0x0badc0de
 
-.globl _datarel_start
-_datarel_start:
-	.word __datarel_start
-
-.globl _datarelrolocal_start
-_datarelrolocal_start:
-	.word __datarelrolocal_start
-
-.globl _datarellocal_start
-_datarellocal_start:
-	.word __datarellocal_start
+.globl _datarel_start_ofs
+_datarel_start_ofs:
+	.word __datarel_start - _start
 
-.globl _datarelro_start
-_datarelro_start:
-	.word __datarelro_start
+.globl _datarelrolocal_start_ofs
+_datarelrolocal_start_ofs:
+	.word __datarelrolocal_start - _start
 
-.globl _got_start
-_got_start:
-	.word __got_start
+.globl _datarellocal_start_ofs
+_datarellocal_start_ofs:
+	.word __datarellocal_start - _start
 
-.globl _got_end
-_got_end:
-	.word __got_end
+.globl _datarelro_start_ofs
+_datarelro_start_ofs:
+	.word __datarelro_start - _start
 
 /*
  * the actual reset code
@@ -226,9 +216,8 @@ stack_setup:
 
 	adr	r0, _start
 	ldr	r2, _TEXT_BASE
-	ldr	r3, _bss_start
-	sub	r2, r3, r2		/* r2 <- size of armboot	    */
-	add	r2, r0, r2		/* r2 <- source end address	    */
+	ldr	r3, _bss_start_ofs
+	add	r2, r0, r3		/* r2 <- source end address	    */
 	cmp	r0, r6
 	beq	clear_bss
 
@@ -240,36 +229,54 @@ copy_loop:
 	ble	copy_loop
 
 #ifndef CONFIG_PRELOADER
-	/* fix got entries */
-	ldr	r1, _TEXT_BASE		/* Text base */
-	mov	r0, r7			/* reloc addr */
-	ldr	r2, _got_start		/* addr in Flash */
-	ldr	r3, _got_end		/* addr in Flash */
-	sub	r3, r3, r1
-	add	r3, r3, r0
-	sub	r2, r2, r1
-	add	r2, r2, r0
-
+	/*
+	 * fix .rel.dyn relocations
+	 */
+	ldr	r0, _TEXT_BASE		/* r0 <- Text base */
+	sub	r9, r7, r0		/* r9 <- relocation offset */
+	ldr	r10, _dynsym_start_ofs	/* r10 <- sym table ofs */
+	add	r10, r10, r0		/* r10 <- sym table in FLASH */
+	ldr	r2, _rel_dyn_start_ofs	/* r2 <- rel dyn start ofs */
+	add	r2, r2, r0		/* r2 <- rel dyn start in FLASH */
+	ldr	r3, _rel_dyn_end_ofs	/* r3 <- rel dyn end ofs */
+	add	r3, r3, r0		/* r3 <- rel dyn end in FLASH */
 fixloop:
-	ldr	r4, [r2]
-	sub	r4, r4, r1
-	add	r4, r4, r0
-	str	r4, [r2]
-	add	r2, r2, #4
+	ldr	r0, [r2]	/* r0 <- location to fix up, IN FLASH! */
+	add	r0, r9		/* r0 <- location to fix up in RAM */
+	ldr	r1, [r2, #4]
+	and	r8, r1, #0xff
+	cmp	r8, #23		/* relative fixup? */
+	beq	fixrel
+	cmp	r8, #2		/* absolute fixup? */
+	beq	fixabs
+	/* ignore unknown type of fixup */
+	b	fixnext
+fixabs:
+	/* absolute fix: set location to (offset) symbol value */
+	mov	r1, r1, LSR #4		/* r1 <- symbol index in .dynsym */
+	add	r1, r10, r1		/* r1 <- address of symbol in table */
+	ldr	r1, [r1, #4]		/* r1 <- symbol value */
+	add	r1, r9			/* r1 <- relocated sym addr */
+	b	fixnext
+fixrel:
+	/* relative fix: increase location by offset */
+	ldr	r1, [r0]
+	add	r1, r1, r9
+fixnext:
+	str	r1, [r0]
+	add	r2, r2, #8	/* each rel.dyn entry is 8 bytes */
 	cmp	r2, r3
-	bne	fixloop
+	ble	fixloop
 #endif
 #endif	/* #ifndef CONFIG_SKIP_RELOCATE_UBOOT */
 
 clear_bss:
 #ifndef CONFIG_PRELOADER
-	ldr	r0, _bss_start
-	ldr	r1, _bss_end
+	ldr	r0, _bss_start_ofs
+	ldr	r1, _bss_end_ofs
 	ldr	r3, _TEXT_BASE		/* Text base */
 	mov	r4, r7			/* reloc addr */
-	sub	r0, r0, r3
 	add	r0, r0, r4
-	sub	r1, r1, r3
 	add	r1, r1, r4
 	mov	r2, #0x00000000		/* clear			    */
 
@@ -287,24 +294,33 @@ clbss_l:str	r2, [r0]		/* clear loop...		    */
  * initialization, now running from RAM.
  */
 #ifdef CONFIG_NAND_SPL
-	ldr     pc, _nand_boot
-
-_nand_boot: .word nand_boot
+	ldr     r0, _nand_boot_ofs
+	adr	r1, _start
+	add	pc, r0, r1
+_nand_boot_ofs
+	: .word nand_boot - _start
 #else
-	ldr	r0, _TEXT_BASE
-	ldr	r2, _board_init_r
-	sub	r2, r2, r0
-	add	r2, r2, r7	/* position from board_init_r in RAM */
+	ldr	r0, _board_init_r_ofs
+	adr	r1, _start
+	add	r0, r0, r1
+	add	lr, r0, r9
 	/* setup parameters for board_init_r */
 	mov	r0, r5		/* gd_t */
 	mov	r1, r7		/* dest_addr */
 	/* jump to it ... */
-	mov	lr, r2
 	mov	pc, lr
 
-_board_init_r: .word board_init_r
+_board_init_r_ofs:
+	.word board_init_r - _start
 #endif
 
+_rel_dyn_start_ofs:
+	.word __rel_dyn_start - _start
+_rel_dyn_end_ofs:
+	.word __rel_dyn_end - _start
+_dynsym_start_ofs:
+	.word __dynsym_start - _start
+
 #else /* #if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC) */
 /*
  * the actual reset code
@@ -333,10 +349,8 @@ relocate:				/* relocate U-Boot to RAM	    */
 	ldr	r1, _TEXT_BASE		/* test if we run from flash or RAM */
 	cmp     r0, r1                  /* don't reloc during debug         */
 	beq     stack_setup
-	ldr	r2, _armboot_start
-	ldr	r3, _bss_start
-	sub	r2, r3, r2		/* r2 <- size of armboot            */
-	add	r2, r0, r2		/* r2 <- source end address         */
+	ldr	r3, _bss_start_ofs	/* r3 <- _bss_start - _start	    */
+	add	r2, r0, r3		/* r2 <- source end address         */
 
 copy_loop:
 	ldmia	r0!, {r3-r10}		/* copy from source address [r0]    */
@@ -360,8 +374,11 @@ stack_setup:
 	bic	sp, sp, #7		/* 8-byte alignment for ABI compliance */
 
 clear_bss:
-	ldr	r0, _bss_start		/* find start of bss segment        */
-	ldr	r1, _bss_end		/* stop here                        */
+	adr	r2, _start
+	ldr	r0, _bss_start_ofs	/* find start of bss segment        */
+	add	r0, r0, r2
+	ldr	r1, _bss_end_ofs	/* stop here                        */
+	add	r1, r1, r2
 	mov	r2, #0x00000000		/* clear                            */
 
 #ifndef CONFIG_PRELOADER
@@ -374,13 +391,16 @@ clbss_l:str	r2, [r0]		/* clear loop...                    */
 	bl red_LED_on
 #endif /* CONFIG_PRELOADER */
 
-	ldr	pc, _start_armboot
+	ldr	r0, _start_armboot_ofs
+	adr	r1, _start
+	add	r0, r0, r1
+	ldr	pc, r0
 
-_start_armboot:
+_start_armboot_ofs:
 #ifdef CONFIG_NAND_SPL
-	.word nand_boot
+	.word nand_boot - _start
 #else
-	.word start_armboot
+	.word start_armboot - _start
 #endif /* CONFIG_NAND_SPL */
 #endif /* #if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC) */
 
@@ -469,7 +489,7 @@ cpu_init_crit:
 	sub	sp, sp, #S_FRAME_SIZE
 	stmia	sp, {r0 - r12}	@ Save user registers (now in svc mode) r0-r12
 #if defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
-	ldr	r2, _armboot_start
+	adr	r2, _start
 	sub	r2, r2, #(CONFIG_STACKSIZE+CONFIG_SYS_MALLOC_LEN)
 	sub	r2, r2, #(CONFIG_SYS_GBL_DATA_SIZE+8)  @ set base 2 words into abort stack
 #else
@@ -507,7 +527,7 @@ cpu_init_crit:
 
 	.macro get_bad_stack
 #if defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
-	ldr	r13, _armboot_start		@ setup our mode stack
+	adr	r13, _start		@ setup our mode stack
 	sub	r13, r13, #(CONFIG_STACKSIZE+CONFIG_SYS_MALLOC_LEN)
 	sub	r13, r13, #(CONFIG_SYS_GBL_DATA_SIZE+8) @ reserved a couple spots in abort stack
 #else
diff --git a/arch/arm/cpu/arm926ejs/u-boot.lds b/arch/arm/cpu/arm926ejs/u-boot.lds
index 02eb8ca..f07a54a 100644
--- a/arch/arm/cpu/arm926ejs/u-boot.lds
+++ b/arch/arm/cpu/arm926ejs/u-boot.lds
@@ -51,6 +51,14 @@ SECTIONS
 		*(.data.rel.ro)
 	}
 
+	. = ALIGN(4);
+	__rel_dyn_start = .;
+	.rel.dyn : { *(.rel.dyn) }
+	__rel_dyn_end = .;
+
+	__dynsym_start = .;
+	.dynsym : { *(.dynsym) }
+
 	__got_start = .;
 	. = ALIGN(4);
 	.got : { *(.got) }
@@ -65,4 +73,5 @@ SECTIONS
 	__bss_start = .;
 	.bss (NOLOAD) : { *(.bss) . = ALIGN(4); }
 	_end = .;
+	
 }
diff --git a/arch/arm/include/asm/u-boot-arm.h b/arch/arm/include/asm/u-boot-arm.h
index faf800a..4ac4f61 100644
--- a/arch/arm/include/asm/u-boot-arm.h
+++ b/arch/arm/include/asm/u-boot-arm.h
@@ -30,18 +30,18 @@
 #define _U_BOOT_ARM_H_	1
 
 /* for the following variables, see start.S */
-extern ulong _bss_start;	/* code + data end == BSS start */
-extern ulong _bss_end;		/* BSS end */
+extern ulong _bss_start_ofs;	/* BSS start relative to _start */
+extern ulong _bss_end_ofs;		/* BSS end relative to _start */
 extern ulong IRQ_STACK_START;	/* top of IRQ stack */
 extern ulong FIQ_STACK_START;	/* top of FIQ stack */
 #if defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
-extern ulong _armboot_start;	/* code start */
+extern ulong _armboot_start_ofs;	/* code start */
 #else
 extern ulong _TEXT_BASE;	/* code start */
-extern ulong _datarel_start;
-extern ulong _datarelrolocal_start;
-extern ulong _datarellocal_start;
-extern ulong _datarelro_start;
+extern ulong _datarel_start_ofs;
+extern ulong _datarelrolocal_start_ofs;
+extern ulong _datarellocal_start_ofs;
+extern ulong _datarelro_start_ofs;
 extern ulong IRQ_STACK_START_IN;	/* 8 bytes in IRQ stack */
 #endif
 
diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c
index 5f2dfd0..e411d93 100644
--- a/arch/arm/lib/board.c
+++ b/arch/arm/lib/board.c
@@ -147,7 +147,7 @@ static int display_banner (void)
 #else
 	       _armboot_start,
 #endif
-	       _bss_start, _bss_end);
+	       _bss_start_ofs+_TEXT_BASE, _bss_end_ofs+_TEXT_BASE);
 #ifdef CONFIG_MODEM_SUPPORT
 	debug ("Modem Support enabled\n");
 #endif
@@ -517,7 +517,7 @@ void board_init_f (ulong bootflag)
 
 	memset ((void*)gd, 0, sizeof (gd_t));
 
-	gd->mon_len = _bss_end - _TEXT_BASE;
+	gd->mon_len = _bss_end_ofs;
 
 	for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
 		if ((*init_fnc_ptr)() != 0) {
@@ -679,6 +679,7 @@ static char *failed = "*** failed ***\n";
  *
  ************************************************************************
  */
+
 void board_init_r (gd_t *id, ulong dest_addr)
 {
 	char *s;
@@ -702,7 +703,7 @@ void board_init_r (gd_t *id, ulong dest_addr)
 
 	gd->flags |= GD_FLG_RELOC;	/* tell others: relocation done */
 
-	monitor_flash_len = _bss_start - _TEXT_BASE;
+	monitor_flash_len = _bss_start_ofs;
 	debug ("monitor flash len: %08lX\n", monitor_flash_len);
 	board_init();	/* Setup chipselects */
 
@@ -914,6 +915,7 @@ extern void davinci_eth_set_mac_addr (const u_int8_t *addr);
 
 	/* NOTREACHED - no way out of command loop except booting */
 }
+
 #endif /* defined(CONFIG_SYS_ARM_WITHOUT_RELOC) */
 
 void hang (void)
diff --git a/include/configs/edminiv2.h b/include/configs/edminiv2.h
index ccfc660..8bcdfcc 100644
--- a/include/configs/edminiv2.h
+++ b/include/configs/edminiv2.h
@@ -223,4 +223,11 @@
 #define CONFIG_SYS_RESET_ADDRESS	0xffff0000
 #define CONFIG_SYS_MAXARGS		16
 
+/* additions for new relocation code, must be added to all boards */
+#define CONFIG_RELOC_FIXUP_WORKS
+#undef CONFIG_SYS_ARM_WITHOUT_RELOC
+#define CONFIG_SYS_SDRAM_BASE		0
+#define CONFIG_SYS_INIT_SP_ADDR	\
+	(CONFIG_SYS_SDRAM_BASE + 0x1000 - CONFIG_SYS_GBL_DATA_SIZE)
+
 #endif /* _CONFIG_EDMINIV2_H */
-- 
1.7.0.4



More information about the U-Boot mailing list