c3c icon indicating copy to clipboard operation
c3c copied to clipboard

Support outputing correct executables for Termux (a Linux shell for Android)

Open alsakandari opened this issue 3 months ago • 18 comments

Running c3c run on Termux gives the following error when executing the output file:

error: ".....": executable's TLS segment is underaligned: alignment is 8, needs to be at least 64 for ARM64 Bionic

alsakandari avatar Sep 07 '25 07:09 alsakandari

https://github.com/termux/termux-elf-cleaner is a project to fix the alignment, but I wonder if it is possible to output the right alignment for bionic libc

alsakandari avatar Sep 07 '25 08:09 alsakandari

After cleaning the elf, then running it again:

ERROR: 'No method 'acquire' could be found on target', in _$main (mem_allocator.c3:86)
fish: Job 1, './nur' terminated by signal SIGTRAP (Trace or breakpoint trap)

alsakandari avatar Sep 07 '25 08:09 alsakandari

You can close this as not planned and declare Termux to be unsupported

alsakandari avatar Sep 07 '25 08:09 alsakandari

Ah, this seems to be duplicate of #1396

alsakandari avatar Sep 07 '25 11:09 alsakandari

No, this is different. The error you get seems to be due to libc not getting started. So I think it's as simple as the wrong libraries are being linked.

lerno avatar Sep 10 '25 21:09 lerno

Can you show me what compiling with -vv added to compilation outputs?

lerno avatar Sep 10 '25 21:09 lerno

Can you show me what compiling with -vv added to compilation outputs?

$ c3c run -vv

-- AST/EXPR/TYPE INFO --
 * Ast size: 56 bytes
 * Decl size: 136 bytes
 * Expr size: 56 bytes
 * TypeInfo size: 40 bytes
 * Ast memory use: 4226kb (77286 elements)
 * Decl memory use: 5729kb (43141 elements)
 * Expr memory use: 19647kb (359273 elements)
 * TypeInfo memory use: 1824kb (46718 elements)
-- ARENA INFO --
 * Memory used:  42160 Kb
 * Allocations: 150648
 * String memory used:  389 Kb
cc -o build/c3testproject -rdynamic -pthread build/obj/android-aarch64/std.math.math_rt.o build/obj/android-aarch64/std.math.o build/obj/android-aarch64/libc.o build/obj/android-aarch64/std.io.os.o build/obj/android-aarch64/std.io.file.o build/obj/android-aarch64/std.io.o build/obj/android-aarch64/std.core.types.o build/obj/android-aarch64/std.core.string.o build/obj/android-aarch64/std.core.mem.o build/obj/android-aarch64/std.core.dstring.o build/obj/android-aarch64/std.core.string.conv.o build/obj/android-aarch64/std.core.builtin.o build/obj/android-aarch64/std.core.ascii.o build/obj/android-aarch64/std.core.mem.allocator.o build/obj/android-aarch64/std.atomic.o build/obj/android-aarch64/c3testproject.o -ldl
Program linked to executable 'build/c3testproject'.
--------- Compilation time statistics --------

Frontend -------------------- Time --- % total
Initialization took:      5.918 ms       0.3 %
Parsing took:           321.153 ms      18.0 %
Analysis took:          124.574 ms       7.0 %
TOTAL:                  451.645 ms      25.3 %

Backend --------------------- Time --- % total
Ir gen took:            160.757 ms       9.0 %
Codegen took:           932.191 ms      52.2 %  (8 threads)
Linking took:           241.381 ms      13.5 %
TOTAL:                 1334.328 ms      74.7 %
----------------------------------------------
TOTAL compile time: 1785.973 ms.
----------------------------------------------
Launching ./build/c3testproject
error: "/data/data/com.termux/files/home/c3testproject/build/c3testproject": executable's TLS segment is underaligned: alignment is 8, needs to be at least 64 for ARM64 Bionic
Program interrupted by signal 6.

$ cd build
$ termux-elf-cleaner c3testproject
termux-elf-cleaner: Changing TLS alignment for 'c3testproject' to 64, instead of 8
termux-elf-cleaner: Replacing unsupported DF_1_* flags 134217729 with 1 in 'c3testproject'
$ ./c3testproject

ERROR: 'No method 'acquire' could be found on target', in _$main (mem_allocator.c3:86)
fish: Job 1, './c3testproject' terminated by signal SIGTRAP (Trace or breakpoint trap)

alsakandari avatar Sep 11 '25 02:09 alsakandari

Can you check what the correct arguments are for compiling for termux with cc?

lerno avatar Sep 12 '25 18:09 lerno

Can you check what the correct arguments are for compiling for termux with cc?

$ cat test.c
#include <stdio.h>

int main(void) {
    printf("Hello, World!");
}
$ cc -o test test.c
$ ./test
Hello, World!

This just works, it has nothing to do with clang in particular, the object files it links are the ones with problems

alsakandari avatar Sep 13 '25 05:09 alsakandari

If I use compile-only then link it with the command that showed in c3c run -vv, but remove build/obj/android-aarch64/std.core.mem.allocator.o, it doesn't show the TLS segement alignment error nor the acquire method missing error, but it segfaults though

alsakandari avatar Sep 13 '25 06:09 alsakandari

Running gdb, it segfaults at dyn_search, no source file information provided

alsakandari avatar Sep 13 '25 06:09 alsakandari

(gdb) bt 10
#0  0x00000055555895dc in dyn_search ()
#1  0x0000005555591900 in malloc_try ()
    at /data/data/com.termux/files/home/.local/bin/c3/lib/std/core/mem_allocator.c3:8
#2  alloc_array_try ()
    at /data/data/com.termux/files/home/.local/bin/c3/lib/std/core/mem_allocator.c3:304
#3  alloc_array ()
    at /data/data/com.termux/files/home/.local/bin/c3/lib/std/core/mem_allocator.c3:287
#4  alloc_array ()
    at /data/data/com.termux/files/home/.local/bin/c3/lib/std/core/mem.c3:911
#5  args_to_strings ()
    at /data/data/com.termux/files/home/.local/bin/c3/lib/std/core/private/main_stub.c3:24
#6  @main_to_int_main_args ()
    at /data/data/com.termux/files/home/.local/bin/c3/lib/std/core/private/main_stub.c3:45
#7  main (.anon=0x7fffffee48, .anon=0x7fffffee48) at main.c3:4

How did it find std/core/mem_allocator.c3:86 if I didn't link with it

alsakandari avatar Sep 13 '25 06:09 alsakandari

I'm trying to dig into this to see what Clang does, but so far no luck.

lerno avatar Sep 14 '25 08:09 lerno

This is the full verbose output of compiling a hello world with gcc (which is just clang lol), hopefully the flags it uses can help:

$ gcc -o main test.c --verbose
clang version 20.1.4
Target: aarch64-unknown-linux-android24
Thread model: posix
InstalledDir: /data/data/com.termux/files/usr/bin
 "/data/data/com.termux/files/usr/bin/clang-20" -cc1 -triple aarch64-unknown-linux-android24 -emit-obj -dumpdir main- -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name test.c -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=non-leaf -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu generic -target-feature +v8a -target-feature +fp-armv8 -target-feature +neon -target-feature +fix-cortex-a53-835769 -target-abi aapcs -debugger-tuning=gdb -fdebug-compilation-dir=/data/data/com.termux/files/home -v -fcoverage-compilation-dir=/data/data/com.termux/files/home -resource-dir /data/data/com.termux/files/usr/lib/clang/20 -isysroot /data/data/com.termux/files -internal-isystem /data/data/com.termux/files/usr/lib/clang/20/include -internal-isystem /data/data/com.termux/files/usr/local/include -internal-externc-isystem /data/data/com.termux/files/usr/include/aarch64-linux-android -internal-externc-isystem /data/data/com.termux/files/include -internal-externc-isystem /data/data/com.termux/files/usr/include -ferror-limit 19 -femulated-tls -fno-signed-char -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcolor-diagnostics -target-feature +outline-atomics -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /data/data/com.termux/files/usr/tmp/test-9c1443.o -x c test.c
clang -cc1 version 20.1.4 based upon LLVM 20.1.4 default target aarch64-unknown-linux-android24
ignoring nonexistent directory "/data/data/com.termux/files/usr/local/include"
ignoring nonexistent directory "/data/data/com.termux/files/include"
#include "..." search starts here:
#include <...> search starts here:
 /data/data/com.termux/files/usr/lib/clang/20/include
 /data/data/com.termux/files/usr/include/aarch64-linux-android
 /data/data/com.termux/files/usr/include
End of search list.
 "/data/data/com.termux/files/usr/bin/ld.lld" --sysroot=/data/data/com.termux/files -EL --fix-cortex-a53-843419 -z now -z relro -z max-page-size=16384 --no-rosegment --hash-style=gnu -rpath=/data/data/com.termux/files/usr/lib --eh-frame-hdr -m aarch64linux -pie -dynamic-linker /system/bin/linker64 -o main /data/data/com.termux/files/usr/lib/crtbegin_dynamic.o -L/data/data/com.termux/files/usr/lib -L/system/lib64 /data/data/com.termux/files/usr/tmp/test-9c1443.o /data/data/com.termux/files/usr/lib/clang/20/lib/linux/libclang_rt.builtins-aarch64-android.a -l:libunwind.a -ldl -lc /data/data/com.termux/files/usr/lib/clang/20/lib/linux/libclang_rt.builtins-aarch64-android.a -l:libunwind.a -ldl /data/data/com.termux/files/usr/lib/crtend_android.o

Book-reader avatar Sep 28 '25 01:09 Book-reader

termux - Samsung Android

  1. on termux you have clang, lld, cmake, llvm

    $ pkg install clang lld llvm cmake

  2. I compiled from the source.

    removing a bunch of -lLLVMxxxx linker flags adding -lLLVM -lz -lzstd flags

~/c3c/CMakeLists.txt:

 set(CMAKE_EXE_LINKER_FLAGS "-lLLVM -lz -lzstd")

#llvm_map_components_to_libname....

c3c binary created successfuly.

  1. changed all LogPriority to log::LogPriority in runtime_test.c3

~/c3c/build $ ./c3c compile test.c3

(/data/data/com.termux/files/home/c3c/lib/std/core/runtime_test.c3:22:2) Error: The enum 'LogPriority' is defined in both 'std::core::log' and 'std::os::android', please use either std::core::log::LogPriority or std::os::android::LogPriority to resolve the ambiguity.

  1. ELF cleaning

~/c3c/build $ ./test

error: "./test": executable's TLS segment is underaligned: alignment is 8 (skew 0), needs to be at least 64 for ARM64 Bionic

~/c3c/build $ termux-elf-cleaner ./test

  1. Error at termination

It worked anyway.

~/c3c/build $ ./test Hello, World!
ERROR: '@require "self.allocated" violated: 'Only a top level allocator should be freed.'.', in destroy_temp_allocators (mem_allocator.c3:530) Trap ./test

Hey lerno, you could do something about 2., 3., 5.

  1. ELF cleaning, but still not work

~ $ c3c compile test2.c3 Program linked to executable './test2'.

~ $ termux-elf-cleaner test2 termux-elf-cleaner: Changing TLS alignment for 'test2' to 64, instead of 8 termux-elf-cleaner: Replacing unsupported DF_1_* flags 134217729 with 1 in 'test2'

~ $ ./test2
error: "./test2": executable's TLS segment is underaligned: alignment is 64 (skew 16), needs to be at least 64 for ARM64 Bionic Aborted ./test2

nomota avatar Dec 06 '25 05:12 nomota

Are we sure it's linking the correct libs?

lerno avatar Dec 06 '25 22:12 lerno

This patch that enables emulated tls seems to have fixed it for me:

diff --git a/src/compiler/target.c b/src/compiler/target.c
index 087d9d4e..3bacf9ca 100644
--- a/src/compiler/target.c
+++ b/src/compiler/target.c
@@ -1976,6 +1976,7 @@ void *llvm_target_machine_create(void)
 										   (LLVMCodeGenOptLevel)compiler.platform.llvm_opt_level,
 										   reloc_mode, model);
 	LLVMSetTargetMachineUseInitArray(result, true);
+	LLVMSetTargetMachineEmulatedTLS(result, true);
 	if (!result) error_exit("Failed to create target machine.");
 	LLVMSetTargetMachineAsmVerbosity(result, 1);
 	return result;
diff --git a/wrapper/include/c3_llvm.h b/wrapper/include/c3_llvm.h
index 8862ebb9..33572ed1 100644
--- a/wrapper/include/c3_llvm.h
+++ b/wrapper/include/c3_llvm.h
@@ -78,8 +78,9 @@ LLVMValueRef LLVMConstBswap(LLVMValueRef ConstantVal);
 void LLVMBuilderSetFastMathFlags(LLVMBuilderRef Builder, FastMathOption option);
 void LLVMSetDSOLocal(LLVMValueRef Global, bool value);
 void LLVMSetTargetMachineUseInitArray(LLVMTargetMachineRef ref, bool use_init_array);
+void LLVMSetTargetMachineEmulatedTLS(LLVMTargetMachineRef ref, bool emulated_tls);
 void LLVMSetNoSanitizeAddress(LLVMValueRef Global);
 
 #ifdef __cplusplus
 }
-#endif
\ No newline at end of file
+#endif
diff --git a/wrapper/src/wrapper.cpp b/wrapper/src/wrapper.cpp
index 786d5d49..81f297db 100644
--- a/wrapper/src/wrapper.cpp
+++ b/wrapper/src/wrapper.cpp
@@ -323,6 +323,11 @@ void LLVMSetTargetMachineUseInitArray(LLVMTargetMachineRef ref, bool use_init_ar
 	auto machine = (llvm::TargetMachine*)ref;
 	machine->Options.UseInitArray = use_init_array;
 }
+void LLVMSetTargetMachineEmulatedTLS(LLVMTargetMachineRef ref, bool emulated_tls)
+{
+	auto machine = (llvm::TargetMachine*)ref;
+	machine->Options.EmulatedTLS = emulated_tls;
+}
 void LLVMSetDSOLocal(LLVMValueRef Global, bool value)
 {
 	llvm::unwrap<llvm::GlobalValue>(Global)->setDSOLocal(value);
Image

Book-reader avatar Dec 10 '25 05:12 Book-reader

emulated tls is also something that was enabled by clang, so it seems to be the correct solution

Image

Book-reader avatar Dec 10 '25 05:12 Book-reader