1

I'm tring to use gcc link-time optimizer, but encounter some issue related to the gcc linker cannot correctly resolving references to symbols in 'newlib_syscalls.c'. However, same source code , libraries and compile options, clang works just fine.

Here is the output of 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

Here is the output of 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'
...

And I do check the newlib_syscalls.o, it has the object codes of these symbols.

❯ 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

I add '-ffat-lto-objects' to newlib_syscalls.c to make sure it generate the object code, cuz the libc.a come with gnu toolchain didn't build with '-flto', do not have GIMPLE bytecode, I was concerned maybe only GIMPLE is not compatible with the libc.a, anyways it doesn't work either, and clang works with or without '-ffat-lto-objects'.

Here is my example project:

/*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;}
/*link.ld*/
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
3
  • This question is similar to: Why does the order in which libraries are linked sometimes cause errors in GCC?. If you believe it’s different, please edit the question, make it clear how it’s different and/or how the answers on that question are not helpful for your problem. Commented Jul 3, 2024 at 6:21
  • @NateEldredge thanks for ur comment. the newlib_syscalls.o here is just a object file, not a archive file, I don't think this's the same issue here. Commented Jul 3, 2024 at 8:16
  • But the references to it come from libc.a, which is. Did you try the solutions listed there, such as -( ... -) Commented Jul 3, 2024 at 15:05

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.