链接器脚本问题(对“puts”的未定义引用)
Problem with linker script (undefined reference to `puts')
所以,这是我的问题。
我一直在尝试使用 ld 脚本 link 一个带有 .c 文件的 .asm,但我得到的只是
hello.c:(.text+0xa): 未定义对“puts”的引用
我的文件如下:
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
}
生成文件:
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 $@ $<
.c 和 .asm 可以毫无问题地 linked,如果我 运行
gcc -m64 $(OBJ) -o $@
而不是相应的 ld 命令,但这没有考虑 linker.ld .
我尝试了 -lc 选项,但它也不起作用。
我用的是 fedora 33,如果有作用的话。
有什么建议吗?
要将汇编文件集成到普通的 C 程序中,您只需编写汇编代码,然后 link 将它正常地放入程序中。例如,您可以简单地做
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");
}
然后 assemble,编译,然后 link 像这样:
nasm -felf64 main.asm
cc -o hello main.o hello.c
这会做正确的事情,你最终会得到一个可以工作的二进制文件。无需编写 linker 脚本、初始化代码、堆栈设置代码,甚至无需自己调用 linker。让 C 编译器处理所有这些。
需要注意的是,无论何时调用 C 函数,都需要满足 AMD64 SysV ABI。这不仅规定哪些参数进入哪些寄存器,而且还告诉您堆栈指针必须在函数调用时与 16 的倍数对齐。为此,使用了 push rbp; mov rbp, rsp
序言。它在堆栈上压入 8 个字节以恢复在启动代码压入 main
的 return 地址时丢失的对齐。
所以,这是我的问题。
我一直在尝试使用 ld 脚本 link 一个带有 .c 文件的 .asm,但我得到的只是 hello.c:(.text+0xa): 未定义对“puts”的引用
我的文件如下:
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
}
生成文件:
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 $@ $<
.c 和 .asm 可以毫无问题地 linked,如果我 运行
gcc -m64 $(OBJ) -o $@
而不是相应的 ld 命令,但这没有考虑 linker.ld .
我尝试了 -lc 选项,但它也不起作用。
我用的是 fedora 33,如果有作用的话。
有什么建议吗?
要将汇编文件集成到普通的 C 程序中,您只需编写汇编代码,然后 link 将它正常地放入程序中。例如,您可以简单地做
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");
}
然后 assemble,编译,然后 link 像这样:
nasm -felf64 main.asm
cc -o hello main.o hello.c
这会做正确的事情,你最终会得到一个可以工作的二进制文件。无需编写 linker 脚本、初始化代码、堆栈设置代码,甚至无需自己调用 linker。让 C 编译器处理所有这些。
需要注意的是,无论何时调用 C 函数,都需要满足 AMD64 SysV ABI。这不仅规定哪些参数进入哪些寄存器,而且还告诉您堆栈指针必须在函数调用时与 16 的倍数对齐。为此,使用了 push rbp; mov rbp, rsp
序言。它在堆栈上压入 8 个字节以恢复在启动代码压入 main
的 return 地址时丢失的对齐。