diff options
| author | 2025-12-13 14:21:22 +0100 | |
|---|---|---|
| committer | 2025-12-13 14:24:30 +0100 | |
| commit | 854df54e1839c8b96d1aaa9aeaa32c2ebbf535f8 (patch) | |
| tree | ba0d2d8b79300d0af2a53aeccd628111733ae7e8 /x86_64 | |
| parent | 17e5a9f573b1a60e12ed60948f45f5992914d324 (diff) | |
fix position independent loads of function symbols.
For `extern int x[1];`, can use PCREL32 for &x. But for `extern int
x(int)`, must use GOTREL, when not being called directly (that's PLT).
Therefore the type of an external symbol (actually just whether it
denotes a function) matters when deciding what kind of relocation to
emit, so keep that information.
Diffstat (limited to 'x86_64')
| -rw-r--r-- | x86_64/emit.c | 14 | ||||
| -rw-r--r-- | x86_64/isel.c | 2 |
2 files changed, 9 insertions, 7 deletions
diff --git a/x86_64/emit.c b/x86_64/emit.c index 14a62db..2f7db11 100644 --- a/x86_64/emit.c +++ b/x86_64/emit.c @@ -333,9 +333,11 @@ encode(uchar **pcode, const struct desc *tab, int ntab, enum irclass k, struct o if (mem.cindex == NOINDEX) { /* %rip(var) */ static uchar offs[NOPERENC] = { [EN_MI8] = 1, [EN_MI16] = 2, [EN_MI32] = 4 }; - enum relockind r = - (!conht[mem.con].deref && ccopt.pic) ? (rex ? REL_GOTPCRELX_REX : REL_GOTPCRELX) - : REL_PCREL32; + enum relockind r; + if ((!conht[mem.con].deref && ccopt.pic) || conht[mem.con].isfunc) + r = (rex ? REL_GOTPCRELX_REX : REL_GOTPCRELX); + else + r = REL_PCREL32; B(/*mod 0*/ (reg & 7) << 3 | RBP); objreloc(xcon2sym(mem.con), r, Stext, *pcode - objout.textbegin, mem.disp - 4 - offs[en->operenc]); } else { @@ -521,7 +523,7 @@ DEFINSTR2(Xxchg, ) DEFINSTR2(Xlea, {4|8, PGPR, PMEM, O("\x8D"), EN_RM}, /* LEA r32/64,m32/64 */ - { 8, PGPR, PSYM, O("\x8D"), EN_RM}, /* LEA rel32 */ + { 8, PGPR, PSYM, O("\x8D"), EN_RM}, /* LEA r32/64,rel32 */ ) DEFINSTR2(Xadd, {4|8, PGPR, PGPR, O("\x03"), EN_RR}, /* ADD r32/64, r32/64 */ @@ -862,7 +864,7 @@ gencopy(uchar **pcode, enum irclass cls, struct block *blk, int curi, struct ope } /* normal (not 2-address) case */ Lea: - if (isaddrcon(addr->base,0) && ccopt.pic) { + if (isaddrcon(addr->base,0) && (ccopt.pic || conht[addr->base.i].isfunc)) { assert(!addr->disp && !addr->index.bits); val = addr->base; goto GOTLoad; @@ -872,7 +874,7 @@ gencopy(uchar **pcode, enum irclass cls, struct block *blk, int curi, struct ope /* dst = 0 -> xor dst, dst; but only if it is ok to clobber flags */ Xxor(pcode, kisint(cls) ? KI32 : cls, dst, dst); } else if (isaddrcon(val,0)) { - if (ccopt.pic) GOTLoad: + if (ccopt.pic || conht[val.i].isfunc) GOTLoad: /* for mov reg, [rip(sym@GOTPCREL)] */ Xmov(pcode, cls, dst, mkoper(OSYM, .con = val.i, .cindex = NOINDEX)); else diff --git a/x86_64/isel.c b/x86_64/isel.c index 5d373f3..67a4358 100644 --- a/x86_64/isel.c +++ b/x86_64/isel.c @@ -310,7 +310,7 @@ fuseaddr(union ref *r, struct block *blk, int *curi) if (r->t != RTMP) return 0; if (!aadd(&addr, blk, curi, *r)) return 0; - if (isaddrcon(addr.base,0) && (ccopt.pic || (ccopt.pie && addr.index.bits))) { + if (isaddrcon(addr.base,0) && (ccopt.pic || (ccopt.pie && addr.index.bits) || conht[addr.base.i].isfunc)) { /* pic needs to load from GOT */ /* pie cannot encode RIP-relative address with index register */ /* first load symbol address into a temp register */ |