How to call a C function from assembly file? - c

I have the source code of a static library. I'm trying to compile it into a dynamic library. The source code has .c files and one .S file. While compiling I'm getting a relocation error from the assembly code. Going through the assembly code, I find out that this error is generated while calling a function from one of the C files. Assembly code segment is,
.extern dune_syscall_handler // I added it
__dune_syscall:
testq $1, %gs:IN_USERMODE
jnz 1f
pushq %r11
popfq
vmcall
jmp *%rcx
1:
/* first switch to the kernel stack */
movq %rsp, %gs:TMP
movq %gs:TRAP_STACK, %rsp
/* now push the trap frame onto the stack */
subq $TF_END, %rsp
movq %rcx, RIP(%rsp)
movq %r11, RFLAGS(%rsp)
movq %r10, RCX(%rsp) /* fixup to standard 64-bit calling ABI */
SAVE_REGS 0, 1
movq %gs:TMP, %rax
movq %rax, RSP(%rsp)
SET_G0_FS_BASE
/* re-enable interrupts and jump to the handler */
sti
movq %rsp, %rdi /* argument 0 */
lea dune_syscall_handler, %rax <-------------------- Causing error
call *%rax
SET_G3_FS_BASE
RESTORE_REGS 0, 1
movq RCX(%rsp), %r10
movq RFLAGS(%rsp), %r11
movq RIP(%rsp), %rcx
/* switch to the user stack and return to ring 3 */
movq RSP(%rsp), %rsp
sysretq
Causing the following error,
ld: dune.o: relocation R_X86_64_32S against `dune_syscall_handler' can not be used when
making a shared object; recompile with -fPIC
dune.o: error adding symbols: Bad value
dune_syscall_handler is defined in a separate C file. I use -fPIC flag while compiling. readelf shows the following,
$readelf -r dune.o
Relocation section '.rela.text' at offset 0x18c8 contains 2 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000000219 00120000000b R_X86_64_32S 0000000000000000 dune_syscall_handler + 0
I guess Sym. Value suppose to filledup by linker during runtime? That's why it is empty? Listing symbols from the object shows,
$nm dune.o
0000000000000070 t __dune_retry
00000000000002e5 T dune_jump_to_user
000000000000016c T __dune_syscall
000000000000028e T __dune_syscall_end
U dune_syscall_handler
0000000000000100 a I
I'm new to assembly. My understanding is while trying to load the effective address of the C function dune_syscall_handler, the linker could not find it. I just can't figure out why. Can someone please tell me how can I call a C function from an assembly file? There is a similar post with a same tile How to call a C function from Assembly code. But I guess my problem is different.

Related

Operand type mismatch for `push' [duplicate]

This question already has answers here:
Reading program counter directly
(7 answers)
Closed 4 years ago.
I need help with C code that uses ASSEMBLY parts. GCC has a problem compiling the assembly, error:
$ make
gcc -Wall -g -std=c99 -pedantic -c -o sthread.o sthread.c
sthread.c: In function ‘sthread_create’:
sthread.c:159:57: warning: pointer of type ‘void *’ used in arithmetic [-Wpointer-arith]
t->context = __sthread_initialize_context(t->memory + DEFAULT_STACKSIZE, f, arg);
^
gcc -Wall -g -std=c99 -pedantic -c -o queue.o queue.c
as -g -o glue.o glue.s
glue.s: Assembler messages:
glue.s:32: Error: operand type mismatch for `push'
<wbudowane>: polecenia dla obiektu 'glue.o' nie powiodły się
make: *** [glue.o] Błąd 1
Code in question:
__sthread_switch:
# preserve CPU state on the stack, with exception of stack pointer, instruction pointer first, reverse order
pushq %rip #line 32
pushf
pushq %rdi
pushq %rsi
pushq %rbp
pushq %rbx
pushq %rdx
pushq %rcx
pushq %rax
# Call the high-level scheduler with the current context as an argument
movq %rsp, %rdi
movq scheduler_context, %rsp
call __sthread_scheduler
With X86_64 you cannot push the %rip, in fact you cannot access it directly at all.
If you still need to do it, you can do
leaq 0(%rip), %rax # Or any other GPR that is free
pushq %rax
OR
callq . + 5 # no label, hard-code instruction length
# or
callq 1f ; 1: # with a local numbered label
Although I am not sure why you would want to stash the %rip, if you restore it from here, the execution will continue from the push instruction. Is there any value to that? You need to rethink your thread switching logic.
To push RIP, simply execute call with a zero displacement.
call next_insn
next_insn:
So the jump part of call is a no-op, so you just get the effect of pushing a return address (i.e. the current RIP).
Fun fact: call rel32=0 is a special case and doesn't unbalance the return address predictor stack on CPUs more recent than PPro. So call next_insn / pop eax is useful in 32-bit mode as an equivalent to lea (%rip), %rax.
It's still a branch instruction, and still decodes to multiple uops (unlike a push of a GPR which is 1 micro-fused uop), so lea (%rip), %rax ; push %rax may be more efficient.

subq $40 %rsp crash with AS but GCC not

I meet a strange phenomenon, I record the code in following.
My test bed is x86_64 and gcc is 5.3.0
When I reserve some space in the stack for local value, sometimes it would crash.
| AS and LD | gcc |
--------------------------------------------
40 bytes in stack | crash | ok |
--------------------------------------------
32 bytes in stack | ok | crash |
--------------------------------------------
.section .data
fmt:
.ascii "0x%lx\n\0"
.section .text
.global _start
_start:
subq $40, %rsp # subq $32, %rsp is OK
# I want to reserve some place for local value.
movq $8, %rsi
movq $fmt, %rdi
call printf #print something
addq $40, %rsp
movq $1, %rax
int $0x80
as tsp.s -o tsp.o
ld -lc -I /lib64/ld-linux-x86-64.so.2 tsp.o -o tsp
./tsp
Segmentation fault (core dumped)
This time I use gcc to compile and link.
It is ok, when I reserve 40 bytes in the stack.
It crash, when I reserve 32 bytes in the stack.
.section .data
fmt:
.ascii "0x%lx\n\0"
.section .text
.global main
main:
subq $40, %rsp # if subq $32, %rsp, it would crash.
movq $8, %rsi
movq $fmt, %rdi
call printf
addq $40, %rsp
movq $1, %rax
int $0x80
gcc tsp.s -o tsp
./tsp
0x8
When I tested your code printf crashed when accessing xmm registers. There are two reasons for it. When you let gcc do the compilation and linking it will actually have additional code before main. That code will correctly align the stack and then call main.
Since main was called like a normal function the stack will be aligned at 8 mod 16 because of the call instruction, but when calling a function the stack has to be correctly aligned (0 mod 16). The reason for the alignment requirement is because of xmm registers (among others).
Now, why did printf touch xmm registers in the first place? Because you called printf incorrectly. The ABI for amd64 says:
When a function taking variable-arguments is called, %rax must be set to the total number of floating point parameters passed to the function in SSE registers.
Your rax probably has some non-zero value in it.
So, two things to fix your problems. xorl %eax, %eax to zero %rax before the call to printf. And be aware of how you have been called and how to align the stack. If you've been called as a normal function, you need to subtract 8+n*16 (n can be 0) from your stack pointer before doing a call. If you've been called as an entry point to be safe you need to properly align your stack pointer because I'm not sure if the kernel always guarantees that your stack pointer will be aligned.

Passing 128 bit register to C function from Assembly [duplicate]

This question already has an answer here:
Printing floating point numbers from x86-64 seems to require %rbp to be saved
(1 answer)
Closed 5 years ago.
I am attempting to test passing a floating point value to a C function from assembly on 64-bit Linux. The C file containing my C function looks like this:
#include <stdio.h>
extern void printer(double k){
printf("%f\n",k);
}
Its expected behavior is to simply print the floating point number passed to it. I am trying to accomplish this from an AT&T-syntax assembly file. If I am not mistaken, in 64-bit linux, the calling convention is to pass floating point arguments on the XMM registers. My .s file is the following:
.extern printer
.data
var:
.double 120.1
.global main
main:
movups (var),%xmm0
call printer
mov $60,%rax
syscall
What I'm hoping this could do is have a variable (var) with value 120.1. This is then moved to the xmm0 register, which I expect is what is used to pass the argument k. This understanding of the calling convention is also backed up by the assembly code generated from the C file, a portion of which is below:
printer:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movsd %xmm0, -8(%rbp)
movq -8(%rbp), %rax
movq %rax, -16(%rbp)
movsd -16(%rbp), %xmm0
movl $.LC0, %edi
movl $1, %eax
call printf
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
My .s file assembles to an executable, but running it only gives a segmentation fault, and doesn't print the floating point value. I can only assume this is because I'm not properly moving the value to xmm0 and/or using the register to pass it to the function. Can somebody explain how I should pass the value to the function?
You have defined main in the data section, which makes it non-executable. Add a .text directive before main.

GCC assembly code shows 32bit registers on 64bit machine

I am trying to learn how to use ptrace library for tracing all system calls and their arguments. I am stuck in getting the arguments passed to system call.
I went through many online resources and SO questions and figured out that on 64 bit machine the arguments are stored in registers rax(sys call number), rdi, rsi, rdx, r10, r8, r9
in the same order. Check this website .
Just to confirm this I wrote a simple C program as follows
#include<stdio.h>
#include<fcntl.h>
int main() {
printf("some print data");
open("/tmp/sprintf.c", O_RDWR);
}
and generated assembly code for this using gcc -S t.c but assembly code generated is as below
.file "t.c"
.section .rodata
.LC0:
.string "some print data"
.LC1:
.string "/tmp/sprintf.c"
.text
.globl main
.type main, #function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $.LC0, %edi
movl $0, %eax
call printf
movl $2, %esi
movl $.LC1, %edi
movl $0, %eax
call open
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4"
.section .note.GNU-stack,"",#progbits
As you can see this code is storing parameters on esi and edi instead.
Why is happening?
Also please guide me on what is the best way to access these passed arguments from these registers/memory location from a C code? How can I figure out if the contents of register is the argument itself or is it a memory location where actual argument is stored?
Thanks!
this code is storing parameters on esi and edi
32-bit instructions are smaller, thus preferred when possible. See also Why do most x64 instructions zero the upper part of a 32 bit register.
How can I figure out if the contents of register is the argument itself or is it a memory location where actual argument is stored?
The AMD64 SystemV calling convention never implicitly replaces a function arg with a hidden pointer. Integer / pointer args in the C prototype always go in the arg-passing registers directly.
structs / unions passed by value go in one or more registers, or on the stack.
The full details are documented in the ABI. See more links in the x86 tag wiki. http://www.x86-64.org/documentation.html is down right now, so I linked the current revision on github.

gcc - structures as label for debugging

Context:
Linux 64.
I would like a way to tell gcc to keep the structure as they are when generating assembly with gcc -O0 -S -g myprog.c
By that, I mean: instead of referencing the structure by address, I would like them to be referenced by label. That would ease the parsing without reading the source code again.
So, for example:
struct mystruct{
int32_t a;
char * b;
}
would become something like:
label_mystruct:
-4(label_mystruct)
-12(label_mystruct)
and for example, referenced by:
add $56, -4(label_mystruct)
Currently, it is referenced like
.globl _main
_main:
LFB13:
LM157:
pushq %rbp #
LCFI27:
movq %rsp, %rbp#,
LCFI28:
subq $80, %rsp#,
movl %edi,-68(%rbp) # argc, argc,
movq %rsi,-80(%rbp) # argv, argv
Next line is the culprit:
movq -56(%rbp), %rdx # list, D.3781
movq -16(%rbp), %rax # arr, D.3780
movq %rdx, %rsi # D.3781,
movq %rax, %rdi # D.3780,
call _myaddhu #
I would like it to be
label_mystruct:
-4(label_mystruct)
-12(label_mystruct)
.globl _main
_main:
LFB13:
LM157:
pushq %rbp #
LCFI27:
movq %rsp, %rbp#,
LCFI28:
subq $80, %rsp#,
movl %edi,-68(%rbp) # argc, argc,
movq %rsi,-80(%rbp) # argv, argv
Now it is fine:
movq label_mystruct, %rdx # list, D.3781
movq -16(%rbp), %rax # arr, D.3780
movq %rdx, %rsi # D.3781,
movq %rax, %rdi # D.3780,
call _myaddhu #
Question:
Is that possible with gcc and without using external tools?
I think it's not possible, and this is by the setup used in GCC.
The problem here is that the struct here is stored on the stack and you cannot really have a label referring to something on the stack. If the struct was not on the stack it would have had a label referring to it (for example if it were a global variable).
What you have on the other hand is that GCC would generate debugging info which has information about what data is placed when running specific code. In your example it would in essense say that "when executing this code -56(%ebp) points to mystruct".
On the other hand if you would write assembler code by hand you could certainly have symbolic references to a variable. You could for example do:
#define MYSTRUCT -56(%ebp)
...
movq MYSTRUCT, %rdx
however the MYSTRUCT will be expanded and that symbol being lost during assembling the code. It would be of no help if GCC did this (except maybe that the assembler code generated by -s could be more readable), in addition GCC does not pass the assembler through preprocessor anyway (because it don't do this).
You get that if you put your struct into static storage. This of course alters the meaning of the code. For example, this code
struct {
int a, b;
} test;
int settest(int a, b) {
test.a = a;
test.b = b;
}
compiles to (cleaned up):
settest:
movl %edi, test(%rip)
movl %esi, test+4(%rip)
ret
.comm test,8,4
You could also try to pass the option -fverbose-asm to gcc which instructs gcc to add some annotations that might make the assembly easier to read.

Resources