given the following hello.c: ``` #include <stdio.h> int main (int argc, const char **argv) { printf("Hello, World!\n"); return 0; } ``` when invoking tcc to compile a binary (tcc -o hello hello.c) we get a SIGSEGV in tcc_load_object_file. Here's the full lldb output, with tcc compiled with `-O0 -g`: ``` meena@defbix /u/p/l/t/w/tinycc-release_0_9_26 ❯❯❯ lldb ./tcc -- /home/meena/src/hello.c -o hello (lldb) target create "./tcc" Current executable set to '/usr/ports/lang/tcc/work/tinycc-release_0_9_26/tcc' (x86_64). (lldb) settings set -- target.run-args "/home/meena/src/hello.c" "-o" "hello" (lldb) run Process 20766 launched: '/usr/ports/lang/tcc/work/tinycc-release_0_9_26/tcc' (x86_64) Process 20766 stopped * thread #1, name = 'tcc', stop reason = signal SIGSEGV: invalid address (fault address: 0x1c) frame #0: 0x000000000022aa26 tcc`tcc_load_object_file(s1=0x00002e6d3ec09000, fd=3, file_offset=0) at tccelf.c:2533:51 2530 if (sh->sh_link > 0) 2531 s->link = sm_table[sh->sh_link].s; 2532 if (sh->sh_type == SHT_RELX) { -> 2533 s->sh_info = sm_table[sh->sh_info].s->sh_num; 2534 /* update backward link */ 2535 s1->sections[s->sh_info]->reloc = s; 2536 } (lldb) bt all * thread #1, name = 'tcc', stop reason = signal SIGSEGV: invalid address (fault address: 0x1c) * frame #0: 0x000000000022aa26 tcc`tcc_load_object_file(s1=0x00002e6d3ec09000, fd=3, file_offset=0) at tccelf.c:2533:51 frame #1: 0x00000000002112fe tcc`tcc_add_file_internal(s1=0x00002e6d3ec09000, filename="/usr/lib/crt1.o", flags=0) at libtcc.c:1181:19 frame #2: 0x0000000000211538 tcc`tcc_add_library_internal(s=0x00002e6d3ec09000, fmt="%s/%s", filename="crt1.o", flags=0, paths=0x00002e6d3ec08010, nb_paths=1) at libtcc.c:1254:13 frame #3: 0x00000000002115bf tcc`tcc_add_crt(s=0x00002e6d3ec09000, filename="crt1.o") at libtcc.c:1270:15 frame #4: 0x0000000000211864 tcc`tcc_set_output_type(s=0x00002e6d3ec09000, output_type=1) at libtcc.c:1360:13 frame #5: 0x000000000020e6a3 tcc`main(argc=4, argv=0x0000000820c88778) at tcc.c:302:5 frame #6: 0x0000000822e9dbea libc.so.7`__libc_start1(argc=4, argv=0x0000000820c88778, env=0x0000000820c887a0, cleanup=<unavailable>, mainX=(tcc`main at tcc.c:245)) at libc_start1.c:157:7 frame #7: 0x000000000020e3c0 tcc`_start at crt1_s.S:83 (lldb) ``` n.b.: Given that this bug only occurs on 14.x / 15.0-CURRENT, chances are that it's got something to do with recent libc/csu changes. also note that setting ARCHLEVEL=scalar doesn't change the behaviour.
Can you run it under Valgrind? If that gives nothing, can you build with address sanitizer?
Created attachment 245415 [details] valgrind --leak-check=full --show-leak-kinds=all -s tcc (In reply to Paul Floyd from comment #1) rebuild and rerun with ASAN: ``` AddressSanitizer:DEADLYSIGNAL ================================================================= ==90002==ERROR: AddressSanitizer: SEGV on unknown address 0x00000000001c (pc 0x00000035ac8f bp 0x7fffffffd710 sp 0x7fffffffcdc0 T0) ==90002==The signal is caused by a READ memory access. ==90002==Hint: address points to the zero page. #0 0x35ac8f in tcc_load_object_file /usr/ports/lang/tcc/work/tinycc-release_0_9_26/tccelf.c:2533:51 #1 0x3052da in tcc_add_file_internal /usr/ports/lang/tcc/work/tinycc-release_0_9_26/libtcc.c:1181:19 #2 0x3058f6 in tcc_add_library_internal /usr/ports/lang/tcc/work/tinycc-release_0_9_26/libtcc.c:1254:13 #3 0x305a6b in tcc_add_crt /usr/ports/lang/tcc/work/tinycc-release_0_9_26/libtcc.c:1270:15 #4 0x3062e0 in tcc_set_output_type /usr/ports/lang/tcc/work/tinycc-release_0_9_26/libtcc.c:1360:13 #5 0x2fd12a in main /usr/ports/lang/tcc/work/tinycc-release_0_9_26/tcc.c:302:5 #6 0x8004e4be9 in __libc_start1 /poudriere/jails/current-amd64/usr/src/lib/libc/csu/libc_start1.c:157:7 #7 0x251d6f in _start /poudriere/jails/current-amd64/usr/src/lib/csu/amd64/crt1_s.S:83 #8 0x8003a7007 (<unknown module>) AddressSanitizer can not provide additional info. SUMMARY: AddressSanitizer: SEGV /usr/ports/lang/tcc/work/tinycc-release_0_9_26/tccelf.c:2533:51 in tcc_load_object_file ==90002==ABORTING ```
I just tried building the code. So many warnings that it overflowed my terminal history. Most of them seem to be related to some crappy macro that was probably written for 1970s compilers that didn't have "static". No surprise that junk like that crashes. I fought with BSD make to get tcc to build something debuggable. In the end I just ran make WITH_DEBUG=1 then cd'd to work/tinycc-release_0_9_26 and ran gmake clean ; gmake CFLAGS="-g -fno-omit-frame-pointer" LDFLAGS="-g" Valgrind still didn't want to read the debuginfo, don't know why. The crash is here 2532 if (sh->sh_type == SHT_RELX) { > 2533 s->sh_info = sm_table[sh->sh_info].s->sh_num; because sm_table[sh->sh_info].s is NULL. It looks like sm_table is big enough - 26 elements allocated on line 2395 and sh->sh_info is 3. The file that tcc is reading is /usr/lib/crt1.o readelf -a on that says Section Headers: [Nr] Name Type Address Offset Size EntSize Flags Link Info Align [ 0] NULL 0000000000000000 00000000 0000000000000000 0000000000000000 0 0 0 [ 1] .text PROGBITS 0000000000000000 00000040 0000000000000034 0000000000000000 AX 0 0 8 [ 2] .rela.text RELA 0000000000000000 00000108 0000000000000030 0000000000000018 I 23 1 8 [ 3] .eh_frame X86_64_UNWIND 0000000000000000 00000078 0000000000000038 0000000000000000 A 0 0 8 [ 4] .rela.eh_frame RELA 0000000000000000 00000138 0000000000000018 0000000000000018 I 23 3 8 (and there are 26 section headers). Something looks wrong there. Assuming that sh->sh_info corresponds to the section header number above, but the "if" in the code makes it look like SHT_RELX / RELA when in fact header 3 is [ 3] .eh_frame X86_64_UNWIND If I compare the readelf -a output on FreeBSD 13.2 it is quite different. For a start there is no .eh_frame at all. So I reckon that tcc can't cope with the changed ELF contents of the object file. That's likely to be down to the use of LLVM 16 in FreeBSD 14. That's all for this morning.
As I see it there are 2 possible fixes. At the crash if (sh->sh_type == SHT_RELX) { s->sh_info = sm_table[sh->sh_info].s->sh_num; sh is referring to section header 4 for which a new section was created. sh->sh_info refers to section header 3 which got skipped. So either the above code needs changing to something like if (sh->sh_type == SHT_RELX) { if (sm_table[sh->sh_info].new_section) { s->sh_info = sm_table[sh->sh_info].s->sh_num; Or section header 3 needs to be handled so that sm_table[3] has been initialized. Trying the easy one as above, I get lots of errors in /usr/include/sys/_types.h because it seems like tcc does not know the size of any builtin types. I also tried "hello world" on FreeBSD 13.2 amd64 and it compiled but the exe coredumps between _start() and main(). From what I see in the port git history there was a code fix back in 2015. Otherwise totally dead. In the github history a lot has changed. I don't think that it is worth trying to patch the ports version 0_9_26. It would probably be easier to switch to the upstream 9.28