On 12/21/25 15:10, Dylan Fei wrote:
Hi TCC developers,A critical and basic bug is found in the AArch64 backend (aarch64-gen.c) regarding pointer difference calculation. The Issue: When calculating the difference between two pointers (TOK_PDIV), the AArch64 backend currently uses the udiv (Unsigned Divide) instruction. However, the result of pointer subtraction (ptrdiff_t) is signed. This causes incorrect results when the difference is negative (i.e., low_addr - high_addr) and the structure size is not a power of 2 (which prevents bitwise optimization). Reproduction Code: #include <stdio.h> struct Node { long a; long b; long c; }; // sizeof(struct Node) == 24 int main() { struct Node data[2]; struct Node *f = &data[0]; struct Node *mp = &data[1]; // On aarch64, this should print -1, but prints -1431655767 due to udiv printf("%d\n", (int)(f - mp)); return 0; } The Fix: In aarch64-gen.c, TOK_PDIV is currently grouped with TOK_UDIV. It should be grouped with the signed division operator /. Here is the patch: diff --git a/arm64-gen.c b/arm64-gen.c index 01ea3909..2038aeba 100644 --- a/arm64-gen.c +++ b/arm64-gen.c @@ -1756,6 +1756,7 @@ static void arm64_gen_opil(int op, uint32_t l) o(0x4b000000 | l << 31 | x | a << 5 | b << 16); // sub break; case '/': + case TOK_PDIV: o(0x1ac00c00 | l << 31 | x | a << 5 | b << 16); // sdiv break; case '^': @@ -1798,7 +1799,6 @@ static void arm64_gen_opil(int op, uint32_t l) o(0x1ac02400 | l << 31 | x | a << 5 | b << 16); // lsr break; case TOK_UDIV: - case TOK_PDIV: o(0x1ac00800 | l << 31 | x | a << 5 | b << 16); // udiv break; case TOK_UGE: This change fixes the issue on AArch64 and produces the correct signed result.
This is ok. You can apply it. I see that riscv64-gen.c has the same problem. Can you change that as well? The other targets seem ok. Herman _______________________________________________ Tinycc-devel mailing list [email protected] https://lists.nongnu.org/mailman/listinfo/tinycc-devel
