Why "symbol@GOT" is not permitted on pie binary?

186 views Asked by At

Here is sample assembly file, test.s

.global main  
main:  
 mov __progname@GOT, %eax         // failed to compile
 mov __progname@GOT(%ebx), %eax   //succeed to compile

I tried compiling it with -pie flag, but failed.

$ gcc -pie -o test test.s
osboxes@osboxes:/mnt/hgfs/VM_Shared/Reassemblabla/src$ gcc -pie -o test test.s
/usr/bin/ld: /tmp/ccPGMLlH.o: direct GOT relocation R_386_GOT32X against `__progname' without base register can not be used when making a shared object
/usr/bin/ld: failed to set dynamic section sizes: File format not recognized
collect2: error: ld returned 1 exit status

Error said, In pie binary, access to GOT entry is only available using base register.

Question.
I don't know why compiler is complaining like above.
More specifically, why __progname@GOT addressing is not permitted on pie binary?



My opinion.
Loader knows the address of __progname@GOT in loading time of pie binary.

So, loader can simply write this address at location of __progname@GOT in loading time.
That's what loader can do.

So I cannot understand why compiler insist on register-relative accessing like
mov __progname@GOT(%ebx), %eax.

1

There are 1 answers

0
mevets On

PIE is supposed to use pc-relative addressing; ia32 is crap at this, so you need to do something like:

    call thunk
    add  $_GLOBAL_OFFSET_TABLE__, %eax
    mov  __progname@GOT(%eax), %eax
    ret
thunk:
    mov (%esp), %eax
    ret

Notice offset from this program address to the _GLOBAL_OFFSET_TABLE__ is computed to reference GOT. Thus the program can be loaded (as opposed to linked or located) at any address, and will find the GOT, and all variables, because the relative offset is the same. For reference, the amd64 version of the above is something like:

mov    __progname(%rip), %rax
ret

Notice that both of these keep the text ‘pure’....