GeoMldr
GeoMldr

Reputation: 78

Problem with linker script (undefined reference to `puts')

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

Answers (1)

fuz
fuz

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

main.asm

        global  main:function
        extern  zain
        section .text
main:   push    rbp
        mov     rbp, rsp
        call    zain
        pop     rbp
        ret

hello.c

#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

Related Questions