apache / nuttx

Apache NuttX is a mature, real-time embedded operating system (RTOS)
https://nuttx.apache.org/
Apache License 2.0
2.62k stars 1.11k forks source link

Loading ELFs which contain a global offset table. #8886

Open g2gps opened 1 year ago

g2gps commented 1 year ago

I've been experimenting with building the some of the risc-v targets, primarily on boards/risc-v/litex/arty-a7 and boards/risc-v/qemu-rv with newer versions of the riscv-gnu-toolchain. The intention being to enable some of the newer language features, and a more recent version of libcxx (#8244).

I've noticed that some toolchain configurations, particularly when musl is used, generate elfs which contain relocations involving a global offset table (GOT). From what I can see in binfmt/libelf, there's currently no support for relocations through a GOT, either during loading or at the architecture level (libs/libc/machine/*/arch_elf.c).

I've seen comments in boards/sim/sim/sim/scripts/Make.defs regarding using -fno-pic to avoid a GOT being generated, so possibly this is by design, and I'm overlooking something more fundamental here.

Currently, it seems that building the toolchain with newlib avoids a GOT being generated at all for the applications I've tested. However, I'm not sure if this is the case in general.

Perhaps someone has some insight on this?

The toolchain configuration which currently works:

$ riscv32-unknown-elf-gcc -v
Using built-in specs.
COLLECT_GCC=riscv32-unknown-elf-gcc
COLLECT_LTO_WRAPPER=/home/xx/projects/riscv-gnu-toolchain/bin/libexec/gcc/riscv32-unknown-elf/12.2.0/lto-wrapper
Target: riscv32-unknown-elf
Configured with: /home/xx/projects/riscv-gnu-toolchain/build/../gcc/configure --target=riscv32-unknown-elf --prefix=/home/xx/projects/riscv-gnu-toolchain/bin --disable-shared --disable-threads --enable-languages=c,c++ --with-pkgversion=g2ee5e430018 --with-system-zlib --enable-tls --with-newlib --with-sysroot=/home/xx/projects/riscv-gnu-toolchain/bin/riscv32-unknown-elf --with-native-system-header-dir=/include --disable-libmudflap --disable-libssp --disable-libquadmath --disable-libgomp --disable-nls --disable-tm-clone-registry --src=/home/xx/projects/riscv-gnu-toolchain/gcc --disable-multilib --with-abi=ilp32 --with-arch=rv32imac --with-tune=rocket --with-isa-spec=2.2 'CFLAGS_FOR_TARGET=-Os   -mcmodel=medany' 'CXXFLAGS_FOR_TARGET=-Os   -mcmodel=medany'
Thread model: single
Supported LTO compression algorithms: zlib zstd
gcc version 12.2.0 (g2ee5e430018) 

The same configuration with musl generates a GOT and relocation relative to it.

acassis commented 1 year ago

I think @masayuki2009 worked on improving ELF support some time ago. Maybe he has more information and could help about it. I think support to GOT is welcome.

GooTal commented 1 year ago

I was porting a kernel build version for loongarch and encounterd this too. We used some CXXFLAGS to avoid using got. BTW, i saw linux ignored the got symbol, maybe we could do this.

static int ignore_undef_symbol(struct elf_info *info, const char *symname)
{
    /* ignore __this_module, it will be resolved shortly */
    if (strcmp(symname, "__this_module") == 0)
        return 1;
    /* ignore global offset table */
    if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0)
        return 1;
    if (info->hdr->e_machine == EM_PPC)
        /* Special register function linked on all modules during final link of .ko */
        if (strstarts(symname, "_restgpr_") ||
            strstarts(symname, "_savegpr_") ||
            strstarts(symname, "_rest32gpr_") ||
            strstarts(symname, "_save32gpr_") ||
            strstarts(symname, "_restvr_") ||
            strstarts(symname, "_savevr_"))
            return 1;
    if (info->hdr->e_machine == EM_PPC64)
        /* Special register function linked on all modules during final link of .ko */
        if (strstarts(symname, "_restgpr0_") ||
            strstarts(symname, "_savegpr0_") ||
            strstarts(symname, "_restvr_") ||
            strstarts(symname, "_savevr_") ||
            strcmp(symname, ".TOC.") == 0)
            return 1;
    /* Do not ignore this symbol */
    return 0;
}