133 lines
3.7 KiB
Rust
133 lines
3.7 KiB
Rust
use crate::{
|
|
arch::x86_64::*,
|
|
backend::{Instr as BInstr, Program},
|
|
};
|
|
use std::{fs::OpenOptions, io::Write, os::unix::fs::OpenOptionsExt, process::Command};
|
|
|
|
pub fn run() {
|
|
if let Err(err) = linux() {
|
|
println!("{err:?}");
|
|
}
|
|
}
|
|
|
|
fn linux() -> Result<(), CompilerMsg> {
|
|
let mut program = Program::<X86_64>::default();
|
|
let text = b"Hello world!\n";
|
|
let text_sym = program.ro_data("hello_en", text);
|
|
let text2 = "世界、こんにちは!\n";
|
|
let text_sym2 = program.ro_data("hello_jp", text2);
|
|
let hello2 = program.func(
|
|
"hello2",
|
|
[BInstr::Asm(encode(|c| {
|
|
c.mov(ax, 1)?;
|
|
c.mov(di, 1)?;
|
|
c.lea(rsi, text_sym2);
|
|
c.mov(dx, text2.len() as u64)?;
|
|
c.syscall();
|
|
c.ret();
|
|
Ok(())
|
|
})?)],
|
|
);
|
|
let entry = program.func(
|
|
"main",
|
|
[BInstr::Asm(encode(|c| {
|
|
c.mov(rdi, 39)?;
|
|
c.push(rdi)?;
|
|
c.mov(ax, 1)?;
|
|
c.mov(di, 1)?;
|
|
c.lea(rsi, text_sym);
|
|
c.mov(dx, text.len() as u64)?;
|
|
c.syscall();
|
|
c.call(hello2);
|
|
c.mov(ax, 0x3c)?;
|
|
c.pop(rdi)?;
|
|
c.syscall();
|
|
Ok(())
|
|
})?)],
|
|
);
|
|
program.entry = Some(entry);
|
|
let linked = program.compile().expect("failed to compile");
|
|
let binary = linked.to_elf();
|
|
let path = "./x86_64_test";
|
|
write(path, &binary);
|
|
println!("running...");
|
|
let gdb = false;
|
|
let mut proc = if gdb {
|
|
let mut cmd = Command::new("gdb");
|
|
#[rustfmt::skip]
|
|
cmd.args([
|
|
"-q",
|
|
"-ex", "starti",
|
|
"-ex", "layout asm",
|
|
"-ex", "focus next",
|
|
"x86_64_test",
|
|
]);
|
|
cmd
|
|
} else {
|
|
Command::new(path)
|
|
}
|
|
.spawn()
|
|
.expect("failed to run");
|
|
let status = proc.wait().expect("failed to wait");
|
|
if let Some(code) = status.code() {
|
|
std::process::exit(code);
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn windows() -> Result<(), CompilerMsg> {
|
|
let mut program = Program::<X86_64>::default();
|
|
let [get_std_handle, write_file, exit_process] =
|
|
program.external("KERNEL32.dll", ["GetStdHandle", "WriteFile", "ExitProcess"]);
|
|
let text = b"Hello world!\n";
|
|
let text_sym = program.ro_data("hello_en", text);
|
|
let written = program.ro_data("written", [0; 4]);
|
|
let entry = program.func(
|
|
"main",
|
|
[BInstr::Asm(encode(|c| {
|
|
c.sub();
|
|
// stdout
|
|
c.mov(ecx, -11)?;
|
|
c.call_mem(get_std_handle);
|
|
// write
|
|
c.mov(rcx, rax)?;
|
|
c.lea(rdx, text_sym);
|
|
c.mov(r8d, text.len() as u64)?;
|
|
c.lea(r9, written);
|
|
c.mov(mem(rsp, 0x20), 0)?;
|
|
c.call_mem(write_file);
|
|
// exit
|
|
c.mov(ecx, 39)?;
|
|
c.call_mem(exit_process);
|
|
Ok(())
|
|
})?)],
|
|
);
|
|
program.entry = Some(entry);
|
|
let linked = program.compile().expect("failed to compile");
|
|
|
|
let binary = linked.to_pe();
|
|
let path = "./x86_64_test.exe";
|
|
write(path, &binary);
|
|
|
|
let mut cmd = Command::new("wine");
|
|
cmd.arg("x86_64_test");
|
|
let mut proc = cmd.spawn().expect("failed to run");
|
|
let status = proc.wait().expect("failed to wait");
|
|
if let Some(code) = status.code() {
|
|
std::process::exit(code);
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn write(path: &str, binary: &[u8]) {
|
|
let mut file = OpenOptions::new()
|
|
.create(true)
|
|
.write(true)
|
|
.truncate(true)
|
|
.mode(0o750)
|
|
.open(path)
|
|
.expect("Failed to create file");
|
|
file.write_all(binary).expect("Failed to write to file");
|
|
file.sync_all().expect("Failed to sync file");
|
|
}
|