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)
This commit is contained in:
grischka 2024-03-02 12:48:44 +01:00
parent 9675c1e245
commit ca061f3a96
4 changed files with 17 additions and 2 deletions

View File

@ -487,7 +487,7 @@ ST_FUNC void gen_expr32(ExprValue *pe)
if (pe->pcrel) if (pe->pcrel)
/* If PC-relative, always set VT_SYM, even without symbol, /* If PC-relative, always set VT_SYM, even without symbol,
so as to force a relocation to be emitted. */ 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 else
gen_addr32(pe->sym ? VT_SYM : 0, pe->sym, pe->v); gen_addr32(pe->sym ? VT_SYM : 0, pe->sym, pe->v);
} }

View File

@ -323,6 +323,8 @@ static inline void asm_expr_sum(TCCState *s1, ExprValue *pe)
ElfSym *esym1, *esym2; ElfSym *esym1, *esym2;
esym1 = elfsym(pe->sym); esym1 = elfsym(pe->sym);
esym2 = elfsym(e2.sym); esym2 = elfsym(e2.sym);
if (!esym2)
goto cannot_relocate;
if (esym1 && esym1->st_shndx == esym2->st_shndx if (esym1 && esym1->st_shndx == esym2->st_shndx
&& esym1->st_shndx != SHN_UNDEF) { && esym1->st_shndx != SHN_UNDEF) {
/* we also accept defined symbols in the same section */ /* 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) { } else if (esym2->st_shndx == cur_text_section->sh_num) {
/* When subtracting a defined symbol in current section /* When subtracting a defined symbol in current section
this actually makes the value PC-relative. */ this actually makes the value PC-relative. */
pe->v -= esym2->st_value - ind - 4; pe->v += 0 - esym2->st_value;
pe->pcrel = 1; pe->pcrel = 1;
e2.sym = NULL; e2.sym = NULL;
} else { } else {

View File

@ -1204,6 +1204,8 @@ static void patch_type(Sym *sym, CType *type)
/* stay static if both are static */ /* stay static if both are static */
sym->type.t = type->t & (sym->type.t | ~VT_STATIC); sym->type.t = type->t & (sym->type.t | ~VT_STATIC);
sym->type.ref = type->ref; 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)) { if (!is_compatible_types(&sym->type, type)) {

View File

@ -3758,6 +3758,16 @@ void asm_dot_test(void)
#endif #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) void asm_test(void)
{ {
char buf[128]; char buf[128];
@ -3849,6 +3859,7 @@ void asm_test(void)
test_asm_dead_code(); test_asm_dead_code();
test_asm_call(); test_asm_call();
asm_dot_test(); asm_dot_test();
asm_pcrel_test();
return; return;
label1: label1:
goto label2; goto label2;