aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--c/c.c6
-rw-r--r--ir/intrin.c2
-rw-r--r--ir/ir.c6
-rw-r--r--ir/ir.h4
-rw-r--r--test/15-reloc.c29
-rw-r--r--test/reloc.c9
-rwxr-xr-xtest/run.sh2
-rw-r--r--x86_64/emit.c14
-rw-r--r--x86_64/isel.c2
9 files changed, 48 insertions, 26 deletions
diff --git a/c/c.c b/c/c.c
index aff0a9d..7e521b6 100644
--- a/c/c.c
+++ b/c/c.c
@@ -2755,7 +2755,7 @@ expraddr(struct function *fn, const struct expr *ex)
assert(decl->id >= 0);
return mkref(RTMP, decl->id);
case SCEXTERN: case SCNONE: case SCSTATIC:
- return mksymref(decl->sym);
+ return mksymref(decl->sym, decl->ty.t == TYFUNC);
default:
assert(0);
}
@@ -2798,7 +2798,7 @@ expraddr(struct function *fn, const struct expr *ex)
ip->off = objnewdat(sym, ip->sec, 0, typesize(ty), typealign(ty));
if (!iniwriterec(NULL, ip, 0, (struct expr *)ex))
error(&ex->span, "cannot not evaluate expression statically");
- return mksymref(sym);
+ return mksymref(sym, 0);
}
case ESEQ:
expreffects(fn, &ex->sub[0]);
@@ -2888,7 +2888,7 @@ geninit(struct function *fn, union type t, union ref dst, const struct expr *src
addinstr(fn, mkarginstr(cls2type(KPTR), dst));
addinstr(fn, mkarginstr(cls2type(KI32), ZEROREF));
addinstr(fn, mkarginstr(cls2type(type2cls[targ_sizetype]), mkintcon(type2cls[targ_sizetype], siz)));
- call.l = mksymref("memset");
+ call.l = mksymref("memset", 1);
call.r = mkcallarg(cls2type(KPTR), 3, -1);
addinstr(fn, call);
}
diff --git a/ir/intrin.c b/ir/intrin.c
index cd2865a..2ef826c 100644
--- a/ir/intrin.c
+++ b/ir/intrin.c
@@ -24,7 +24,7 @@ intrin(struct block *blk, int *curi, enum intrin in, struct arg *args, int narg,
/* memcpy */
*args[1].ty = *args[0].ty = mktyperef(cls2type(KPTR));
insertinstr(blk, (*curi)++, mkarginstr(cls2type(cls), mkintcon(cls, td->siz)));
- *this = mkinstr(Ocall, 0, mksymref("memcpy"), this->r);
+ *this = mkinstr(Ocall, 0, mksymref("memcpy", 1), this->r);
calltab.p[this->r.i].narg = 3;
calltab.p[this->r.i].ret = cls2type(0);
return 0;
diff --git a/ir/ir.c b/ir/ir.c
index dbd6206..cd93992 100644
--- a/ir/ir.c
+++ b/ir/ir.c
@@ -94,7 +94,7 @@ addcon(const struct xcon *con)
{
uint h = hashb(0, con, sizeof *con);
uint i = h, n = countof(conht);
- assert(con->issym || con->isdat || con->cls);
+ assert((con->issym ^ con->isdat && !(con->isdat && con->isfunc)) || con->cls);
for (;; ++i) {
i &= countof(conht) - 1;
if (!conht[i].issym && !conht[i].isdat && !conht[i].cls) {
@@ -138,9 +138,9 @@ mkfltcon(enum irclass k, double f)
}
union ref
-mksymref(const char *s)
+mksymref(const char *s, bool isfunc)
{
- struct xcon con = { .issym = 1, .sym = s };
+ struct xcon con = { .issym = 1, .sym = s, .isfunc = isfunc };
return mkref(RXCON, addcon(&con));
}
diff --git a/ir/ir.h b/ir/ir.h
index e16cdda..1a1d907 100644
--- a/ir/ir.h
+++ b/ir/ir.h
@@ -26,7 +26,7 @@ struct irdat {
};
struct xcon {
- bool issym, isdat, deref;
+ bool issym, isdat, isfunc, deref;
uchar cls;
union {
const char *sym;
@@ -250,7 +250,7 @@ union ref mkfltcon(enum irclass, double);
#define isaddrcon(r,derefok) ((r).t == RXCON && !conht[(r).i].cls && (derefok || !conht[(r).i].deref))
#define intconval(r) ((r).t == RICON ? (r).i : conht[(r).i].i)
#define fltconval(r) ((r).t == RICON ? (r).i : conht[(r).i].f)
-union ref mksymref(const char *);
+union ref mksymref(const char *, bool isfunc);
union ref mkdatref(const char *name, union type ctype, uint siz, uint align, const void *, uint n, bool deref);
const char *xcon2sym(int ref);
struct instr mkalloca(uint siz, uint align);
diff --git a/test/15-reloc.c b/test/15-reloc.c
new file mode 100644
index 0000000..8d1b323
--- /dev/null
+++ b/test/15-reloc.c
@@ -0,0 +1,29 @@
+/* EXPECT:
+1.3
+5
+ok
+*/
+
+const void *const relro = &relro;
+float get_value(unsigned x) {
+ static const float values [] = {1.1f, 1.2f, 1.3f, 1.4f};
+ return x < 4 ? values[x] : 0.0f;
+}
+
+static const short tb[] = { 1,3,34,5,23,2,5,5,-7 };
+static const short *ptb = &tb[4];
+
+static int ou(int k) { return ptb[k]; }
+
+int (*(getputs(void)))(const char *) {
+ extern int puts(const char *);
+ int (*t)(const char *) = puts;
+ return t;
+}
+
+#include <stdio.h>
+int main() {
+ printf("%g\n", get_value(2));
+ printf("%d\n", ou(2));
+ getputs()("ok");
+}
diff --git a/test/reloc.c b/test/reloc.c
deleted file mode 100644
index ccc03ec..0000000
--- a/test/reloc.c
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-const void *const relro = &relro;
-
-float get_value(unsigned x)
-{
- static const float values [] = {1.1f, 1.2f, 1.3f, 1.4f};
- return x < 4 ? values[x] : 0.0f;
-}
diff --git a/test/run.sh b/test/run.sh
index 34d8101..8954ea7 100755
--- a/test/run.sh
+++ b/test/run.sh
@@ -1,7 +1,7 @@
#!/bin/env sh
cd $(dirname "$0")
-ANTCC=../antcc
+ANTCC="../antcc $CFLAGS"
ntest=0
npass=0
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 */