This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

ld relocation problem on ARM (PIC related)


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



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]