[U-Boot] Relocation size penalty calculation

Joakim Tjernlund
2009-10-14T12:38:51Z

Graeme Russ <graeme.russ@gmail.com> wrote on 14/10/2009 13:48:27:
>
> On Wed, Oct 14, 2009 at 6:25 PM, Joakim Tjernlund
> <joakim.tjernlund@transmode.se> wrote:
> > "J. William Campbell" <jwilliamcampbell@comcast.net> wrote on 14/10/2009 01:48:52:
> >>
> >> Joakim Tjernlund wrote:
> >> > Graeme Russ <graeme.russ@gmail.com> wrote on 13/10/2009 22:06:56:
> >> >
> >> >
> >> >> On Tue, Oct 13, 2009 at 10:53 PM, Joakim Tjernlund
> >> >> <joakim.tjernlund@transmode.se> wrote:
> >> >>
> >> >>> Graeme Russ <graeme.russ@gmail.com> wrote on 13/10/2009 13:21:05:
> >> >>>
> >> >>>> On Sun, Oct 11, 2009 at 11:51 PM, Joakim Tjernlund
> >> >>>> <joakim.tjernlund@transmode.se> wrote:
> >> >>>>
> >> >>>>> Graeme Russ <graeme.russ@gmail.com> wrote on 11/10/2009 12:47:19:
> >> >>>>>
> >> >>>> [Massive Snip :)]
> >> >>>>
> >> >>>>
> >> >>>>>> So, all that is left are .dynsym and .dynamic ...
> >> >>>>>> .dynsym
> >> >>>>>> - Contains 70 entries (16 bytes each, 1120 bytes)
> >> >>>>>> - 44 entries mimic those entries in .got which are not relocated
> >> >>>>>> - 21 entries are the remaining symbols exported from the linker
> >> >>>>>> script
> >> >>>>>> - 4 entries are labels defined in inline asm and used in C
> >> >>>>>>
> >> >>>>> Try adding proper asm declarations. Look at what gcc
> >> >>>>> generates for a function/variable and mimic these.
> >> >>>>>
> >> >>>> Thanks - Now .dynsym contains only exports from the linker script
> >> >>>>
> >> >>> :)
> >> >>>
> >> >>>>>> - 1 entry is a NULL entry
> >> >>>>>>
> >> >>>>>> .dynamic
> >> >>>>>> - 88 bytes
> >> >>>>>> - Array of Elf32_Dyn
> >> >>>>>> - typedef struct {
> >> >>>>>> Elf32_Sword d_tag;
> >> >>>>>> union {
> >> >>>>>> Elf32_Word d_val;
> >> >>>>>> Elf32_Addr d_ptr;
> >> >>>>>> } d_un;
> >> >>>>>> } Elf32_Dyn;
> >> >>>>>> - 0x11 entries
> >> >>>>>> [00] 0x00000010, 0x00000000 DT_SYMBOLIC, (ignored)
> >> >>>>>> [01] 0x00000004, 0x38059994 DT_HASH, points to .hash
> >> >>>>>> [02] 0x00000005, 0x380595AB DT_STRTAB, points to .dynstr
> >> >>>>>> [03] 0x00000006, 0x3805BDCC DT_SYMTAB, points to .dynsym
> >> >>>>>> [04] 0x0000000A, 0x000003E6 DT_STRSZ, size of .dynstr
> >> >>>>>> [05] 0x0000000B, 0x00000010 DT_SYMENT, ???
> >> >>>>>> [06] 0x00000015, 0x00000000 DT_DEBUG, ???
> >> >>>>>> [07] 0x00000011, 0x3805A8F4 DT_REL, points to .rel.text
> >> >>>>>> [08] 0x00000012, 0x000014D8 DT_RELSZ, ???
> >> >>>>>>
> >> >>>>> How big DT_REL is
> >> >>>>>
> >> >>>>>> [09] 0x00000013, 0x00000008 DT_RELENT, ???
> >> >>>>>>
> >> >>>>> hmm, cannot remeber :)
> >> >>>>>
> >> >>>> How big an entry in DT_REL is
> >> >>>>
> >> >>> Right, how could I forget :)
> >> >>>
> >> >>>>>> [0a] 0x00000016, 0x00000000 DT_TEXTREL, ???
> >> >>>>>>
> >> >>>>> Oops, you got text relocations. This is generally a bad thing.
> >> >>>>> TEXTREL is commonly caused by asm code that arent truly pic so it needs
> >> >>>>> to modify the .text segment to adjust for relocation.
> >> >>>>> You should get rid of this one. Look for DT_TEXTREL in .o files to find
> >> >>>>> the culprit.
> >> >>>>>
> >> >>>>>
> >> >>>> Alas I cannot - The relocations are a result of loading a register with a
> >> >>>> return address when calling show_boot_progress in the very early stages of
> >> >>>> initialisation prior to the stack becoming available. The x86 does not
> >> >>>> allow direct access to the IP so the only way to find the 'current
> >> >>>> execution address' is to 'call' to the next instruction and pop the return
> >> >>>> address off the stack
> >> >>>>
> >> >>> hmm, same as ppc but that in it self should not cause a TEXREL, should it?
> >> >>> Ahh, the 'call' is absolute, not relative? I guess there is some way around it
> >> >>> but it is not important ATM I guess.
> >> >>>
> >> >>> Evil idea, skip -fpic et. all and add the full reloc procedure
> >> >>> to relocate by rewriting directly in TEXT segment. Then you save space
> >> >>> but you need more relocation code. Something like dl_do_reloc from
> >> >>> uClibc. Wonder how much extra code that would be? Not too much I think.
> >> >>>
> >> >>>
> >> >> With the following flags
> >> >>
> >> >> PLATFORM_RELFLAGS += -fvisibility=hidden
> >> >> PLATFORM_CPPFLAGS += -fno-dwarf2-cfi-asm
> >> >> PLATFORM_LDFLAGS += -pic --emit-relocs -Bsymbolic -Bsymbolic-functions
> >> >>
> >> >> I get no .got, but a lot of R_386_PC32 and R_386_32 relocations. I think
> >> >> this might mean I need the symbol table in the binary in order to resolve
> >> >> them
> >> >>
> >
> > BTW, how many relocs do you get compared with -fPIC? I suspect you more
> > now but hopefully not that many more.
> >
> >> >
> >> > Possibly, but I think you only need to add an offset to all those
> >> > relocs.
> >> >
> >> Almost right. The relocations specify a symbol value that needs to be
> >> added to the data in memory to relocate the reference. The symbol values
> >> involved should be the start of the text section for program references,
> >> the start of the uninitialized data section for bss references, and the
> >> start of the data section for initialized data and constants. So there
> >> are about four symbols whose value you need to keep. Take a look at
> >> http://refspecs.freestandards.org/elf/elf.pdf (which you have probably
> >> already looked at) and it tells you what to do with R_386_PC32 ad
> >> R_386_32 relocations. Hopefully the objcopy with the --strip-unneeded
> >> will remove all the symbols you don't actually need, but I don't know
> >> that for sure. Note also that you can change the section flags of a
> >> section marked noload to load.
> >
> > Still think you can get away with just ADDING an offset. The image is linked to a
> > specific address and then you move the whole image to a new address. Therefore
> > you should be able to read the current address, add offset, write back the
> new address.
> >
>
> OK, I don't really get this at all....
>
> This code:
>
> printf ("\n\n%s\n\n", version_string);
>
> gets compiled into:
>
> 380403e7: 68 a4 18 05 38 push $0x380518a4
> 380403ec: 68 de 2c 05 38 push $0x38052cde
> 380403f1: e8 4f 84 00 00 call 38048845 <printf>
>
> With relocation entries in .rel.text of:
>
> Offset Info Type Sym.Value Sym. Name
> 380403e8 00016201 R_386_32 380519f0 version_string
> 380403ed 00000201 R_386_32 380519f0 .rodata
> 380403f2 00016b02 R_386_PC32 38048991 printf
>
> Now I get the first two (R_386_32) entries - Relocation involves a simple
> addition of an offset to the values at addresses 0x380403e8 and 0x380403ed
> (of course, these addresses will be offset)
>
> However, the R_386_PC32 is an enigma - The call is already relative -
> there is no need to relocate it at all (call is a position independent
> opcode because it is a relative jump!)

Yes, but printf is defined in glibc s? the app needs to relocate the call
to glibc. U-boot has all it needs so there you should not have PC32 I think.
Try defining a local static function. For non static functions
you may need to define visibility=hidden and/or -Bsymbolic too.
You also need to look at the img after final linking.

>
> Will all R_386_PC32 be like this? Can I simply ignore them all? If so, why
> do they even need to be generated?

Hopefully you won't have any. Not sure about weak functions though. These might
need PC32 relocs in some cases.

Also, if you look at _dl_do_reloc() in uClibc/ldso/ldso/i386/elfinterp.c I think
you can replace symbol_addr with relocation offset.

Jocke