views:

104

answers:

1

Is there a way to have gcc generate %pc relative addresses of constants? Even when the string appears in the text segment, arm-elf-gcc will generate a constant pointer to the data, load the address of the pointer via a %pc relative address and then dereference it. For a variety of reasons, I need to skip the middle step. As an example, this simple function:

const char * filename(void)
{
    static const char _filename[]
            __attribute__((section(".text")))
            = "logfile";
    return _filename;
}

generates (when compiled with arm-elf-gcc-4.3.2 -nostdlib -c -O3 -W -Wall logfile.c):

00000000 <filename>:
   0:   e59f0000        ldr     r0, [pc, #0]    ; 8 <filename+0x8>
   4:   e12fff1e        bx      lr
   8:   0000000c        .word   0x0000000c

0000000c <_filename.1175>:
   c:   66676f6c        .word   0x66676f6c
  10:   00656c69        .word   0x00656c69

I would have expected it to generate something more like:

filename:
    add r0, pc, #0
    bx lr
_filename.1175:
    .ascii "logfile\000"

The code in question needs to be partially position independent since it will be relocated in memory at load time, but also integrate with code that was not compiled -fPIC, so there is no global offset table.

My current work around is to call a non-inline function (which will be done via a %pc relative address) to find the offset from the compiled location in a technique similar to how -fPIC code works:

static intptr_t
__attribute__((noinline))
find_offset( void )
{
    uintptr_t pc;
    asm __volatile__ (
            "mov %0, %%pc" : "=&r"(pc)
    );

    return pc - 8 - (uintptr_t) find_offset;
}

But this technique requires that all data references be fixed up manually, so the filename() function in the above example would become:

const char * filename(void)
{
    static const char _filename[]
            __attribute__((section(".text")))
            = "logfile";
    return _filename + find_offset();
}
+1  A: 

Hmmm, maybe you have to compile it as -fPIC to get PIC. Or simply write it in assembler, assembler is a lot easier than the C you are writing.

00000000 :
   0:   e59f300c    ldr r3, [pc, #12]   ; 14 
   4:   e59f000c    ldr r0, [pc, #12]   ; 18 
   8:   e08f3003    add r3, pc, r3
   c:   e0830000    add r0, r3, r0
  10:   e12fff1e    bx  lr
  14:   00000004    andeq   r0, r0, r4
  18:   00000000    andeq   r0, r0, r0

0000001c :
  1c:   66676f6c    strbtvs r6, [r7], -ip, ror #30
  20:   00656c69    rsbeq   r6, r5, r9, ror #24

Are you getting the same warning I am getting?

/tmp/ccySyaUE.s: Assembler messages:
/tmp/ccySyaUE.s:35: Warning: ignoring changed section attributes for .text
dwelch
Yes, I do get the same warning. The easiest hack around it is to add a bogus newline and comment: __attribute__((section(".text\n#"))).It can't be compiled with -fPIC since there are functions in ROM that are at explicit addresses. Assembly works for me, but not for the other users of the system...
Hudson