C and Assembly can be used together to provide extra flexibility. You can create static libraries in Assembly that you call from C, and vice-versa, you can call C functions from within Assembly. Check out the code samples below that demonstrate that process.
It's actually slightly incorrect to say we are 'calling C from Assembly' or vice-versa because once the code is compiled, it is the same machine language. Whether you compile the object files from Assembly or from C they turn out the same. Once they are object files they can be called from anywhere, but they have to be defined as externals and linked. You could create static libraries as object files from other languages too. It doesn't just have to be Assembly and C.
Creating a Static Library with Assembly
The first step to calling an assembly function from C is to package it as a static library. Create a function and then compile the assembly source to an object file. We will link that later when we compile the c program. Save the assembly source here as say_hi.asm.
SECTION .DATA
hello: db 'Hello world!',10
helloLen: equ $-hello
SECTION .TEXT
GLOBAL say_hi
say_hi:
mov eax,4 ; write()
mov ebx,1 ; STDOUT
mov ecx,hello
mov edx,helloLen
int 80h ; Interrupt
ret ; Return control
Then compile the assembly source to an object file with
nasm -f elf64 say_hi.asm say_hi.o
Calling Assembly From C
/* example.c */
#include <stdio.h>
int main(int argc, char *argv[]) {
extern say_hi();
say_hi();
}
Next, compile and link the C program with gcc. Do that with
gcc example.c say_hi.o -o hello
You can then run the hello program that was just created.
./hello
Calling C from Assembly
You can call C functions from Assembly as well. This example calls printf(). In the main function, we push and pop the stack and put our operations in between. We move all the parameters in to the appropriate registers, and then we call the function.
; Define printf as an external function
extern printf
SECTION .DATA
msg: db "Hello world", 0 ; Zero is Null terminator
fmt: db "%s", 10, 0 ; printf format string follow by a newline(10) and a null terminator(0), "\n",'0'
SECTION .TEXT
global main
main:
push rbp ; Push stack
; Set up parameters and call the C function
mov rdi,fmt
mov rsi,msg
mov rax,0
call printf
pop rbp ; Pop stack
mov rax,0 ; Exit code 0
ret ; Return
Compile and run that with
nasm printf.asm -f elf64 -o printf.o
gcc printf.o
./a.out