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

Graeme Russ graeme.russ at gmail.com
Tue Oct 5 12:49:12 CEST 2010


On 05/10/10 21:36, Reinhard Meyer wrote:
> Albert ARIBAUD schrieb:
>> Le 05/10/2010 11:39, Reinhard Meyer a écrit :
>>>> for (p = start; p<  end; p += 8)
>>>>     work;
>>>> and not
>>>
>>> Give me some time, and I will complete this loop to do
>>> relocation in "C".
> 
> Almost finished with it :)
> 
>>> Reinhard
>>
>> Be careful, though, that you need a way to obtain the 'source' address
>> of the .rel.dyn start and end and of the .dynsym start, plus the offset
>> from 'source' to 'target'; these may not be easy to compute in C
> 
> No problem, the statements
> 
> .globl _rel_dyn_start_ofs
> _rel_dyn_start_ofs:
> 	.word __rel_dyn_start - _start
> .globl _rel_dyn_end_ofs
> _rel_dyn_end_ofs:
> 	.word __rel_dyn_end - _start
> .globl _dynsym_start_ofs
> _dynsym_start_ofs:
> 	.word __dynsym_start - _start
> 
> get the values to "C".

Odd, is x86 different:

extern ulong _i386boot_rel_dyn_start;
extern ulong _i386boot_rel_dyn_end;

void board_init_f (ulong stack_limit)
{
...
	Elf32_Rel *rel_dyn_start = (Elf32_Rel *)&_i386boot_rel_dyn_start;
	Elf32_Rel *rel_dyn_end = (Elf32_Rel *)&_i386boot_rel_dyn_end;
...

>>
>> I think the right balance might be to have an ASM framework to prepare
>> these four values and pass them to the C relocation routine.
> 
> see above.
> 
>>
>> Note that you may also have to make sure the routine itself is
>> insensitive to relocation too.
> 
> Why? It runs while code is at the right TEXT_BASE. If that shall
> be weakened, I am not sure it can be done in "C".

Provided you only use local variables (i.e. stored on the stack) the code
might be relocatable anyway (the jump from asm to C will hopefully be
relative). If you run the code at another address you will need to
calculate the load offset and adjust rel_dyn_start and rel_dyn_end
accordingly (see recent x86 patch series)

[snip]

> Is an entry in _dynsym really 16 bytes long?

Yes, it is an Elf32_Rel struct - see include/elf.h in the U-Boot tree

typedef struct
{
	Elf32_Addr	r_offset;	/* offset of relocation */
	Elf32_Word	r_info;		/* symbol table index and type */
} Elf32_Rel;


> PS: I am about there:
> 
> #ifdef CONFIG_USE_C_RELOCATION
> 	/* TODO: check for identical source and destination */
> 	/* TODO: check for overlapping */
> 	/* copy image, including initialized data */
> 	debug ("memcpy(%08lx,%08lx,%ld)\n",
> 		addr, _TEXT_BASE, _bss_start_ofs);
> 	memcpy (addr, _TEXT_BASE, _bss_start_ofs);
> 	/* now fix the code */
> 	debug ("_dynsym_start_ofs=%08lx _rel_dyn_start_ofs=%08lx _rel_dyn_end_ofs=%08lx\n",
> 		_dynsym_start_ofs, _rel_dyn_start_ofs, _rel_dyn_end_ofs);
> 	for (dyn_ptr = (ulong *)(_TEXT_BASE + _rel_dyn_start_ofs);
> 			dyn_ptr < (ulong *)(_TEXT_BASE + _rel_dyn_end_ofs);
> 			dyn_ptr += 8) {

I too use a for loop, but now use a do loop:

extern ulong __rel_dyn_start;
extern ulong __rel_dyn_end;

void board_init_f (ulong gdp)
{
...
	void *rel_dyn_start = &__rel_dyn_start;
	void *rel_dyn_end = &__rel_dyn_end;
...

	/* Perform relocation adjustments */
	re_src = (Elf32_Rel *)(rel_dyn_start + ((gd_t *)gdp)->load_off);
	re_end = (Elf32_Rel *)(rel_dyn_end + ((gd_t *)gdp)->load_off);

	do {
		if (re_src->r_offset >= TEXT_BASE)
			if (*(Elf32_Addr *)(re_src->r_offset - rel_offset) >= TEXT_BASE)
				*(Elf32_Addr *)(re_src->r_offset - rel_offset) -= rel_offset;
	} while (re_src++ < re_end);


I pass in a pointer to the global data structure which has had load_off
(the difference between TEXT_BASE and the load address) pre-calculated in asm

> 		ulong *patchaddr = (ulong *) dyn_ptr[0] + addr;
> 		debug ("patch %08lx : %08lx\n",
> 			patchaddr, dyn_ptr[1]);
> 		switch (dyn_ptr[1] & 0xff) {

Use Elf32_Rel

> 		case 23: /* rel fixup */
> 			*patchaddr += addr;
> 			break;
> 		case 2: /* abs fixup */
> 			break;
> 		default: /* unhandled fixup */
> 			break;
> 		}
> 	}

Regards,

Graeme


More information about the U-Boot mailing list