start.S (1677B)
1 /* tcc-libc entry stub — riscv64 sibling of tcc/libc/aarch64/start.S. 2 * Linux brings argc at [sp] and argv at sp+8 on entry. Call 3 * __libc_init(argc, argv) so `environ` is set, then main(argc, argv), 4 * then exit with main's return value. 5 * 6 * Built by two assemblers from the same source: GAS (host alpine-gcc 7 * for the Makefile harness path) and tcc 0.9.26's riscv64-asm.c (in 8 * boot/boot3.sh, scratch container). They agree on most mnemonics 9 * but diverge on load/store memory syntax: GAS uses `ld rd, off(rs)`, 10 * tcc-asm uses the 3-operand `ld rd, rs, off`. The LD/SD macros below 11 * branch on __TINYC__ to keep one source of truth. 12 * 13 * `jal ra, sym` and `jalr zero, ra, 0` are the canonical 2/3-operand 14 * forms both assemblers accept (GAS's `call` / `ret` / `j` pseudos are 15 * not in tcc-asm), so callsites use those directly. */ 16 17 /* tcc-asm's S-type encoding takes the base register first, opposite of 18 * GAS: `sd base, src, off` vs GAS's `sd src, off(base)`. Hide the 19 * difference behind ST8(src, base, off). */ 20 #ifdef __TINYC__ 21 # define LD8(rd, base, off) ld rd, base, off 22 # define ST8(src, base, off) sd base, src, off 23 #else 24 # define LD8(rd, base, off) ld rd, off(base) 25 # define ST8(src, base, off) sd src, off(base) 26 #endif 27 28 .globl _start 29 _start: 30 LD8(a0, sp, 0) /* argc */ 31 addi a1, sp, 8 /* argv */ 32 addi sp, sp, -16 /* save argc/argv across __libc_init */ 33 ST8(a0, sp, 0) 34 ST8(a1, sp, 8) 35 jal ra, __libc_init 36 LD8(a0, sp, 0) 37 LD8(a1, sp, 8) 38 addi sp, sp, 16 39 jal ra, main 40 /* main's return is in a0 — feed it to exit(2). */ 41 li a7, 93 /* NR_exit */ 42 ecall