views:

22

answers:

0

I obtained a generic linker script using "ld --verbose test.o" and simply added a memory section. From what I understand this should work fine, but no matter how I setup the memory section the resulting program never functions properly. (ld generated linker script can be found here).

tl;dr; How do you use MEMORY{...} correctly in GNU ld linker scripts?

Test program (sum the elements of an array):

#include <stdio.h>
#include <stdint.h>

uint32_t array[1024];

uint32_t sumArray(uint32_t *arr, size_t size)
{
    size_t i;
    uint32_t sum=0;
    for(i=0; i<size; i++){
            sum += arr[i];
    }
    return sum;
}

int main()
{
    uint32_t sum;
    int i;
    for (i=0; i<1024; i++) array[i] = 1;

    sum = sumArray(array,1024);

    printf("%d\n", sum);
    return 0;
}

If I compile this (gcc -c test.c) then link the .o file via:

ld  --no-add-needed --build-id -m elf_i386 --hash-style=gnu -static -o test /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/gcc/i686-redhat-linux/4.4.4/crtbeginT.o -L/usr/lib/gcc/i686-redhat-linux/4.4.4 -L/usr/lib/gcc/i686-redhat-linux/4.4.4 -L/usr/lib test.o --start-group -lgcc -lgcc_eh -lc --end-group /usr/lib/gcc/i686-redhat-linux/4.4.4/crtend.o /usr/lib/crtn.o -T ld.script -lc

Things work fine.

But when I modify the linker script to include a memory section (I've tried many different memory declarations, this is just an example):

MEMORY
{
    lowMem (wx)   : o = 0x0, l = 2048M
    allocMem (ax) : o = 0x80000000, l = 1024M
}

The process segfaults, gdb reports:

Program received signal SIGSEGV, Segmentation fault.
0x0000092f in __pthread_initialize_minimal ()

Yes, that's an awfully low link address for pthread, but even changing the memory declaration to something like:

lowMem (wx)   : o = 0x08000000, l = 32M

Doesn't seem to help - the pthread address is now somewhere normal, but the process still segfaults at this new, higher, address.

Example disassembly of __pthread_initialize_minimal:

   0x08000900 <+0>:     push   %ebp
   0x08000901 <+1>:     mov    %esp,%ebp
   0x08000903 <+3>:     push   %edi
   0x08000904 <+4>:     push   %esi
   0x08000905 <+5>:     push   %ebx
   0x08000906 <+6>:     sub    $0x4c,%esp
   0x08000909 <+9>:     mov    0x808d07c,%eax
   0x0800090e <+14>:    test   %eax,%eax
   0x08000910 <+16>:    je     0x8000970 <__pthread_initialize_minimal+112>
   0x08000912 <+18>:    mov    0x808d0a0,%edx
   0x08000918 <+24>:    shl    $0x5,%edx
   0x0800091b <+27>:    lea    (%eax,%edx,1),%edx
   0x0800091e <+30>:    cmp    %edx,%eax
   0x08000920 <+32>:    jb     0x800092f <__pthread_initialize_minimal+47>
   0x08000922 <+34>:    jmp    0x8000970 <__pthread_initialize_minimal+112>
   0x08000924 <+36>:    nopl   0x0(%eax)
   0x08000928 <+40>:    add    $0x20,%eax
   0x0800092b <+43>:    cmp    %edx,%eax
   0x0800092d <+45>:    jae    0x8000970 <__pthread_initialize_minimal+112>
=> 0x0800092f <+47>:    cmpl   $0x7,(%eax)

and yes, EAX is pointing out of the memory area... but why?

(gdb) info registers
eax            0x7fff034        134213684