os

An operating system
git clone https://erai.gay/code/os/
Log | Files | Refs | README | LICENSE

commit c78d6b84c9732f62dd0076445727d5807ae1944e
parent 40b0a2c21748fb95d7b3c2455fae94f3a80c41af
Author: erai <erai@omiltem.net>
Date:   Wed,  7 May 2025 13:21:36 -0400

isolate x86 specific stuff

Diffstat:
Mas.om | 373+------------------------------------------------------------------------------
Mbootstrap.sh | 2+-
Mcc1.om | 761-------------------------------------------------------------------------------
Mir.om | 740-------------------------------------------------------------------------------
Mircout.om | 2+-
Mlexer.om | 2+-
Msyscall.om | 185+++++++++++--------------------------------------------------------------------
Asyscall.x86.om | 158+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ax86.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"); + } +}