This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
ld relocation problem on ARM (PIC related)
- From: jeroen dobbelaere <jeroen dot dobbelaere at acunia dot com>
- To: binutils at sources dot redhat dot com
- Date: Wed, 06 Nov 2002 17:24:38 +0100
- Subject: ld relocation problem on ARM (PIC related)
- Organization: ACUNIA
Hi,
I'm looking at a problem when linking in PIC code on an ARM platform (actual, XScale).
I'm using binutils 'GNU ld version 2.13.90.0.10 20021010'
The problem I encounter is that references to global variables are not resolved.
Example :
Following code ;
---
extern const unsigned long var;
const unsigned long var=999;
int main()
{
printf("%p\n", &var);
}
---
when compiling with ' gcc -O3 -fpic test4.c', (gcc-3.2) , this results in :
000083d4 <main>:
83d4: e92d4400 stmdb sp!, {sl, lr}
83d8: e59fa018 ldr sl, [pc, #24] ; 83f8 <main+0x24>
83dc: e59f1018 ldr r1, [pc, #24] ; 83fc <main+0x28>
83e0: e59f3018 ldr r3, [pc, #24] ; 8400 <main+0x2c>
83e4: e08fa00a add sl, pc, sl
83e8: e79a0001 ldr r0, [sl, r1]
83ec: e79a1003 ldr r1, [sl, r3]
83f0: e8bd4400 ldmia sp!, {sl, lr}
83f4: eaffffb1 b 82c0 <_init+0x44>
83f8: 0000815c andeq r8, r0, ip, asr r1
-> global offset table
83fc: 0000001c andeq r0, r0, ip, lsl r0
-> offset for '"%p\n"'
8400: 00000020 andeq r0, r0, r0, lsr #32
-> offset for &var
00010548 <_GLOBAL_OFFSET_TABLE_>:
10548: 0001046c andeq r0, r1, ip, ror #8
1054c: 00000000 andeq r0, r0, r0
10550: 00000000 andeq r0, r0, r0
10554: 00008290 muleq r0, r0, r2
10558: 00008290 muleq r0, r0, r2
1055c: 00008290 muleq r0, r0, r2
10560: 00000000 andeq r0, r0, r0
10564: 00008458 andeq r8, r0, r8, asr r4
10568: 00000000 andeq r0, r0, r0
At 0x83e4, 'sl' becomes : 0x815c + (0x83e4+8) = 0x10548
Which is the global offset table.
r1, becomes 0x1c
r3, becomes 0x20
Afterwards, [sl, r1] is loaded :
sl+r1 = 0x10564, which contains a (valid) pointer to the string '%p\n"
Than, [sl, r3] is loaded, sl+r3 = 0x10568, which contains a NULL pointer.
(Thus, &var == NULL !!)
After adding various debug messages to the bfd part of binutils, I
found a part of code in 'bfd/elf32-arm.h' which seems to produce the
'bad' output :
in 'elf32_arm_finish_dynamic_symbol'
[...]
/* If this is a -Bsymbolic link, and the symbol is defined
locally, we just want to emit a RELATIVE reloc. The entry in
the global offset table will already have been initialized in
the relocate_section function. */
if (info->shared
&& (info->symbolic || h->dynindx == -1)
&& (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))
rel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE);
else
{
bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset);
/* ****MARK***** */
rel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_GLOB_DAT);
}
bfd_elf32_swap_reloc_out (output_bfd, &rel,
((Elf32_External_Rel *) srel->contents
+ srel->reloc_count));
[...]
The part above 'MARK' is responsible for the NULL content of those variables.
So, I have the impression that there are two possibilities :
- the location of the symbol is known already, but we let the dynamic linker resolve it
at run time.
-> in this case there should be a symbol added (somehow) to indicate this to the dynamic linker
- the location of the symbol is known already and we should fill it in here...
-> in this case, we should find out the address of the symbol (in stead of 0).
Note. doing an 'nm' on the produced binary, only shows one entry for 'var' :
00008454 R var
indicating that it is defined, and in the read-only section.
Any idea how to resolve this problem ?
Greetings,
--
Jeroen Dobbelaere
Embedded Software Engineer
ACUNIA Embedded Solutions
http://www.acunia.com/aes