x86-64: Fix calls via absolute function pointers

linkers don't treat relocations using symindex 0 (undefined)
very well, it can't be misused as indicator for an absolute number.
Just don't bother with special casing this, rather emit an indirect
call/jump right away. ARM64 needs the same (and didn't handle
calls via constant absolute func pointers before).

The testcase as is doesn't fail without the patch, it actually
needs separate compilation (to -fPIC .o file, then to shared lib)
to fail.
This commit is contained in:
Michael Matz 2018-07-02 01:54:45 +02:00
parent 65c7f19deb
commit d79caa9ff6
3 changed files with 11 additions and 13 deletions

View File

@ -580,8 +580,8 @@ ST_FUNC void store(int r, SValue *sv)
static void arm64_gen_bl_or_b(int b)
{
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
assert(!b && (vtop->r & VT_SYM));
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST && (vtop->r & VT_SYM)) {
assert(!b);
greloca(cur_text_section, vtop->sym, ind, R_AARCH64_CALL26, 0);
o(0x94000000); // bl .
}

View File

@ -15,6 +15,11 @@ void qfunc()
printf("qfunc()\n");
}
void zfunc()
{
((void (*)(void))0) ();
}
int main()
{
printf("%d\n", myfunc(3));

View File

@ -623,20 +623,13 @@ static void gcall_or_jmp(int is_jmp)
{
int r;
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST &&
((vtop->r & VT_SYM) || (vtop->c.i-4) == (int)(vtop->c.i-4))) {
/* constant case */
if (vtop->r & VT_SYM) {
/* relocation case */
((vtop->r & VT_SYM) && (vtop->c.i-4) == (int)(vtop->c.i-4))) {
/* constant symbolic case -> simple relocation */
#ifdef TCC_TARGET_PE
greloca(cur_text_section, vtop->sym, ind + 1, R_X86_64_PC32, (int)(vtop->c.i-4));
greloca(cur_text_section, vtop->sym, ind + 1, R_X86_64_PC32, (int)(vtop->c.i-4));
#else
greloca(cur_text_section, vtop->sym, ind + 1, R_X86_64_PLT32, (int)(vtop->c.i-4));
greloca(cur_text_section, vtop->sym, ind + 1, R_X86_64_PLT32, (int)(vtop->c.i-4));
#endif
} else {
/* put an empty PC32 relocation */
put_elf_reloca(symtab_section, cur_text_section,
ind + 1, R_X86_64_PC32, 0, (int)(vtop->c.i-4));
}
oad(0xe8 + is_jmp, 0); /* call/jmp im */
} else {
/* otherwise, indirect call */