You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用GCC链接时优化器出现undefined references问题求助

GCC LTO链接时无法解析newlib_syscalls.c中的符号(Clang可正常编译)

我在为AArch64裸机项目启用GCC的链接时优化(LTO)功能,遇到链接错误——链接器无法解析newlib_syscalls.c中定义的_close、_write等系统调用符号,但相同源码、库和编译选项下,Clang可以正常完成编译。

Clang编译成功输出

❯ CC=clang make               
clang -mlittle-endian -mcpu=cortex-a55 -mtune=cortex-a55 -target aarch64-none-elf --sysroot=/Applications/ArmGNUToolchain/13.2.Rel1/aarch64-none-elf/bin/../aarch64-none-elf -flto -c startup.c -o startup.o
clang -mlittle-endian -mcpu=cortex-a55 -mtune=cortex-a55 -target aarch64-none-elf --sysroot=/Applications/ArmGNUToolchain/13.2.Rel1/aarch64-none-elf/bin/../aarch64-none-elf -flto -ffat-lto-objects -c newlib_syscalls.c -o newlib_syscalls.o
clang -static -nostdlib -T link.ld -target aarch64-none-elf --sysroot=/Applications/ArmGNUToolchain/13.2.Rel1/aarch64-none-elf/bin/../aarch64-none-elf -flto -o test.elf startup.o newlib_syscalls.o -lc /Applications/ArmGNUToolchain/13.2.Rel1/aarch64-none-elf/bin/../lib/gcc/aarch64-none-elf/13.2.1/libgcc.a

GCC编译错误输出

❯ CC=aarch64-none-elf-gcc make
aarch64-none-elf-gcc -mlittle-endian -mcpu=cortex-a55 -mtune=cortex-a55 -flto -c startup.c -o startup.o
aarch64-none-elf-gcc -mlittle-endian -mcpu=cortex-a55 -mtune=cortex-a55 -flto -ffat-lto-objects -c newlib_syscalls.c -o newlib_syscalls.o
aarch64-none-elf-gcc -static -nostdlib -T link.ld -flto -o test.elf startup.o newlib_syscalls.o -lc /Applications/ArmGNUToolchain/13.2.Rel1/aarch64-none-elf/bin/../lib/gcc/aarch64-none-elf/13.2.1/libgcc.a
/Applications/ArmGNUToolchain/13.2.Rel1/aarch64-none-elf/bin/../lib/gcc/aarch64-none-elf/13.2.1/../../../../aarch64-none-elf/bin/ld: /Applications/ArmGNUToolchain/13.2.Rel1/aarch64-none-elf/bin/../lib/gcc/aarch64-none-elf/13.2.1/../../../../aarch64-none-elf/lib/libc.a(libc_a-closer.o): in function `_close_r':
/Volumes/data/jenkins/workspace/GNU-toolchain/arm-13/src/newlib-cygwin/newlib/libc/reent/closer.c:47:(.text._close_r+0x1c): undefined reference to `_close'
...

已确认的信息

  • 用aarch64-none-elf-nm检查newlib_syscalls.o,确认目标文件中包含缺失的符号:
❯ aarch64-none-elf-nm newlib_syscalls.o
000000000000006c T _close
00000000000000d4 T _exit
0000000000000080 T _fstat
00000000000000f8 T _getpid
00000000000000a4 T _isatty
00000000000000e0 T _kill
00000000000000b8 T _lseek
000000000000011c T _read
0000000000000000 T _sbrk
0000000000000100 T _write
                 U end
0000000000000000 b heap.0
  • 由于GNU工具链自带的libc.a未用-flto编译,没有GIMPLE字节码,已经为newlib_syscalls.c添加-ffat-lto-objects参数确保生成目标代码,但问题依旧。Clang无论是否添加该参数都能正常编译。

项目代码

startup.c

#include <stdio.h>

void entrypoint()
{
    printf("Hello, World!\n");
}

newlib_syscalls.c

#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <errno.h>
#include <sys/stat.h>
extern int end;
void *_sbrk(int incr) {
  static unsigned char *heap = NULL;
  unsigned char *prev_heap;

  if (heap == NULL) {
    heap = (unsigned char *)&end;
  }
  prev_heap = heap;

  heap += incr;

  return prev_heap;
}
int _close(int file) {return -1;}
int _fstat(int file, struct stat *st) { st->st_mode = S_IFCHR; return 0; }
int _isatty(int file) { return 1; }
int _lseek(int file, int ptr, int dir) { return 0; }
void _exit(int status) {while(1) asm volatile("");}
void _kill(int pid, int sig) {return;}
int _getpid(void) {return -1;}
int _write (int file, char * ptr, int len) {return len;}
int _read (int file, char * ptr, int len) {return len;}
OUTPUT_FORMAT("elf64-littleaarch64")
OUTPUT_ARCH(aarch64)
ENTRY(entrypoint)
MEMORY {
 ROM (rx): ORIGIN = 0x00000000, LENGTH = 256K
 SRAM (rwx): ORIGIN = 0x00100000, LENGTH = 512K
 DRAM (rwx): ORIGIN = 0x40000000, LENGTH = 0xC0000000
}
SECTIONS
{
 .ro :
 {
  _ro_start = .;
  *entrypoint*(.text*)
  *(SORT_BY_ALIGNMENT(.text*))
  *(SORT_BY_ALIGNMENT(.rodata*))
  *(.vectors)
  _ro_end = .;
 } >ROM
 .data :
 ALIGN(32)
 {
  _data_start = .;
  *(SORT_BY_ALIGNMENT(.data*))
  . = ALIGN(32);
  _data_end = .;
 } >SRAM AT>ROM
 _data_start_lma = LOADADDR(.data);
 _data_size = SIZEOF(.data);
 .bss (NOLOAD) :
 ALIGN(32)
 {
  _bss_start = .;
  *(SORT_BY_ALIGNMENT(.bss*))
  *(COMMON)
  . = ALIGN(32);
  _bss_end = .;
 } >SRAM
 .heap (NOLOAD) :
 {
  end = .;
  _heap_start = .;
  . += 0x4000;
  _heap_end = .;
 } >SRAM
 .stack (NOLOAD) :
 {
  _stack_start = .;
  . += 0x4000;
  _stack_end = .;
  _stack_top = .;
 } >SRAM
 _all_end = .;
 /DISCARD/ : { *(.eh_frame*) }
}

Makefile

CC ?= aarch64-none-elf-gcc

CFLAGS = -mlittle-endian -mcpu=cortex-a55 -mtune=cortex-a55
LTO = -flto
LDFLAGS = -static -nostdlib -T link.ld
EXTRA_LDFLAGS = -lc $(shell aarch64-none-elf-gcc -print-libgcc-file-name)

ifeq ($(CC),clang)
    CFLAGS += -target aarch64-none-elf --sysroot=$(shell aarch64-none-elf-gcc -print-sysroot)
    LDFLAGS += -target aarch64-none-elf --sysroot=$(shell aarch64-none-elf-gcc -print-sysroot)
endif

newlib_syscalls.o :
    $(CC) $(CFLAGS) $(LTO) -ffat-lto-objects -c newlib_syscalls.c -o $@

startup.o :
    $(CC) $(CFLAGS) $(LTO) -c startup.c -o $@

test.elf : startup.o newlib_syscalls.o
    $(CC) $(LDFLAGS) $(LTO) -o $@ $? $(EXTRA_LDFLAGS)

.PHONY : clean
clean :
    rm -f *.o *.elf

.DEFAULT_GOAL := test.elf

# ❯ aarch64-none-elf-gcc --version
# aarch64-none-elf-gcc (Arm GNU Toolchain 13.2.rel1 (Build arm-13.7)) 13.2.1 20231009
# Copyright (C) 2023 Free Software Foundation, Inc.
# This is free software; see the source for copying conditions.  There is NO
# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

# ❯ clang --version                  
# Homebrew clang version 18.1.7
# Target: arm64-apple-darwin23.5.0
# Thread model: posix
# InstalledDir: /opt/homebrew/opt/llvm/bin

内容的提问来源于stack exchange,提问作者sskk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 14:23:11