aboutsummaryrefslogtreecommitdiffhomepage
path: root/amd64
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2023-06-17 23:26:45 +0200
committerlemon <lsof@mailbox.org>2023-06-17 23:26:45 +0200
commit962ad175aee634274b408ead38b13e6bc90e2fe7 (patch)
treecfda733adf56ed12e829f594e0b6d66f0a1a7a70 /amd64
parentec28e9057e84b92acabb7ebf9122af59738917ad (diff)
basic ELF output
Diffstat (limited to 'amd64')
-rw-r--r--amd64/all.h6
-rw-r--r--amd64/emit.c36
-rw-r--r--amd64/isel.c18
3 files changed, 44 insertions, 16 deletions
diff --git a/amd64/all.h b/amd64/all.h
index 3b08761..a038ffd 100644
--- a/amd64/all.h
+++ b/amd64/all.h
@@ -13,6 +13,12 @@ enum reg {
};
static inline void
+wr16le(uchar *p, ushort x)
+{
+ p[0] = x >> 0; p[1] = x >> 8;
+}
+
+static inline void
wr32le(uchar *p, uint x)
{
p[0] = x >> 0; p[1] = x >> 8;
diff --git a/amd64/emit.c b/amd64/emit.c
index b7cea24..ec04de7 100644
--- a/amd64/emit.c
+++ b/amd64/emit.c
@@ -149,6 +149,7 @@ enum operpat {
PFPR,
P1, /* imm = 1 */
PI8,
+ PI16,
PI32,
PU32,
PMEM,
@@ -162,6 +163,9 @@ enum operenc {
EN_M, /* mem */
EN_RI8, /* reg, imm8 with /0 */
EN_RI32, /* reg, imm32 with /0 */
+ EN_MI8, /* mem, imm8 with /x */
+ EN_MI16, /* mem, imm16 with /x */
+ EN_MI32, /* mem, imm32 with /x */
EN_OI, /* reg, imm32 with op + reg */
EN_I32, /* imm32 */
EN_R32, /* rel32 */
@@ -188,6 +192,7 @@ opermatch(enum operpat pat, struct oper oper)
case PFPR: return oper.t == OREG && oper.reg >= XMM0;
case P1: return oper.t == OIMM && oper.imm == 1;
case PI8: return oper.t == OIMM && (uint)(oper.imm+128) < 256;
+ case PI16: return oper.t == OIMM && (short)oper.imm == oper.imm;
case PI32: return oper.t == OIMM;
case PU32: return oper.t == OIMM && oper.imm >= 0;
case PMEM: return in_range(oper.t, OMEM, OCONR);
@@ -199,6 +204,7 @@ opermatch(enum operpat pat, struct oper oper)
/* code output helpers */
#define B(b) (*(*pcode)++ = (b))
#define D(xs, N) (memcpy(*pcode, (xs), (N)), (*pcode) += (N))
+#define I16(w) (wr16le(*pcode, (w)), *pcode += 4)
#define I32(w) (wr32le(*pcode, (w)), *pcode += 4)
#define DS(S) D(S, sizeof S - 1)
@@ -247,7 +253,7 @@ encode(uchar **pcode, const struct desc *tab, int ntab, enum irclass k, struct o
mem = src;
reg = dst.reg;
goto Mem;
- case EN_M:
+ case EN_M: case EN_MI8: case EN_MI16: case EN_MI32:
mem = dst;
reg = en->ext;
Mem:
@@ -277,7 +283,16 @@ encode(uchar **pcode, const struct desc *tab, int ntab, enum irclass k, struct o
if (sib)
B(mem.shift << 6 | (mem.index & 7) << 3 | (mem.base & 7));
if (mod == 1) B(mem.disp);
- else if (mod == 2 || (mod == 0 && mem.base == RBP)) I32(mem.disp);
+ else if (mod == 2 || (mod == 0 && mem.base == RBP/*RIP-rel*/)) {
+ if (mem.t == OCONR) {
+ objreloc(xcon2sym(mem.con), REL_PCREL32, Stext, *pcode - objout.textbegin, -4);
+ mem.disp = 0;
+ }
+ I32(mem.disp);
+ }
+ if (en->operenc == EN_MI8) B(src.imm);
+ if (en->operenc == EN_MI16) I16(src.imm);
+ if (en->operenc == EN_MI32) I32(src.imm);
break;
case EN_R: case EN_RI32: case EN_RI8:
rex |= (dst.reg >> 3) << 0; /* REX.B */
@@ -304,7 +319,9 @@ encode(uchar **pcode, const struct desc *tab, int ntab, enum irclass k, struct o
case EN_R32:
if (rex) B(0x40 | rex);
D(opc, nopc);
- I32(-1);
+ assert(dst.t == OCONR);
+ objreloc(xcon2sym(dst.con), REL_PCREL32, Stext, *pcode - objout.textbegin, -4);
+ I32(0);
break;
}
}
@@ -326,10 +343,12 @@ encode(uchar **pcode, const struct desc *tab, int ntab, enum irclass k, struct o
}
DEFINSTR2(Xmovb,
- {-1, PMEM, PGPR, "\x88", EN_MR, .r8=1}, /* MOV m8, r8 */
+ {-1, PMEM, PGPR, "\x88", EN_MR, .r8=1}, /* MOV m8, r8 */
+ {-1, PMEM, PI8, "\xC6", EN_MI8, .r8=1}, /* MOV m8, imm8 */
)
DEFINSTR2(Xmovw,
{-1, PMEM, PGPR, "\x66\x89", EN_MR}, /* MOV m16, r16 */
+ {-1, PMEM, PI16, "\xC6", EN_MI16}, /* MOV m16, imm16 */
)
static void Xmov(uchar **pcode, enum irclass k, struct oper dst, struct oper src)
{
@@ -430,9 +449,9 @@ DEFINSTR1(Xidiv,
{4|8, PMEM, 0, "\xF7", EN_M, .ext=7}, /* IDIV m32/64 */
)
DEFINSTR1(Xcall,
- {-1, PSYM, 0, "\xE8", EN_R32}, /* CALL rel32 */
- {-1, PGPR, 0, "\xFF", EN_R, .ext=2}, /* CALL r64 */
- {-1, PMEM, 0, "\xFF", EN_M, .ext=2}, /* CALL m64 */
+ {-1, PSYM, 0, "\xE8", EN_R32, .norexw=1}, /* CALL rel32 */
+ {-1, PGPR, 0, "\xFF", EN_R, .ext=2, .norexw=1}, /* CALL r64 */
+ {-1, PMEM, 0, "\xFF", EN_M, .ext=2, .norexw=1}, /* CALL m64 */
)
static void
@@ -637,8 +656,10 @@ emitbin(struct function *fn)
{
struct block *blk;
uchar **pcode = &objout.code;
+ uchar *start;
aligncode(pcode, 16);
+ start = *pcode;
/** prologue **/
if (fn->stksiz != 0)
@@ -667,6 +688,7 @@ emitbin(struct function *fn)
B(0xC3); /* ret */
}
} while ((blk = blk->lnext) != fn->entry);
+ objdeffunc(fn->name, fn->globl, start - objout.textbegin, *pcode - start);
}
void
diff --git a/amd64/isel.c b/amd64/isel.c
index 7725013..0205313 100644
--- a/amd64/isel.c
+++ b/amd64/isel.c
@@ -202,7 +202,15 @@ sel(struct function *fn, struct instr *ins, struct block *blk, int *curi)
}
goto ALU;
case Oadd:
- if (ins->l.bits == mkref(RICON, 1).bits) {
+ if (kisint(ins->cls) && (addarg4addrp(ins->l) || addarg4addrp(ins->r))) {
+ temp.op = Ocopy;
+ temp.cls = ins->cls;
+ temp.l = mkref(RTMP, ins - instrtab);
+ if (fuseaddr(fn, &temp.l)) {
+ *ins = temp;
+ break;
+ }
+ } else if (ins->l.bits == mkref(RICON, 1).bits) {
/* add 1,x -> inc x */
ins->op = op = Oxinc;
ins->l = ins->r;
@@ -213,14 +221,6 @@ sel(struct function *fn, struct instr *ins, struct block *blk, int *curi)
ins->op = op = Oxinc;
ins->r = NOREF;
goto ALU;
- } else if (kisint(ins->cls) && (addarg4addrp(ins->l) || addarg4addrp(ins->r))) {
- temp.op = Ocopy;
- temp.cls = ins->cls;
- temp.l = mkref(RTMP, ins - instrtab);
- if (fuseaddr(fn, &temp.l)) {
- *ins = temp;
- break;
- }
}
/* fallthru */
case Omul: case Oumul: