commit c78d6b84c9732f62dd0076445727d5807ae1944e
parent 40b0a2c21748fb95d7b3c2455fae94f3a80c41af
Author: erai <erai@omiltem.net>
Date: Wed, 7 May 2025 13:21:36 -0400
isolate x86 specific stuff
Diffstat:
M | as.om | | | 373 | +------------------------------------------------------------------------------ |
M | bootstrap.sh | | | 2 | +- |
M | cc1.om | | | 761 | ------------------------------------------------------------------------------- |
M | ir.om | | | 740 | ------------------------------------------------------------------------------- |
M | ircout.om | | | 2 | +- |
M | lexer.om | | | 2 | +- |
M | syscall.om | | | 185 | +++++++++++-------------------------------------------------------------------- |
A | syscall.x86.om | | | 158 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | x86.om | | | 1873 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
9 files changed, 2060 insertions(+), 2036 deletions(-)
diff --git a/as.om b/as.om
@@ -1,146 +1,4 @@
-enum {
- R_RAX,
- R_RCX,
- R_RDX,
- R_RBX,
- R_RSP,
- R_RBP,
- R_RSI,
- R_RDI,
- R_R8,
- R_R9,
- R_R10,
- R_R11,
- R_R12,
- R_R13,
- R_R14,
- R_R15,
- R_RIP,
-
- R_ES = 0,
- R_CS = 1,
- R_SS = 2,
- R_DS = 3,
- R_FS = 4,
- R_GS = 5,
-
- R_CR0 = 0,
- R_CR1 = 1,
- R_CR2 = 2,
- R_CR3 = 3,
- R_CR4 = 4,
- R_CR5 = 5,
- R_CR6 = 6,
- R_CR7 = 7,
-}
-
-enum {
- CC_O = 0x00,
- CC_NO = 0x01,
- CC_B = 0x02,
- CC_AE = 0x03,
- CC_E = 0x04,
- CC_NE = 0x05,
- CC_BE = 0x06,
- CC_A = 0x07,
- CC_S = 0x08,
- CC_NS = 0x09,
- CC_P = 0x0a,
- CC_NP = 0x0b,
- CC_L = 0x0c,
- CC_GE = 0x0d,
- CC_LE = 0x0e,
- CC_G = 0x0f,
-}
-
-enum {
- OP_GS = 0x65,
- OP_OS = 0x66,
-
- OP_CLD = 0xfc,
- OP_CLI = 0xfa,
- OP_STI = 0xfb,
- OP_CPUID = 0x0fa2,
- OP_IN = 0xec,
- OP_IND = 0xed,
- OP_OUT = 0xee,
- OP_OUTD = 0xef,
- OP_HLT = 0xf4,
- OP_NOP = 0x90,
- OP_WBINVD = 0x0f09,
- OP_UD2 = 0x0f0b,
-
- OP_INVLPGM = 0x070f01,
- OP_LLDM = 0x020f00,
- OP_LTRM = 0x030f00,
-
- OP_WRSR = 0x8e,
- OP_RDSR = 0x8c,
-
- OP_RET = 0xc3,
- OP_CALL = 0xe8,
- OP_JMP = 0xe9,
- OP_JCC = 0x0f80,
- OP_SETCC = 0x0f90,
-
- OP_PUSHF = 0x9c,
- OP_POPF = 0x9d,
- OP_IRET = 0xcf,
- OP_IRETQ = 0x48cf,
- OP_WRMSR = 0x0f30,
- OP_RDMSR = 0x0f32,
- OP_RDCRR = 0x0f20,
- OP_WRCRR = 0x0f22,
- OP_LGDTM = 0x020f01,
- OP_LIDTM = 0x030f01,
- OP_LLDTM = 0x020f00,
-
- OP_ICALLM = 0x0200ff,
-
- OP_NOTM = 0x0200f7,
- OP_NEGM = 0x0300f7,
-
- OP_ANDRM = 0x23,
- OP_ORRM = 0x0b,
- OP_CMPRM = 0x3b,
- OP_TESTRM = 0x85,
- OP_SUBRM = 0x2b,
- OP_ADDRM = 0x03,
- OP_ADCRM = 0x13,
- OP_XORRM = 0x33,
-
- OP_ANDI = 0x040081,
- OP_ADDI = 0x000081,
- OP_SUBI = 0x050081,
- OP_ORI = 0x010081,
- OP_CMPI = 0x070081,
-
- OP_RDRAND = 0x060fc7,
-
- OP_IMULM = 0x0400f7,
- OP_IDIVM = 0x0700f7,
- OP_SHLM = 0x0400d3,
- OP_SHRM = 0x0500d3,
-
- OP_PUSHR = 0x50,
-
- OP_POPR = 0x58,
-
- OP_MOVI = 0x00c7,
- OP_MOVABS = 0xb8,
-
- OP_SYSCALL = 0x0f05,
- OP_SYSRET = 0x0f07,
-
- OP_LEA = 0x8d,
- OP_LOAD = 0x8b,
- OP_LOADB = 0x8a,
- OP_LOAD16 = 0x668a,
- OP_STOREB = 0x88,
- OP_STORE = 0x89,
- OP_STORE16 = 0x6689,
- OP_MOVE = 0x8b,
-}
+func setup_machdep_x86(c: *compiler);
struct fixup {
next: *fixup;
@@ -1101,232 +959,3 @@ func writeout(c: *assembler, start: *label, kstart: *label) {
func as_emit(a: *assembler, b: int) {
emit(a, b);
}
-
-func as_rex(a: *assembler, op: int, r: int, i: int, b: int) {
- var w: int;
- if a.bits32 {
- return;
- }
- w = 0x08;
- if op == OP_LOADB || op == OP_STOREB {
- w = 0;
- if r < 8 && i < 8 && b < 8 {
- return;
- }
- }
- as_emit(a, 0x40 + w + ((r >> 1) & 4) + ((i >> 2) & 2) + ((b >> 3) & 1));
-}
-
-func as_op(a: *assembler, op: int) {
- if op > 0xff {
- as_emit(a, op >> 8);
- as_emit(a, op);
- } else {
- as_emit(a, op);
- }
-}
-
-// op + r
-func as_opr(a: *assembler, op: int, r: int) {
- if r < 0 || r > 15 {
- die("invalid reg");
- }
- if (op != OP_PUSHR && op != OP_POPR) || r > 7 {
- as_rex(a, op, r, 0, 0);
- }
- as_op(a, op + (r & 7));
-}
-
-func as_opri64(a: *assembler, op: int, r: int, x: int) {
- if op != OP_MOVABS {
- die("only movabs");
- }
- as_opr(a, op, r);
- as_emit(a, x);
- as_emit(a, x >> 8);
- as_emit(a, x >> 16);
- as_emit(a, x >> 24);
- as_emit(a, x >> 32);
- as_emit(a, x >> 40);
- as_emit(a, x >> 48);
- as_emit(a, x >> 56);
-}
-
-// modrm
-func as_modrr(a: *assembler, op: int, r: int, b: int) {
- if r < 0 || r > 15 || b < 0 || b > 15 {
- die("invalid reg");
- }
- if (op != (OP_ICALLM & 0xffff) && (op & -16) != OP_SETCC) || b >= 8 {
- as_rex(a, op, r, 0, b);
- }
- as_op(a, op);
- as_emit(a, 0xc0 + ((r << 3) & 0x38) + (b & 0x07));
-}
-
-// modrm /op
-func as_modr(a: *assembler, op: int, b: int) {
- as_modrr(a, op & 0xffff, op >> 16, b);
-}
-
-// modrm + disp
-func as_modra(a: *assembler, op: int, r: int, d: int) {
- as_rex(a, op, r, 0, 0);
- as_op(a, op);
- as_emit(a, ((r << 3) & 0x38) + R_RSP);
- as_emit(a, (R_RSP << 3) + R_RBP);
- as_emit(a, d);
- as_emit(a, d >> 8);
- as_emit(a, d >> 16);
- as_emit(a, d >> 24);
-}
-
-// modrm + sib + disp
-func as_modrm(a: *assembler, op: int, r: int, b: int, i: int, s: int, d: int) {
- var sib: int;
- var mod: int;
- var rm: int;
- var dw: int;
-
- if r < 0 || r > 15 {
- die("invalid reg");
- }
-
- rm = (r << 3) & 0x38;
-
- if d != 0 {
- if d >= -128 && d <= 127 {
- mod = 1;
- dw = 1;
- } else {
- mod = 2;
- dw = 4;
- }
- } else {
- mod = 0;
- dw = 0;
- }
-
- if mod == 0 {
- if b < 0 || b > 16 {
- die("invalid reg");
- }
-
- if s {
- if b == R_RIP {
- die("invalid base");
- }
-
- if i == R_RSP {
- die("invalid index");
- }
-
- rm = rm + R_RSP;
- } else {
- if i != 0 {
- die("invalid index");
- }
-
- if b == R_RIP {
- mod = 0;
- dw = 4;
- rm = rm + R_RBP;
- } else if b == R_RSP || b == R_R12 {
- s = 1;
- i = R_RSP;
- rm = rm + R_RSP;
- } else if b == R_RBP || b == R_R13 {
- mod = 1;
- dw = 1;
- rm = rm + R_RBP;
- } else {
- rm = rm + (b & 7);
- }
- }
- } else {
- if b < 0 || b > 16 || i < 0 || i > 15 {
- die("invalid reg");
- }
-
- if s {
- if b == R_RIP {
- die("invalid base");
- }
-
- if i == R_RSP {
- die("invalid index");
- }
-
- rm = rm + R_RSP;
- } else {
- if i != 0 {
- die("invalid index");
- }
-
- if b == R_RIP {
- mod = 0;
- dw = 4;
- rm = rm + R_RBP;
- } else if b == R_RSP || b == R_R12 {
- s = 1;
- i = R_RSP;
- rm = rm + R_RSP;
- } else {
- rm = rm + (b & 7);
- }
- }
- }
-
- as_rex(a, op, r, i, b);
- as_op(a, op);
- as_emit(a, (mod << 6) + rm);
-
- if s {
- sib = ((i << 3) & 0x38) + (b & 0x07);
- if s == 2 {
- sib = sib + 0x40;
- } else if s == 4 {
- sib = sib + 0x80;
- } else if s == 8 {
- sib = sib + 0xc0;
- } else if s != 1 {
- die("invalid scale");
- }
- as_emit(a, sib);
- }
-
- if dw == 1 {
- as_emit(a, d);
- } else if dw == 4 {
- as_emit(a, d);
- as_emit(a, d >> 8);
- as_emit(a, d >> 16);
- as_emit(a, d >> 24);
- }
-}
-
-// modrm /op
-func as_modm(a: *assembler, op: int, b: int, i: int, s: int, d: int) {
- as_modrm(a, op & 0xffff, op >> 16, b, i, s, d);
-}
-
-func as_modri(a: *assembler, op: int, r: int, x: int) {
- if x < -(1 << 31) || x >= (1 << 31) {
- die("immediate too large");
- }
- as_modrr(a, op & 0xffff, op >> 16, r);
- as_emit(a, x);
- as_emit(a, x >> 8);
- as_emit(a, x >> 16);
- as_emit(a, x >> 24);
-}
-
-func as_jmp(a: *assembler, op: int, l: *label) {
- reserve(a, 16);
- as_op(a, op);
- as_emit(a, 0);
- as_emit(a, 0);
- as_emit(a, 0);
- as_emit(a, 0);
- addfixup(a, l);
-}
diff --git a/bootstrap.sh b/bootstrap.sh
@@ -2,7 +2,7 @@
BOOTSTRAP="cc0.c"
LIBS="bufio.om lib.om alloc.om syscall.om"
-SOURCES="cc1.om cc4.om type.om as.om decl.om node.om ir.om ircout.om rb.om table.om lexer.om lalr.om"
+SOURCES="cc1.om cc4.om type.om as.om decl.om node.om ir.om ircout.om rb.om table.om lexer.om lalr.om x86.om syscall.x86.om"
# Build the bootstrap compiler from c
[ cc0 -nt cc0.c ] || ${CC:-gcc} -O1 -g ${BOOTSTRAP} -o cc0
diff --git a/cc1.om b/cc1.om
@@ -1374,767 +1374,6 @@ func call_check(c: *compiler, n: *node): int {
return result;
}
-func emit_ssr(c: *compiler) {
- var d: *decl;
- var v: *decl;
-
- v = find(c, "global", "_save", 0);
- if (!v || !v.member_defined) {
- cdie(c, "no _save");
- }
-
- // Save the current stack
- as_emit(c.s, OP_GS);
- as_modra(c.s, OP_STORE, R_RSP, v.member_offset);
-
- v = find(c, "global", "curtask", 0);
- if (!v || !v.member_defined) {
- cdie(c, "no global.curtask");
- }
-
- // Load the current task
- as_emit(c.s, OP_GS);
- as_modra(c.s, OP_LOAD, R_RSP, v.member_offset);
-
- v = find(c, "task", "stack", 0);
- if (!v || !v.member_defined) {
- cdie(c, "no task.stack");
- }
-
- // Load the kernel stack but reserve some space for the regs struct
- as_modrm(c.s, OP_LOAD, R_RSP, R_RSP, 0, 0, v.member_offset);
- as_modri(c.s, OP_ADDI, R_RSP, 4096 - 176);
-
- // Save general purpose registers
- as_modrm(c.s, OP_STORE, R_RAX, R_RSP, 0, 0, 0);
- as_modrm(c.s, OP_STORE, R_RDX, R_RSP, 0, 0, 16);
- as_modrm(c.s, OP_STORE, R_RBX, R_RSP, 0, 0, 24);
- as_modrm(c.s, OP_STORE, R_RBP, R_RSP, 0, 0, 40);
- as_modrm(c.s, OP_STORE, R_RSI, R_RSP, 0, 0, 48);
- as_modrm(c.s, OP_STORE, R_RDI, R_RSP, 0, 0, 56);
- as_modrm(c.s, OP_STORE, R_R8, R_RSP, 0, 0, 64);
- as_modrm(c.s, OP_STORE, R_R9, R_RSP, 0, 0, 72);
- as_modrm(c.s, OP_STORE, R_R10, R_RSP, 0, 0, 80);
- as_modrm(c.s, OP_STORE, R_R12, R_RSP, 0, 0, 96);
- as_modrm(c.s, OP_STORE, R_R13, R_RSP, 0, 0, 104);
- as_modrm(c.s, OP_STORE, R_R14, R_RSP, 0, 0, 112);
- as_modrm(c.s, OP_STORE, R_R15, R_RSP, 0, 0, 120);
- as_modrm(c.s, OP_STORE, R_RCX, R_RSP, 0, 0, 128);
- as_modrm(c.s, OP_STORE, R_R11, R_RSP, 0, 0, 136);
-
- // Clear rcx, r11, trap, err
- as_modrr(c.s, OP_XORRM, R_RAX, R_RAX);
- as_modrm(c.s, OP_STORE, R_RAX, R_RSP, 0, 0, 8);
- as_modrm(c.s, OP_STORE, R_RAX, R_RSP, 0, 0, 88);
- as_modrm(c.s, OP_STORE, R_RAX, R_RSP, 0, 0, 160);
- as_modrm(c.s, OP_STORE, R_RAX, R_RSP, 0, 0, 168);
-
- // Save cs and ds
- as_modri(c.s, OP_MOVI, R_RAX, 43);
- as_modrm(c.s, OP_STORE, R_RAX, R_RSP, 0, 0, 144);
- as_modri(c.s, OP_MOVI, R_RAX, 35);
- as_modrm(c.s, OP_STORE, R_RAX, R_RSP, 0, 0, 152);
-
- v = find(c, "global", "_save", 0);
- if (!v || !v.member_defined) {
- cdie(c, "no _save");
- }
-
- // Save the saved stack and switch back
- as_emit(c.s, OP_GS);
- as_modra(c.s, OP_LOAD, R_RAX, v.member_offset);
- as_modrm(c.s, OP_STORE, R_RAX, R_RSP, 0, 0, 32);
- as_modrr(c.s, OP_MOVE, R_RAX, R_RSP);
-
- // Create a frame
- as_modrr(c.s, OP_XORRM, R_RBP, R_RBP);
- as_opr(c.s, OP_PUSHR, R_RBP);
- as_opr(c.s, OP_PUSHR, R_RBP);
- as_modrr(c.s, OP_MOVE, R_RBP, R_RSP);
-
- as_modrr(c.s, OP_MOVE, R_RDI, R_RAX);
-
- // Call _ssr
- d = find(c, "_ssr", nil, 1);
- if (d.func_defined && d.func_label.fixed) {
- as_jmp(c.s, OP_CALL, d.func_label);
- }
-
- as_op(c.s, OP_CLI);
-
- // Delete the frame
- as_modri(c.s, OP_ADDI, R_RSP, 2 * 8);
-
- // Restore the old registers
- as_modrm(c.s, OP_LOAD, R_RAX, R_RSP, 0, 0, 0);
- as_modrm(c.s, OP_LOAD, R_RDX, R_RSP, 0, 0, 16);
- as_modrm(c.s, OP_LOAD, R_RBX, R_RSP, 0, 0, 24);
- as_modrm(c.s, OP_LOAD, R_RBP, R_RSP, 0, 0, 40);
- as_modrm(c.s, OP_LOAD, R_RSI, R_RSP, 0, 0, 48);
- as_modrm(c.s, OP_LOAD, R_RDI, R_RSP, 0, 0, 56);
- as_modrm(c.s, OP_LOAD, R_R8, R_RSP, 0, 0, 64);
- as_modrm(c.s, OP_LOAD, R_R9, R_RSP, 0, 0, 72);
- as_modrm(c.s, OP_LOAD, R_R10, R_RSP, 0, 0, 80);
- as_modrm(c.s, OP_LOAD, R_R12, R_RSP, 0, 0, 96);
- as_modrm(c.s, OP_LOAD, R_R13, R_RSP, 0, 0, 104);
- as_modrm(c.s, OP_LOAD, R_R14, R_RSP, 0, 0, 112);
- as_modrm(c.s, OP_LOAD, R_R15, R_RSP, 0, 0, 120);
-
- as_modrm(c.s, OP_LOAD, R_RCX, R_RSP, 0, 0, 128);
- as_modrm(c.s, OP_LOAD, R_R11, R_RSP, 0, 0, 136);
-
- as_modrm(c.s, OP_LOAD, R_RSP, R_RSP, 0, 0, 32);
-
- // Return to the user
- as_rex(c.s, OP_SYSRET, 0, 0, 0);
- as_op(c.s, OP_SYSRET);
-}
-
-func emit_isr(c: *compiler) {
- var d: *decl;
- var out: *label;
- var i: int;
-
- out = mklabel(c.s);
-
- i = 0;
- loop {
- if i == 256 {
- break;
- }
- reserve(c.s, 16);
-
- if i == 8 || i == 10 || i == 11 || i == 12
- || i == 13 || i == 14 || i == 17 || i == 21
- || i == 29 || i == 30 {
- // nop
- as_emit(c.s, 0x90);
- as_emit(c.s, 0x90);
- } else {
- // push 0
- as_emit(c.s, 0x6a);
- as_emit(c.s, 0x00);
- }
-
- // push i
- as_emit(c.s, 0x68);
- as_emit(c.s, i);
- as_emit(c.s, 0x00);
- as_emit(c.s, 0x00);
- as_emit(c.s, 0x00);
-
- // jmp out
- as_emit(c.s, 0xe9);
- as_emit(c.s, 0x00);
- as_emit(c.s, 0x00);
- as_emit(c.s, 0x00);
- as_emit(c.s, 0x00);
- addfixup(c.s, out);
-
- // Align to 16
- as_emit(c.s, 0x90);
- as_emit(c.s, 0x90);
- as_emit(c.s, 0x90);
- as_emit(c.s, 0x90);
-
- i = i + 1;
- }
-
- fixup_label(c.s, out);
-
- // Allocate a regs struct
- as_modri(c.s, OP_SUBI, R_RSP, 176);
-
- // Save rbp and use it as the regs pointer
- as_modrm(c.s, OP_STORE, R_RBP, R_RSP, 0, 0, 40);
- as_modrr(c.s, OP_MOVE, R_RBP, R_RSP);
-
- // Save general purpose registers
- as_modrm(c.s, OP_STORE, R_RAX, R_RBP, 0, 0, 0);
- as_modrm(c.s, OP_STORE, R_RCX, R_RBP, 0, 0, 8);
- as_modrm(c.s, OP_STORE, R_RDX, R_RBP, 0, 0, 16);
- as_modrm(c.s, OP_STORE, R_RBX, R_RBP, 0, 0, 24);
- as_modrm(c.s, OP_STORE, R_RSI, R_RBP, 0, 0, 48);
- as_modrm(c.s, OP_STORE, R_RDI, R_RBP, 0, 0, 56);
- as_modrm(c.s, OP_STORE, R_R8, R_RBP, 0, 0, 64);
- as_modrm(c.s, OP_STORE, R_R9, R_RBP, 0, 0, 72);
- as_modrm(c.s, OP_STORE, R_R10, R_RBP, 0, 0, 80);
- as_modrm(c.s, OP_STORE, R_R11, R_RBP, 0, 0, 88);
- as_modrm(c.s, OP_STORE, R_R12, R_RBP, 0, 0, 96);
- as_modrm(c.s, OP_STORE, R_R13, R_RBP, 0, 0, 104);
- as_modrm(c.s, OP_STORE, R_R14, R_RBP, 0, 0, 112);
- as_modrm(c.s, OP_STORE, R_R15, R_RBP, 0, 0, 120);
-
- // trap
- as_modrm(c.s, OP_LOAD, R_RAX, R_RBP, 0, 0, 176 + 0);
- as_modrm(c.s, OP_STORE, R_RAX, R_RBP, 0, 0, 160);
- // err
- as_modrm(c.s, OP_LOAD, R_RAX, R_RBP, 0, 0, 176 + 8);
- as_modrm(c.s, OP_STORE, R_RAX, R_RBP, 0, 0, 168);
- // rip
- as_modrm(c.s, OP_LOAD, R_RAX, R_RBP, 0, 0, 176 + 16);
- as_modrm(c.s, OP_STORE, R_RAX, R_RBP, 0, 0, 128);
- // cs
- as_modrm(c.s, OP_LOAD, R_RAX, R_RBP, 0, 0, 176 + 24);
- as_modrm(c.s, OP_STORE, R_RAX, R_RBP, 0, 0, 144);
- // flags
- as_modrm(c.s, OP_LOAD, R_RAX, R_RBP, 0, 0, 176 + 32);
- as_modrm(c.s, OP_STORE, R_RAX, R_RBP, 0, 0, 136);
- // rsp
- as_modrm(c.s, OP_LOAD, R_RAX, R_RBP, 0, 0, 176 + 40);
- as_modrm(c.s, OP_STORE, R_RAX, R_RBP, 0, 0, 32);
- // ss
- as_modrm(c.s, OP_LOAD, R_RAX, R_RBP, 0, 0, 176 + 48);
- as_modrm(c.s, OP_STORE, R_RAX, R_RBP, 0, 0, 152);
-
- // Call _isr
- as_modrr(c.s, OP_MOVE, R_RDI, R_RBP);
- d = find(c, "_isr", nil, 1);
- if (d.func_defined && d.func_label.fixed) {
- as_jmp(c.s, OP_CALL, d.func_label);
- }
-
- // rip
- as_modrm(c.s, OP_LOAD, R_RAX, R_RBP, 0, 0, 128);
- as_modrm(c.s, OP_STORE, R_RAX, R_RBP, 0, 0, 176 + 16);
- // cs
- as_modrm(c.s, OP_LOAD, R_RAX, R_RBP, 0, 0, 144);
- as_modrm(c.s, OP_STORE, R_RAX, R_RBP, 0, 0, 176 + 24);
- // flags
- as_modrm(c.s, OP_LOAD, R_RAX, R_RBP, 0, 0, 136);
- as_modrm(c.s, OP_STORE, R_RAX, R_RBP, 0, 0, 176 + 32);
- // rsp
- as_modrm(c.s, OP_LOAD, R_RAX, R_RBP, 0, 0, 32);
- as_modrm(c.s, OP_STORE, R_RAX, R_RBP, 0, 0, 176 + 40);
- // ss
- as_modrm(c.s, OP_LOAD, R_RAX, R_RBP, 0, 0, 152);
- as_modrm(c.s, OP_STORE, R_RAX, R_RBP, 0, 0, 176 + 48);
-
- // Restore general purpose registers
- as_modrm(c.s, OP_LOAD, R_RAX, R_RBP, 0, 0, 0);
- as_modrm(c.s, OP_LOAD, R_RCX, R_RBP, 0, 0, 8);
- as_modrm(c.s, OP_LOAD, R_RDX, R_RBP, 0, 0, 16);
- as_modrm(c.s, OP_LOAD, R_RBX, R_RBP, 0, 0, 24);
- as_modrm(c.s, OP_LOAD, R_RSI, R_RBP, 0, 0, 48);
- as_modrm(c.s, OP_LOAD, R_RDI, R_RBP, 0, 0, 56);
- as_modrm(c.s, OP_LOAD, R_R8, R_RBP, 0, 0, 64);
- as_modrm(c.s, OP_LOAD, R_R9, R_RBP, 0, 0, 72);
- as_modrm(c.s, OP_LOAD, R_R10, R_RBP, 0, 0, 80);
- as_modrm(c.s, OP_LOAD, R_R11, R_RBP, 0, 0, 88);
- as_modrm(c.s, OP_LOAD, R_R12, R_RBP, 0, 0, 96);
- as_modrm(c.s, OP_LOAD, R_R13, R_RBP, 0, 0, 104);
- as_modrm(c.s, OP_LOAD, R_R14, R_RBP, 0, 0, 112);
- as_modrm(c.s, OP_LOAD, R_R15, R_RBP, 0, 0, 120);
-
- // Restore rbp
- as_modrm(c.s, OP_LOAD, R_RBP, R_RBP, 0, 0, 40);
-
- // Clean up regs + trap + err
- as_modri(c.s, OP_ADDI, R_RSP, 176 + 2 * 8);
-
- as_op(c.s, OP_IRETQ);
-}
-
-func emit_builtin(c: *compiler) {
- var d: *decl;
-
- d = find(c, "syscall", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_modrr(c.s, OP_MOVE, R_RAX, R_RDI);
- as_modrr(c.s, OP_MOVE, R_RDI, R_RSI);
- as_modrr(c.s, OP_MOVE, R_RSI, R_RDX);
- as_modrr(c.s, OP_MOVE, R_RDX, R_RCX);
- as_modrr(c.s, OP_MOVE, R_R10, R_R8);
- as_modrr(c.s, OP_MOVE, R_R8, R_R9);
- as_modrm(c.s, OP_LOAD, R_R9, R_RSP, 0, 0, 8);
- as_op(c.s, OP_SYSCALL);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "_restorer", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_modri(c.s, OP_MOVI, R_RAX, 15);
- as_op(c.s, OP_SYSCALL);
- }
-
- d = find(c, "_include", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_op(c.s, OP_UD2);
- }
-
- d = find(c, "ud2", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_op(c.s, OP_UD2);
- }
-
- d = find(c, "cpuid", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_opr(c.s, OP_PUSHR, R_RCX);
- as_opr(c.s, OP_PUSHR, R_RDX);
- as_opr(c.s, OP_PUSHR, R_RSI);
- as_opr(c.s, OP_PUSHR, R_RDI);
- as_modrm(c.s, OP_LOAD, R_RAX, R_RDI, 0, 0, 0);
- as_modrm(c.s, OP_LOAD, R_RCX, R_RSI, 0, 0, 0);
- as_modrm(c.s, OP_LOAD, R_RDX, R_RDX, 0, 0, 0);
- as_modrm(c.s, OP_LOAD, R_RBX, R_RCX, 0, 0, 0);
- as_op(c.s, OP_CPUID);
- as_opr(c.s, OP_POPR, R_RDI);
- as_opr(c.s, OP_POPR, R_RSI);
- as_opr(c.s, OP_POPR, R_RDX);
- as_opr(c.s, OP_POPR, R_RCX);
- as_modrm(c.s, OP_STORE, R_RAX, R_RDI, 0, 0, 0);
- as_modrm(c.s, OP_STORE, R_RCX, R_RSI, 0, 0, 0);
- as_modrm(c.s, OP_STORE, R_RDX, R_RDX, 0, 0, 0);
- as_modrm(c.s, OP_STORE, R_RBX, R_RCX, 0, 0, 0);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "inb", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_modrr(c.s, OP_MOVE, R_RDX, R_RDI);
- as_op(c.s, OP_IN);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "outb", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_modrr(c.s, OP_MOVE, R_RDX, R_RDI);
- as_modrr(c.s, OP_MOVE, R_RAX, R_RSI);
- as_op(c.s, OP_OUT);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "inw", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_modrr(c.s, OP_MOVE, R_RDX, R_RDI);
- as_emit(c.s, OP_OS);
- as_op(c.s, OP_IND);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "outw", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_modrr(c.s, OP_MOVE, R_RDX, R_RDI);
- as_modrr(c.s, OP_MOVE, R_RAX, R_RSI);
- as_emit(c.s, OP_OS);
- as_op(c.s, OP_OUTD);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "ind", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_modrr(c.s, OP_MOVE, R_RDX, R_RDI);
- as_op(c.s, OP_IND);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "outd", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_modrr(c.s, OP_MOVE, R_RDX, R_RDI);
- as_modrr(c.s, OP_MOVE, R_RAX, R_RSI);
- as_op(c.s, OP_OUTD);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "rdmsr", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_modrr(c.s, OP_MOVE, R_RCX, R_RDI);
- as_op(c.s, OP_RDMSR);
- as_modri(c.s, OP_MOVI, R_RCX, 32);
- as_modr(c.s, OP_SHLM, R_RDX);
- as_modrr(c.s, OP_ORRM, R_RAX, R_RDX);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "wrmsr", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_modrr(c.s, OP_MOVE, R_RAX, R_RSI);
- as_modrr(c.s, OP_MOVE, R_RDX, R_RSI);
- as_modri(c.s, OP_MOVI, R_RCX, 32);
- as_modr(c.s, OP_SHRM, R_RDX);
- as_modrr(c.s, OP_MOVE, R_RCX, R_RDI);
- as_op(c.s, OP_WRMSR);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "rdcr0", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_modrr(c.s, OP_RDCRR, R_CR0, R_RAX);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "wrcr0", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_modrr(c.s, OP_WRCRR, R_CR0, R_RDI);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "rdcr2", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_modrr(c.s, OP_RDCRR, R_CR2, R_RAX);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "wrcr2", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_modrr(c.s, OP_WRCRR, R_CR2, R_RDI);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "rdcr3", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_modrr(c.s, OP_RDCRR, R_CR3, R_RAX);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "wrcr3", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_modrr(c.s, OP_WRCRR, R_CR3, R_RDI);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "rdcr4", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_modrr(c.s, OP_RDCRR, R_CR4, R_RAX);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "wrcr4", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_modrr(c.s, OP_WRCRR, R_CR4, R_RDI);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "lgdt", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_modri(c.s, OP_SUBI, R_RSP, 16);
- as_modri(c.s, OP_SUBI, R_RSI, 1);
- as_modrm(c.s, OP_STORE, R_RSI, R_RSP, 0, 0, 0);
- as_modrm(c.s, OP_STORE, R_RDI, R_RSP, 0, 0, 2);
- as_modm(c.s, OP_LGDTM, R_RSP, 0, 0, 0);
- as_modri(c.s, OP_ADDI, R_RSP, 16);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "lidt", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_modri(c.s, OP_SUBI, R_RSP, 16);
- as_modri(c.s, OP_SUBI, R_RSI, 1);
- as_modrm(c.s, OP_STORE, R_RSI, R_RSP, 0, 0, 0);
- as_modrm(c.s, OP_STORE, R_RDI, R_RSP, 0, 0, 2);
- as_modm(c.s, OP_LIDTM, R_RSP, 0, 0, 0);
- as_modri(c.s, OP_ADDI, R_RSP, 16);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "lldt", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_modr(c.s, OP_LLDTM, R_RDI);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "ltr", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_modr(c.s, OP_LTRM, R_RDI);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "lseg", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_opr(c.s, OP_PUSHR, R_RBP);
- as_modrr(c.s, OP_MOVE, R_RBP, R_RSP);
- // es ds fs gs
- as_modrr(c.s, OP_WRSR, R_ES, R_RSI);
- as_modrr(c.s, OP_WRSR, R_DS, R_RSI);
- as_modrr(c.s, OP_WRSR, R_FS, R_RSI);
- as_modrr(c.s, OP_WRSR, R_GS, R_RSI);
- // ss
- as_opr(c.s, OP_PUSHR, R_RSI);
- // rsp
- as_opr(c.s, OP_PUSHR, R_RBP);
- // flags
- as_op(c.s, OP_PUSHF);
- // cs
- as_opr(c.s, OP_PUSHR, R_RDI);
- // rip
- as_op(c.s, OP_CALL);
- as_emit(c.s, 5);
- as_emit(c.s, 0);
- as_emit(c.s, 0);
- as_emit(c.s, 0);
- as_op(c.s, OP_JMP);
- as_emit(c.s, 2);
- as_emit(c.s, 0);
- as_emit(c.s, 0);
- as_emit(c.s, 0);
- as_op(c.s, OP_IRETQ);
- as_opr(c.s, OP_POPR, R_RBP);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "hlt", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_op(c.s, OP_HLT);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "cli", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_op(c.s, OP_CLI);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "sti", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_op(c.s, OP_STI);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "rdflags", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_op(c.s, OP_PUSHF);
- as_opr(c.s, OP_POPR, R_RAX);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "wrflags", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_opr(c.s, OP_PUSHR, R_RDI);
- as_op(c.s, OP_POPF);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "wbinvld", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_modm(c.s, OP_WBINVD, R_RDI, 0, 0, 0);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "invlpg", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_modm(c.s, OP_INVLPGM, R_RDI, 0, 0, 0);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "_ssr0", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- emit_ssr(c);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "_isr0", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- emit_isr(c);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "_rgs", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_modrm(c.s, OP_LOAD, R_RSI, R_RBP, 0, 0, 16);
- as_emit(c.s, OP_GS);
- as_modrm(c.s, OP_LOAD, R_RAX, R_RSI, 0, 0, 0);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "_r32", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- c.s.bits32 = 1;
- as_modrm(c.s, OP_LOAD, R_RAX, R_RDI, 0, 0, 0);
- c.s.bits32 = 0;
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "_w32", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- c.s.bits32 = 1;
- as_modrm(c.s, OP_STORE, R_RSI, R_RDI, 0, 0, 0);
- c.s.bits32 = 0;
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "_r16", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_modrr(c.s, OP_XORRM, R_RAX, R_RAX);
- c.s.bits32 = 1;
- as_modrm(c.s, OP_LOAD16, R_RAX, R_RDI, 0, 0, 0);
- c.s.bits32 = 0;
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "_w16", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- c.s.bits32 = 1;
- as_modrm(c.s, OP_STORE16, R_RSI, R_RDI, 0, 0, 0);
- c.s.bits32 = 0;
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "_rdrand", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
- as_modr(c.s, OP_RDRAND, R_RAX);
- as_op(c.s, OP_RET);
- }
-
- d = find(c, "taskswitch", nil, 1);
- if (d.func_defined && !d.func_label.fixed) {
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
-
- // save
- as_modrm(c.s, OP_STORE, R_RAX, R_RDI, 0, 0, 0);
- as_modrm(c.s, OP_STORE, R_RCX, R_RDI, 0, 0, 8);
- as_modrm(c.s, OP_STORE, R_RDX, R_RDI, 0, 0, 16);
- as_modrm(c.s, OP_STORE, R_RBX, R_RDI, 0, 0, 24);
- as_modrm(c.s, OP_STORE, R_RBP, R_RDI, 0, 0, 40);
- as_modrm(c.s, OP_STORE, R_RSI, R_RDI, 0, 0, 48);
- as_modrm(c.s, OP_STORE, R_RDI, R_RDI, 0, 0, 56);
- as_modrm(c.s, OP_STORE, R_R8, R_RDI, 0, 0, 64);
- as_modrm(c.s, OP_STORE, R_R9, R_RDI, 0, 0, 72);
- as_modrm(c.s, OP_STORE, R_R10, R_RDI, 0, 0, 80);
- as_modrm(c.s, OP_STORE, R_R11, R_RDI, 0, 0, 88);
- as_modrm(c.s, OP_STORE, R_R12, R_RDI, 0, 0, 96);
- as_modrm(c.s, OP_STORE, R_R13, R_RDI, 0, 0, 104);
- as_modrm(c.s, OP_STORE, R_R14, R_RDI, 0, 0, 112);
- as_modrm(c.s, OP_STORE, R_R15, R_RDI, 0, 0, 120);
-
- // rip
- as_opr(c.s, OP_POPR, R_RAX);
- as_modrm(c.s, OP_STORE, R_RAX, R_RDI, 0, 0, 128);
- // cs
- as_modrr(c.s, OP_RDSR, R_CS, R_RAX);
- as_modrm(c.s, OP_STORE, R_RAX, R_RDI, 0, 0, 144);
- // flags
- as_op(c.s, OP_PUSHF);
- as_opr(c.s, OP_POPR, R_RAX);
- as_modrm(c.s, OP_STORE, R_RAX, R_RDI, 0, 0, 136);
- // rsp
- as_modrm(c.s, OP_STORE, R_RSP, R_RDI, 0, 0, 32);
- // ss
- as_modrr(c.s, OP_RDSR, R_SS, R_RAX);
- as_modrm(c.s, OP_STORE, R_RAX, R_RDI, 0, 0, 152);
-
- // restore
- as_modrm(c.s, OP_STORE, R_RCX, R_RDI, 0, 0, 8);
- as_modrm(c.s, OP_STORE, R_RDX, R_RDI, 0, 0, 16);
- as_modrm(c.s, OP_STORE, R_RBX, R_RDI, 0, 0, 24);
- as_modrm(c.s, OP_STORE, R_RBP, R_RDI, 0, 0, 40);
- as_modrm(c.s, OP_STORE, R_RDI, R_RDI, 0, 0, 56);
- as_modrm(c.s, OP_STORE, R_R8, R_RDI, 0, 0, 64);
- as_modrm(c.s, OP_STORE, R_R9, R_RDI, 0, 0, 72);
- as_modrm(c.s, OP_STORE, R_R10, R_RDI, 0, 0, 80);
- as_modrm(c.s, OP_STORE, R_R11, R_RDI, 0, 0, 88);
- as_modrm(c.s, OP_STORE, R_R12, R_RDI, 0, 0, 96);
- as_modrm(c.s, OP_STORE, R_R13, R_RDI, 0, 0, 104);
- as_modrm(c.s, OP_STORE, R_R14, R_RDI, 0, 0, 112);
- as_modrm(c.s, OP_STORE, R_R15, R_RDI, 0, 0, 120);
-
- // ss
- as_modrm(c.s, OP_LOAD, R_RAX, R_RSI, 0, 0, 152);
- as_opr(c.s, OP_PUSHR, R_RAX);
- // rsp
- as_modrm(c.s, OP_LOAD, R_RAX, R_RSI, 0, 0, 32);
- as_opr(c.s, OP_PUSHR, R_RAX);
- // flags
- as_modrm(c.s, OP_LOAD, R_RAX, R_RSI, 0, 0, 136);
- as_opr(c.s, OP_PUSHR, R_RAX);
- // cs
- as_modrm(c.s, OP_LOAD, R_RAX, R_RSI, 0, 0, 144);
- as_opr(c.s, OP_PUSHR, R_RAX);
- // rip
- as_modrm(c.s, OP_LOAD, R_RAX, R_RSI, 0, 0, 128);
- as_opr(c.s, OP_PUSHR, R_RAX);
-
- // restore temporaries
- as_modrm(c.s, OP_LOAD, R_RAX, R_RSI, 0, 0, 0);
- as_modrm(c.s, OP_LOAD, R_RSI, R_RSI, 0, 0, 40);
-
- // iretq
- as_op(c.s, OP_IRETQ);
- }
-}
-
func open_call_out(c: *compiler, filename: *byte) {
var fd: int;
diff --git a/ir.om b/ir.om
@@ -1453,746 +1453,6 @@ func irshow(out: *file, b: *irblock) {
irreset(b);
}
-func emit_kstart(c: *assembler) {
- var hang: *label;
- var do_iret: *label;
- var do_ret: *label;
- var done: *label;
-
- c.bits32 = 1;
-
- hang = mklabel(c);
- do_iret = mklabel(c);
- do_ret = mklabel(c);
- done = mklabel(c);
-
- // Check for valid multiboot magic
- as_modri(c, OP_MOVI, R_RDX, 0x2badb002);
- as_modrr(c, OP_CMPRM, R_RAX, R_RDX);
- as_jmp(c, OP_JCC + CC_NE, hang);
-
- // Setup an initial stack
- as_modri(c, OP_MOVI, R_RSP, 0x00300000); // FIXME bss
-
- // Align stack to page
- as_modri(c, OP_ANDI, R_RSP, -0x1000);
-
- // pt3 -> 1g
- as_modri(c, OP_SUBI, R_RSP, 0x1000);
- as_modri(c, OP_MOVI, R_RAX, 0x83);
- as_modri(c, OP_MOVI, R_RDX, 0);
- as_modrm(c, OP_STORE, R_RAX, R_RSP, 0, 0, 0);
- as_modrm(c, OP_STORE, R_RDX, R_RSP, 0, 0, 4);
- as_modrm(c, OP_STORE, R_RAX, R_RSP, 0, 0, 510 * 8 + 0);
- as_modrm(c, OP_STORE, R_RDX, R_RSP, 0, 0, 510 * 8 + 4);
-
- // pt4 -> pt3
- as_modrr(c, OP_MOVE, R_RAX, R_RSP);
- as_modri(c, OP_SUBI, R_RSP, 0x1000);
- as_modri(c, OP_ORI, R_RAX, 3);
- as_modri(c, OP_MOVI, R_RDX, 0);
- as_modrm(c, OP_STORE, R_RAX, R_RSP, 0, 0, 0);
- as_modrm(c, OP_STORE, R_RDX, R_RSP, 0, 0, 4);
- as_modrm(c, OP_STORE, R_RAX, R_RSP, 0, 0, 511 * 8 + 0);
- as_modrm(c, OP_STORE, R_RDX, R_RSP, 0, 0, 511 * 8 + 4);
-
- // Load page table pt4
- as_modrr(c, OP_WRCRR, R_CR3, R_RSP);
-
- // Allocate space for the gdt
- as_modri(c, OP_SUBI, R_RSP, 64);
- as_modrr(c, OP_MOVE, R_RBP, R_RSP);
-
- // Null Segment
- as_modri(c, OP_MOVI, R_RAX, 0x00000000);
- as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 8);
- as_modri(c, OP_MOVI, R_RAX, 0x00000000);
- as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 12);
-
- // Kernel code segment
- as_modri(c, OP_MOVI, R_RAX, 0x00000000);
- as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 16);
- as_modri(c, OP_MOVI, R_RAX, 0x00209800);
- as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 20);
-
- // Kernel data segment
- as_modri(c, OP_MOVI, R_RAX, 0x00000000);
- as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 24);
- as_modri(c, OP_MOVI, R_RAX, 0x00009200);
- as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 28);
-
- // Load gdt
- as_modri(c, OP_MOVI, R_RAX, 23);
- as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 0);
- as_modrm(c, OP_LEA, R_RAX, R_RBP, 0, 0, 8);
- as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 2);
- as_modm(c, OP_LGDTM, R_RBP, 0, 0, 0);
-
- // Load null lldt
- as_modri(c, OP_MOVI, R_RAX, 0);
- as_modr(c, OP_LLDTM, R_RAX);
-
- // Load null idt
- as_modm(c, OP_LIDTM, R_RBP, 0, 0, 8);
-
- // Enable pae
- as_modri(c, OP_MOVI, R_RAX, 0xa0);
- as_modrr(c, OP_WRCRR, R_CR4, R_RAX);
-
- // Enable long mode
- as_modri(c, OP_MOVI, R_RCX, (-1 << 32) + (0xc0 << 24) + 0x000080);
- as_op(c, OP_RDMSR);
- as_modri(c, OP_ORI, R_RAX, 0x100);
- as_op(c, OP_WRMSR);
-
- // Enable paging
- as_modrr(c, OP_RDCRR, R_CR0, R_RAX);
- as_modri(c, OP_ORI, R_RAX, (-0x80000000) | 0x0001);
- as_modrr(c, OP_WRCRR, R_CR0, R_RAX);
-
- // flags
- as_modri(c, OP_MOVI, R_RAX, 0);
- as_opr(c, OP_PUSHR, R_RAX);
- // cs
- as_modri(c, OP_MOVI, R_RAX, 8);
- as_opr(c, OP_PUSHR, R_RAX);
- // pointer
- as_jmp(c, OP_CALL, do_iret);
-
- c.bits32 = 0;
-
- // Jump to top half
- as_jmp(c, OP_CALL, do_ret);
-
- // Reload the gdt in the top half
- as_modri(c, OP_ORI, R_RBP, -0x80000000);
- as_modri(c, OP_MOVI, R_RAX, 23);
- as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 0);
- as_modrm(c, OP_LEA, R_RAX, R_RBP, 0, 0, 8);
- as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 2);
- as_modm(c, OP_LGDTM, R_RBP, 0, 0, 0);
-
- // Reload segments
- as_modri(c, OP_MOVI, R_RAX, 16);
- as_modrr(c, OP_WRSR, R_ES, R_RAX);
- as_modrr(c, OP_WRSR, R_DS, R_RAX);
- as_modrr(c, OP_WRSR, R_FS, R_RAX);
- as_modrr(c, OP_WRSR, R_GS, R_RAX);
- as_modrr(c, OP_WRSR, R_SS, R_RAX);
- as_modrr(c, OP_MOVE, R_RSP, R_RSP);
-
- // Reload stack in the top half
- as_modri(c, OP_ORI, R_RSP, -0x80000000);
-
- // Kill the lower mapping
- as_modri(c, OP_MOVI, R_RAX, 0);
- as_modrm(c, OP_LEA, R_RDI, R_RBP, 0, 0, 64);
- as_modrm(c, OP_STORE, R_RAX, R_RDI, 0, 0, 4096);
- as_modrm(c, OP_STORE, R_RAX, R_RDI, 0, 0, 0);
- as_modri(c, OP_ANDI, R_RDI, 0x7fffffff);
- as_modrr(c, OP_WRCRR, R_CR3, R_RDI);
-
- // Setup a call frame for _kstart
- as_jmp(c, OP_JMP, done);
-
- // hlt forever
- fixup_label(c, hang);
- as_op(c, OP_CLI);
- as_op(c, OP_HLT);
- as_jmp(c, OP_JMP, hang);
-
- // iret to long mode
- fixup_label(c, do_iret);
- as_op(c, OP_IRET);
-
- // ret to top half
- fixup_label(c, do_ret);
- as_opr(c, OP_POPR, R_RAX);
- as_modri(c, OP_ORI, R_RAX, -0x80000000);
- as_opr(c, OP_PUSHR, R_RAX);
- as_op(c, OP_RET);
-
- // Setup a call frame for _kstart
- fixup_label(c, done);
- as_modrr(c, OP_XORRM, R_RBP, R_RBP);
- as_modrr(c, OP_MOVE, R_RDI, R_RBX);
- as_opr(c, OP_PUSHR, R_RBP);
-}
-
-func emit_align(c: *assembler, n: int, b: int) {
- var pad: int;
-
- pad = c.at & (n - 1);
-
- if pad == 0 {
- return;
- }
-
- loop {
- if pad == n {
- break;
- }
-
- as_emit(c, b);
-
- pad = pad + 1;
- }
-}
-
-func output_ir(c: *compiler, d: *decl) {
- var ic: *irfunc;
-
- ic = d.func_ir;
-
- ic.c.filename = ic.filename;
- ic.c.lineno = ic.lineno;
- ic.c.colno = ic.colno;
- ic.s.filename = ic.filename;
- ic.s.lineno = ic.lineno;
-
- fixup_label(c.s, d.func_label);
- add_symbol(c.s, d.name, d.func_label);
-
- if strcmp(d.name, "_start") == 0 {
- as_modrm(c.s, OP_LOAD, R_RDI, R_RSP, 0, 0, 0);
- as_modrm(c.s, OP_LEA, R_RSI, R_RSP, 0, 0, 8);
- as_modrm(c.s, OP_LEA, R_RDX, R_RSI, R_RDI, 8, 8);
- as_opr(c.s, OP_PUSHR, R_RBP);
- } else if strcmp(d.name, "_kstart") == 0 {
- emit_kstart(c.s);
- }
-
- //fputc(nil, '\n');
- //fputs(nil, d.name);
- //irshow(nil, ic.blocks[0]);
-
- // Setup the frame
- as_opr(ic.s, OP_PUSHR, R_RBP);
- as_modrr(ic.s, OP_MOVE, R_RBP, R_RSP);
-
- // Allocate local variables
- output_irvars(ic);
-
- // Output all blocks
- output_irblock(ic, ic.blocks[0]);
-
- // Clear the marks
- irreset(ic.blocks[0]);
-}
-
-func output_irvars(ic: *irfunc) {
- var offset: int;
- var size: int;
- var i: int;
- var v: *irvar;
-
- // Allocate local variables
- offset = 0;
- i = 0;
- loop {
- if i == ic.vars_len {
- break;
- }
-
- v = ic.vars[i];
-
- if v.dead {
- i = i + 1;
- continue;
- }
-
- if v.t && v.t.kind != TY_VOID {
- size = type_sizeof(ic.c, v.t);
- } else {
- size = sizeof(i);
- }
-
- size = (size + 7) & -8;
-
- offset = offset + size;
-
- v.offset = -offset;
-
- i = i + 1;
- }
-
- // Zero initialize local variables
- if offset != 0 {
- as_modri(ic.s, OP_SUBI, R_RSP, offset);
-
- as_modrr(ic.s, OP_XORRM, R_RAX, R_RAX);
-
- i = 0;
- loop {
- if i == offset {
- break;
- }
-
- i = i + 8;
-
- as_modrm(ic.s, OP_STORE, R_RAX, R_RBP, 0, 0, -i);
- }
- }
-
- // Save parameters
- i = 0;
- loop {
- if i == ic.arg_count {
- break;
- }
-
- v = ic.vars[i];
-
- if i == 0 {
- as_modrm(ic.s, OP_STORE, R_RDI, R_RBP, 0, 0, v.offset);
- } else if i == 1 {
- as_modrm(ic.s, OP_STORE, R_RSI, R_RBP, 0, 0, v.offset);
- } else if i == 2 {
- as_modrm(ic.s, OP_STORE, R_RDX, R_RBP, 0, 0, v.offset);
- } else if i == 3 {
- as_modrm(ic.s, OP_STORE, R_RCX, R_RBP, 0, 0, v.offset);
- } else if i == 4 {
- as_modrm(ic.s, OP_STORE, R_R8, R_RBP, 0, 0, v.offset);
- } else if i == 5 {
- as_modrm(ic.s, OP_STORE, R_R9, R_RBP, 0, 0, v.offset);
- } else {
- // Stack argument
- as_modrm(ic.s, OP_LOAD, R_RAX, R_RBP, 0, 0, (i - 6 + 2) * sizeof(i));
- as_modrm(ic.s, OP_STORE, R_RAX, R_RBP, 0, 0, v.offset);
- }
-
- i = i + 1;
- }
-}
-
-func output_irblock(ic: *irfunc, b: *irblock) {
- var op: *irop;
- var i: int;
-
- b.mark = 1;
-
- if !b.done {
- cdie(ic.c, "no return in function");
- }
-
- fixup_label(ic.s, b.label);
-
- i = 0;
- loop {
- if i == b.ops_len {
- break;
- }
-
- op = b.ops[i];
-
- output_irstmt(ic, b, op);
-
- i = i + 1;
- }
-}
-
-func output_irstmt(ic: *irfunc, b: *irblock, o: *irop) {
- var kind: int;
-
- ic.c.filename = o.filename;
- ic.c.lineno = o.lineno;
- ic.c.colno = o.colno;
- ic.s.filename = o.filename;
- ic.s.lineno = o.lineno;
-
- kind = o.kind;
- if kind == IOP_STORE {
- // Evaluate the address
- if o.a.kind == IOP_LOAD {
- output_irexpr(ic, b, o.a.a);
- } else if o.a.kind == IOP_VAR {
- as_modrm(ic.s, OP_LEA, R_RAX, R_RBP, 0, 0, ic.vars[o.a.n].offset);
- } else {
- die("invalid store");
- }
-
- as_opr(ic.s, OP_PUSHR, R_RAX);
-
- // Evaluate the value
- output_irexpr(ic, b, o.b);
-
- as_opr(ic.s, OP_POPR, R_RDI);
-
- // Execute the store
- if o.t.kind == TY_BYTE {
- as_modrm(ic.s, OP_STOREB, R_RAX, R_RDI, 0, 0, 0);
- } else if type_isprim(o.t) {
- as_modrm(ic.s, OP_STORE, R_RAX, R_RDI, 0, 0, 0);
- } else {
- cdie(ic.c, "invalid store");
- }
- } else if kind == IOP_RETVAL {
- // Do nothing
- } else if kind == IOP_ARG {
- // Do nothing
- } else if kind == IOP_CALL {
- // Allocate some space for the arguments
- if o.n > 6 {
- as_modri(ic.s, OP_SUBI, R_RSP, (o.n - 6) * sizeof(kind));
- }
-
- // Setup arguments
- output_irargs(ic, b, o);
-
- // Call the function
- if o.a.kind == IOP_FUNC {
- output_ircall(ic, b, o.a);
- } else {
- output_irexpr(ic, b, o.a);
- as_modr(ic.s, OP_ICALLM, R_RAX);
- }
-
- // Release space reserved for the arguments
- if o.n > 6 {
- as_modri(ic.s, OP_ADDI, R_RSP, (o.n - 6) * sizeof(kind));
- }
-
- // Save the return value
- output_irretval(ic, b, o);
-
- if b.out.mark {
- as_jmp(ic.s, OP_JMP, b.out.label);
- } else {
- output_irblock(ic, b.out);
- }
- return;
- } else if kind == IOP_JUMP {
- if b.out.mark {
- // Jump to an already output block
- as_jmp(ic.s, OP_JMP, b.out.label);
- } else {
- // Output a new block
- output_irblock(ic, b.out);
- }
- return;
- } else if kind == IOP_BRANCH {
- // Evaluate the condition and branch if zero
- output_irexpr(ic, b, o.a);
- as_modrr(ic.s, OP_TESTRM, R_RAX, R_RAX);
- as_jmp(ic.s, OP_JCC + CC_E, b.alt.label);
-
- // Then jump to the output
- if b.out.mark {
- as_jmp(ic.s, OP_JCC + CC_NE, b.out.label);
- } else {
- output_irblock(ic, b.out);
- }
-
- // And if we haven't already, output the alt branch
- if !b.alt.mark {
- output_irblock(ic, b.alt);
- }
-
- return;
- } else if kind == IOP_RETURN {
- // Evaluate the return expression and return
- if o.a {
- output_irexpr(ic, b, o.a);
- }
-
- as_modrr(ic.s, OP_MOVE, R_RSP, R_RBP);
- as_opr(ic.s, OP_POPR, R_RBP);
- as_op(ic.s, OP_RET);
- } else {
- // Evaluate and discard the result
- output_irexpr(ic, b, o);
- }
-}
-
-func output_irargs(ic: *irfunc, b: *irblock, o: *irop) {
- var i: int;
- var op: *irop;
-
- i = 0;
- loop {
- if i == b.ops_len {
- return;
- }
-
- op = b.ops[i];
- if op.kind == IOP_ARG {
- // Compute the value
- output_irexpr(ic, b, op.a);
-
- if op.n == 0 {
- as_modrr(ic.s, OP_MOVE, R_RDI, R_RAX);
- } else if op.n == 1 {
- as_modrr(ic.s, OP_MOVE, R_RSI, R_RAX);
- } else if op.n == 2 {
- as_modrr(ic.s, OP_MOVE, R_RDX, R_RAX);
- } else if op.n == 3 {
- as_modrr(ic.s, OP_MOVE, R_RCX, R_RAX);
- } else if op.n == 4 {
- as_modrr(ic.s, OP_MOVE, R_R8, R_RAX);
- } else if op.n == 5 {
- as_modrr(ic.s, OP_MOVE, R_R9, R_RAX);
- } else {
- // Stack argument
- as_modrm(ic.s, OP_STORE, R_RAX, R_RSP, 0, 0, (op.n - 6) * sizeof(i));
- }
- }
-
- i = i + 1;
- }
-}
-
-func output_irretval(ic: *irfunc, b: *irblock, o: *irop) {
- var i: int;
- var op: *irop;
-
- // Find the retval place
- op = nil;
- i = 0;
- loop {
- if i == b.ops_len {
- return;
- }
-
- op = b.ops[i];
- if op.kind == IOP_RETVAL {
- break;
- }
-
- i = i + 1;
- }
-
- // Do nothing if there was no return value
- if op.t.kind == TY_VOID {
- return;
- }
-
- // Save the value
- as_modrr(ic.s, OP_MOVE, R_RDI, R_RAX);
-
- // Compute the address
- if op.a.kind == IOP_LOAD {
- output_irexpr(ic, b, op.a.a);
- } else if op.a.kind == IOP_VAR {
- as_modrm(ic.s, OP_LEA, R_RAX, R_RBP, 0, 0, ic.vars[op.a.n].offset);
- } else {
- die("invalid store");
- }
-
- // Execute the store
- if op.t.kind == TY_BYTE {
- as_modrm(ic.s, OP_STOREB, R_RDI, R_RAX, 0, 0, 0);
- } else if type_isprim(op.t) {
- as_modrm(ic.s, OP_STORE, R_RDI, R_RAX, 0, 0, 0);
- } else {
- cdie(ic.c, "invalid store");
- }
-}
-
-func output_irstr(ic: *irfunc, b: *irblock, o: *irop) {
- var s: *label;
-
- s = as_blob(ic.s, o.s, o.slen + 1);
-
- reserve(ic.s, 16);
- as_modrm(ic.s, OP_LEA, R_RAX, R_RIP, 0, 0, 128);
- addfixup(ic.s, s);
-}
-
-func output_irfuncptr(ic: *irfunc, b: *irblock, o: *irop) {
- var d: *decl;
-
- d = find(ic.c, o.s, nil, 0);
-
- if !d || !d.func_defined {
- cdie(ic.c, "no such function");
- }
-
- reserve(ic.s, 16);
- as_modrm(ic.s, OP_LEA, R_RAX, R_RIP, 0, 0, 128);
- addfixup(ic.s, d.func_label);
-}
-
-func output_ircall(ic: *irfunc, b: *irblock, o: *irop) {
- var d: *decl;
-
- d = find(ic.c, o.s, nil, 0);
-
- if !d || !d.func_defined {
- cdie(ic.c, "no such function");
- }
-
- as_jmp(ic.s, OP_CALL, d.func_label);
-}
-
-func output_irexpr(ic: *irfunc, b: *irblock, o: *irop) {
- var kind: int;
-
- if !o {
- cdie(ic.c, "no expr");
- }
-
- kind = o.kind;
- if kind == IOP_VAR {
- as_modrm(ic.s, OP_LOAD, R_RAX, R_RBP, 0, 0, ic.vars[o.n].offset);
- } else if kind == IOP_VARREF {
- as_modrm(ic.s, OP_LEA, R_RAX, R_RBP, 0, 0, ic.vars[o.n].offset);
- } else if kind == IOP_FUNC {
- output_irfuncptr(ic, b, o);
- } else if kind == IOP_CONST {
- if o.n == 0 {
- as_modrr(ic.s, OP_XORRM, R_RAX, R_RAX);
- } else if o.n < (-1 >> 33) && o.n >= (-1 << 31) {
- as_modri(ic.s, OP_MOVI, R_RAX, o.n);
- } else {
- as_opri64(ic.s, OP_MOVABS, R_RAX, o.n);
- }
- } else if kind == IOP_STR {
- output_irstr(ic, b, o);
- } else if kind == IOP_LOAD {
- output_irexpr(ic, b, o.a);
- if o.t.kind == TY_BYTE {
- as_modrr(ic.s, OP_MOVE, R_RSI, R_RAX);
- as_modrr(ic.s, OP_XORRM, R_RAX, R_RAX);
- as_modrm(ic.s, OP_LOADB, R_RAX, R_RSI, 0, 0, 0);
- } else if type_isprim(o.t) {
- as_modrm(ic.s, OP_LOAD, R_RAX, R_RAX, 0, 0, 0);
- } else {
- cdie(ic.c, "invalid load");
- }
- } else if kind == IOP_NEG {
- output_irexpr(ic, b, o.a);
- as_modr(ic.s, OP_NEGM, R_RAX);
- } else if kind == IOP_NOT {
- output_irexpr(ic, b, o.a);
- as_modr(ic.s, OP_NOTM, R_RAX);
- } else if kind == IOP_ADD {
- output_irexpr(ic, b, o.b);
- as_opr(ic.s, OP_PUSHR, R_RAX);
- output_irexpr(ic, b, o.a);
- as_opr(ic.s, OP_POPR, R_RCX);
- as_modrr(ic.s, OP_ADDRM, R_RAX, R_RCX);
- } else if kind == IOP_AND {
- output_irexpr(ic, b, o.b);
- as_opr(ic.s, OP_PUSHR, R_RAX);
- output_irexpr(ic, b, o.a);
- as_opr(ic.s, OP_POPR, R_RCX);
- as_modrr(ic.s, OP_ANDRM, R_RAX, R_RCX);
- } else if kind == IOP_OR {
- output_irexpr(ic, b, o.b);
- as_opr(ic.s, OP_PUSHR, R_RAX);
- output_irexpr(ic, b, o.a);
- as_opr(ic.s, OP_POPR, R_RCX);
- as_modrr(ic.s, OP_ORRM, R_RAX, R_RCX);
- } else if kind == IOP_XOR {
- output_irexpr(ic, b, o.b);
- as_opr(ic.s, OP_PUSHR, R_RAX);
- output_irexpr(ic, b, o.a);
- as_opr(ic.s, OP_POPR, R_RCX);
- as_modrr(ic.s, OP_XORRM, R_RAX, R_RCX);
- } else if kind == IOP_DIV {
- output_irexpr(ic, b, o.b);
- as_opr(ic.s, OP_PUSHR, R_RAX);
- output_irexpr(ic, b, o.a);
- as_opr(ic.s, OP_POPR, R_RCX);
- as_modrr(ic.s, OP_XORRM, R_RDX, R_RDX);
- as_modrr(ic.s, OP_TESTRM, R_RAX, R_RAX);
- as_modrr(ic.s, OP_SETCC + CC_S, 0, R_RDX);
- as_modr(ic.s, OP_NEGM, R_RDX);
- as_modr(ic.s, OP_IDIVM, R_RCX);
- } else if kind == IOP_MOD {
- output_irexpr(ic, b, o.b);
- as_opr(ic.s, OP_PUSHR, R_RAX);
- output_irexpr(ic, b, o.a);
- as_opr(ic.s, OP_POPR, R_RCX);
- as_modrr(ic.s, OP_XORRM, R_RDX, R_RDX);
- as_modrr(ic.s, OP_TESTRM, R_RAX, R_RAX);
- as_modrr(ic.s, OP_SETCC + CC_S, 0, R_RDX);
- as_modr(ic.s, OP_NEGM, R_RDX);
- as_modr(ic.s, OP_IDIVM, R_RCX);
- as_modrr(ic.s, OP_MOVE, R_RAX, R_RDX);
- } else if kind == IOP_LSH {
- output_irexpr(ic, b, o.b);
- as_opr(ic.s, OP_PUSHR, R_RAX);
- output_irexpr(ic, b, o.a);
- as_opr(ic.s, OP_POPR, R_RCX);
- as_modr(ic.s, OP_SHLM, R_RAX);
- } else if kind == IOP_RSH {
- output_irexpr(ic, b, o.b);
- as_opr(ic.s, OP_PUSHR, R_RAX);
- output_irexpr(ic, b, o.a);
- as_opr(ic.s, OP_POPR, R_RCX);
- as_modr(ic.s, OP_SHRM, R_RAX);
- } else if kind == IOP_MUL {
- output_irexpr(ic, b, o.b);
- as_opr(ic.s, OP_PUSHR, R_RAX);
- output_irexpr(ic, b, o.a);
- as_opr(ic.s, OP_POPR, R_RCX);
- as_modr(ic.s, OP_IMULM, R_RCX);
- } else if kind == IOP_SUB {
- output_irexpr(ic, b, o.b);
- as_opr(ic.s, OP_PUSHR, R_RAX);
- output_irexpr(ic, b, o.a);
- as_opr(ic.s, OP_POPR, R_RCX);
- as_modrr(ic.s, OP_SUBRM, R_RAX, R_RCX);
- } else if kind == IOP_EQ {
- output_irexpr(ic, b, o.b);
- as_opr(ic.s, OP_PUSHR, R_RAX);
- output_irexpr(ic, b, o.a);
- as_opr(ic.s, OP_POPR, R_RCX);
- as_modrr(ic.s, OP_MOVE, R_RDX, R_RAX);
- as_modrr(ic.s, OP_XORRM, R_RAX, R_RAX);
- as_modrr(ic.s, OP_CMPRM, R_RDX, R_RCX);
- as_modrr(ic.s, OP_SETCC + CC_E, 0, R_RAX);
- } else if kind == IOP_NE {
- output_irexpr(ic, b, o.b);
- as_opr(ic.s, OP_PUSHR, R_RAX);
- output_irexpr(ic, b, o.a);
- as_opr(ic.s, OP_POPR, R_RCX);
- as_modrr(ic.s, OP_MOVE, R_RDX, R_RAX);
- as_modrr(ic.s, OP_XORRM, R_RAX, R_RAX);
- as_modrr(ic.s, OP_CMPRM, R_RDX, R_RCX);
- as_modrr(ic.s, OP_SETCC + CC_NE, 0, R_RAX);
- } else if kind == IOP_GT {
- output_irexpr(ic, b, o.b);
- as_opr(ic.s, OP_PUSHR, R_RAX);
- output_irexpr(ic, b, o.a);
- as_opr(ic.s, OP_POPR, R_RCX);
- as_modrr(ic.s, OP_MOVE, R_RDX, R_RAX);
- as_modrr(ic.s, OP_XORRM, R_RAX, R_RAX);
- as_modrr(ic.s, OP_CMPRM, R_RDX, R_RCX);
- as_modrr(ic.s, OP_SETCC + CC_G, 0, R_RAX);
- } else if kind == IOP_GE {
- output_irexpr(ic, b, o.b);
- as_opr(ic.s, OP_PUSHR, R_RAX);
- output_irexpr(ic, b, o.a);
- as_opr(ic.s, OP_POPR, R_RCX);
- as_modrr(ic.s, OP_MOVE, R_RDX, R_RAX);
- as_modrr(ic.s, OP_XORRM, R_RAX, R_RAX);
- as_modrr(ic.s, OP_CMPRM, R_RDX, R_RCX);
- as_modrr(ic.s, OP_SETCC + CC_GE, 0, R_RAX);
- } else if kind == IOP_LT {
- output_irexpr(ic, b, o.b);
- as_opr(ic.s, OP_PUSHR, R_RAX);
- output_irexpr(ic, b, o.a);
- as_opr(ic.s, OP_POPR, R_RCX);
- as_modrr(ic.s, OP_MOVE, R_RDX, R_RAX);
- as_modrr(ic.s, OP_XORRM, R_RAX, R_RAX);
- as_modrr(ic.s, OP_CMPRM, R_RDX, R_RCX);
- as_modrr(ic.s, OP_SETCC + CC_L, 0, R_RAX);
- } else if kind == IOP_LE {
- output_irexpr(ic, b, o.b);
- as_opr(ic.s, OP_PUSHR, R_RAX);
- output_irexpr(ic, b, o.a);
- as_opr(ic.s, OP_POPR, R_RCX);
- as_modrr(ic.s, OP_MOVE, R_RDX, R_RAX);
- as_modrr(ic.s, OP_XORRM, R_RAX, R_RAX);
- as_modrr(ic.s, OP_CMPRM, R_RDX, R_RCX);
- as_modrr(ic.s, OP_SETCC + CC_LE, 0, R_RAX);
- } else {
- cdie(ic.c, "invalid op");
- }
-}
-
func iruseop(ic: *irfunc, ib: *irblock, op: *irop) {
var kind: int;
diff --git a/ircout.om b/ircout.om
@@ -147,7 +147,7 @@ func ircdefine(c: *compiler, d: *decl) {
fputs(c.cout, " = 0");
} else {
fputs(c.cout, "[");
- fputd(c.cout, (size + 7) / 8);
+ fputd(c.cout, (size + sizeof(i) + 1) / sizeof(i));
fputs(c.cout, "] = {0}");
}
diff --git a/lexer.om b/lexer.om
@@ -1199,7 +1199,7 @@ func lexer_compile_get_tag_table(c: *compiler, cg: *dfa_codegen) {
if cg.tag[i] {
a = mkirop(ic, IOP_VAR, nil, nil);
a.n = v.n;
- b = mkirconst(ic, 8 * i);
+ b = mkirconst(ic, sizeof(i) * i);
a = mkirop(ic, IOP_ADD, a, b);
a = mkirop(ic, IOP_LOAD, a, nil);
b = mkirfuncref(ic, cg.tag[i]);
diff --git a/syscall.om b/syscall.om
@@ -1,165 +1,30 @@
-func syscall(n: int, a1: int, a2: int, a3: int, a4: int, a5: int, a6: int): int;
-
-enum {
- O_RDONLY = 0,
- O_WRONLY = 1,
- O_RDWR = 2,
- O_CREAT = 64,
- O_TRUNC = 512,
- O_APPEND = 1024,
- O_DIRECTORY = 0x1000,
-
- EINTR = 4,
- EPIPE = 32,
-
- AF_INET = 2,
- SOCK_STREAM = 1,
-
- POLLIN = 0x01,
- POLLPRI = 0x02,
- POLLOUT = 0x04,
- POLLERR = 0x08,
- POLLHUP = 0x10,
- POLLNVAL = 0x20,
-
- PROT_NONE = 0,
- PROT_READ = 1,
- PROT_WRITE = 2,
- PROT_EXEC = 4,
-
- MAP_PRIVATE = 2,
- MAP_ANON = 32,
-
- WNOHANG = 1,
-
- SIG_DFL = 0,
- SIG_IGN = 1,
-
- SIGINT = 2,
- SIGPIPE = 13,
- SIGALRM = 14,
- SIGCHLD = 17,
- SIGWINCH = 28,
-}
-
func _start(argc: int, argv: **byte, envp: **byte) {
main(argc, argv, envp);
exit(0);
}
-func read(fd: int, buf: *byte, n: int): int {
- return syscall(0, fd, buf as int, n, 0, 0, 0);
-}
-
-func write(fd: int, buf: *byte, n: int): int {
- return syscall(1, fd, buf as int, n, 0, 0, 0);
-}
-
-func open(name: *byte, flags: int, mode: int): int {
- return syscall(2, name as int, flags, mode, 0, 0, 0);
-}
-
-func close(fd: int): int {
- return syscall(3, fd, 0, 0, 0, 0, 0);
-}
-
-func fstat(fd: int, buf: *byte): int {
- return syscall(5, fd, buf as int, 0, 0, 0, 0);
-}
-
-func poll(pfd: *int, nfd: int, timeout: int): int {
- return syscall(7, pfd as int, nfd, timeout, 0, 0, 0);
-}
-
-func lseek(fd: int, off: int, whence: int): int {
- return syscall(8, fd, off, whence, 0, 0, 0);
-}
-
-func mmap(addr: int, len: int, prot: int, flags: int, fd: int, off: int): int {
- return syscall(9, addr, len, prot, flags, fd, off);
-}
-
-func munmap(addr: int, len: int): int {
- return syscall(11, addr, len, 0, 0, 0, 0);
-}
-
-struct sigaction {
- handler: int;
- flags: int;
- restorer: int;
- mask: int;
-}
-
-func sigaction(sig: int, act: *sigaction, oact: *sigaction): int {
- return syscall(13, sig, act as int, oact as int, 8, 0, 0);
-}
-
-func pipe(rfd: *int, wfd: *int): int {
- var buf: int;
- var ret: int;
- ret = syscall(22, (&buf) as int, 0, 0, 0, 0, 0);
- if ret == 0 {
- *rfd = buf & (-1 >> 32);
- *wfd = buf >> 32;
- }
- return ret;
-}
-
-func dup2(old: int, new: int): int {
- return syscall(33, old, new, 0, 0, 0, 0);
-}
-
-func socket(pf: int, ty: int, pc: int): int {
- return syscall(41, pf, ty, pc, 0, 0, 0);
-}
-
-func accept(fd: int, addr: *byte, len: *int): int {
- return syscall(43, fd, addr as int, len as int, 0, 0, 0);
-}
-
-func bind(fd: int, addr: *byte, len: int): int {
- return syscall(49, fd, addr as int, len as int, 0, 0, 0);
-}
-
-func listen(fd: int, backlog: int): int {
- return syscall(50, fd, backlog, 0, 0, 0, 0);
-}
-
-func fork(): int {
- return syscall(57, 0, 0, 0, 0, 0, 0);
-}
-
-func exec(cmd: *byte, argv: **byte, envp: **byte): int {
- return syscall(59, cmd as int, argv as int, envp as int, 0, 0, 0);
-}
-
-func exit(n: int) {
- syscall(60, n, 0, 0, 0, 0, 0);
-}
-
-func wait(pid: int, status: *int, flags: int): int {
- var s: int;
- var ret: int;
- s = 0;
- ret = syscall(61, pid, s as int, flags, 0, 0, 0);
- if status {
- *status = s & (-1 >> 32);
- }
- return ret;
-}
-
-func rename(oldname: *byte, newname: *byte): int {
- return syscall(82, oldname as int, newname as int, 0, 0, 0, 0);
-}
-
-func mkdir(name: *byte): int {
- return syscall(83, name as int, 0, 0, 0, 0, 0);
-}
-
-func unlink(name: *byte): int {
- return syscall(87, name as int, 0, 0, 0, 0, 0);
-}
-
-func getdirents(fd: int, buf: *byte, len: int): int {
- return syscall(217, fd, buf as int, len, 0, 0, 0);
-}
+func syscall(n: int, a1: int, a2: int, a3: int, a4: int, a5: int, a6: int): int;
+func read(fd: int, buf: *byte, n: int): int;
+func write(fd: int, buf: *byte, n: int): int;
+func open(name: *byte, flags: int, mode: int): int;
+func close(fd: int): int;
+func fstat(fd: int, buf: *byte): int;
+func poll(pfd: *int, nfd: int, timeout: int): int;
+func lseek(fd: int, off: int, whence: int): int;
+func mmap(addr: int, len: int, prot: int, flags: int, fd: int, off: int): int;
+func munmap(addr: int, len: int): int;
+func sigaction(sig: int, act: *sigaction, oact: *sigaction): int;
+func pipe(rfd: *int, wfd: *int): int;
+func dup2(old: int, new: int): int;
+func socket(pf: int, ty: int, pc: int): int;
+func accept(fd: int, addr: *byte, len: *int): int;
+func bind(fd: int, addr: *byte, len: int): int;
+func listen(fd: int, backlog: int): int;
+func fork(): int;
+func exec(cmd: *byte, argv: **byte, envp: **byte): int;
+func exit(n: int);
+func wait(pid: int, status: *int, flags: int): int;
+func rename(oldname: *byte, newname: *byte): int;
+func mkdir(name: *byte): int;
+func unlink(name: *byte): int;
+func getdirents(fd: int, buf: *byte, len: int): int;
diff --git a/syscall.x86.om b/syscall.x86.om
@@ -0,0 +1,158 @@
+enum {
+ O_RDONLY = 0,
+ O_WRONLY = 1,
+ O_RDWR = 2,
+ O_CREAT = 64,
+ O_TRUNC = 512,
+ O_APPEND = 1024,
+ O_DIRECTORY = 0x1000,
+
+ EINTR = 4,
+ EPIPE = 32,
+
+ AF_INET = 2,
+ SOCK_STREAM = 1,
+
+ POLLIN = 0x01,
+ POLLPRI = 0x02,
+ POLLOUT = 0x04,
+ POLLERR = 0x08,
+ POLLHUP = 0x10,
+ POLLNVAL = 0x20,
+
+ PROT_NONE = 0,
+ PROT_READ = 1,
+ PROT_WRITE = 2,
+ PROT_EXEC = 4,
+
+ MAP_PRIVATE = 2,
+ MAP_ANON = 32,
+
+ WNOHANG = 1,
+
+ SIG_DFL = 0,
+ SIG_IGN = 1,
+
+ SIGINT = 2,
+ SIGPIPE = 13,
+ SIGALRM = 14,
+ SIGCHLD = 17,
+ SIGWINCH = 28,
+}
+
+func read(fd: int, buf: *byte, n: int): int {
+ return syscall(0, fd, buf as int, n, 0, 0, 0);
+}
+
+func write(fd: int, buf: *byte, n: int): int {
+ return syscall(1, fd, buf as int, n, 0, 0, 0);
+}
+
+func open(name: *byte, flags: int, mode: int): int {
+ return syscall(2, name as int, flags, mode, 0, 0, 0);
+}
+
+func close(fd: int): int {
+ return syscall(3, fd, 0, 0, 0, 0, 0);
+}
+
+func fstat(fd: int, buf: *byte): int {
+ return syscall(5, fd, buf as int, 0, 0, 0, 0);
+}
+
+func poll(pfd: *int, nfd: int, timeout: int): int {
+ return syscall(7, pfd as int, nfd, timeout, 0, 0, 0);
+}
+
+func lseek(fd: int, off: int, whence: int): int {
+ return syscall(8, fd, off, whence, 0, 0, 0);
+}
+
+func mmap(addr: int, len: int, prot: int, flags: int, fd: int, off: int): int {
+ return syscall(9, addr, len, prot, flags, fd, off);
+}
+
+func munmap(addr: int, len: int): int {
+ return syscall(11, addr, len, 0, 0, 0, 0);
+}
+
+struct sigaction {
+ handler: int;
+ flags: int;
+ restorer: int;
+ mask: int;
+}
+
+func sigaction(sig: int, act: *sigaction, oact: *sigaction): int {
+ return syscall(13, sig, act as int, oact as int, 8, 0, 0);
+}
+
+func pipe(rfd: *int, wfd: *int): int {
+ var buf: int;
+ var ret: int;
+ ret = syscall(22, (&buf) as int, 0, 0, 0, 0, 0);
+ if ret == 0 {
+ *rfd = buf & (-1 >> 32);
+ *wfd = buf >> 32;
+ }
+ return ret;
+}
+
+func dup2(old: int, new: int): int {
+ return syscall(33, old, new, 0, 0, 0, 0);
+}
+
+func socket(pf: int, ty: int, pc: int): int {
+ return syscall(41, pf, ty, pc, 0, 0, 0);
+}
+
+func accept(fd: int, addr: *byte, len: *int): int {
+ return syscall(43, fd, addr as int, len as int, 0, 0, 0);
+}
+
+func bind(fd: int, addr: *byte, len: int): int {
+ return syscall(49, fd, addr as int, len as int, 0, 0, 0);
+}
+
+func listen(fd: int, backlog: int): int {
+ return syscall(50, fd, backlog, 0, 0, 0, 0);
+}
+
+func fork(): int {
+ return syscall(57, 0, 0, 0, 0, 0, 0);
+}
+
+func exec(cmd: *byte, argv: **byte, envp: **byte): int {
+ return syscall(59, cmd as int, argv as int, envp as int, 0, 0, 0);
+}
+
+func exit(n: int) {
+ syscall(60, n, 0, 0, 0, 0, 0);
+}
+
+func wait(pid: int, status: *int, flags: int): int {
+ var s: int;
+ var ret: int;
+ s = 0;
+ ret = syscall(61, pid, s as int, flags, 0, 0, 0);
+ if status {
+ *status = s & (-1 >> 32);
+ }
+ return ret;
+}
+
+func rename(oldname: *byte, newname: *byte): int {
+ return syscall(82, oldname as int, newname as int, 0, 0, 0, 0);
+}
+
+func mkdir(name: *byte): int {
+ return syscall(83, name as int, 0, 0, 0, 0, 0);
+}
+
+func unlink(name: *byte): int {
+ return syscall(87, name as int, 0, 0, 0, 0, 0);
+}
+
+func getdirents(fd: int, buf: *byte, len: int): int {
+ return syscall(217, fd, buf as int, len, 0, 0, 0);
+}
diff --git a/x86.om b/x86.om
@@ -0,0 +1,1873 @@
+enum {
+ R_RAX,
+ R_RCX,
+ R_RDX,
+ R_RBX,
+ R_RSP,
+ R_RBP,
+ R_RSI,
+ R_RDI,
+ R_R8,
+ R_R9,
+ R_R10,
+ R_R11,
+ R_R12,
+ R_R13,
+ R_R14,
+ R_R15,
+ R_RIP,
+
+ R_ES = 0,
+ R_CS = 1,
+ R_SS = 2,
+ R_DS = 3,
+ R_FS = 4,
+ R_GS = 5,
+
+ R_CR0 = 0,
+ R_CR1 = 1,
+ R_CR2 = 2,
+ R_CR3 = 3,
+ R_CR4 = 4,
+ R_CR5 = 5,
+ R_CR6 = 6,
+ R_CR7 = 7,
+}
+
+enum {
+ CC_O = 0x00,
+ CC_NO = 0x01,
+ CC_B = 0x02,
+ CC_AE = 0x03,
+ CC_E = 0x04,
+ CC_NE = 0x05,
+ CC_BE = 0x06,
+ CC_A = 0x07,
+ CC_S = 0x08,
+ CC_NS = 0x09,
+ CC_P = 0x0a,
+ CC_NP = 0x0b,
+ CC_L = 0x0c,
+ CC_GE = 0x0d,
+ CC_LE = 0x0e,
+ CC_G = 0x0f,
+}
+
+enum {
+ OP_GS = 0x65,
+ OP_OS = 0x66,
+
+ OP_CLD = 0xfc,
+ OP_CLI = 0xfa,
+ OP_STI = 0xfb,
+ OP_CPUID = 0x0fa2,
+ OP_IN = 0xec,
+ OP_IND = 0xed,
+ OP_OUT = 0xee,
+ OP_OUTD = 0xef,
+ OP_HLT = 0xf4,
+ OP_NOP = 0x90,
+ OP_WBINVD = 0x0f09,
+ OP_UD2 = 0x0f0b,
+
+ OP_INVLPGM = 0x070f01,
+ OP_LLDM = 0x020f00,
+ OP_LTRM = 0x030f00,
+
+ OP_WRSR = 0x8e,
+ OP_RDSR = 0x8c,
+
+ OP_RET = 0xc3,
+ OP_CALL = 0xe8,
+ OP_JMP = 0xe9,
+ OP_JCC = 0x0f80,
+ OP_SETCC = 0x0f90,
+
+ OP_PUSHF = 0x9c,
+ OP_POPF = 0x9d,
+ OP_IRET = 0xcf,
+ OP_IRETQ = 0x48cf,
+ OP_WRMSR = 0x0f30,
+ OP_RDMSR = 0x0f32,
+ OP_RDCRR = 0x0f20,
+ OP_WRCRR = 0x0f22,
+ OP_LGDTM = 0x020f01,
+ OP_LIDTM = 0x030f01,
+ OP_LLDTM = 0x020f00,
+
+ OP_ICALLM = 0x0200ff,
+
+ OP_NOTM = 0x0200f7,
+ OP_NEGM = 0x0300f7,
+
+ OP_ANDRM = 0x23,
+ OP_ORRM = 0x0b,
+ OP_CMPRM = 0x3b,
+ OP_TESTRM = 0x85,
+ OP_SUBRM = 0x2b,
+ OP_ADDRM = 0x03,
+ OP_ADCRM = 0x13,
+ OP_XORRM = 0x33,
+
+ OP_ANDI = 0x040081,
+ OP_ADDI = 0x000081,
+ OP_SUBI = 0x050081,
+ OP_ORI = 0x010081,
+ OP_CMPI = 0x070081,
+
+ OP_RDRAND = 0x060fc7,
+
+ OP_IMULM = 0x0400f7,
+ OP_IDIVM = 0x0700f7,
+ OP_SHLM = 0x0400d3,
+ OP_SHRM = 0x0500d3,
+
+ OP_PUSHR = 0x50,
+
+ OP_POPR = 0x58,
+
+ OP_MOVI = 0x00c7,
+ OP_MOVABS = 0xb8,
+
+ OP_SYSCALL = 0x0f05,
+ OP_SYSRET = 0x0f07,
+
+ OP_LEA = 0x8d,
+ OP_LOAD = 0x8b,
+ OP_LOADB = 0x8a,
+ OP_LOAD16 = 0x668a,
+ OP_STOREB = 0x88,
+ OP_STORE = 0x89,
+ OP_STORE16 = 0x6689,
+ OP_MOVE = 0x8b,
+}
+
+func as_rex(a: *assembler, op: int, r: int, i: int, b: int) {
+ var w: int;
+ if a.bits32 {
+ return;
+ }
+ w = 0x08;
+ if op == OP_LOADB || op == OP_STOREB {
+ w = 0;
+ if r < 8 && i < 8 && b < 8 {
+ return;
+ }
+ }
+ as_emit(a, 0x40 + w + ((r >> 1) & 4) + ((i >> 2) & 2) + ((b >> 3) & 1));
+}
+
+func as_op(a: *assembler, op: int) {
+ if op > 0xff {
+ as_emit(a, op >> 8);
+ as_emit(a, op);
+ } else {
+ as_emit(a, op);
+ }
+}
+
+// op + r
+func as_opr(a: *assembler, op: int, r: int) {
+ if r < 0 || r > 15 {
+ die("invalid reg");
+ }
+ if (op != OP_PUSHR && op != OP_POPR) || r > 7 {
+ as_rex(a, op, r, 0, 0);
+ }
+ as_op(a, op + (r & 7));
+}
+
+func as_opri64(a: *assembler, op: int, r: int, x: int) {
+ if op != OP_MOVABS {
+ die("only movabs");
+ }
+ as_opr(a, op, r);
+ as_emit(a, x);
+ as_emit(a, x >> 8);
+ as_emit(a, x >> 16);
+ as_emit(a, x >> 24);
+ as_emit(a, x >> 32);
+ as_emit(a, x >> 40);
+ as_emit(a, x >> 48);
+ as_emit(a, x >> 56);
+}
+
+// modrm
+func as_modrr(a: *assembler, op: int, r: int, b: int) {
+ if r < 0 || r > 15 || b < 0 || b > 15 {
+ die("invalid reg");
+ }
+ if (op != (OP_ICALLM & 0xffff) && (op & -16) != OP_SETCC) || b >= 8 {
+ as_rex(a, op, r, 0, b);
+ }
+ as_op(a, op);
+ as_emit(a, 0xc0 + ((r << 3) & 0x38) + (b & 0x07));
+}
+
+// modrm /op
+func as_modr(a: *assembler, op: int, b: int) {
+ as_modrr(a, op & 0xffff, op >> 16, b);
+}
+
+// modrm + disp
+func as_modra(a: *assembler, op: int, r: int, d: int) {
+ as_rex(a, op, r, 0, 0);
+ as_op(a, op);
+ as_emit(a, ((r << 3) & 0x38) + R_RSP);
+ as_emit(a, (R_RSP << 3) + R_RBP);
+ as_emit(a, d);
+ as_emit(a, d >> 8);
+ as_emit(a, d >> 16);
+ as_emit(a, d >> 24);
+}
+
+// modrm + sib + disp
+func as_modrm(a: *assembler, op: int, r: int, b: int, i: int, s: int, d: int) {
+ var sib: int;
+ var mod: int;
+ var rm: int;
+ var dw: int;
+
+ if r < 0 || r > 15 {
+ die("invalid reg");
+ }
+
+ rm = (r << 3) & 0x38;
+
+ if d != 0 {
+ if d >= -128 && d <= 127 {
+ mod = 1;
+ dw = 1;
+ } else {
+ mod = 2;
+ dw = 4;
+ }
+ } else {
+ mod = 0;
+ dw = 0;
+ }
+
+ if mod == 0 {
+ if b < 0 || b > 16 {
+ die("invalid reg");
+ }
+
+ if s {
+ if b == R_RIP {
+ die("invalid base");
+ }
+
+ if i == R_RSP {
+ die("invalid index");
+ }
+
+ rm = rm + R_RSP;
+ } else {
+ if i != 0 {
+ die("invalid index");
+ }
+
+ if b == R_RIP {
+ mod = 0;
+ dw = 4;
+ rm = rm + R_RBP;
+ } else if b == R_RSP || b == R_R12 {
+ s = 1;
+ i = R_RSP;
+ rm = rm + R_RSP;
+ } else if b == R_RBP || b == R_R13 {
+ mod = 1;
+ dw = 1;
+ rm = rm + R_RBP;
+ } else {
+ rm = rm + (b & 7);
+ }
+ }
+ } else {
+ if b < 0 || b > 16 || i < 0 || i > 15 {
+ die("invalid reg");
+ }
+
+ if s {
+ if b == R_RIP {
+ die("invalid base");
+ }
+
+ if i == R_RSP {
+ die("invalid index");
+ }
+
+ rm = rm + R_RSP;
+ } else {
+ if i != 0 {
+ die("invalid index");
+ }
+
+ if b == R_RIP {
+ mod = 0;
+ dw = 4;
+ rm = rm + R_RBP;
+ } else if b == R_RSP || b == R_R12 {
+ s = 1;
+ i = R_RSP;
+ rm = rm + R_RSP;
+ } else {
+ rm = rm + (b & 7);
+ }
+ }
+ }
+
+ as_rex(a, op, r, i, b);
+ as_op(a, op);
+ as_emit(a, (mod << 6) + rm);
+
+ if s {
+ sib = ((i << 3) & 0x38) + (b & 0x07);
+ if s == 2 {
+ sib = sib + 0x40;
+ } else if s == 4 {
+ sib = sib + 0x80;
+ } else if s == 8 {
+ sib = sib + 0xc0;
+ } else if s != 1 {
+ die("invalid scale");
+ }
+ as_emit(a, sib);
+ }
+
+ if dw == 1 {
+ as_emit(a, d);
+ } else if dw == 4 {
+ as_emit(a, d);
+ as_emit(a, d >> 8);
+ as_emit(a, d >> 16);
+ as_emit(a, d >> 24);
+ }
+}
+
+// modrm /op
+func as_modm(a: *assembler, op: int, b: int, i: int, s: int, d: int) {
+ as_modrm(a, op & 0xffff, op >> 16, b, i, s, d);
+}
+
+func as_modri(a: *assembler, op: int, r: int, x: int) {
+ if x < -(1 << 31) || x >= (1 << 31) {
+ die("immediate too large");
+ }
+ as_modrr(a, op & 0xffff, op >> 16, r);
+ as_emit(a, x);
+ as_emit(a, x >> 8);
+ as_emit(a, x >> 16);
+ as_emit(a, x >> 24);
+}
+
+func as_jmp(a: *assembler, op: int, l: *label) {
+ reserve(a, 16);
+ as_op(a, op);
+ as_emit(a, 0);
+ as_emit(a, 0);
+ as_emit(a, 0);
+ as_emit(a, 0);
+ addfixup(a, l);
+}
+
+func emit_ssr(c: *compiler) {
+ var d: *decl;
+ var v: *decl;
+
+ v = find(c, "global", "_save", 0);
+ if (!v || !v.member_defined) {
+ cdie(c, "no _save");
+ }
+
+ // Save the current stack
+ as_emit(c.s, OP_GS);
+ as_modra(c.s, OP_STORE, R_RSP, v.member_offset);
+
+ v = find(c, "global", "curtask", 0);
+ if (!v || !v.member_defined) {
+ cdie(c, "no global.curtask");
+ }
+
+ // Load the current task
+ as_emit(c.s, OP_GS);
+ as_modra(c.s, OP_LOAD, R_RSP, v.member_offset);
+
+ v = find(c, "task", "stack", 0);
+ if (!v || !v.member_defined) {
+ cdie(c, "no task.stack");
+ }
+
+ // Load the kernel stack but reserve some space for the regs struct
+ as_modrm(c.s, OP_LOAD, R_RSP, R_RSP, 0, 0, v.member_offset);
+ as_modri(c.s, OP_ADDI, R_RSP, 4096 - 176);
+
+ // Save general purpose registers
+ as_modrm(c.s, OP_STORE, R_RAX, R_RSP, 0, 0, 0);
+ as_modrm(c.s, OP_STORE, R_RDX, R_RSP, 0, 0, 16);
+ as_modrm(c.s, OP_STORE, R_RBX, R_RSP, 0, 0, 24);
+ as_modrm(c.s, OP_STORE, R_RBP, R_RSP, 0, 0, 40);
+ as_modrm(c.s, OP_STORE, R_RSI, R_RSP, 0, 0, 48);
+ as_modrm(c.s, OP_STORE, R_RDI, R_RSP, 0, 0, 56);
+ as_modrm(c.s, OP_STORE, R_R8, R_RSP, 0, 0, 64);
+ as_modrm(c.s, OP_STORE, R_R9, R_RSP, 0, 0, 72);
+ as_modrm(c.s, OP_STORE, R_R10, R_RSP, 0, 0, 80);
+ as_modrm(c.s, OP_STORE, R_R12, R_RSP, 0, 0, 96);
+ as_modrm(c.s, OP_STORE, R_R13, R_RSP, 0, 0, 104);
+ as_modrm(c.s, OP_STORE, R_R14, R_RSP, 0, 0, 112);
+ as_modrm(c.s, OP_STORE, R_R15, R_RSP, 0, 0, 120);
+ as_modrm(c.s, OP_STORE, R_RCX, R_RSP, 0, 0, 128);
+ as_modrm(c.s, OP_STORE, R_R11, R_RSP, 0, 0, 136);
+
+ // Clear rcx, r11, trap, err
+ as_modrr(c.s, OP_XORRM, R_RAX, R_RAX);
+ as_modrm(c.s, OP_STORE, R_RAX, R_RSP, 0, 0, 8);
+ as_modrm(c.s, OP_STORE, R_RAX, R_RSP, 0, 0, 88);
+ as_modrm(c.s, OP_STORE, R_RAX, R_RSP, 0, 0, 160);
+ as_modrm(c.s, OP_STORE, R_RAX, R_RSP, 0, 0, 168);
+
+ // Save cs and ds
+ as_modri(c.s, OP_MOVI, R_RAX, 43);
+ as_modrm(c.s, OP_STORE, R_RAX, R_RSP, 0, 0, 144);
+ as_modri(c.s, OP_MOVI, R_RAX, 35);
+ as_modrm(c.s, OP_STORE, R_RAX, R_RSP, 0, 0, 152);
+
+ v = find(c, "global", "_save", 0);
+ if (!v || !v.member_defined) {
+ cdie(c, "no _save");
+ }
+
+ // Save the saved stack and switch back
+ as_emit(c.s, OP_GS);
+ as_modra(c.s, OP_LOAD, R_RAX, v.member_offset);
+ as_modrm(c.s, OP_STORE, R_RAX, R_RSP, 0, 0, 32);
+ as_modrr(c.s, OP_MOVE, R_RAX, R_RSP);
+
+ // Create a frame
+ as_modrr(c.s, OP_XORRM, R_RBP, R_RBP);
+ as_opr(c.s, OP_PUSHR, R_RBP);
+ as_opr(c.s, OP_PUSHR, R_RBP);
+ as_modrr(c.s, OP_MOVE, R_RBP, R_RSP);
+
+ as_modrr(c.s, OP_MOVE, R_RDI, R_RAX);
+
+ // Call _ssr
+ d = find(c, "_ssr", nil, 1);
+ if (d.func_defined && d.func_label.fixed) {
+ as_jmp(c.s, OP_CALL, d.func_label);
+ }
+
+ as_op(c.s, OP_CLI);
+
+ // Delete the frame
+ as_modri(c.s, OP_ADDI, R_RSP, 2 * 8);
+
+ // Restore the old registers
+ as_modrm(c.s, OP_LOAD, R_RAX, R_RSP, 0, 0, 0);
+ as_modrm(c.s, OP_LOAD, R_RDX, R_RSP, 0, 0, 16);
+ as_modrm(c.s, OP_LOAD, R_RBX, R_RSP, 0, 0, 24);
+ as_modrm(c.s, OP_LOAD, R_RBP, R_RSP, 0, 0, 40);
+ as_modrm(c.s, OP_LOAD, R_RSI, R_RSP, 0, 0, 48);
+ as_modrm(c.s, OP_LOAD, R_RDI, R_RSP, 0, 0, 56);
+ as_modrm(c.s, OP_LOAD, R_R8, R_RSP, 0, 0, 64);
+ as_modrm(c.s, OP_LOAD, R_R9, R_RSP, 0, 0, 72);
+ as_modrm(c.s, OP_LOAD, R_R10, R_RSP, 0, 0, 80);
+ as_modrm(c.s, OP_LOAD, R_R12, R_RSP, 0, 0, 96);
+ as_modrm(c.s, OP_LOAD, R_R13, R_RSP, 0, 0, 104);
+ as_modrm(c.s, OP_LOAD, R_R14, R_RSP, 0, 0, 112);
+ as_modrm(c.s, OP_LOAD, R_R15, R_RSP, 0, 0, 120);
+
+ as_modrm(c.s, OP_LOAD, R_RCX, R_RSP, 0, 0, 128);
+ as_modrm(c.s, OP_LOAD, R_R11, R_RSP, 0, 0, 136);
+
+ as_modrm(c.s, OP_LOAD, R_RSP, R_RSP, 0, 0, 32);
+
+ // Return to the user
+ as_rex(c.s, OP_SYSRET, 0, 0, 0);
+ as_op(c.s, OP_SYSRET);
+}
+
+func emit_isr(c: *compiler) {
+ var d: *decl;
+ var out: *label;
+ var i: int;
+
+ out = mklabel(c.s);
+
+ i = 0;
+ loop {
+ if i == 256 {
+ break;
+ }
+ reserve(c.s, 16);
+
+ if i == 8 || i == 10 || i == 11 || i == 12
+ || i == 13 || i == 14 || i == 17 || i == 21
+ || i == 29 || i == 30 {
+ // nop
+ as_emit(c.s, 0x90);
+ as_emit(c.s, 0x90);
+ } else {
+ // push 0
+ as_emit(c.s, 0x6a);
+ as_emit(c.s, 0x00);
+ }
+
+ // push i
+ as_emit(c.s, 0x68);
+ as_emit(c.s, i);
+ as_emit(c.s, 0x00);
+ as_emit(c.s, 0x00);
+ as_emit(c.s, 0x00);
+
+ // jmp out
+ as_emit(c.s, 0xe9);
+ as_emit(c.s, 0x00);
+ as_emit(c.s, 0x00);
+ as_emit(c.s, 0x00);
+ as_emit(c.s, 0x00);
+ addfixup(c.s, out);
+
+ // Align to 16
+ as_emit(c.s, 0x90);
+ as_emit(c.s, 0x90);
+ as_emit(c.s, 0x90);
+ as_emit(c.s, 0x90);
+
+ i = i + 1;
+ }
+
+ fixup_label(c.s, out);
+
+ // Allocate a regs struct
+ as_modri(c.s, OP_SUBI, R_RSP, 176);
+
+ // Save rbp and use it as the regs pointer
+ as_modrm(c.s, OP_STORE, R_RBP, R_RSP, 0, 0, 40);
+ as_modrr(c.s, OP_MOVE, R_RBP, R_RSP);
+
+ // Save general purpose registers
+ as_modrm(c.s, OP_STORE, R_RAX, R_RBP, 0, 0, 0);
+ as_modrm(c.s, OP_STORE, R_RCX, R_RBP, 0, 0, 8);
+ as_modrm(c.s, OP_STORE, R_RDX, R_RBP, 0, 0, 16);
+ as_modrm(c.s, OP_STORE, R_RBX, R_RBP, 0, 0, 24);
+ as_modrm(c.s, OP_STORE, R_RSI, R_RBP, 0, 0, 48);
+ as_modrm(c.s, OP_STORE, R_RDI, R_RBP, 0, 0, 56);
+ as_modrm(c.s, OP_STORE, R_R8, R_RBP, 0, 0, 64);
+ as_modrm(c.s, OP_STORE, R_R9, R_RBP, 0, 0, 72);
+ as_modrm(c.s, OP_STORE, R_R10, R_RBP, 0, 0, 80);
+ as_modrm(c.s, OP_STORE, R_R11, R_RBP, 0, 0, 88);
+ as_modrm(c.s, OP_STORE, R_R12, R_RBP, 0, 0, 96);
+ as_modrm(c.s, OP_STORE, R_R13, R_RBP, 0, 0, 104);
+ as_modrm(c.s, OP_STORE, R_R14, R_RBP, 0, 0, 112);
+ as_modrm(c.s, OP_STORE, R_R15, R_RBP, 0, 0, 120);
+
+ // trap
+ as_modrm(c.s, OP_LOAD, R_RAX, R_RBP, 0, 0, 176 + 0);
+ as_modrm(c.s, OP_STORE, R_RAX, R_RBP, 0, 0, 160);
+ // err
+ as_modrm(c.s, OP_LOAD, R_RAX, R_RBP, 0, 0, 176 + 8);
+ as_modrm(c.s, OP_STORE, R_RAX, R_RBP, 0, 0, 168);
+ // rip
+ as_modrm(c.s, OP_LOAD, R_RAX, R_RBP, 0, 0, 176 + 16);
+ as_modrm(c.s, OP_STORE, R_RAX, R_RBP, 0, 0, 128);
+ // cs
+ as_modrm(c.s, OP_LOAD, R_RAX, R_RBP, 0, 0, 176 + 24);
+ as_modrm(c.s, OP_STORE, R_RAX, R_RBP, 0, 0, 144);
+ // flags
+ as_modrm(c.s, OP_LOAD, R_RAX, R_RBP, 0, 0, 176 + 32);
+ as_modrm(c.s, OP_STORE, R_RAX, R_RBP, 0, 0, 136);
+ // rsp
+ as_modrm(c.s, OP_LOAD, R_RAX, R_RBP, 0, 0, 176 + 40);
+ as_modrm(c.s, OP_STORE, R_RAX, R_RBP, 0, 0, 32);
+ // ss
+ as_modrm(c.s, OP_LOAD, R_RAX, R_RBP, 0, 0, 176 + 48);
+ as_modrm(c.s, OP_STORE, R_RAX, R_RBP, 0, 0, 152);
+
+ // Call _isr
+ as_modrr(c.s, OP_MOVE, R_RDI, R_RBP);
+ d = find(c, "_isr", nil, 1);
+ if (d.func_defined && d.func_label.fixed) {
+ as_jmp(c.s, OP_CALL, d.func_label);
+ }
+
+ // rip
+ as_modrm(c.s, OP_LOAD, R_RAX, R_RBP, 0, 0, 128);
+ as_modrm(c.s, OP_STORE, R_RAX, R_RBP, 0, 0, 176 + 16);
+ // cs
+ as_modrm(c.s, OP_LOAD, R_RAX, R_RBP, 0, 0, 144);
+ as_modrm(c.s, OP_STORE, R_RAX, R_RBP, 0, 0, 176 + 24);
+ // flags
+ as_modrm(c.s, OP_LOAD, R_RAX, R_RBP, 0, 0, 136);
+ as_modrm(c.s, OP_STORE, R_RAX, R_RBP, 0, 0, 176 + 32);
+ // rsp
+ as_modrm(c.s, OP_LOAD, R_RAX, R_RBP, 0, 0, 32);
+ as_modrm(c.s, OP_STORE, R_RAX, R_RBP, 0, 0, 176 + 40);
+ // ss
+ as_modrm(c.s, OP_LOAD, R_RAX, R_RBP, 0, 0, 152);
+ as_modrm(c.s, OP_STORE, R_RAX, R_RBP, 0, 0, 176 + 48);
+
+ // Restore general purpose registers
+ as_modrm(c.s, OP_LOAD, R_RAX, R_RBP, 0, 0, 0);
+ as_modrm(c.s, OP_LOAD, R_RCX, R_RBP, 0, 0, 8);
+ as_modrm(c.s, OP_LOAD, R_RDX, R_RBP, 0, 0, 16);
+ as_modrm(c.s, OP_LOAD, R_RBX, R_RBP, 0, 0, 24);
+ as_modrm(c.s, OP_LOAD, R_RSI, R_RBP, 0, 0, 48);
+ as_modrm(c.s, OP_LOAD, R_RDI, R_RBP, 0, 0, 56);
+ as_modrm(c.s, OP_LOAD, R_R8, R_RBP, 0, 0, 64);
+ as_modrm(c.s, OP_LOAD, R_R9, R_RBP, 0, 0, 72);
+ as_modrm(c.s, OP_LOAD, R_R10, R_RBP, 0, 0, 80);
+ as_modrm(c.s, OP_LOAD, R_R11, R_RBP, 0, 0, 88);
+ as_modrm(c.s, OP_LOAD, R_R12, R_RBP, 0, 0, 96);
+ as_modrm(c.s, OP_LOAD, R_R13, R_RBP, 0, 0, 104);
+ as_modrm(c.s, OP_LOAD, R_R14, R_RBP, 0, 0, 112);
+ as_modrm(c.s, OP_LOAD, R_R15, R_RBP, 0, 0, 120);
+
+ // Restore rbp
+ as_modrm(c.s, OP_LOAD, R_RBP, R_RBP, 0, 0, 40);
+
+ // Clean up regs + trap + err
+ as_modri(c.s, OP_ADDI, R_RSP, 176 + 2 * 8);
+
+ as_op(c.s, OP_IRETQ);
+}
+
+func emit_builtin(c: *compiler) {
+ var d: *decl;
+
+ d = find(c, "syscall", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_modrr(c.s, OP_MOVE, R_RAX, R_RDI);
+ as_modrr(c.s, OP_MOVE, R_RDI, R_RSI);
+ as_modrr(c.s, OP_MOVE, R_RSI, R_RDX);
+ as_modrr(c.s, OP_MOVE, R_RDX, R_RCX);
+ as_modrr(c.s, OP_MOVE, R_R10, R_R8);
+ as_modrr(c.s, OP_MOVE, R_R8, R_R9);
+ as_modrm(c.s, OP_LOAD, R_R9, R_RSP, 0, 0, 8);
+ as_op(c.s, OP_SYSCALL);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "_restorer", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_modri(c.s, OP_MOVI, R_RAX, 15);
+ as_op(c.s, OP_SYSCALL);
+ }
+
+ d = find(c, "_include", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_op(c.s, OP_UD2);
+ }
+
+ d = find(c, "ud2", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_op(c.s, OP_UD2);
+ }
+
+ d = find(c, "cpuid", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_opr(c.s, OP_PUSHR, R_RCX);
+ as_opr(c.s, OP_PUSHR, R_RDX);
+ as_opr(c.s, OP_PUSHR, R_RSI);
+ as_opr(c.s, OP_PUSHR, R_RDI);
+ as_modrm(c.s, OP_LOAD, R_RAX, R_RDI, 0, 0, 0);
+ as_modrm(c.s, OP_LOAD, R_RCX, R_RSI, 0, 0, 0);
+ as_modrm(c.s, OP_LOAD, R_RDX, R_RDX, 0, 0, 0);
+ as_modrm(c.s, OP_LOAD, R_RBX, R_RCX, 0, 0, 0);
+ as_op(c.s, OP_CPUID);
+ as_opr(c.s, OP_POPR, R_RDI);
+ as_opr(c.s, OP_POPR, R_RSI);
+ as_opr(c.s, OP_POPR, R_RDX);
+ as_opr(c.s, OP_POPR, R_RCX);
+ as_modrm(c.s, OP_STORE, R_RAX, R_RDI, 0, 0, 0);
+ as_modrm(c.s, OP_STORE, R_RCX, R_RSI, 0, 0, 0);
+ as_modrm(c.s, OP_STORE, R_RDX, R_RDX, 0, 0, 0);
+ as_modrm(c.s, OP_STORE, R_RBX, R_RCX, 0, 0, 0);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "inb", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_modrr(c.s, OP_MOVE, R_RDX, R_RDI);
+ as_op(c.s, OP_IN);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "outb", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_modrr(c.s, OP_MOVE, R_RDX, R_RDI);
+ as_modrr(c.s, OP_MOVE, R_RAX, R_RSI);
+ as_op(c.s, OP_OUT);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "inw", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_modrr(c.s, OP_MOVE, R_RDX, R_RDI);
+ as_emit(c.s, OP_OS);
+ as_op(c.s, OP_IND);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "outw", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_modrr(c.s, OP_MOVE, R_RDX, R_RDI);
+ as_modrr(c.s, OP_MOVE, R_RAX, R_RSI);
+ as_emit(c.s, OP_OS);
+ as_op(c.s, OP_OUTD);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "ind", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_modrr(c.s, OP_MOVE, R_RDX, R_RDI);
+ as_op(c.s, OP_IND);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "outd", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_modrr(c.s, OP_MOVE, R_RDX, R_RDI);
+ as_modrr(c.s, OP_MOVE, R_RAX, R_RSI);
+ as_op(c.s, OP_OUTD);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "rdmsr", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_modrr(c.s, OP_MOVE, R_RCX, R_RDI);
+ as_op(c.s, OP_RDMSR);
+ as_modri(c.s, OP_MOVI, R_RCX, 32);
+ as_modr(c.s, OP_SHLM, R_RDX);
+ as_modrr(c.s, OP_ORRM, R_RAX, R_RDX);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "wrmsr", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_modrr(c.s, OP_MOVE, R_RAX, R_RSI);
+ as_modrr(c.s, OP_MOVE, R_RDX, R_RSI);
+ as_modri(c.s, OP_MOVI, R_RCX, 32);
+ as_modr(c.s, OP_SHRM, R_RDX);
+ as_modrr(c.s, OP_MOVE, R_RCX, R_RDI);
+ as_op(c.s, OP_WRMSR);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "rdcr0", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_modrr(c.s, OP_RDCRR, R_CR0, R_RAX);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "wrcr0", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_modrr(c.s, OP_WRCRR, R_CR0, R_RDI);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "rdcr2", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_modrr(c.s, OP_RDCRR, R_CR2, R_RAX);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "wrcr2", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_modrr(c.s, OP_WRCRR, R_CR2, R_RDI);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "rdcr3", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_modrr(c.s, OP_RDCRR, R_CR3, R_RAX);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "wrcr3", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_modrr(c.s, OP_WRCRR, R_CR3, R_RDI);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "rdcr4", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_modrr(c.s, OP_RDCRR, R_CR4, R_RAX);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "wrcr4", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_modrr(c.s, OP_WRCRR, R_CR4, R_RDI);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "lgdt", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_modri(c.s, OP_SUBI, R_RSP, 16);
+ as_modri(c.s, OP_SUBI, R_RSI, 1);
+ as_modrm(c.s, OP_STORE, R_RSI, R_RSP, 0, 0, 0);
+ as_modrm(c.s, OP_STORE, R_RDI, R_RSP, 0, 0, 2);
+ as_modm(c.s, OP_LGDTM, R_RSP, 0, 0, 0);
+ as_modri(c.s, OP_ADDI, R_RSP, 16);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "lidt", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_modri(c.s, OP_SUBI, R_RSP, 16);
+ as_modri(c.s, OP_SUBI, R_RSI, 1);
+ as_modrm(c.s, OP_STORE, R_RSI, R_RSP, 0, 0, 0);
+ as_modrm(c.s, OP_STORE, R_RDI, R_RSP, 0, 0, 2);
+ as_modm(c.s, OP_LIDTM, R_RSP, 0, 0, 0);
+ as_modri(c.s, OP_ADDI, R_RSP, 16);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "lldt", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_modr(c.s, OP_LLDTM, R_RDI);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "ltr", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_modr(c.s, OP_LTRM, R_RDI);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "lseg", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_opr(c.s, OP_PUSHR, R_RBP);
+ as_modrr(c.s, OP_MOVE, R_RBP, R_RSP);
+ // es ds fs gs
+ as_modrr(c.s, OP_WRSR, R_ES, R_RSI);
+ as_modrr(c.s, OP_WRSR, R_DS, R_RSI);
+ as_modrr(c.s, OP_WRSR, R_FS, R_RSI);
+ as_modrr(c.s, OP_WRSR, R_GS, R_RSI);
+ // ss
+ as_opr(c.s, OP_PUSHR, R_RSI);
+ // rsp
+ as_opr(c.s, OP_PUSHR, R_RBP);
+ // flags
+ as_op(c.s, OP_PUSHF);
+ // cs
+ as_opr(c.s, OP_PUSHR, R_RDI);
+ // rip
+ as_op(c.s, OP_CALL);
+ as_emit(c.s, 5);
+ as_emit(c.s, 0);
+ as_emit(c.s, 0);
+ as_emit(c.s, 0);
+ as_op(c.s, OP_JMP);
+ as_emit(c.s, 2);
+ as_emit(c.s, 0);
+ as_emit(c.s, 0);
+ as_emit(c.s, 0);
+ as_op(c.s, OP_IRETQ);
+ as_opr(c.s, OP_POPR, R_RBP);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "hlt", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_op(c.s, OP_HLT);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "cli", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_op(c.s, OP_CLI);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "sti", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_op(c.s, OP_STI);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "rdflags", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_op(c.s, OP_PUSHF);
+ as_opr(c.s, OP_POPR, R_RAX);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "wrflags", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_opr(c.s, OP_PUSHR, R_RDI);
+ as_op(c.s, OP_POPF);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "wbinvld", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_modm(c.s, OP_WBINVD, R_RDI, 0, 0, 0);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "invlpg", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_modm(c.s, OP_INVLPGM, R_RDI, 0, 0, 0);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "_ssr0", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ emit_ssr(c);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "_isr0", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ emit_isr(c);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "_rgs", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_modrm(c.s, OP_LOAD, R_RSI, R_RBP, 0, 0, 16);
+ as_emit(c.s, OP_GS);
+ as_modrm(c.s, OP_LOAD, R_RAX, R_RSI, 0, 0, 0);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "_r32", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ c.s.bits32 = 1;
+ as_modrm(c.s, OP_LOAD, R_RAX, R_RDI, 0, 0, 0);
+ c.s.bits32 = 0;
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "_w32", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ c.s.bits32 = 1;
+ as_modrm(c.s, OP_STORE, R_RSI, R_RDI, 0, 0, 0);
+ c.s.bits32 = 0;
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "_r16", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_modrr(c.s, OP_XORRM, R_RAX, R_RAX);
+ c.s.bits32 = 1;
+ as_modrm(c.s, OP_LOAD16, R_RAX, R_RDI, 0, 0, 0);
+ c.s.bits32 = 0;
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "_w16", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ c.s.bits32 = 1;
+ as_modrm(c.s, OP_STORE16, R_RSI, R_RDI, 0, 0, 0);
+ c.s.bits32 = 0;
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "_rdrand", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+ as_modr(c.s, OP_RDRAND, R_RAX);
+ as_op(c.s, OP_RET);
+ }
+
+ d = find(c, "taskswitch", nil, 1);
+ if (d.func_defined && !d.func_label.fixed) {
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+
+ // save
+ as_modrm(c.s, OP_STORE, R_RAX, R_RDI, 0, 0, 0);
+ as_modrm(c.s, OP_STORE, R_RCX, R_RDI, 0, 0, 8);
+ as_modrm(c.s, OP_STORE, R_RDX, R_RDI, 0, 0, 16);
+ as_modrm(c.s, OP_STORE, R_RBX, R_RDI, 0, 0, 24);
+ as_modrm(c.s, OP_STORE, R_RBP, R_RDI, 0, 0, 40);
+ as_modrm(c.s, OP_STORE, R_RSI, R_RDI, 0, 0, 48);
+ as_modrm(c.s, OP_STORE, R_RDI, R_RDI, 0, 0, 56);
+ as_modrm(c.s, OP_STORE, R_R8, R_RDI, 0, 0, 64);
+ as_modrm(c.s, OP_STORE, R_R9, R_RDI, 0, 0, 72);
+ as_modrm(c.s, OP_STORE, R_R10, R_RDI, 0, 0, 80);
+ as_modrm(c.s, OP_STORE, R_R11, R_RDI, 0, 0, 88);
+ as_modrm(c.s, OP_STORE, R_R12, R_RDI, 0, 0, 96);
+ as_modrm(c.s, OP_STORE, R_R13, R_RDI, 0, 0, 104);
+ as_modrm(c.s, OP_STORE, R_R14, R_RDI, 0, 0, 112);
+ as_modrm(c.s, OP_STORE, R_R15, R_RDI, 0, 0, 120);
+
+ // rip
+ as_opr(c.s, OP_POPR, R_RAX);
+ as_modrm(c.s, OP_STORE, R_RAX, R_RDI, 0, 0, 128);
+ // cs
+ as_modrr(c.s, OP_RDSR, R_CS, R_RAX);
+ as_modrm(c.s, OP_STORE, R_RAX, R_RDI, 0, 0, 144);
+ // flags
+ as_op(c.s, OP_PUSHF);
+ as_opr(c.s, OP_POPR, R_RAX);
+ as_modrm(c.s, OP_STORE, R_RAX, R_RDI, 0, 0, 136);
+ // rsp
+ as_modrm(c.s, OP_STORE, R_RSP, R_RDI, 0, 0, 32);
+ // ss
+ as_modrr(c.s, OP_RDSR, R_SS, R_RAX);
+ as_modrm(c.s, OP_STORE, R_RAX, R_RDI, 0, 0, 152);
+
+ // restore
+ as_modrm(c.s, OP_STORE, R_RCX, R_RDI, 0, 0, 8);
+ as_modrm(c.s, OP_STORE, R_RDX, R_RDI, 0, 0, 16);
+ as_modrm(c.s, OP_STORE, R_RBX, R_RDI, 0, 0, 24);
+ as_modrm(c.s, OP_STORE, R_RBP, R_RDI, 0, 0, 40);
+ as_modrm(c.s, OP_STORE, R_RDI, R_RDI, 0, 0, 56);
+ as_modrm(c.s, OP_STORE, R_R8, R_RDI, 0, 0, 64);
+ as_modrm(c.s, OP_STORE, R_R9, R_RDI, 0, 0, 72);
+ as_modrm(c.s, OP_STORE, R_R10, R_RDI, 0, 0, 80);
+ as_modrm(c.s, OP_STORE, R_R11, R_RDI, 0, 0, 88);
+ as_modrm(c.s, OP_STORE, R_R12, R_RDI, 0, 0, 96);
+ as_modrm(c.s, OP_STORE, R_R13, R_RDI, 0, 0, 104);
+ as_modrm(c.s, OP_STORE, R_R14, R_RDI, 0, 0, 112);
+ as_modrm(c.s, OP_STORE, R_R15, R_RDI, 0, 0, 120);
+
+ // ss
+ as_modrm(c.s, OP_LOAD, R_RAX, R_RSI, 0, 0, 152);
+ as_opr(c.s, OP_PUSHR, R_RAX);
+ // rsp
+ as_modrm(c.s, OP_LOAD, R_RAX, R_RSI, 0, 0, 32);
+ as_opr(c.s, OP_PUSHR, R_RAX);
+ // flags
+ as_modrm(c.s, OP_LOAD, R_RAX, R_RSI, 0, 0, 136);
+ as_opr(c.s, OP_PUSHR, R_RAX);
+ // cs
+ as_modrm(c.s, OP_LOAD, R_RAX, R_RSI, 0, 0, 144);
+ as_opr(c.s, OP_PUSHR, R_RAX);
+ // rip
+ as_modrm(c.s, OP_LOAD, R_RAX, R_RSI, 0, 0, 128);
+ as_opr(c.s, OP_PUSHR, R_RAX);
+
+ // restore temporaries
+ as_modrm(c.s, OP_LOAD, R_RAX, R_RSI, 0, 0, 0);
+ as_modrm(c.s, OP_LOAD, R_RSI, R_RSI, 0, 0, 40);
+
+ // iretq
+ as_op(c.s, OP_IRETQ);
+ }
+}
+
+func emit_kstart(c: *assembler) {
+ var hang: *label;
+ var do_iret: *label;
+ var do_ret: *label;
+ var done: *label;
+
+ c.bits32 = 1;
+
+ hang = mklabel(c);
+ do_iret = mklabel(c);
+ do_ret = mklabel(c);
+ done = mklabel(c);
+
+ // Check for valid multiboot magic
+ as_modri(c, OP_MOVI, R_RDX, 0x2badb002);
+ as_modrr(c, OP_CMPRM, R_RAX, R_RDX);
+ as_jmp(c, OP_JCC + CC_NE, hang);
+
+ // Setup an initial stack
+ as_modri(c, OP_MOVI, R_RSP, 0x00300000); // FIXME bss
+
+ // Align stack to page
+ as_modri(c, OP_ANDI, R_RSP, -0x1000);
+
+ // pt3 -> 1g
+ as_modri(c, OP_SUBI, R_RSP, 0x1000);
+ as_modri(c, OP_MOVI, R_RAX, 0x83);
+ as_modri(c, OP_MOVI, R_RDX, 0);
+ as_modrm(c, OP_STORE, R_RAX, R_RSP, 0, 0, 0);
+ as_modrm(c, OP_STORE, R_RDX, R_RSP, 0, 0, 4);
+ as_modrm(c, OP_STORE, R_RAX, R_RSP, 0, 0, 510 * 8 + 0);
+ as_modrm(c, OP_STORE, R_RDX, R_RSP, 0, 0, 510 * 8 + 4);
+
+ // pt4 -> pt3
+ as_modrr(c, OP_MOVE, R_RAX, R_RSP);
+ as_modri(c, OP_SUBI, R_RSP, 0x1000);
+ as_modri(c, OP_ORI, R_RAX, 3);
+ as_modri(c, OP_MOVI, R_RDX, 0);
+ as_modrm(c, OP_STORE, R_RAX, R_RSP, 0, 0, 0);
+ as_modrm(c, OP_STORE, R_RDX, R_RSP, 0, 0, 4);
+ as_modrm(c, OP_STORE, R_RAX, R_RSP, 0, 0, 511 * 8 + 0);
+ as_modrm(c, OP_STORE, R_RDX, R_RSP, 0, 0, 511 * 8 + 4);
+
+ // Load page table pt4
+ as_modrr(c, OP_WRCRR, R_CR3, R_RSP);
+
+ // Allocate space for the gdt
+ as_modri(c, OP_SUBI, R_RSP, 64);
+ as_modrr(c, OP_MOVE, R_RBP, R_RSP);
+
+ // Null Segment
+ as_modri(c, OP_MOVI, R_RAX, 0x00000000);
+ as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 8);
+ as_modri(c, OP_MOVI, R_RAX, 0x00000000);
+ as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 12);
+
+ // Kernel code segment
+ as_modri(c, OP_MOVI, R_RAX, 0x00000000);
+ as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 16);
+ as_modri(c, OP_MOVI, R_RAX, 0x00209800);
+ as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 20);
+
+ // Kernel data segment
+ as_modri(c, OP_MOVI, R_RAX, 0x00000000);
+ as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 24);
+ as_modri(c, OP_MOVI, R_RAX, 0x00009200);
+ as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 28);
+
+ // Load gdt
+ as_modri(c, OP_MOVI, R_RAX, 23);
+ as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 0);
+ as_modrm(c, OP_LEA, R_RAX, R_RBP, 0, 0, 8);
+ as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 2);
+ as_modm(c, OP_LGDTM, R_RBP, 0, 0, 0);
+
+ // Load null lldt
+ as_modri(c, OP_MOVI, R_RAX, 0);
+ as_modr(c, OP_LLDTM, R_RAX);
+
+ // Load null idt
+ as_modm(c, OP_LIDTM, R_RBP, 0, 0, 8);
+
+ // Enable pae
+ as_modri(c, OP_MOVI, R_RAX, 0xa0);
+ as_modrr(c, OP_WRCRR, R_CR4, R_RAX);
+
+ // Enable long mode
+ as_modri(c, OP_MOVI, R_RCX, (-1 << 32) + (0xc0 << 24) + 0x000080);
+ as_op(c, OP_RDMSR);
+ as_modri(c, OP_ORI, R_RAX, 0x100);
+ as_op(c, OP_WRMSR);
+
+ // Enable paging
+ as_modrr(c, OP_RDCRR, R_CR0, R_RAX);
+ as_modri(c, OP_ORI, R_RAX, (-0x80000000) | 0x0001);
+ as_modrr(c, OP_WRCRR, R_CR0, R_RAX);
+
+ // flags
+ as_modri(c, OP_MOVI, R_RAX, 0);
+ as_opr(c, OP_PUSHR, R_RAX);
+ // cs
+ as_modri(c, OP_MOVI, R_RAX, 8);
+ as_opr(c, OP_PUSHR, R_RAX);
+ // pointer
+ as_jmp(c, OP_CALL, do_iret);
+
+ c.bits32 = 0;
+
+ // Jump to top half
+ as_jmp(c, OP_CALL, do_ret);
+
+ // Reload the gdt in the top half
+ as_modri(c, OP_ORI, R_RBP, -0x80000000);
+ as_modri(c, OP_MOVI, R_RAX, 23);
+ as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 0);
+ as_modrm(c, OP_LEA, R_RAX, R_RBP, 0, 0, 8);
+ as_modrm(c, OP_STORE, R_RAX, R_RBP, 0, 0, 2);
+ as_modm(c, OP_LGDTM, R_RBP, 0, 0, 0);
+
+ // Reload segments
+ as_modri(c, OP_MOVI, R_RAX, 16);
+ as_modrr(c, OP_WRSR, R_ES, R_RAX);
+ as_modrr(c, OP_WRSR, R_DS, R_RAX);
+ as_modrr(c, OP_WRSR, R_FS, R_RAX);
+ as_modrr(c, OP_WRSR, R_GS, R_RAX);
+ as_modrr(c, OP_WRSR, R_SS, R_RAX);
+ as_modrr(c, OP_MOVE, R_RSP, R_RSP);
+
+ // Reload stack in the top half
+ as_modri(c, OP_ORI, R_RSP, -0x80000000);
+
+ // Kill the lower mapping
+ as_modri(c, OP_MOVI, R_RAX, 0);
+ as_modrm(c, OP_LEA, R_RDI, R_RBP, 0, 0, 64);
+ as_modrm(c, OP_STORE, R_RAX, R_RDI, 0, 0, 4096);
+ as_modrm(c, OP_STORE, R_RAX, R_RDI, 0, 0, 0);
+ as_modri(c, OP_ANDI, R_RDI, 0x7fffffff);
+ as_modrr(c, OP_WRCRR, R_CR3, R_RDI);
+
+ // Setup a call frame for _kstart
+ as_jmp(c, OP_JMP, done);
+
+ // hlt forever
+ fixup_label(c, hang);
+ as_op(c, OP_CLI);
+ as_op(c, OP_HLT);
+ as_jmp(c, OP_JMP, hang);
+
+ // iret to long mode
+ fixup_label(c, do_iret);
+ as_op(c, OP_IRET);
+
+ // ret to top half
+ fixup_label(c, do_ret);
+ as_opr(c, OP_POPR, R_RAX);
+ as_modri(c, OP_ORI, R_RAX, -0x80000000);
+ as_opr(c, OP_PUSHR, R_RAX);
+ as_op(c, OP_RET);
+
+ // Setup a call frame for _kstart
+ fixup_label(c, done);
+ as_modrr(c, OP_XORRM, R_RBP, R_RBP);
+ as_modrr(c, OP_MOVE, R_RDI, R_RBX);
+ as_opr(c, OP_PUSHR, R_RBP);
+}
+
+func emit_align(c: *assembler, n: int, b: int) {
+ var pad: int;
+
+ pad = c.at & (n - 1);
+
+ if pad == 0 {
+ return;
+ }
+
+ loop {
+ if pad == n {
+ break;
+ }
+
+ as_emit(c, b);
+
+ pad = pad + 1;
+ }
+}
+
+func output_ir(c: *compiler, d: *decl) {
+ var ic: *irfunc;
+
+ ic = d.func_ir;
+
+ ic.c.filename = ic.filename;
+ ic.c.lineno = ic.lineno;
+ ic.c.colno = ic.colno;
+ ic.s.filename = ic.filename;
+ ic.s.lineno = ic.lineno;
+
+ fixup_label(c.s, d.func_label);
+ add_symbol(c.s, d.name, d.func_label);
+
+ if strcmp(d.name, "_start") == 0 {
+ as_modrm(c.s, OP_LOAD, R_RDI, R_RSP, 0, 0, 0);
+ as_modrm(c.s, OP_LEA, R_RSI, R_RSP, 0, 0, 8);
+ as_modrm(c.s, OP_LEA, R_RDX, R_RSI, R_RDI, 8, 8);
+ as_opr(c.s, OP_PUSHR, R_RBP);
+ } else if strcmp(d.name, "_kstart") == 0 {
+ emit_kstart(c.s);
+ }
+
+ //fputc(nil, '\n');
+ //fputs(nil, d.name);
+ //irshow(nil, ic.blocks[0]);
+
+ // Setup the frame
+ as_opr(ic.s, OP_PUSHR, R_RBP);
+ as_modrr(ic.s, OP_MOVE, R_RBP, R_RSP);
+
+ // Allocate local variables
+ output_irvars(ic);
+
+ // Output all blocks
+ output_irblock(ic, ic.blocks[0]);
+
+ // Clear the marks
+ irreset(ic.blocks[0]);
+}
+
+func output_irvars(ic: *irfunc) {
+ var offset: int;
+ var size: int;
+ var i: int;
+ var v: *irvar;
+
+ // Allocate local variables
+ offset = 0;
+ i = 0;
+ loop {
+ if i == ic.vars_len {
+ break;
+ }
+
+ v = ic.vars[i];
+
+ if v.dead {
+ i = i + 1;
+ continue;
+ }
+
+ if v.t && v.t.kind != TY_VOID {
+ size = type_sizeof(ic.c, v.t);
+ } else {
+ size = sizeof(i);
+ }
+
+ size = (size + 7) & -8;
+
+ offset = offset + size;
+
+ v.offset = -offset;
+
+ i = i + 1;
+ }
+
+ // Zero initialize local variables
+ if offset != 0 {
+ as_modri(ic.s, OP_SUBI, R_RSP, offset);
+
+ as_modrr(ic.s, OP_XORRM, R_RAX, R_RAX);
+
+ i = 0;
+ loop {
+ if i == offset {
+ break;
+ }
+
+ i = i + 8;
+
+ as_modrm(ic.s, OP_STORE, R_RAX, R_RBP, 0, 0, -i);
+ }
+ }
+
+ // Save parameters
+ i = 0;
+ loop {
+ if i == ic.arg_count {
+ break;
+ }
+
+ v = ic.vars[i];
+
+ if i == 0 {
+ as_modrm(ic.s, OP_STORE, R_RDI, R_RBP, 0, 0, v.offset);
+ } else if i == 1 {
+ as_modrm(ic.s, OP_STORE, R_RSI, R_RBP, 0, 0, v.offset);
+ } else if i == 2 {
+ as_modrm(ic.s, OP_STORE, R_RDX, R_RBP, 0, 0, v.offset);
+ } else if i == 3 {
+ as_modrm(ic.s, OP_STORE, R_RCX, R_RBP, 0, 0, v.offset);
+ } else if i == 4 {
+ as_modrm(ic.s, OP_STORE, R_R8, R_RBP, 0, 0, v.offset);
+ } else if i == 5 {
+ as_modrm(ic.s, OP_STORE, R_R9, R_RBP, 0, 0, v.offset);
+ } else {
+ // Stack argument
+ as_modrm(ic.s, OP_LOAD, R_RAX, R_RBP, 0, 0, (i - 6 + 2) * sizeof(i));
+ as_modrm(ic.s, OP_STORE, R_RAX, R_RBP, 0, 0, v.offset);
+ }
+
+ i = i + 1;
+ }
+}
+
+func output_irblock(ic: *irfunc, b: *irblock) {
+ var op: *irop;
+ var i: int;
+
+ b.mark = 1;
+
+ if !b.done {
+ cdie(ic.c, "no return in function");
+ }
+
+ fixup_label(ic.s, b.label);
+
+ i = 0;
+ loop {
+ if i == b.ops_len {
+ break;
+ }
+
+ op = b.ops[i];
+
+ output_irstmt(ic, b, op);
+
+ i = i + 1;
+ }
+}
+
+func output_irstmt(ic: *irfunc, b: *irblock, o: *irop) {
+ var kind: int;
+
+ ic.c.filename = o.filename;
+ ic.c.lineno = o.lineno;
+ ic.c.colno = o.colno;
+ ic.s.filename = o.filename;
+ ic.s.lineno = o.lineno;
+
+ kind = o.kind;
+ if kind == IOP_STORE {
+ // Evaluate the address
+ if o.a.kind == IOP_LOAD {
+ output_irexpr(ic, b, o.a.a);
+ } else if o.a.kind == IOP_VAR {
+ as_modrm(ic.s, OP_LEA, R_RAX, R_RBP, 0, 0, ic.vars[o.a.n].offset);
+ } else {
+ die("invalid store");
+ }
+
+ as_opr(ic.s, OP_PUSHR, R_RAX);
+
+ // Evaluate the value
+ output_irexpr(ic, b, o.b);
+
+ as_opr(ic.s, OP_POPR, R_RDI);
+
+ // Execute the store
+ if o.t.kind == TY_BYTE {
+ as_modrm(ic.s, OP_STOREB, R_RAX, R_RDI, 0, 0, 0);
+ } else if type_isprim(o.t) {
+ as_modrm(ic.s, OP_STORE, R_RAX, R_RDI, 0, 0, 0);
+ } else {
+ cdie(ic.c, "invalid store");
+ }
+ } else if kind == IOP_RETVAL {
+ // Do nothing
+ } else if kind == IOP_ARG {
+ // Do nothing
+ } else if kind == IOP_CALL {
+ // Allocate some space for the arguments
+ if o.n > 6 {
+ as_modri(ic.s, OP_SUBI, R_RSP, (o.n - 6) * sizeof(kind));
+ }
+
+ // Setup arguments
+ output_irargs(ic, b, o);
+
+ // Call the function
+ if o.a.kind == IOP_FUNC {
+ output_ircall(ic, b, o.a);
+ } else {
+ output_irexpr(ic, b, o.a);
+ as_modr(ic.s, OP_ICALLM, R_RAX);
+ }
+
+ // Release space reserved for the arguments
+ if o.n > 6 {
+ as_modri(ic.s, OP_ADDI, R_RSP, (o.n - 6) * sizeof(kind));
+ }
+
+ // Save the return value
+ output_irretval(ic, b, o);
+
+ if b.out.mark {
+ as_jmp(ic.s, OP_JMP, b.out.label);
+ } else {
+ output_irblock(ic, b.out);
+ }
+ return;
+ } else if kind == IOP_JUMP {
+ if b.out.mark {
+ // Jump to an already output block
+ as_jmp(ic.s, OP_JMP, b.out.label);
+ } else {
+ // Output a new block
+ output_irblock(ic, b.out);
+ }
+ return;
+ } else if kind == IOP_BRANCH {
+ // Evaluate the condition and branch if zero
+ output_irexpr(ic, b, o.a);
+ as_modrr(ic.s, OP_TESTRM, R_RAX, R_RAX);
+ as_jmp(ic.s, OP_JCC + CC_E, b.alt.label);
+
+ // Then jump to the output
+ if b.out.mark {
+ as_jmp(ic.s, OP_JCC + CC_NE, b.out.label);
+ } else {
+ output_irblock(ic, b.out);
+ }
+
+ // And if we haven't already, output the alt branch
+ if !b.alt.mark {
+ output_irblock(ic, b.alt);
+ }
+
+ return;
+ } else if kind == IOP_RETURN {
+ // Evaluate the return expression and return
+ if o.a {
+ output_irexpr(ic, b, o.a);
+ }
+
+ as_modrr(ic.s, OP_MOVE, R_RSP, R_RBP);
+ as_opr(ic.s, OP_POPR, R_RBP);
+ as_op(ic.s, OP_RET);
+ } else {
+ // Evaluate and discard the result
+ output_irexpr(ic, b, o);
+ }
+}
+
+func output_irargs(ic: *irfunc, b: *irblock, o: *irop) {
+ var i: int;
+ var op: *irop;
+
+ i = 0;
+ loop {
+ if i == b.ops_len {
+ return;
+ }
+
+ op = b.ops[i];
+ if op.kind == IOP_ARG {
+ // Compute the value
+ output_irexpr(ic, b, op.a);
+
+ if op.n == 0 {
+ as_modrr(ic.s, OP_MOVE, R_RDI, R_RAX);
+ } else if op.n == 1 {
+ as_modrr(ic.s, OP_MOVE, R_RSI, R_RAX);
+ } else if op.n == 2 {
+ as_modrr(ic.s, OP_MOVE, R_RDX, R_RAX);
+ } else if op.n == 3 {
+ as_modrr(ic.s, OP_MOVE, R_RCX, R_RAX);
+ } else if op.n == 4 {
+ as_modrr(ic.s, OP_MOVE, R_R8, R_RAX);
+ } else if op.n == 5 {
+ as_modrr(ic.s, OP_MOVE, R_R9, R_RAX);
+ } else {
+ // Stack argument
+ as_modrm(ic.s, OP_STORE, R_RAX, R_RSP, 0, 0, (op.n - 6) * sizeof(i));
+ }
+ }
+
+ i = i + 1;
+ }
+}
+
+func output_irretval(ic: *irfunc, b: *irblock, o: *irop) {
+ var i: int;
+ var op: *irop;
+
+ // Find the retval place
+ op = nil;
+ i = 0;
+ loop {
+ if i == b.ops_len {
+ return;
+ }
+
+ op = b.ops[i];
+ if op.kind == IOP_RETVAL {
+ break;
+ }
+
+ i = i + 1;
+ }
+
+ // Do nothing if there was no return value
+ if op.t.kind == TY_VOID {
+ return;
+ }
+
+ // Save the value
+ as_modrr(ic.s, OP_MOVE, R_RDI, R_RAX);
+
+ // Compute the address
+ if op.a.kind == IOP_LOAD {
+ output_irexpr(ic, b, op.a.a);
+ } else if op.a.kind == IOP_VAR {
+ as_modrm(ic.s, OP_LEA, R_RAX, R_RBP, 0, 0, ic.vars[op.a.n].offset);
+ } else {
+ die("invalid store");
+ }
+
+ // Execute the store
+ if op.t.kind == TY_BYTE {
+ as_modrm(ic.s, OP_STOREB, R_RDI, R_RAX, 0, 0, 0);
+ } else if type_isprim(op.t) {
+ as_modrm(ic.s, OP_STORE, R_RDI, R_RAX, 0, 0, 0);
+ } else {
+ cdie(ic.c, "invalid store");
+ }
+}
+
+func output_irstr(ic: *irfunc, b: *irblock, o: *irop) {
+ var s: *label;
+
+ s = as_blob(ic.s, o.s, o.slen + 1);
+
+ reserve(ic.s, 16);
+ as_modrm(ic.s, OP_LEA, R_RAX, R_RIP, 0, 0, 128);
+ addfixup(ic.s, s);
+}
+
+func output_irfuncptr(ic: *irfunc, b: *irblock, o: *irop) {
+ var d: *decl;
+
+ d = find(ic.c, o.s, nil, 0);
+
+ if !d || !d.func_defined {
+ cdie(ic.c, "no such function");
+ }
+
+ reserve(ic.s, 16);
+ as_modrm(ic.s, OP_LEA, R_RAX, R_RIP, 0, 0, 128);
+ addfixup(ic.s, d.func_label);
+}
+
+func output_ircall(ic: *irfunc, b: *irblock, o: *irop) {
+ var d: *decl;
+
+ d = find(ic.c, o.s, nil, 0);
+
+ if !d || !d.func_defined {
+ cdie(ic.c, "no such function");
+ }
+
+ as_jmp(ic.s, OP_CALL, d.func_label);
+}
+
+func output_irexpr(ic: *irfunc, b: *irblock, o: *irop) {
+ var kind: int;
+
+ if !o {
+ cdie(ic.c, "no expr");
+ }
+
+ kind = o.kind;
+ if kind == IOP_VAR {
+ as_modrm(ic.s, OP_LOAD, R_RAX, R_RBP, 0, 0, ic.vars[o.n].offset);
+ } else if kind == IOP_VARREF {
+ as_modrm(ic.s, OP_LEA, R_RAX, R_RBP, 0, 0, ic.vars[o.n].offset);
+ } else if kind == IOP_FUNC {
+ output_irfuncptr(ic, b, o);
+ } else if kind == IOP_CONST {
+ if o.n == 0 {
+ as_modrr(ic.s, OP_XORRM, R_RAX, R_RAX);
+ } else if o.n < (-1 >> 33) && o.n >= (-1 << 31) {
+ as_modri(ic.s, OP_MOVI, R_RAX, o.n);
+ } else {
+ as_opri64(ic.s, OP_MOVABS, R_RAX, o.n);
+ }
+ } else if kind == IOP_STR {
+ output_irstr(ic, b, o);
+ } else if kind == IOP_LOAD {
+ output_irexpr(ic, b, o.a);
+ if o.t.kind == TY_BYTE {
+ as_modrr(ic.s, OP_MOVE, R_RSI, R_RAX);
+ as_modrr(ic.s, OP_XORRM, R_RAX, R_RAX);
+ as_modrm(ic.s, OP_LOADB, R_RAX, R_RSI, 0, 0, 0);
+ } else if type_isprim(o.t) {
+ as_modrm(ic.s, OP_LOAD, R_RAX, R_RAX, 0, 0, 0);
+ } else {
+ cdie(ic.c, "invalid load");
+ }
+ } else if kind == IOP_NEG {
+ output_irexpr(ic, b, o.a);
+ as_modr(ic.s, OP_NEGM, R_RAX);
+ } else if kind == IOP_NOT {
+ output_irexpr(ic, b, o.a);
+ as_modr(ic.s, OP_NOTM, R_RAX);
+ } else if kind == IOP_ADD {
+ output_irexpr(ic, b, o.b);
+ as_opr(ic.s, OP_PUSHR, R_RAX);
+ output_irexpr(ic, b, o.a);
+ as_opr(ic.s, OP_POPR, R_RCX);
+ as_modrr(ic.s, OP_ADDRM, R_RAX, R_RCX);
+ } else if kind == IOP_AND {
+ output_irexpr(ic, b, o.b);
+ as_opr(ic.s, OP_PUSHR, R_RAX);
+ output_irexpr(ic, b, o.a);
+ as_opr(ic.s, OP_POPR, R_RCX);
+ as_modrr(ic.s, OP_ANDRM, R_RAX, R_RCX);
+ } else if kind == IOP_OR {
+ output_irexpr(ic, b, o.b);
+ as_opr(ic.s, OP_PUSHR, R_RAX);
+ output_irexpr(ic, b, o.a);
+ as_opr(ic.s, OP_POPR, R_RCX);
+ as_modrr(ic.s, OP_ORRM, R_RAX, R_RCX);
+ } else if kind == IOP_XOR {
+ output_irexpr(ic, b, o.b);
+ as_opr(ic.s, OP_PUSHR, R_RAX);
+ output_irexpr(ic, b, o.a);
+ as_opr(ic.s, OP_POPR, R_RCX);
+ as_modrr(ic.s, OP_XORRM, R_RAX, R_RCX);
+ } else if kind == IOP_DIV {
+ output_irexpr(ic, b, o.b);
+ as_opr(ic.s, OP_PUSHR, R_RAX);
+ output_irexpr(ic, b, o.a);
+ as_opr(ic.s, OP_POPR, R_RCX);
+ as_modrr(ic.s, OP_XORRM, R_RDX, R_RDX);
+ as_modrr(ic.s, OP_TESTRM, R_RAX, R_RAX);
+ as_modrr(ic.s, OP_SETCC + CC_S, 0, R_RDX);
+ as_modr(ic.s, OP_NEGM, R_RDX);
+ as_modr(ic.s, OP_IDIVM, R_RCX);
+ } else if kind == IOP_MOD {
+ output_irexpr(ic, b, o.b);
+ as_opr(ic.s, OP_PUSHR, R_RAX);
+ output_irexpr(ic, b, o.a);
+ as_opr(ic.s, OP_POPR, R_RCX);
+ as_modrr(ic.s, OP_XORRM, R_RDX, R_RDX);
+ as_modrr(ic.s, OP_TESTRM, R_RAX, R_RAX);
+ as_modrr(ic.s, OP_SETCC + CC_S, 0, R_RDX);
+ as_modr(ic.s, OP_NEGM, R_RDX);
+ as_modr(ic.s, OP_IDIVM, R_RCX);
+ as_modrr(ic.s, OP_MOVE, R_RAX, R_RDX);
+ } else if kind == IOP_LSH {
+ output_irexpr(ic, b, o.b);
+ as_opr(ic.s, OP_PUSHR, R_RAX);
+ output_irexpr(ic, b, o.a);
+ as_opr(ic.s, OP_POPR, R_RCX);
+ as_modr(ic.s, OP_SHLM, R_RAX);
+ } else if kind == IOP_RSH {
+ output_irexpr(ic, b, o.b);
+ as_opr(ic.s, OP_PUSHR, R_RAX);
+ output_irexpr(ic, b, o.a);
+ as_opr(ic.s, OP_POPR, R_RCX);
+ as_modr(ic.s, OP_SHRM, R_RAX);
+ } else if kind == IOP_MUL {
+ output_irexpr(ic, b, o.b);
+ as_opr(ic.s, OP_PUSHR, R_RAX);
+ output_irexpr(ic, b, o.a);
+ as_opr(ic.s, OP_POPR, R_RCX);
+ as_modr(ic.s, OP_IMULM, R_RCX);
+ } else if kind == IOP_SUB {
+ output_irexpr(ic, b, o.b);
+ as_opr(ic.s, OP_PUSHR, R_RAX);
+ output_irexpr(ic, b, o.a);
+ as_opr(ic.s, OP_POPR, R_RCX);
+ as_modrr(ic.s, OP_SUBRM, R_RAX, R_RCX);
+ } else if kind == IOP_EQ {
+ output_irexpr(ic, b, o.b);
+ as_opr(ic.s, OP_PUSHR, R_RAX);
+ output_irexpr(ic, b, o.a);
+ as_opr(ic.s, OP_POPR, R_RCX);
+ as_modrr(ic.s, OP_MOVE, R_RDX, R_RAX);
+ as_modrr(ic.s, OP_XORRM, R_RAX, R_RAX);
+ as_modrr(ic.s, OP_CMPRM, R_RDX, R_RCX);
+ as_modrr(ic.s, OP_SETCC + CC_E, 0, R_RAX);
+ } else if kind == IOP_NE {
+ output_irexpr(ic, b, o.b);
+ as_opr(ic.s, OP_PUSHR, R_RAX);
+ output_irexpr(ic, b, o.a);
+ as_opr(ic.s, OP_POPR, R_RCX);
+ as_modrr(ic.s, OP_MOVE, R_RDX, R_RAX);
+ as_modrr(ic.s, OP_XORRM, R_RAX, R_RAX);
+ as_modrr(ic.s, OP_CMPRM, R_RDX, R_RCX);
+ as_modrr(ic.s, OP_SETCC + CC_NE, 0, R_RAX);
+ } else if kind == IOP_GT {
+ output_irexpr(ic, b, o.b);
+ as_opr(ic.s, OP_PUSHR, R_RAX);
+ output_irexpr(ic, b, o.a);
+ as_opr(ic.s, OP_POPR, R_RCX);
+ as_modrr(ic.s, OP_MOVE, R_RDX, R_RAX);
+ as_modrr(ic.s, OP_XORRM, R_RAX, R_RAX);
+ as_modrr(ic.s, OP_CMPRM, R_RDX, R_RCX);
+ as_modrr(ic.s, OP_SETCC + CC_G, 0, R_RAX);
+ } else if kind == IOP_GE {
+ output_irexpr(ic, b, o.b);
+ as_opr(ic.s, OP_PUSHR, R_RAX);
+ output_irexpr(ic, b, o.a);
+ as_opr(ic.s, OP_POPR, R_RCX);
+ as_modrr(ic.s, OP_MOVE, R_RDX, R_RAX);
+ as_modrr(ic.s, OP_XORRM, R_RAX, R_RAX);
+ as_modrr(ic.s, OP_CMPRM, R_RDX, R_RCX);
+ as_modrr(ic.s, OP_SETCC + CC_GE, 0, R_RAX);
+ } else if kind == IOP_LT {
+ output_irexpr(ic, b, o.b);
+ as_opr(ic.s, OP_PUSHR, R_RAX);
+ output_irexpr(ic, b, o.a);
+ as_opr(ic.s, OP_POPR, R_RCX);
+ as_modrr(ic.s, OP_MOVE, R_RDX, R_RAX);
+ as_modrr(ic.s, OP_XORRM, R_RAX, R_RAX);
+ as_modrr(ic.s, OP_CMPRM, R_RDX, R_RCX);
+ as_modrr(ic.s, OP_SETCC + CC_L, 0, R_RAX);
+ } else if kind == IOP_LE {
+ output_irexpr(ic, b, o.b);
+ as_opr(ic.s, OP_PUSHR, R_RAX);
+ output_irexpr(ic, b, o.a);
+ as_opr(ic.s, OP_POPR, R_RCX);
+ as_modrr(ic.s, OP_MOVE, R_RDX, R_RAX);
+ as_modrr(ic.s, OP_XORRM, R_RAX, R_RAX);
+ as_modrr(ic.s, OP_CMPRM, R_RDX, R_RCX);
+ as_modrr(ic.s, OP_SETCC + CC_LE, 0, R_RAX);
+ } else {
+ cdie(ic.c, "invalid op");
+ }
+}