[U-Boot] [PATCH] [x86] Don't relocate symbols which point to things that aren't relocated

This change adds an upper bound for symbols which are fixed up after u-boot is relocated into RAM. This way portions that are left at their original location can be referred to without having to manually fix up any pointers.
Signed-off-by: Gabe Black gabeblack@chromium.org --- arch/x86/lib/bios_setup.c | 7 ++----- arch/x86/lib/board.c | 14 +++++++++++--- arch/x86/lib/realmode.c | 7 ++----- 3 files changed, 15 insertions(+), 13 deletions(-)
diff --git a/arch/x86/lib/bios_setup.c b/arch/x86/lib/bios_setup.c index 6c6b0fe..8112f33 100644 --- a/arch/x86/lib/bios_setup.c +++ b/arch/x86/lib/bios_setup.c @@ -140,11 +140,8 @@ static void setvector(int vector, u16 segment, void *handler)
int bios_setup(void) { - /* - * The BIOS section is not relocated and still in the ROM. The - * __bios_start symbol was adjusted, though, so adjust it back. - */ - ulong bios_start = (ulong)&__bios_start - gd->reloc_off; + /* The BIOS section is not relocated and still in the ROM. */ + ulong bios_start = (ulong)&__bios_start; ulong bios_size = (ulong)&__bios_size;
static int done=0; diff --git a/arch/x86/lib/board.c b/arch/x86/lib/board.c index 8963580..ac135b7 100644 --- a/arch/x86/lib/board.c +++ b/arch/x86/lib/board.c @@ -227,10 +227,18 @@ static int do_elf_reloc_fixups(void) Elf32_Rel *re_src = (Elf32_Rel *)(&__rel_dyn_start); Elf32_Rel *re_end = (Elf32_Rel *)(&__rel_dyn_end);
+ /* The size of the region of u-boot that runs out of RAM. */ + uintptr_t size = &__bss_end - &__text_start; + do { - if (re_src->r_offset >= CONFIG_SYS_TEXT_BASE) - if (*(Elf32_Addr *)(re_src->r_offset + gd->reloc_off) >= CONFIG_SYS_TEXT_BASE) - *(Elf32_Addr *)(re_src->r_offset + gd->reloc_off) += gd->reloc_off; + if (re_src->r_offset >= CONFIG_SYS_TEXT_BASE) { + Elf32_Addr *addr = (Elf32_Addr *) + (re_src->r_offset + gd->reloc_off); + if (*addr >= CONFIG_SYS_TEXT_BASE && + *addr < (CONFIG_SYS_TEXT_BASE + size)) { + *addr += gd->reloc_off; + } + } } while (re_src++ < re_end);
return 0; diff --git a/arch/x86/lib/realmode.c b/arch/x86/lib/realmode.c index f8f2251..7637e2c 100644 --- a/arch/x86/lib/realmode.c +++ b/arch/x86/lib/realmode.c @@ -34,11 +34,8 @@ extern char realmode_enter;
int realmode_setup(void) { - /* - * The realmode section is not relocated and still in the ROM. The - * __realmode_start symbol was adjusted, though, so adjust it back. - */ - ulong realmode_start = (ulong)&__realmode_start - gd->reloc_off; + /* The realmode section is not relocated and still in the ROM. */ + ulong realmode_start = (ulong)&__realmode_start; ulong realmode_size = (ulong)&__realmode_size;
/* copy the realmode switch code */

This and my previous patch are quite related and could have been combined into a series or even a single patch. I didn't see this one until I'd already sent the other one, though. Even though keeping them separate was unintentional, these are doing slightly different things. The first one fixes a bug and is important to get in, while the second improves the mechanism to avoid the bug all together.
Gabe
On Mon, Nov 7, 2011 at 10:58 PM, Gabe Black gabeblack@chromium.org wrote:
This change adds an upper bound for symbols which are fixed up after u-boot is relocated into RAM. This way portions that are left at their original location can be referred to without having to manually fix up any pointers.
Signed-off-by: Gabe Black gabeblack@chromium.org
arch/x86/lib/bios_setup.c | 7 ++----- arch/x86/lib/board.c | 14 +++++++++++--- arch/x86/lib/realmode.c | 7 ++----- 3 files changed, 15 insertions(+), 13 deletions(-)
diff --git a/arch/x86/lib/bios_setup.c b/arch/x86/lib/bios_setup.c index 6c6b0fe..8112f33 100644 --- a/arch/x86/lib/bios_setup.c +++ b/arch/x86/lib/bios_setup.c @@ -140,11 +140,8 @@ static void setvector(int vector, u16 segment, void *handler)
int bios_setup(void) {
/*
* The BIOS section is not relocated and still in the ROM. The
* __bios_start symbol was adjusted, though, so adjust it back.
*/
ulong bios_start = (ulong)&__bios_start - gd->reloc_off;
/* The BIOS section is not relocated and still in the ROM. */
ulong bios_start = (ulong)&__bios_start; ulong bios_size = (ulong)&__bios_size; static int done=0;
diff --git a/arch/x86/lib/board.c b/arch/x86/lib/board.c index 8963580..ac135b7 100644 --- a/arch/x86/lib/board.c +++ b/arch/x86/lib/board.c @@ -227,10 +227,18 @@ static int do_elf_reloc_fixups(void) Elf32_Rel *re_src = (Elf32_Rel *)(&__rel_dyn_start); Elf32_Rel *re_end = (Elf32_Rel *)(&__rel_dyn_end);
/* The size of the region of u-boot that runs out of RAM. */
uintptr_t size = &__bss_end - &__text_start;
do {
if (re_src->r_offset >= CONFIG_SYS_TEXT_BASE)
if (*(Elf32_Addr *)(re_src->r_offset +
gd->reloc_off) >= CONFIG_SYS_TEXT_BASE)
*(Elf32_Addr *)(re_src->r_offset +
gd->reloc_off) += gd->reloc_off;
if (re_src->r_offset >= CONFIG_SYS_TEXT_BASE) {
Elf32_Addr *addr = (Elf32_Addr *)
(re_src->r_offset + gd->reloc_off);
if (*addr >= CONFIG_SYS_TEXT_BASE &&
*addr < (CONFIG_SYS_TEXT_BASE + size)) {
*addr += gd->reloc_off;
}
} } while (re_src++ < re_end); return 0;
diff --git a/arch/x86/lib/realmode.c b/arch/x86/lib/realmode.c index f8f2251..7637e2c 100644 --- a/arch/x86/lib/realmode.c +++ b/arch/x86/lib/realmode.c @@ -34,11 +34,8 @@ extern char realmode_enter;
int realmode_setup(void) {
/*
* The realmode section is not relocated and still in the ROM. The
* __realmode_start symbol was adjusted, though, so adjust it back.
*/
ulong realmode_start = (ulong)&__realmode_start - gd->reloc_off;
/* The realmode section is not relocated and still in the ROM. */
ulong realmode_start = (ulong)&__realmode_start; ulong realmode_size = (ulong)&__realmode_size; /* copy the realmode switch code */
-- 1.7.3.1

This change adds an upper bound for symbols which are fixed up after u-boot is relocated into RAM. This way portions that are left at their original location can be referred to without having to manually fix up any pointers.
Signed-off-by: Gabe Black gabeblack@chromium.org --- Changes in v2: Merge in a fix in a later patch which gets rid of some unintentional pointer arithmetic.
arch/x86/lib/bios_setup.c | 7 ++----- arch/x86/lib/board.c | 15 ++++++++++++--- arch/x86/lib/realmode.c | 7 ++----- 3 files changed, 16 insertions(+), 13 deletions(-)
diff --git a/arch/x86/lib/bios_setup.c b/arch/x86/lib/bios_setup.c index 6c6b0fe..8112f33 100644 --- a/arch/x86/lib/bios_setup.c +++ b/arch/x86/lib/bios_setup.c @@ -140,11 +140,8 @@ static void setvector(int vector, u16 segment, void *handler)
int bios_setup(void) { - /* - * The BIOS section is not relocated and still in the ROM. The - * __bios_start symbol was adjusted, though, so adjust it back. - */ - ulong bios_start = (ulong)&__bios_start - gd->reloc_off; + /* The BIOS section is not relocated and still in the ROM. */ + ulong bios_start = (ulong)&__bios_start; ulong bios_size = (ulong)&__bios_size;
static int done=0; diff --git a/arch/x86/lib/board.c b/arch/x86/lib/board.c index 8963580..cf20703 100644 --- a/arch/x86/lib/board.c +++ b/arch/x86/lib/board.c @@ -227,10 +227,19 @@ static int do_elf_reloc_fixups(void) Elf32_Rel *re_src = (Elf32_Rel *)(&__rel_dyn_start); Elf32_Rel *re_end = (Elf32_Rel *)(&__rel_dyn_end);
+ /* The size of the region of u-boot that runs out of RAM. */ + uintptr_t size = (uintptr_t)&__bss_end - + (uintptr_t)&__text_start; + do { - if (re_src->r_offset >= CONFIG_SYS_TEXT_BASE) - if (*(Elf32_Addr *)(re_src->r_offset + gd->reloc_off) >= CONFIG_SYS_TEXT_BASE) - *(Elf32_Addr *)(re_src->r_offset + gd->reloc_off) += gd->reloc_off; + if (re_src->r_offset >= CONFIG_SYS_TEXT_BASE) { + Elf32_Addr *addr = (Elf32_Addr *) + (re_src->r_offset + gd->reloc_off); + if (*addr >= CONFIG_SYS_TEXT_BASE && + *addr < (CONFIG_SYS_TEXT_BASE + size)) { + *addr += gd->reloc_off; + } + } } while (re_src++ < re_end);
return 0; diff --git a/arch/x86/lib/realmode.c b/arch/x86/lib/realmode.c index f8f2251..7637e2c 100644 --- a/arch/x86/lib/realmode.c +++ b/arch/x86/lib/realmode.c @@ -34,11 +34,8 @@ extern char realmode_enter;
int realmode_setup(void) { - /* - * The realmode section is not relocated and still in the ROM. The - * __realmode_start symbol was adjusted, though, so adjust it back. - */ - ulong realmode_start = (ulong)&__realmode_start - gd->reloc_off; + /* The realmode section is not relocated and still in the ROM. */ + ulong realmode_start = (ulong)&__realmode_start; ulong realmode_size = (ulong)&__realmode_size;
/* copy the realmode switch code */

On Tuesday 08 November 2011 02:08:42 Gabe Black wrote:
This change adds an upper bound for symbols which are fixed up after u-boot is relocated into RAM. This way portions that are left at their original location can be referred to without having to manually fix up any pointers.
i'm not familiar with the u-boot relocation handling on x86, but if a symbol shouldn't be relocated, then why does it have an elf reloc ? shouldn't it be an absolute symbol ? -mike

I don't think the symbols that are left in place are compiled or linked any differently than the rest, and I believe the compiler/linker is explicitly instructed to leave relocation information in the final binary. You could leave those out as a space saving optimization, although that seems like it's outside the scope of this change.
Gabe
On Tue, Nov 8, 2011 at 5:46 AM, Mike Frysinger vapier@gentoo.org wrote:
On Tuesday 08 November 2011 02:08:42 Gabe Black wrote:
This change adds an upper bound for symbols which are fixed up after
u-boot
is relocated into RAM. This way portions that are left at their original location can be referred to without having to manually fix up any
pointers.
i'm not familiar with the u-boot relocation handling on x86, but if a symbol shouldn't be relocated, then why does it have an elf reloc ? shouldn't it be an absolute symbol ? -mike

Hi Mike,
On Wed, Nov 9, 2011 at 12:46 AM, Mike Frysinger vapier@gentoo.org wrote:
On Tuesday 08 November 2011 02:08:42 Gabe Black wrote:
This change adds an upper bound for symbols which are fixed up after u-boot is relocated into RAM. This way portions that are left at their original location can be referred to without having to manually fix up any pointers.
i'm not familiar with the u-boot relocation handling on x86, but if a symbol shouldn't be relocated, then why does it have an elf reloc ? shouldn't it be an absolute symbol ?
As Gabe pointed out, all x86 source files are compiled with the same options (i.e. with relocation enabled). This includes the 16-bit realmode sections which are actually designed to run at a fixed location in memory. Now this introduces a few issues:
a) There are entries in the relocation table that point to relocations in lower memory (i.e. below TEXT_BASE) - That's the first test b) Where the 32-bit bit code transitions to 16-bit, there is a relocation entry which points to a location above TEXT_BASE, but because the jump is to a fixed location in memory (below TEXT_BASE) it must not be adjusted (this is the second test)
There is also a couple of relocations that do not need adjusting in the reset vector code and real-to-protected mode switch, but these are a don't care case because by that stage, the code has already been run and will not be run again so it really does not matter what we do to them
Now I think we might be able to compile the 16-bit code without relocations (would need to tweak how the compiler flags are handled and split them up a bit) and also change the 32-to-16 bit jump so it does not get a relocation entry (I think I have a patch somewhere already as part of my massive 32-to-16 bit switch change) so we might be able to get rid of both test at some stage...
Regards,
Graeme

This change adds an upper bound for symbols which are fixed up after u-boot is relocated into RAM. This way portions that are left at their original location can be referred to without having to manually fix up any pointers.
Signed-off-by: Gabe Black gabeblack@chromium.org --- Changes in v2: Merge in a fix in a later patch which gets rid of some unintentional pointer arithmetic.
Changes in v3: Update x86 tag.
arch/x86/lib/bios_setup.c | 7 ++----- arch/x86/lib/board.c | 15 ++++++++++++--- arch/x86/lib/realmode.c | 7 ++----- 3 files changed, 16 insertions(+), 13 deletions(-)
diff --git a/arch/x86/lib/bios_setup.c b/arch/x86/lib/bios_setup.c index 6c6b0fe..8112f33 100644 --- a/arch/x86/lib/bios_setup.c +++ b/arch/x86/lib/bios_setup.c @@ -140,11 +140,8 @@ static void setvector(int vector, u16 segment, void *handler)
int bios_setup(void) { - /* - * The BIOS section is not relocated and still in the ROM. The - * __bios_start symbol was adjusted, though, so adjust it back. - */ - ulong bios_start = (ulong)&__bios_start - gd->reloc_off; + /* The BIOS section is not relocated and still in the ROM. */ + ulong bios_start = (ulong)&__bios_start; ulong bios_size = (ulong)&__bios_size;
static int done=0; diff --git a/arch/x86/lib/board.c b/arch/x86/lib/board.c index 8963580..cf20703 100644 --- a/arch/x86/lib/board.c +++ b/arch/x86/lib/board.c @@ -227,10 +227,19 @@ static int do_elf_reloc_fixups(void) Elf32_Rel *re_src = (Elf32_Rel *)(&__rel_dyn_start); Elf32_Rel *re_end = (Elf32_Rel *)(&__rel_dyn_end);
+ /* The size of the region of u-boot that runs out of RAM. */ + uintptr_t size = (uintptr_t)&__bss_end - + (uintptr_t)&__text_start; + do { - if (re_src->r_offset >= CONFIG_SYS_TEXT_BASE) - if (*(Elf32_Addr *)(re_src->r_offset + gd->reloc_off) >= CONFIG_SYS_TEXT_BASE) - *(Elf32_Addr *)(re_src->r_offset + gd->reloc_off) += gd->reloc_off; + if (re_src->r_offset >= CONFIG_SYS_TEXT_BASE) { + Elf32_Addr *addr = (Elf32_Addr *) + (re_src->r_offset + gd->reloc_off); + if (*addr >= CONFIG_SYS_TEXT_BASE && + *addr < (CONFIG_SYS_TEXT_BASE + size)) { + *addr += gd->reloc_off; + } + } } while (re_src++ < re_end);
return 0; diff --git a/arch/x86/lib/realmode.c b/arch/x86/lib/realmode.c index f8f2251..7637e2c 100644 --- a/arch/x86/lib/realmode.c +++ b/arch/x86/lib/realmode.c @@ -34,11 +34,8 @@ extern char realmode_enter;
int realmode_setup(void) { - /* - * The realmode section is not relocated and still in the ROM. The - * __realmode_start symbol was adjusted, though, so adjust it back. - */ - ulong realmode_start = (ulong)&__realmode_start - gd->reloc_off; + /* The realmode section is not relocated and still in the ROM. */ + ulong realmode_start = (ulong)&__realmode_start; ulong realmode_size = (ulong)&__realmode_size;
/* copy the realmode switch code */

Hi Gabe,
On 09/11/11 09:21, Gabe Black wrote:
This change adds an upper bound for symbols which are fixed up after u-boot is relocated into RAM. This way portions that are left at their original location can be referred to without having to manually fix up any pointers.
Signed-off-by: Gabe Black gabeblack@chromium.org
Changes in v2: Merge in a fix in a later patch which gets rid of some unintentional pointer arithmetic.
Changes in v3: Update x86 tag.
arch/x86/lib/bios_setup.c | 7 ++----- arch/x86/lib/board.c | 15 ++++++++++++--- arch/x86/lib/realmode.c | 7 ++----- 3 files changed, 16 insertions(+), 13 deletions(-)
Can you please rebase against u-boot-x86/master and re-submit
Thanks,
Graeme

This change adds an upper bound for symbols which are fixed up after u-boot is relocated into RAM. This way portions that are left at their original location can be referred to without having to manually fix up any pointers.
Signed-off-by: Gabe Black gabeblack@chromium.org --- Changes in v2: Merge in a fix in a later patch which gets rid of some unintentional pointer arithmetic.
Changes in v3: Update x86 tag.
Changes in v4: Rebase onto the x86 repository.
arch/x86/lib/bios_setup.c | 7 ++----- arch/x86/lib/board.c | 5 ++++- arch/x86/lib/realmode.c | 7 ++----- 3 files changed, 8 insertions(+), 11 deletions(-)
diff --git a/arch/x86/lib/bios_setup.c b/arch/x86/lib/bios_setup.c index 0dfe4a1..265f7d6 100644 --- a/arch/x86/lib/bios_setup.c +++ b/arch/x86/lib/bios_setup.c @@ -78,11 +78,8 @@ static void setvector(int vector, u16 segment, void *handler)
int bios_setup(void) { - /* - * The BIOS section is not relocated and still in the ROM. The - * __bios_start symbol was adjusted, though, so adjust it back. - */ - ulong bios_start = (ulong)&__bios_start - gd->reloc_off; + /* The BIOS section is not relocated and still in the ROM. */ + ulong bios_start = (ulong)&__bios_start; ulong bios_size = (ulong)&__bios_size;
static int done; diff --git a/arch/x86/lib/board.c b/arch/x86/lib/board.c index 244a021..18e0ede 100644 --- a/arch/x86/lib/board.c +++ b/arch/x86/lib/board.c @@ -231,8 +231,11 @@ static int do_elf_reloc_fixups(void) offset_ptr_ram = offset_ptr_rom + gd->reloc_off;
/* Check that the target points into .text */ - if (*offset_ptr_ram >= CONFIG_SYS_TEXT_BASE) + if (*offset_ptr_ram >= CONFIG_SYS_TEXT_BASE && + *offset_ptr_ram < + (CONFIG_SYS_TEXT_BASE + size)) { *offset_ptr_ram += gd->reloc_off; + } } } while (re_src++ < re_end);
diff --git a/arch/x86/lib/realmode.c b/arch/x86/lib/realmode.c index bf0d0aa..75511b2 100644 --- a/arch/x86/lib/realmode.c +++ b/arch/x86/lib/realmode.c @@ -30,11 +30,8 @@
int realmode_setup(void) { - /* - * The realmode section is not relocated and still in the ROM. The - * __realmode_start symbol was adjusted, though, so adjust it back. - */ - ulong realmode_start = (ulong)&__realmode_start - gd->reloc_off; + /* The realmode section is not relocated and still in the ROM. */ + ulong realmode_start = (ulong)&__realmode_start; ulong realmode_size = (ulong)&__realmode_size;
/* copy the realmode switch code */

On 13/11/11 13:34, Gabe Black wrote:
This change adds an upper bound for symbols which are fixed up after u-boot is relocated into RAM. This way portions that are left at their original location can be referred to without having to manually fix up any pointers.
Signed-off-by: Gabe Black gabeblack@chromium.org
Changes in v2: Merge in a fix in a later patch which gets rid of some unintentional pointer arithmetic.
Changes in v3: Update x86 tag.
Changes in v4: Rebase onto the x86 repository.
arch/x86/lib/bios_setup.c | 7 ++----- arch/x86/lib/board.c | 5 ++++- arch/x86/lib/realmode.c | 7 ++----- 3 files changed, 8 insertions(+), 11 deletions(-)
Applied to u-boot-x86/master
Thanks,
Graeme

Hi Gabe,
On Sun, Nov 13, 2011 at 1:34 PM, Gabe Black gabeblack@chromium.org wrote:
This change adds an upper bound for symbols which are fixed up after u-boot is relocated into RAM. This way portions that are left at their original location can be referred to without having to manually fix up any pointers.
Signed-off-by: Gabe Black gabeblack@chromium.org
Changes in v2: Merge in a fix in a later patch which gets rid of some unintentional pointer arithmetic.
Changes in v3: Update x86 tag.
Changes in v4: Rebase onto the x86 repository.
arch/x86/lib/bios_setup.c | 7 ++----- arch/x86/lib/board.c | 5 ++++- arch/x86/lib/realmode.c | 7 ++----- 3 files changed, 8 insertions(+), 11 deletions(-)
[snip]
diff --git a/arch/x86/lib/board.c b/arch/x86/lib/board.c index 244a021..18e0ede 100644 --- a/arch/x86/lib/board.c +++ b/arch/x86/lib/board.c @@ -231,8 +231,11 @@ static int do_elf_reloc_fixups(void) offset_ptr_ram = offset_ptr_rom + gd->reloc_off;
/* Check that the target points into .text */
- if (*offset_ptr_ram >= CONFIG_SYS_TEXT_BASE)
- if (*offset_ptr_ram >= CONFIG_SYS_TEXT_BASE &&
- *offset_ptr_ram <
- (CONFIG_SYS_TEXT_BASE + size)) {
*offset_ptr_ram += gd->reloc_off;
- }
} } while (re_src++ < re_end);
You forgot the following:
+ /* The size of the region of u-boot that runs out of RAM. */ + uintptr_t size = (uintptr_t)&__bss_end - + (uintptr_t)&__text_start; +
And I didn't check before committing, and now it's in u-boot-x86/master :(
Can you please send a fix
I'll add a fix for my fubar as a fresh commit as well
Regards,
Graeme
participants (3)
-
Gabe Black
-
Graeme Russ
-
Mike Frysinger