If we need to pass five arguments in a system call, the inline assembly statement won't work with PIC since x86 doesn't have enough registers to go around. We need to program in assembly language directly.
The normal assembly language code for
syscall (int syscall_number, ...);
looks like:
.file "syscall.S" .text .global syscall .global errno .align 16 syscall: pushl %ebp movl %esp,%ebp pushl %edi pushl %esi pushl %ebx movl 8(%ebp),%eax movl 12(%ebp),%ebx movl 16(%ebp),%ecx movl 20(%ebp),%edx movl 24(%ebp),%esi movl 28(%ebp),%edi int $0x80 test %eax,%eax jge .LLexit negl %eax movl %eax,errno movl $-1,%eax .LLexit: popl %ebx popl %esi popl %edi movl %ebp,%esp popl %ebp ret .type syscall,@function .L_syscall_end: .size syscall,.L_syscall_end - syscall
Under PIC, we have to access any global variable via the global offset table in addition to preserving the base register ebx. The modified code is:
.file "syscall.S" .text .global syscall .global errno .align 16 syscall: pushl %ebp movl %esp,%ebp pushl %edi pushl %esi pushl %ebx call .LL4 .LL4: popl %ebx addl $_GLOBAL_OFFSET_TABLE_+[.- .LL4],%ebx pushl %ebx movl 8(%ebp),%eax movl 12(%ebp),%ebx movl 16(%ebp),%ecx movl 20(%ebp),%edx movl 24(%ebp),%esi movl 28(%ebp),%edi int $0x80 popl %ebx movl %eax,%edx test %edx,%edx jge .LLexit negl %edx movl errno@GOT(%ebx),%eax movl %edx,(%eax) movl $-1,%eax .LLexit: popl %ebx popl %esi popl %edi movl %ebp,%esp popl %ebp ret .type syscall,@function .L_syscall_end: .size syscall,.L_syscall_end - syscall
Finally, if one wants to program in assembly language for PIC and one is not sure how to do it, one can always write the C code and then do
# gcc -O -fPIC -S foo.c
This will tell gcc to generate the assembly output, foo.s. One can take a look at and modify it according to one's needs.