From ca061f3a96216f85f6fe72868083208aa0a740b9 Mon Sep 17 00:00:00 2001 From: grischka Date: Sat, 2 Mar 2024 12:48:44 +0100 Subject: [PATCH] i386-asm: fix pc-relative label ariths See test. We need to use 'ind' from later when the address field of the instruction is put. Also: fix crash when the substracted symbol is undefined Also: assume asm-symbols to be lvalues (except func/array) --- i386-asm.c | 2 +- tccasm.c | 4 +++- tccgen.c | 2 ++ tests/tcctest.c | 11 +++++++++++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/i386-asm.c b/i386-asm.c index e134d804..57bd7e6d 100644 --- a/i386-asm.c +++ b/i386-asm.c @@ -487,7 +487,7 @@ ST_FUNC void gen_expr32(ExprValue *pe) if (pe->pcrel) /* If PC-relative, always set VT_SYM, even without symbol, so as to force a relocation to be emitted. */ - gen_addrpc32(VT_SYM, pe->sym, pe->v); + gen_addrpc32(VT_SYM, pe->sym, pe->v + (ind + 4)); else gen_addr32(pe->sym ? VT_SYM : 0, pe->sym, pe->v); } diff --git a/tccasm.c b/tccasm.c index 19425976..c5ee4173 100644 --- a/tccasm.c +++ b/tccasm.c @@ -323,6 +323,8 @@ static inline void asm_expr_sum(TCCState *s1, ExprValue *pe) ElfSym *esym1, *esym2; esym1 = elfsym(pe->sym); esym2 = elfsym(e2.sym); + if (!esym2) + goto cannot_relocate; if (esym1 && esym1->st_shndx == esym2->st_shndx && esym1->st_shndx != SHN_UNDEF) { /* we also accept defined symbols in the same section */ @@ -331,7 +333,7 @@ static inline void asm_expr_sum(TCCState *s1, ExprValue *pe) } else if (esym2->st_shndx == cur_text_section->sh_num) { /* When subtracting a defined symbol in current section this actually makes the value PC-relative. */ - pe->v -= esym2->st_value - ind - 4; + pe->v += 0 - esym2->st_value; pe->pcrel = 1; e2.sym = NULL; } else { diff --git a/tccgen.c b/tccgen.c index f6aaf6c1..791c5c6d 100644 --- a/tccgen.c +++ b/tccgen.c @@ -1204,6 +1204,8 @@ static void patch_type(Sym *sym, CType *type) /* stay static if both are static */ sym->type.t = type->t & (sym->type.t | ~VT_STATIC); sym->type.ref = type->ref; + if ((type->t & VT_BTYPE) != VT_FUNC && !(type->t & VT_ARRAY)) + sym->r |= VT_LVAL; } if (!is_compatible_types(&sym->type, type)) { diff --git a/tests/tcctest.c b/tests/tcctest.c index b49cd450..eb47a0eb 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -3758,6 +3758,16 @@ void asm_dot_test(void) #endif } +void asm_pcrel_test(void) +{ + unsigned o1, o2; + /* subtract text-section label from forward or other-section label */ + asm("1: mov $2f-1b,%%eax; mov %%eax,%0" : "=m"(o1)); + /* verify ... */ + asm("2: mov $2b,%%eax; sub $1b,%%eax; mov %%eax,%0" : "=m"(o2)); + printf("%s : %x\n", __FUNCTION__, o1 - o2); /* should be zero */ +} + void asm_test(void) { char buf[128]; @@ -3849,6 +3859,7 @@ void asm_test(void) test_asm_dead_code(); test_asm_call(); asm_dot_test(); + asm_pcrel_test(); return; label1: goto label2;