From mboxrd@z Thu Jan 1 00:00:00 1970 From: Graeme Russ Date: Tue, 05 Oct 2010 21:49:12 +1100 Subject: [U-Boot] [RFC] [PATCH V2] arm: arm926ejs: use ELF relocations In-Reply-To: <4CAAFFA3.6060602@emk-elektronik.de> References: <1286260287-1571-1-git-send-email-albert.aribaud@free.fr> <20101005064516.AEA4C153A7E@gemini.denx.de> <4CAACE47.5090105@emk-elektronik.de> <4CAAD255.1080501@emk-elektronik.de> <4CAAD944.2040309@emk-elektronik.de> <4CAAE2C5.4040304@denx.de> <4CAAE4BF.3030306@free.fr> <4CAAE949.1010200@denx.de> <4CAAEB84.2070602@emk-elektronik.de> <4CAAECA1.8090903@denx.de> <4CAAEDAE.9040908@emk-elektronik.de> <4CAAEFDF.5080803@denx.de> <4CAAF0E3.20801@emk-elektronik.de> <4CAAF264.6030305@emk-elektronik.de> <4CAAF9D6.6040803@free.fr> <4CAAFFA3.6060602@emk-elektronik.de> Message-ID: <4CAB02A8.1010200@gmail.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de 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