Reputation: 78
So, here is my problem.
I have been trying to link an .asm with a .c file using a ld script, but all I get is hello.c:(.text+0xa): undefined reference to `puts'
My files are as follows:
bootinit.asm:
global main
extern zain
KERNEL_STACK_SIZE equ 4096 ; size of stack in bytes
section .bss
align 4 ; align at 4 bytes
kernel_stack: ; label points to beginning of memory
resb KERNEL_STACK_SIZE ; reserve stack for the kernel
mov esp, kernel_stack + KERNEL_STACK_SIZE ; point esp to the start of the
; stack (end of memory area)
section .text
main:
mov ecx,'A'
mov edx, 1
int 0x80
call zain
ret
hello.c:
#include <stdio.h>
void zain(){
printf("Hello! \n\n");
}
linker.ld:
ENTRY(main)
MEMORY {
bootsector(rwx) : ORIGIN = 0x70000, LENGTH = 50k
}
makefile:
ARCH_PREFIX:=i386
LINKER=linker.ld
LDFLAGS = \
-T$(LINKER)
C_FILES := $(shell find ./ -type f -name '*.c' | sort)
ASM_FILES := $(shell find ./ -type f -name '*.asm' | sort)
OBJ := $(ASM_FILES:.asm=.o) $(C_FILES:.c=.o)
all: bootFinal.bin
bootFinal.bin: bootinit.elf
objcopy --binary-architecture=i386:x86-64 --remove-section=.comment $< $@
bootinit.elf: $(OBJ)
ld -melf_x86_64 -T$(LINKER) $(OBJ) -o $@
%.o: %.asm
nasm $< -f elf64 -o $@
%.o: %.c
gcc -I/usr/include -m64 -libc -Wall -Wextra -Werror -c -o $@ $<
The .c and the .asm can be linked without problem and call one another if I run
gcc -m64 $(OBJ) -o $@
instead of the corresponding ld command, but this doesn't take into account the linker.ld .
I tried the -lc option but it doesn't work either.
I use fedora 33 if that plays any role.
Any suggestions?
Upvotes: 0
Views: 1008
Reputation: 93062
To integrate an assembly file into a normal C program, you just write your assembly code and link it in the program as normal. For example, you can simply do
global main:function
extern zain
section .text
main: push rbp
mov rbp, rsp
call zain
pop rbp
ret
#include <stdio.h>
void zain(){
printf("Hello! \n\n");
}
and then assemble, compile, and link like this:
nasm -felf64 main.asm
cc -o hello main.o hello.c
This'll do the right thing and you end up with a working binary. There's no need to write linker scripts, initialisation code, stack set up code, or to even invoke the linker yourself. Just let the C compiler deal with all this.
One caveat is that you need to fulfil the AMD64 SysV ABI whenever you call C functions. This not only mandates which arguments go into which registers, but also tells you that the stack pointer must be aligned to a multiple of 16 on function call. For this reason, a push rbp; mov rbp, rsp
prologue is used. It pushes 8 bytes on the stack to restore the alignment that was lost when the startup code pushed the return address of main
.
Upvotes: 1