Linking C with NASM - c

I have a NASM file and a C file. How do I call a function in the C file from the NASM file? How do I call a NASM function from the C file?
Many Thanks
DD

Calling assembly function from C:
C file:
#include <stdio.h>
int add(int a, int b);
int main(int argc, char **argv)
{
printf("%d\n", add(2, 6));
return 0;
}
assembly file:
global add
section .data
section .text
add:
mov eax, [esp+4] ; argument 1
add eax, [esp+8] ; argument 2
ret
compiling:
$ nasm -f elf add.asm
$ gcc -Wall main.c add.o
$ ./a.out
8
$
Calling C function from assembly:
C file:
int add(int a, int b)
{
return a + b;
}
assembly file:
extern add
extern printf
extern exit
global _start
section .data
format db "%d", 10, 0
section .text
_start:
push 6
push 2
call add ; add(2, 6)
push eax
push format
call printf ; printf(format, eax)
push 0
call exit ; exit(0)
compiling:
$ gcc -Wall -c add.c
$ nasm -f elf main.asm
$ ld main.o add.o -lc -I /lib/ld-linux.so.2
$ ./a.out
8
$

Related

Cant run compiled file in Ubuntu

I have a problem I cant fix with a simple exercise my teacher assigned us.
I have this main.c that takes in a simple assembly function and I compile it with a make file, when I hit make run I get the following error :
"make: execvp: ./main: invalid argument make:***
[makefile:12:run] Error 127"
This is my make file:
main: main.o asm.o
gcc main.o asm.o -o main
main.o: main.c asm.h
gcc -Wall -g -c main.c -o main.o
asm.o: asm.s
gcc -Wall -g -c asm.s -o asm.o
run: main
./main
clean:
rm *.o main
My main.c file:
#include "asm.h"
int op1 = 0, op2 = 0, res = 0;
int main()
{
printf("Valor op1:");
scanf("%d", &op1);
printf("Valor op2:");
scanf("%d", &op2);
sum();
printf("sum = %d:0x%x\n", res, res);
return 0;
}
My asm.s:
.section .data
.global op1
.global op2
.global res
.section .text
.global sum # void sum(void)
sum:
movl op1(%rip), %ecx #place op1 in ecx
movl op2(%rip), %eax #place op2 in eax
addl %ecx, %eax #add ecx to eax. Result is in eax
movl %eax, res(%rip) # copy the result to res
ret
my asm.h:
#ifndef ASM_H
#define ASM_H
void sum();
#endif

Convert a Compiled C Program to shellcode (Hex)

So I wanted to convert a compiled C program into Hex format so that I can inject it inside the memory. The problem I am currently facing is that I have no idea how to convert a compiled C file to hex. Can someone show me how it's done?
My C Code (temp.c):
#include <stdio.h>
void main(){
printf("Working!");
}
Compiled it using gcc:
gcc -g temp.c -o temp -m32
You can write in assembly using write(); syscall and exit(); syscall.
Here code I wrote, file w.asm :
global _start
section .text
_start:
push byte 0x0a
push dword "ing!"
push dword "Work"
inc ebx
mov ecx, esp
mov dl, 9
mov al, 4
int 0x80
xor ebx, ebx
mov al, 1
int 0x80
Assembling and linking using nasm and ld :
nasm -f elf w.asm && ld -o w w.o
Dump binary file into hex (shellcode style) using objdump one-liner like this:
objdump -d ./w | grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
You will get the result like this :
"\x6a\x0a\x68\x69\x6e\x67\x21\x68\x57\x6f\x72\x6b\x43\x89\xe1\xb2\x09\xb0\x04\xcd\x80\x31\xdb\xb0\x01\xcd\x80"

C makefile issue, undefined reference to function

Im trying to do a simple excercise in compilation.
I have 1 c file 1 assembly file and a makefile.
when I run the 'make' command I get the following error:
gcc -g -m32 -Wall -o mainAssignment0.o mainAssignment0.c
/tmp/ccXfVxtg.o: In function `main':
/home/caspl202/Desktop/tasks/Assignment0/mainAssignment0.c:12: undefined reference to `do_Str'
collect2: error: ld returned 1 exit status
makefile:10: recipe for target 'mainAssignment0.o' failed
make: * [mainAssignment0.o] Error 1
Meaning that for some reason the c program doesnt recognize the external ASM function.
Whats even weirder is that when I run the same makefile on the same files on a different machine it works like a charm. I would really like someone to shed some light on this thing.
C code:
#include <stdio.h>
#define MAX_LEN 100
extern int do_Str(char*);
int main(int argc, char** argv) {
char str_buf[MAX_LEN];
int counter = 0;
fgets(str_buf, MAX_LEN, stdin);
counter = do_Str (str_buf);
printf("%s%d\n",str_buf,counter);
return 0;
}
ASM code:
section .data
an: dd 0
section .text
global do_Str
do_Str:
push ebp
mov ebp, esp
pushad
mov ecx, dword [ebp+8]
loop:
cmp byte [ecx], 32
jnz noS
inc dword [an]
noS:
cmp byte [ecx], 65
jl noC
cmp byte [ecx], 90
jg noC
add byte [ecx], 32
noC:
inc ecx
cmp byte [ecx], 0
jnz loop
popad
mov eax,[an]
mov esp, ebp
pop ebp
ret
Makefile:
all: exec
libs: asm-lib
asm-lib: asmAssignment0.s
nasm -g -f elf -o asmAssignment0.o asmAssignment0.s
exec: mainAssignment0.c libs
gcc -g -m32 -c -o mainAssignment0.o mainAssignment0.c
gcc -g -m32 -o Assignment0.out mainAssignment0.o asmAssignment0.o
.PHONY: clean
clean:
rm -rf ./*.o Assignment0.out
You don't need to declare the function external.
int do_Str(char*);
Also, a function in C is prefixed with an underscore, so you must name it accordingly in your asm file.
global _do_Str
_do_Str:
The underscore is automatically added by the C compiler, so you don't have to use it in the C module.
The reason for your error you quote here is that your compile line is wrong. You can tell because you're trying to create an object file, but getting errors from the linker, so something is clearly not right:
gcc -g -m32 -Wall -o mainAssignment0.o mainAssignment0.c
...
collect2: error: ld returned 1 exit status
The problem is you forgot to add the -c flag to this compile line, so that the compiler generates an object file.
However, in your makefile the -c is present, so clearly this error you quote is not generated from the makefile you show us.
exec: mainAssignment0.c libs
gcc -g -m32 -c -o mainAssignment0.o mainAssignment0.c

How to tell compiler to not generate "retq" after inline asm in a _Noreturn function?

I wrote the following code to call syscall exit without linking with glibc:
// a.c
#include <stdlib.h>
#include <sys/syscall.h>
#include <unistd.h>
_Noreturn void _start()
{
register int syscall_num asm ("rax") = __NR_exit;
register int exit_code asm ("rdi") = 0;
// The actual syscall to exit
asm volatile ("syscall"
: /* no output Operands */
: "r" (syscall_num), "r" (exit_code));
}
The Makefile:
.PHONY: clean
a.out: a.o
$(CC) -nostartfiles -nostdlib -Wl,--strip-all a.o
a.o: a.c
$(CC) -Oz -c a.c
clean:
rm a.o a.out
I make it with CC=clang-7 and it works perfectly well except that when I inspect the assembly generated by objdump -d a.out:
a.out: file format elf64-x86-64
Disassembly of section .text:
0000000000201000 <.text>:
201000: 6a 3c pushq $0x3c
201002: 58 pop %rax
201003: 31 ff xor %edi,%edi
201005: 0f 05 syscall
201007: c3 retq
there is a useless retq following the syscall. I wonder, is there any way to remove that without resorting to writing the whole function in assembly?
Add this after the system call that doesn't return:
__builtin_unreachable();

Assembly function call from c

I cannot combine my kernel_entry.asm and main.c. My main.c calls an asm function Sum. Both nasm and gcc compiles respective files. However, the linker gives an error.
Kernel_entry.asm:
[bits 32]
[extern _start]
[global _Sum]
....
_Sum:
push ebp
mov ebp, esp
mov eax, [ebp+8]
mov ecx, [ebp+12]
add eax, ecx
pop ebp
ret
main.c:
....
extern int Sum();
void start() {
....
int x = Sum(4, 5);
....
}
To compile source files, I use following commands:
nasm kernel_entry.asm -f win32 -o kernel_entry.o
gcc -ffreestanding -c main.c -o main.o
....
ld -T NUL -o kernel.tmp -Ttext 0x1000 kernel_entry.o main.o mem.o port_in_out.o screen.o idt.o
Linker gives following error:main.o:main.c:(.text+0xa82): undifened reference to 'Sum'. I tried everything but couldn't find any solution. When I remove asm function call from main.c, it works.
The TL;DR version of the answer is that mixing nasm's -f win32 generates an object file that is not compatible with the GNU toolchain on Windows - you need to use -f elf if you want to link using ld. That is described in NASM's documentation here under sections 7.5 and 7.9.
The hint for me was that by running nm kernel_entry.o generated:
00000000 a .absolut
00000000 t .text
00000001 a #feat.00
U _start
U _Sum
Which basically shows Sum as an undefined symbol. After compiling as ELF, I got:
U _start
00000000 T _Sum
indicating Sum as a recognised symbol in the text section.

Resources