RISC-V交叉编译链接错误:undefined reference to fseek/fread
问题描述
在VMware Ubuntu 22.04环境下使用riscv64-linux-gnu交叉编译工具链时,遇到以下链接错误:
riscv64-linux-gnu-ld: loader.c:(.text.naive_uload+0x4c): undefined reference to
fseek' riscv64-linux-gnu-ld: loader.c:(.text.naive_uload+0x78): undefined reference tofread'
riscv64-linux-gnu-ld: loader.c:(.text.naive_uload+0xbc): undefined reference tofseek' riscv64-linux-gnu-ld: loader.c:(.text.naive_uload+0xe0): undefined reference tofread'
相关Makefile代码
主Makefile
# Makefile for AbstractMachine Kernels and Libraries ### *Get a more readable version of this Makefile* by `make html` (requires python-markdown) html: cat Makefile | sed 's/^\([^#]\)/ \1/g' | markdown_py > Makefile.html .PHONY: html ## 1. Basic Setup and Checks ### Default to create a bare-metal kernel image ifeq ($(MAKECMDGOALS),) MAKECMDGOALS = image .DEFAULT_GOAL = image endif ### Override checks when `make clean/clean-all/html` ifeq ($(findstring $(MAKECMDGOALS),clean|clean-all|html),) ### Print build info message $(info # Building $(NAME)-$(MAKECMDGOALS) [$(ARCH)]) ### Check: environment variable `$AM_HOME` looks sane ifeq ($(wildcard $(AM_HOME)/am/include/am.h),) $(error $$AM_HOME must be an AbstractMachine repo) endif ### Check: environment variable `$ARCH` must be in the supported list ARCHS = $(basename $(notdir $(shell ls $(AM_HOME)/scripts/*.mk))) ifeq ($(filter $(ARCHS), $(ARCH)), ) $(error Expected $$ARCH in {$(ARCHS)}, Got "$(ARCH)") endif ### Extract instruction set architecture (`ISA`) and platform from `$ARCH`. Example: `ARCH=x86_64-qemu -> ISA=x86_64; PLATFORM=qemu` ARCH_SPLIT = $(subst -, ,$(ARCH)) ISA = $(word 1,$(ARCH_SPLIT)) PLATFORM = $(word 2,$(ARCH_SPLIT)) ### Check if there is something to build ifeq ($(flavor SRCS), undefined) $(error Nothing to build) endif ### Checks end here endif ## 2. General Compilation Targets ### Create the destination directory (`build/$ARCH`) WORK_DIR = $(shell pwd) DST_DIR = $(WORK_DIR)/build/$(ARCH) $(shell mkdir -p $(DST_DIR)) ### Compilation targets (a binary image or archive) IMAGE_REL = build/$(NAME)-$(ARCH) IMAGE = $(abspath $(IMAGE_REL)) ARCHIVE = $(WORK_DIR)/build/$(NAME)-$(ARCH).a ### Collect the files to be linked: object files (`.o`) and libraries (`.a`) OBJS = $(addprefix $(DST_DIR)/, $(addsuffix .o, $(basename $(SRCS)))) LIBS := $(sort $(LIBS) am klib) # lazy evaluation ("=") causes infinite recursions LINKAGE = $(OBJS) \ $(addsuffix -$(ARCH).a, $(join \ $(addsuffix /build/, $(addprefix $(AM_HOME)/, $(LIBS))), \ $(LIBS) )) ## 3. General Compilation Flags ### (Cross) compilers, e.g., mips-linux-gnu-g++ AS = $(CROSS_COMPILE)gcc CC = $(CROSS_COMPILE)gcc CXX = $(CROSS_COMPILE)g++ LD = $(CROSS_COMPILE)ld OBJDUMP = $(CROSS_COMPILE)objdump OBJCOPY = $(CROSS_COMPILE)objcopy READELF = $(CROSS_COMPILE)readelf ### Compilation flags INC_PATH += $(WORK_DIR)/include $(addsuffix /include/, $(addprefix $(AM_HOME)/, $(LIBS))) INCFLAGS += $(addprefix -I, $(INC_PATH)) CFLAGS += -O2 -MMD -Wall -Werror $(INCFLAGS) \ -D__ISA__=\"$(ISA)\" -D__ISA_$(shell echo $(ISA) | tr a-z A-Z)__ \ -D__ARCH__=$(ARCH) -D__ARCH_$(shell echo $(ARCH) | tr a-z A-Z | tr - _) \ -D__PLATFORM__=$(PLATFORM) -D__PLATFORM_$(shell echo $(PLATFORM) | tr a-z A-Z | tr - _) \ -DARCH_H=\"arch/$(ARCH).h\" \ -fno-asynchronous-unwind-tables -fno-builtin -fno-stack-protector \ -Wno-main -U_FORTIFY_SOURCE CXXFLAGS += $(CFLAGS) -ffreestanding -fno-rtti -fno-exceptions ASFLAGS += -MMD $(INCFLAGS) LDFLAGS += -z noexecstack ## 4. Arch-Specific Configurations ### Paste in arch-specific configurations (e.g., from `scripts/x86_64-qemu.mk`) -include $(AM_HOME)/scripts/$(ARCH).mk ### Fall back to native gcc/binutils if there is no cross compiler ifeq ($(wildcard $(shell which $(CC))),) $(info # $(CC) not found; fall back to default gcc and binutils) CROSS_COMPILE := endif ## 5. Compilation Rules ### Rule (compile): a single `.c` -> `.o` (gcc) $(DST_DIR)/%.o: %.c @mkdir -p $(dir $@) && echo + CC $< @$(CC) -std=gnu11 $(CFLAGS) -c -o $@ $(realpath $<) ### Rule (compile): a single `.cc` -> `.o` (g++) $(DST_DIR)/%.o: %.cc @mkdir -p $(dir $@) && echo + CXX $< @$(CXX) -std=c++17 $(CXXFLAGS) -c -o $@ $(realpath $<) ### Rule (compile): a single `.cpp` -> `.o` (g++) $(DST_DIR)/%.o: %.cpp @mkdir -p $(dir $@) && echo + CXX $< @$(CXX) -std=c++17 $(CXXFLAGS) -c -o $@ $(realpath $<) ### Rule (compile): a single `.S` -> `.o` (gcc, which preprocesses and calls as) $(DST_DIR)/%.o: %.S @mkdir -p $(dir $@) && echo + AS $< @$(AS) $(ASFLAGS) -c -o $@ $(realpath $<) ### Rule (recursive make): build a dependent library (am, klib, ...) $(LIBS): %: @$(MAKE) -s -C $(AM_HOME)/$* archive ### Rule (link): objects (`*.o`) and libraries (`*.a`) -> `IMAGE.elf`, the final ELF binary to be packed into image (ld) $(IMAGE).elf: $(OBJS) am $(LIBS) @echo + LD "->" $(IMAGE_REL).elf @$(LD) $(LDFLAGS) -o $(IMAGE).elf --start-group $(LINKAGE) --end-group ### Rule (archive): objects (`*.o`) -> `ARCHIVE.a` (ar) $(ARCHIVE): $(OBJS) @echo + AR "->" $(shell realpath $@ --relative-to .) @ar rcs $(ARCHIVE) $(OBJS) ### Rule (`#include` dependencies): paste in `.d` files generated by gcc on `-MMD` -include $(addprefix $(DST_DIR)/, $(addsuffix .d, $(basename $(SRCS)))) ## 6. Miscellaneous ### Build order control image: image-dep archive: $(ARCHIVE) image-dep: $(OBJS) am $(LIBS) @echo \# Creating image [$(ARCH)] .PHONY: image image-dep archive run $(LIBS) ### Clean a single project (remove `build/`) clean: rm -rf Makefile.html $(WORK_DIR)/build/ .PHONY: clean ### Clean all sub-projects within depth 2 (and ignore errors) CLEAN_ALL = $(dir $(shell find . -mindepth 2 -name Makefile)) clean-all: $(CLEAN_ALL) clean $(CLEAN_ALL): -@$(MAKE) -s -C $@ clean .PHONY: clean-all $(CLEAN_ALL)
项目Makefile
#HAS_NAVY = 1 RAMDISK_FILE = build/ramdisk.img NAME = nanos-lite SRCS = $(shell find -L ./src/ -name "*.c" -o -name "*.cpp" -o -name "*.S") include $(AM_HOME)/Makefile ifeq ($(ARCH),native) ISA = am_native else INC_PATH += include $(NAVY_HOME)/libs/libc/include endif ./src/resources.S: $(RAMDISK_FILE) @touch $@ ifeq ($(HAS_NAVY),) files = $(RAMDISK_FILE) src/files.h src/syscall.h # create an empty file if it does not exist $(foreach f,$(files),$(if $(wildcard $f),, $(shell touch $f))) else ifeq ($(wildcard $(NAVY_HOME)/libs/libos/src/syscall.h),) $(error $$NAVY_HOME must be a Navy-apps repo) endif update: $(MAKE) -s -C $(NAVY_HOME) ISA=$(ISA) ramdisk @ln -sf $(NAVY_HOME)/build/ramdisk.img $(RAMDISK_FILE) @ln -sf $(NAVY_HOME)/build/ramdisk.h src/files.h @ln -sf $(NAVY_HOME)/libs/libos/src/syscall.h src/syscall.h .PHONY: update endif
解决方案
错误原因是链接阶段未包含实现fseek/fread的标准C库或项目自带的libc库,以下是几种可行的修复方式:
方式1:链接项目自带的NAVY libc
取消项目Makefile中#HAS_NAVY = 1的注释,启用NAVY环境:
HAS_NAVY = 1
启用后,Makefile会自动链接NAVY的libc库,同时确保NAVY_HOME环境变量正确指向Navy-apps仓库路径。
方式2:在主Makefile中添加libc到链接库列表
修改主Makefile中的LIBS定义,加入libc:
LIBS := $(sort $(LIBS) am klib libc)
这会让Makefile自动编译并链接AM_HOME或NAVY_HOME下的libc库。
方式3:直接链接交叉编译工具链的标准libc
在主Makefile的LDFLAGS中添加-lc参数,强制链接riscv64-linux-gnu工具链的标准C库:
LDFLAGS += -z noexecstack -lc
方式4:改用gcc而非ld进行链接
当前链接命令使用ld直接链接,而gcc会自动处理标准库的依赖和路径。修改主Makefile中的链接规则,将$(LD)替换为$(CC):
$(IMAGE).elf: $(OBJS) am $(LIBS) @echo + LD "->" $(IMAGE_REL).elf @$(CC) $(LDFLAGS) -o $(IMAGE).elf --start-group $(LINKAGE) --end-group
内容的提问来源于stack exchange,提问作者Lonely George

