I have written a small x86/32 assembler program that calls printf and gets compiled with gcc -m32 x.s:
.data
format:
.string "%d\n"
.text
.global main
.type main, @function
main:
mov $56, %eax
push %eax
call get_pc_eax
add $format - ., %eax
push %eax
# call printf@PLT
call get_pc_eax
add $_GLOBAL_OFFSET_TABLE_, %eax
mov printf@GOT(%eax), %eax
call *%eax
add $8, %esp
xor %eax, %eax
ret
get_pc_eax:
mov (%esp), %eax
ret
.section .note.GNU-stack,"",@progbits
If I enable the commented-out line call printf@PLT instead of the 4 lines after it (like it is now), then nothing happens on execution. I have some questions:
- Do I have to initialize the PLT before calling into it?
- Is this the recommended way to call a function in position independent code? It feels somewhat clumsy.
- I have searched for several hours and could not find a tutorial for i386 assembler on Linux using gas/gcc that also explains calling into libc and position independent code. I would be grateful if anyone could post a link.
UPDATE:
After some extended discussion I came up with this code for main:
1 push %ebx
2 mov $56, %ebx
3 push %ebx
4 call get_pc_ebx
5 add $format - ., %ebx
6 push %ebx
7 call get_pc_ebx
8 add $_GLOBAL_OFFSET_TABLE_, %ebx
9 xor %eax, %eax
10 call printf@PLT
11 add $8, %esp
12 pop %ebx
13 xor %eax, %eax
14 ret
This code works. If I comment out the setup of %ebx in lines 7 and 8 the code crashes. From this I figure %ebx needs to point to the global offset table.
Can anyone link a tutorial/article/source that explains this mechanism?