Thank you for your review and guidance. As you suggested, I have also
fixed the same issue in riscv64-gen.c. This new patch includes the fix
for both aarch64 and riscv64. Please review.

Thanks,
Dylan Fei

-----------

From 11118be71770cefc3bf971798ac610dd2b4df807 Mon Sep 17 00:00:00 2001
From: Dylan Fei <[email protected]>
Date: Tue, 23 Dec 2025 15:54:35 +0800
Subject: [PATCH] Fix pointer difference issue in aarch64/riscv64

When calculating the difference between two pointers (TOK_PDIV), the
AArch64 and RISC-V64 backends used unsigned division
instructions (udiv/divu).

This patch moves TOK_PDIV to use signed division instructions (sdiv/div)
for both backends, ensuring correct behavior as per the C standard.
---
arm64-gen.c | 2 +-
riscv64-gen.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)

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:
diff --git a/riscv64-gen.c b/riscv64-gen.c
index e03d6e42..19c76682 100644
--- a/riscv64-gen.c
+++ b/riscv64-gen.c
@@ -1110,6 +1110,7 @@ static void gen_opil(int op, int ll)
ER(0x33 | ll, 0, d, a, b, 1); // mul d, a, b
break;
case '/':
+ case TOK_PDIV:
ER(0x33 | ll, 4, d, a, b, 1); // div d, a, b
break;
case '&':
@@ -1127,7 +1128,6 @@ static void gen_opil(int op, int ll)
case TOK_UMOD:
ER(0x33 | ll, 7, d, a, b, 1); // remu d, a, b
break;
- case TOK_PDIV:
case TOK_UDIV:
ER(0x33 | ll, 5, d, a, b, 1); // divu d, a, b
break;
-- 
2.51.2


On Mon, Dec 22, 2025 at 8:18 PM Herman ten Brugge via Tinycc-devel
<[email protected]> wrote:
>
> 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

_______________________________________________
Tinycc-devel mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/tinycc-devel

Reply via email to