diff --git a/tccgen.c b/tccgen.c index 5c74971..b490c04 100644 --- a/tccgen.c +++ b/tccgen.c @@ -1775,8 +1775,13 @@ static void gen_opic(int op) /* symbol + constant case */ if (op == '-') l2 = -l2; + l2 += vtop[-1].c.i; + /* The backends can't always deal with addends to symbols + larger than +-1<<31. Don't construct such. */ + if ((int)l2 != l2) + goto general_case; vtop--; - vtop->c.i += l2; + vtop->c.i = l2; } else { general_case: if (!nocode_wanted) { diff --git a/tests/tcctest.c b/tests/tcctest.c index 5124a4f..bdbcb60 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -2429,6 +2429,19 @@ void getmyaddress(void) { printf("in getmyaddress\n"); } + +#ifdef __LP64__ +long __pa_symbol(void) +{ + /* This 64bit constant was handled incorrectly, it was used as addend + (which can hold 64bit just fine) in connection with a symbol, + and TCC generates wrong code for that (displacements are 32bit only). + This effectively is "+ 0x80000000", and if addresses of globals + are below 2GB the result should be a number without high 32 bits set. */ + return ((long)(((unsigned long)(&rel1))) - (0xffffffff80000000UL)); +} +#endif + unsigned long theaddress = (unsigned long)getmyaddress; void relocation_test(void) { @@ -2436,6 +2449,9 @@ void relocation_test(void) printf("*rel1=%d\n", *rel1); printf("*rel2=%d\n", *rel2); fptr(); +#ifdef __LP64__ + printf("pa_symbol=0x%lx\n", __pa_symbol() >> 63); +#endif } void old_style_f(a,b,c) diff --git a/x86_64-gen.c b/x86_64-gen.c index 408bb91..b765806 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -349,6 +349,8 @@ void load(int r, SValue *sv) fr = sv->r; ft = sv->type.t & ~VT_DEFSIGN; fc = sv->c.i; + if (fc != sv->c.i && (fr & VT_SYM)) + tcc_error("64 bit addend in load"); ft &= ~(VT_VOLATILE | VT_CONSTANT); @@ -528,9 +530,11 @@ void store(int r, SValue *v) v = pe_getimport(v, &v2); #endif + fr = v->r & VT_VALMASK; ft = v->type.t; fc = v->c.i; - fr = v->r & VT_VALMASK; + if (fc != v->c.i && (fr & VT_SYM)) + tcc_error("64 bit addend in store"); ft &= ~(VT_VOLATILE | VT_CONSTANT); bt = ft & VT_BTYPE;