mirror of
https://github.com/Noratrieb/jompiler.git
synced 2026-01-14 14:05:01 +01:00
prepare stack
This commit is contained in:
parent
767cebafd8
commit
c0a2c8d1aa
3 changed files with 129 additions and 30 deletions
3
dump-main.gdb
Normal file
3
dump-main.gdb
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
set disassembly-flavor intel
|
||||||
|
set style enabled on
|
||||||
|
disas main
|
||||||
141
index.js
141
index.js
|
|
@ -415,7 +415,6 @@ function lower(ast) {
|
||||||
array[6] = 0xff;
|
array[6] = 0xff;
|
||||||
array[7] = 0xff;
|
array[7] = 0xff;
|
||||||
}
|
}
|
||||||
console.log(array);
|
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -456,15 +455,70 @@ function lower(ast) {
|
||||||
|
|
||||||
const REG_IGNORED = 0;
|
const REG_IGNORED = 0;
|
||||||
function modRm(mod, rm, reg) {
|
function modRm(mod, rm, reg) {
|
||||||
|
assert(mod <= 0b11);
|
||||||
|
assert(rm <= 0b111);
|
||||||
|
assert(reg <= 0b111);
|
||||||
return (mod << 6) | rm | (reg << 3);
|
return (mod << 6) | rm | (reg << 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const REX = {
|
||||||
|
W_OPERAND_SIZE_DETERMINED: 0,
|
||||||
|
W_64_BIT_OPERAND_SIZE: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
function rex(w, r, x, b) {
|
||||||
|
assert(w <= 1);
|
||||||
|
assert(r <= 1);
|
||||||
|
assert(x <= 1);
|
||||||
|
assert(b <= 1);
|
||||||
|
return 0b0100_0000 | (w << 3) | (r << 2) | (x << 1) | b;
|
||||||
|
}
|
||||||
|
|
||||||
class InstBuilder {
|
class InstBuilder {
|
||||||
|
/**
|
||||||
|
* The reserved stack space for locals and intermediary values.
|
||||||
|
* todo todo something
|
||||||
|
*/
|
||||||
#stackSize;
|
#stackSize;
|
||||||
|
#patches;
|
||||||
constructor() {
|
constructor() {
|
||||||
this.out = new Uint8Array();
|
this.out = new Uint8Array();
|
||||||
this.relocations = [];
|
this.relocations = [];
|
||||||
this.#stackSize = 0;
|
this.#stackSize = 0;
|
||||||
|
this.#patches = [];
|
||||||
|
|
||||||
|
this.#prologue();
|
||||||
|
}
|
||||||
|
|
||||||
|
#prologue() {
|
||||||
|
// push rbp
|
||||||
|
this.pushReg64(REG_BP); // push british petroleum
|
||||||
|
// sub rsp, SIZE
|
||||||
|
this.subImm(REG_SP, 0);
|
||||||
|
this.#patches.push({
|
||||||
|
start: this.out.length - 4,
|
||||||
|
patch: () => littleEndian32(this.#stackSize),
|
||||||
|
});
|
||||||
|
// mov rbp, rsp
|
||||||
|
this.movRegReg64(REG_BP, REG_SP);
|
||||||
|
}
|
||||||
|
|
||||||
|
#epilogue() {
|
||||||
|
// mov rsp, rbp
|
||||||
|
this.movRegReg64(REG_SP, REG_BP);
|
||||||
|
// pop rbp
|
||||||
|
this.popReg64(REG_BP);
|
||||||
|
}
|
||||||
|
|
||||||
|
finish() {
|
||||||
|
this.#epilogue();
|
||||||
|
this.#patches.forEach((patch) => {
|
||||||
|
const result = patch.patch();
|
||||||
|
assert(Array.isArray(result));
|
||||||
|
result.forEach((v, i) => {
|
||||||
|
this.out[patch.start + i] = v;
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
reserveStack(size) {
|
reserveStack(size) {
|
||||||
|
|
@ -481,9 +535,38 @@ function lower(ast) {
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
movEaxToEdi() {
|
movRegReg32(to, from) {
|
||||||
// mov edi, eax ; Move r/m32 to r32
|
// ; Move r/m32 to r32
|
||||||
this.#append([0x8b, modRm(MOD_REG, RM_A, RM_DI)]);
|
this.#append([0x8b, modRm(MOD_REG, from, to)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
movRegReg64(to, from) {
|
||||||
|
// ; Move r/m64 to r64.
|
||||||
|
this.#append([
|
||||||
|
rex(REX.W_64_BIT_OPERAND_SIZE, 0, 0, 0),
|
||||||
|
0x8b,
|
||||||
|
modRm(MOD_REG, from, to),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pushReg64(reg) {
|
||||||
|
// 58+rd ; Push r64.
|
||||||
|
this.#append([0x50 | reg]);
|
||||||
|
}
|
||||||
|
|
||||||
|
popReg64(reg) {
|
||||||
|
// 50+rd ; Pop top of stack into r64; increment stack pointer.
|
||||||
|
this.#append([0x58 | reg]);
|
||||||
|
}
|
||||||
|
|
||||||
|
subImm(reg, imm) {
|
||||||
|
// REX.W + 81 /5 id ; Subtract imm32 sign-extended to 64-bits from r/m64.
|
||||||
|
this.#append([
|
||||||
|
rex(REX.W_64_BIT_OPERAND_SIZE, 0, 0, 0),
|
||||||
|
0x81,
|
||||||
|
modRm(MOD_REG, reg, 5 /* /5*/),
|
||||||
|
...littleEndian32(imm),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
call(symbol) {
|
call(symbol) {
|
||||||
|
|
@ -522,7 +605,8 @@ function lower(ast) {
|
||||||
|
|
||||||
// TODO: save
|
// TODO: save
|
||||||
codegenExpr(ib, expr.args[0]);
|
codegenExpr(ib, expr.args[0]);
|
||||||
ib.movEaxToEdi();
|
// mov edi, eax
|
||||||
|
ib.movRegReg32(REG_DI, REG_A);
|
||||||
ib.call(expr.lhs.string);
|
ib.call(expr.lhs.string);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
@ -550,16 +634,22 @@ function lower(ast) {
|
||||||
codegenExpr(ib, stmt.expr);
|
codegenExpr(ib, stmt.expr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
case "return": {
|
||||||
if (stmt.rhs) {
|
if (stmt.rhs) {
|
||||||
codegenExpr(ib, stmt.rhs);
|
codegenExpr(ib, stmt.rhs);
|
||||||
}
|
}
|
||||||
|
ib.finish();
|
||||||
ib.ret();
|
ib.ret();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
assert(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ib.movEaxImm32(0);
|
ib.movEaxImm32(0);
|
||||||
|
ib.finish();
|
||||||
ib.ret();
|
ib.ret();
|
||||||
|
|
||||||
return ib;
|
return ib;
|
||||||
|
|
@ -642,7 +732,7 @@ function lower(ast) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(funcRelocations);
|
console.log("relocations", funcRelocations);
|
||||||
|
|
||||||
let out = new BufferBuilder();
|
let out = new BufferBuilder();
|
||||||
// ident
|
// ident
|
||||||
|
|
@ -782,7 +872,6 @@ function lower(ast) {
|
||||||
size: 0,
|
size: 0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
console.log(rel.buffer.length);
|
|
||||||
// r_offset
|
// r_offset
|
||||||
rel.append([...littleEndian32(relocation.offset), ...[0, 0, 0, 0]]);
|
rel.append([...littleEndian32(relocation.offset), ...[0, 0, 0, 0]]);
|
||||||
// r_info type,sym
|
// r_info type,sym
|
||||||
|
|
@ -918,20 +1007,13 @@ function lower(ast) {
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
function link(object) {
|
async function link(object) {
|
||||||
// we could use a temporary directory in the future, but let's keep this debuggable for now
|
async function execWithForwardedOutput(command, args) {
|
||||||
const outputFile = "output.o";
|
|
||||||
fs.writeFile(outputFile, object);
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const gcc = spawn("gcc", [outputFile]);
|
const child = spawn(command, args, {
|
||||||
gcc.stdout.on("data", (data) => {
|
stdio: "inherit",
|
||||||
process.stdout.write(data);
|
|
||||||
});
|
});
|
||||||
gcc.stderr.on("data", (data) => {
|
child.on("close", (code) => {
|
||||||
process.stderr.write(data);
|
|
||||||
});
|
|
||||||
gcc.on("close", (code) => {
|
|
||||||
if (code === 0) {
|
if (code === 0) {
|
||||||
resolve();
|
resolve();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -939,13 +1021,26 @@ function link(object) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// we could use a temporary directory in the future, but let's keep this debuggable for now
|
||||||
|
const outputFile = "output.o";
|
||||||
|
fs.writeFile(outputFile, object);
|
||||||
|
|
||||||
|
await execWithForwardedOutput("gcc", [outputFile]);
|
||||||
|
await execWithForwardedOutput("gdb", [
|
||||||
|
"--batch",
|
||||||
|
"--command",
|
||||||
|
"dump-main.gdb",
|
||||||
|
"a.out",
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function compile(input) {
|
async function compile(input) {
|
||||||
const tokens = lex(input);
|
const tokens = lex(input);
|
||||||
console.log(tokens);
|
console.log("tokens", tokens);
|
||||||
const ast = parse(tokens);
|
const ast = parse(tokens);
|
||||||
console.dir(ast, { depth: 20 });
|
console.dir("ast", ast, { depth: 20 });
|
||||||
const object = lower(ast);
|
const object = lower(ast);
|
||||||
|
|
||||||
return link(object);
|
return link(object);
|
||||||
|
|
@ -953,7 +1048,7 @@ async function compile(input) {
|
||||||
|
|
||||||
const fileName = process.argv[2];
|
const fileName = process.argv[2];
|
||||||
const input = await fs.readFile(fileName, "utf-8");
|
const input = await fs.readFile(fileName, "utf-8");
|
||||||
console.log(input);
|
console.log("input", input);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await compile(input);
|
await compile(input);
|
||||||
|
|
|
||||||
5
input.c
5
input.c
|
|
@ -2,10 +2,11 @@
|
||||||
|
|
||||||
int main(int argc)
|
int main(int argc)
|
||||||
{
|
{
|
||||||
exit(thisismyfakeconstantbecauseidonthaveconstant(1));
|
thisismyfakeconstantbecauseidonthaveconstant(1);
|
||||||
|
exit(42);
|
||||||
}
|
}
|
||||||
|
|
||||||
int thisismyfakeconstantbecauseidonthaveconstant(int x)
|
int thisismyfakeconstantbecauseidonthaveconstant(int x)
|
||||||
{
|
{
|
||||||
return 1 + 1;
|
// return 1 + 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue