use crate::codegen::MachineFunction;
use crate::mc_assembler::encode_x86_64;
use crate::mc_inst::MCInst;
use crate::object_writer::{ObjectFormat, ObjectWriter, SectionFlags};
use crate::opcode::Opcode;
use crate::value::ValueRef;
pub fn compile_to_object(funcs: &[&ValueRef], target_triple: &str) -> Vec<u8> {
let mut emitter = ObjectEmitter::new(ObjectFormat::ELF, target_triple);
for func in funcs {
emitter.add_function(func);
}
emitter.finish()
}
pub fn compile_to_macho(funcs: &[&ValueRef], target_triple: &str) -> Vec<u8> {
let mut emitter = ObjectEmitter::new(ObjectFormat::MachO, target_triple);
for func in funcs {
emitter.add_function(func);
}
emitter.finish()
}
pub fn compile_to_coff(funcs: &[&ValueRef], target_triple: &str) -> Vec<u8> {
let mut emitter = ObjectEmitter::new(ObjectFormat::COFF, target_triple);
for func in funcs {
emitter.add_function(func);
}
emitter.finish()
}
pub fn compile_to_wasm(funcs: &[&ValueRef], target_triple: &str) -> Vec<u8> {
let mut emitter = ObjectEmitter::new(ObjectFormat::Wasm, target_triple);
for func in funcs {
emitter.add_function(func);
}
emitter.finish()
}
pub struct ObjectEmitter {
writer: ObjectWriter,
text_data: Vec<u8>,
data_data: Vec<u8>,
rodata_data: Vec<u8>,
bss_size: u64,
function_count: usize,
global_count: usize,
}
impl ObjectEmitter {
pub fn new(format: ObjectFormat, target_triple: &str) -> Self {
Self {
writer: ObjectWriter::new(format, target_triple),
text_data: Vec::new(),
data_data: Vec::new(),
rodata_data: Vec::new(),
bss_size: 0,
function_count: 0,
global_count: 0,
}
}
pub fn add_function(&mut self, func: &ValueRef) {
let f = func.borrow();
if !f.is_function() || f.num_operands == 0 {
return;
}
let mut mf = MachineFunction::new(&f.name);
for op in &f.operands {
let bb = op.borrow();
if bb.is_basic_block() {
for inst_val in &bb.operands {
let inst = inst_val.borrow();
if inst.is_instruction() {
if let Some(ref opcode) = inst.opcode {
let mc_opcode = match *opcode {
Opcode::Ret => 0xC3,
Opcode::Add => 0x01,
Opcode::Sub => 0x29,
Opcode::Call => 0xE8,
Opcode::Br => 0xEB,
_ => 0x90, };
let mc_inst = MCInst::new(mc_opcode);
if let Some(encoded) = encode_x86_64(&mc_inst) {
self.text_data.extend_from_slice(&encoded);
}
}
}
}
}
}
self.function_count += 1;
}
pub fn add_global_data(&mut self, data: &[u8]) {
self.data_data.extend_from_slice(data);
self.global_count += 1;
}
pub fn add_rodata(&mut self, data: &[u8]) {
self.rodata_data.extend_from_slice(data);
}
pub fn add_bss(&mut self, size: u64) {
self.bss_size += size;
}
pub fn finish(&mut self) -> Vec<u8> {
if !self.text_data.is_empty() {
self.writer.add_section(
".text",
std::mem::take(&mut self.text_data),
SectionFlags::text(),
);
}
if !self.data_data.is_empty() {
self.writer.add_section(
".data",
std::mem::take(&mut self.data_data),
SectionFlags::data(),
);
}
if !self.rodata_data.is_empty() {
self.writer.add_section(
".rodata",
std::mem::take(&mut self.rodata_data),
SectionFlags::rodata(),
);
}
if self.bss_size > 0 {
self.writer.add_bss_section(".bss", self.bss_size);
}
self.writer.write()
}
pub fn function_count(&self) -> usize {
self.function_count
}
pub fn global_count(&self) -> usize {
self.global_count
}
}
impl ObjectEmitter {
pub fn emit_elf(&mut self) -> Vec<u8> {
let mut buf = Vec::new();
buf.extend_from_slice(&self.build_elf_header());
let text_offset = buf.len() as u64;
buf.extend_from_slice(&self.text_data);
let rodata_offset = buf.len() as u64;
buf.extend_from_slice(&self.rodata_data);
let data_offset = buf.len() as u64;
buf.extend_from_slice(&self.data_data);
let shdr_offset = buf.len() as u64;
buf.extend_from_slice(&self.build_elf_section_headers(
text_offset,
rodata_offset,
data_offset,
shdr_offset,
));
buf
}
fn build_elf_header(&self) -> Vec<u8> {
let mut hdr = Vec::with_capacity(64);
hdr.extend_from_slice(&[0x7f, b'E', b'L', b'F']); hdr.push(2); hdr.push(1); hdr.push(1); hdr.push(0); hdr.push(0); hdr.extend_from_slice(&[0u8; 7]); hdr.extend_from_slice(&1u16.to_le_bytes()); hdr.extend_from_slice(&0x3Eu16.to_le_bytes()); hdr.extend_from_slice(&1u32.to_le_bytes()); hdr.extend_from_slice(&0u64.to_le_bytes()); hdr.extend_from_slice(&0u64.to_le_bytes()); hdr.extend_from_slice(&0u64.to_le_bytes()); hdr.extend_from_slice(&0u32.to_le_bytes()); hdr.extend_from_slice(&64u16.to_le_bytes()); hdr.extend_from_slice(&0u16.to_le_bytes()); hdr.extend_from_slice(&0u16.to_le_bytes()); hdr.extend_from_slice(&64u16.to_le_bytes()); hdr.extend_from_slice(&4u16.to_le_bytes()); hdr.extend_from_slice(&3u16.to_le_bytes()); hdr
}
fn build_elf_section_headers(
&self,
text_off: u64,
rodata_off: u64,
data_off: u64,
shdr_off: u64,
) -> Vec<u8> {
let mut sh = Vec::new();
sh.extend_from_slice(&[0u8; 64]);
sh.extend_from_slice(&1u32.to_le_bytes()); sh.extend_from_slice(&1u32.to_le_bytes()); sh.extend_from_slice(&6u64.to_le_bytes()); sh.extend_from_slice(&0u64.to_le_bytes()); sh.extend_from_slice(&text_off.to_le_bytes()); sh.extend_from_slice(&(self.text_data.len() as u64).to_le_bytes()); sh.extend_from_slice(&0u32.to_le_bytes()); sh.extend_from_slice(&0u32.to_le_bytes()); sh.extend_from_slice(&16u64.to_le_bytes()); sh.extend_from_slice(&0u64.to_le_bytes()); sh.extend_from_slice(&7u32.to_le_bytes());
sh.extend_from_slice(&1u32.to_le_bytes());
sh.extend_from_slice(&2u64.to_le_bytes()); sh.extend_from_slice(&0u64.to_le_bytes());
sh.extend_from_slice(&rodata_off.to_le_bytes());
sh.extend_from_slice(&(self.rodata_data.len() as u64).to_le_bytes());
sh.extend_from_slice(&0u32.to_le_bytes());
sh.extend_from_slice(&0u32.to_le_bytes());
sh.extend_from_slice(&16u64.to_le_bytes());
sh.extend_from_slice(&0u64.to_le_bytes());
sh.extend_from_slice(&15u32.to_le_bytes());
sh.extend_from_slice(&1u32.to_le_bytes());
sh.extend_from_slice(&3u64.to_le_bytes()); sh.extend_from_slice(&0u64.to_le_bytes());
sh.extend_from_slice(&data_off.to_le_bytes());
sh.extend_from_slice(&(self.data_data.len() as u64).to_le_bytes());
sh.extend_from_slice(&0u32.to_le_bytes());
sh.extend_from_slice(&0u32.to_le_bytes());
sh.extend_from_slice(&16u64.to_le_bytes());
sh.extend_from_slice(&0u64.to_le_bytes());
sh
}
pub fn emit_macho(&mut self) -> Vec<u8> {
let mut buf = Vec::new();
buf.extend_from_slice(&self.build_macho_header());
buf.extend_from_slice(&self.build_macho_load_commands());
buf.extend_from_slice(&self.text_data);
buf.extend_from_slice(&self.rodata_data);
buf.extend_from_slice(&self.data_data);
buf
}
fn build_macho_header(&self) -> Vec<u8> {
let mut h = Vec::with_capacity(32);
h.extend_from_slice(&0x01000007u32.to_le_bytes()); h.extend_from_slice(&0x01000007u32.to_le_bytes()); h.extend_from_slice(&0x80000003u32.to_le_bytes()); h.extend_from_slice(&1u32.to_le_bytes()); h.extend_from_slice(&1u32.to_le_bytes()); h.extend_from_slice(&0u32.to_le_bytes()); h.extend_from_slice(&0u32.to_le_bytes()); h.extend_from_slice(&0u32.to_le_bytes()); h
}
fn build_macho_load_commands(&self) -> Vec<u8> {
let mut lc = Vec::new();
lc.extend_from_slice(&0x19u32.to_le_bytes()); lc.extend_from_slice(&0u32.to_le_bytes()); lc.extend_from_slice(b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
lc.extend_from_slice(&0u64.to_le_bytes()); lc.extend_from_slice(&0u64.to_le_bytes()); lc.extend_from_slice(&0u64.to_le_bytes()); lc.extend_from_slice(&0u64.to_le_bytes()); lc.extend_from_slice(&7u32.to_le_bytes()); lc.extend_from_slice(&7u32.to_le_bytes()); lc.extend_from_slice(&3u32.to_le_bytes()); lc.extend_from_slice(&0u32.to_le_bytes()); lc.extend_from_slice(b"__text\0\0\0\0\0\0\0\0\0\0");
lc.extend_from_slice(b"__TEXT\0\0\0\0\0\0\0\0\0\0");
lc.extend_from_slice(&0u64.to_le_bytes()); lc.extend_from_slice(&(self.text_data.len() as u64).to_le_bytes()); lc.extend_from_slice(&0u32.to_le_bytes()); lc.extend_from_slice(&2u32.to_le_bytes()); lc.extend_from_slice(&0u32.to_le_bytes()); lc.extend_from_slice(&0u32.to_le_bytes()); lc.extend_from_slice(&0x80000400u32.to_le_bytes()); lc.extend_from_slice(&0u32.to_le_bytes()); lc.extend_from_slice(&0u32.to_le_bytes()); lc.extend_from_slice(&0u32.to_le_bytes()); lc.extend_from_slice(b"__rodata\0\0\0\0\0\0\0\0\0");
lc.extend_from_slice(b"__TEXT\0\0\0\0\0\0\0\0\0\0");
lc.extend_from_slice(&0u64.to_le_bytes());
lc.extend_from_slice(&(self.rodata_data.len() as u64).to_le_bytes());
lc.extend_from_slice(&0u32.to_le_bytes());
lc.extend_from_slice(&2u32.to_le_bytes());
lc.extend_from_slice(&0u32.to_le_bytes());
lc.extend_from_slice(&0u32.to_le_bytes());
lc.extend_from_slice(&0u32.to_le_bytes());
lc.extend_from_slice(&0u32.to_le_bytes());
lc.extend_from_slice(&0u32.to_le_bytes());
lc.extend_from_slice(&0u32.to_le_bytes());
lc.extend_from_slice(b"__data\0\0\0\0\0\0\0\0\0\0");
lc.extend_from_slice(b"__DATA\0\0\0\0\0\0\0\0\0\0");
lc.extend_from_slice(&0u64.to_le_bytes());
lc.extend_from_slice(&(self.data_data.len() as u64).to_le_bytes());
lc.extend_from_slice(&0u32.to_le_bytes());
lc.extend_from_slice(&2u32.to_le_bytes());
lc.extend_from_slice(&0u32.to_le_bytes());
lc.extend_from_slice(&0u32.to_le_bytes());
lc.extend_from_slice(&0u32.to_le_bytes());
lc.extend_from_slice(&0u32.to_le_bytes());
lc.extend_from_slice(&0u32.to_le_bytes());
lc.extend_from_slice(&0u32.to_le_bytes());
lc
}
pub fn emit_coff(&mut self) -> Vec<u8> {
let mut buf = Vec::new();
buf.extend_from_slice(&self.build_coff_header());
let text_header =
self.build_coff_section_header(".text", self.text_data.len() as u32, 0x60500020);
let data_header =
self.build_coff_section_header(".data", self.data_data.len() as u32, 0xC0500040);
let rodata_header =
self.build_coff_section_header(".rdata", self.rodata_data.len() as u32, 0x40500040);
buf.extend_from_slice(&text_header);
buf.extend_from_slice(&data_header);
buf.extend_from_slice(&rodata_header);
buf.extend_from_slice(&self.text_data);
buf.extend_from_slice(&self.data_data);
buf.extend_from_slice(&self.rodata_data);
buf.extend_from_slice(&self.build_coff_symbol_table());
buf.extend_from_slice(&self.build_coff_string_table());
buf
}
fn build_coff_header(&self) -> Vec<u8> {
let mut h = Vec::with_capacity(20);
h.extend_from_slice(&0x8664u16.to_le_bytes()); h.extend_from_slice(&3u16.to_le_bytes()); h.extend_from_slice(&0u32.to_le_bytes()); h.extend_from_slice(&0u32.to_le_bytes()); h.extend_from_slice(&0u32.to_le_bytes()); h.extend_from_slice(&0u16.to_le_bytes()); h.extend_from_slice(&0u16.to_le_bytes()); h
}
fn build_coff_section_header(&self, name: &str, size: u32, characteristics: u32) -> Vec<u8> {
let mut sh = Vec::with_capacity(40);
let mut name_bytes = [0u8; 8];
let name_bytes_src = name.as_bytes();
let copy_len = name_bytes_src.len().min(8);
name_bytes[..copy_len].copy_from_slice(&name_bytes_src[..copy_len]);
sh.extend_from_slice(&name_bytes);
sh.extend_from_slice(&size.to_le_bytes()); sh.extend_from_slice(&0u32.to_le_bytes()); sh.extend_from_slice(&size.to_le_bytes()); sh.extend_from_slice(&0u32.to_le_bytes()); sh.extend_from_slice(&0u32.to_le_bytes()); sh.extend_from_slice(&0u32.to_le_bytes()); sh.extend_from_slice(&0u16.to_le_bytes()); sh.extend_from_slice(&0u16.to_le_bytes()); sh.extend_from_slice(&characteristics.to_le_bytes());
sh
}
fn build_coff_symbol_table(&self) -> Vec<u8> {
let mut sym = Vec::with_capacity(18);
sym.extend_from_slice(b".file\0\0\0"); sym.extend_from_slice(&0u32.to_le_bytes()); sym.extend_from_slice(&0i16.to_le_bytes()); sym.extend_from_slice(&0u16.to_le_bytes()); sym.extend_from_slice(&0u8.to_le_bytes()); sym.extend_from_slice(&0u8.to_le_bytes()); sym
}
fn build_coff_string_table(&self) -> Vec<u8> {
let len: u32 = 4; let mut st = Vec::with_capacity(4);
st.extend_from_slice(&len.to_le_bytes());
st
}
pub fn emit_wasm(&mut self) -> Vec<u8> {
let mut buf = Vec::new();
buf.extend_from_slice(&[0x00, 0x61, 0x73, 0x6D]); buf.extend_from_slice(&1u32.to_le_bytes()); buf.extend_from_slice(&self.build_wasm_type_section());
buf.extend_from_slice(&self.build_wasm_function_section());
buf.extend_from_slice(&self.build_wasm_code_section());
if self.function_count > 0 {
buf.extend_from_slice(&self.build_wasm_export_section());
}
buf
}
fn build_wasm_type_section(&self) -> Vec<u8> {
let mut s = Vec::new();
s.push(0x01); let body: Vec<u8> = vec![0x01, 0x60, 0x00, 0x00]; s.extend_from_slice(&encode_wasm_uleb128(body.len() as u64));
s.extend_from_slice(&body);
s
}
fn build_wasm_function_section(&self) -> Vec<u8> {
let mut s = Vec::new();
s.push(0x03); let body: Vec<u8> = vec![0x01, 0x00]; s.extend_from_slice(&encode_wasm_uleb128(body.len() as u64));
s.extend_from_slice(&body);
s
}
fn build_wasm_code_section(&self) -> Vec<u8> {
let mut s = Vec::new();
s.push(0x0A); let func_body: Vec<u8> = vec![0x00, 0x01, 0x0B]; let body: Vec<u8> = {
let mut b = Vec::new();
b.push(0x01); b.extend_from_slice(&encode_wasm_uleb128(func_body.len() as u64));
b.extend_from_slice(&func_body);
b
};
s.extend_from_slice(&encode_wasm_uleb128(body.len() as u64));
s.extend_from_slice(&body);
s
}
fn build_wasm_export_section(&self) -> Vec<u8> {
let mut s = Vec::new();
s.push(0x07); let export_name = "main";
let mut body = Vec::new();
body.push(0x01); body.extend_from_slice(&encode_wasm_uleb128(export_name.len() as u64));
body.extend_from_slice(export_name.as_bytes());
body.push(0x00); body.push(0x00); s.extend_from_slice(&encode_wasm_uleb128(body.len() as u64));
s.extend_from_slice(&body);
s
}
}
pub fn encode_wasm_uleb128(mut val: u64) -> Vec<u8> {
let mut bytes = Vec::new();
loop {
let mut byte = (val & 0x7F) as u8;
val >>= 7;
if val != 0 {
byte |= 0x80;
}
bytes.push(byte);
if val == 0 {
break;
}
}
bytes
}
pub fn encode_wasm_sleb128(mut val: i64) -> Vec<u8> {
let mut bytes = Vec::new();
loop {
let mut byte = (val as u8) & 0x7F;
val >>= 7;
if (val == 0 && (byte & 0x40) == 0) || (val == -1 && (byte & 0x40) != 0) {
bytes.push(byte);
break;
}
byte |= 0x80;
bytes.push(byte);
}
bytes
}
#[derive(Debug, Clone)]
pub struct EmittedSymbol {
pub name: String,
pub section_index: u32,
pub value: u64,
pub size: u64,
pub binding: SymbolBinding,
pub sym_type: SymbolType,
pub visibility: SymbolVisibility,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SymbolBinding {
Local,
Global,
Weak,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SymbolType {
NoType,
Object,
Function,
Section,
File,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SymbolVisibility {
Default,
Hidden,
Protected,
}
impl ObjectEmitter {
pub fn emit_elf_symtab(&self) -> (Vec<u8>, Vec<u8>) {
let mut strtab = Vec::new();
strtab.push(0u8); let mut symtab = Vec::new();
symtab.extend_from_slice(&[0u8; 24]);
for i in 0..self.function_count {
let name = format!("func_{}", i);
let name_offset = strtab.len() as u32;
strtab.extend_from_slice(name.as_bytes());
strtab.push(0);
symtab.extend_from_slice(&name_offset.to_le_bytes());
symtab.push(0x12);
symtab.push(0);
symtab.extend_from_slice(&1u16.to_le_bytes());
symtab.extend_from_slice(&0u64.to_le_bytes());
symtab.extend_from_slice(&0u64.to_le_bytes());
}
(symtab, strtab)
}
pub fn emit_macho_symtab(&self) -> (Vec<u8>, Vec<u8>) {
let mut strtab = Vec::new();
strtab.extend_from_slice(b"\0\0"); strtab.push(0u8);
let mut symtab = Vec::new();
for i in 0..self.function_count {
let name = format!("_func_{}", i);
let name_idx = strtab.len() as u32;
strtab.extend_from_slice(name.as_bytes());
strtab.push(0);
symtab.extend_from_slice(&name_idx.to_le_bytes());
symtab.push(0x0F);
symtab.push(1);
symtab.extend_from_slice(&0u16.to_le_bytes());
symtab.extend_from_slice(&0u64.to_le_bytes());
}
(symtab, strtab)
}
pub fn emit_coff_full_symtab(&self) -> Vec<u8> {
let mut syms = Vec::new();
for i in 0..self.function_count {
let name = format!("func_{}", i);
let mut name_bytes = [0u8; 8];
let src = name.as_bytes();
name_bytes[..src.len().min(8)].copy_from_slice(&src[..src.len().min(8)]);
syms.extend_from_slice(&name_bytes);
syms.extend_from_slice(&0u32.to_le_bytes()); syms.extend_from_slice(&1i16.to_le_bytes()); syms.extend_from_slice(&0x20u16.to_le_bytes()); syms.push(2); syms.push(0); }
syms
}
}
#[derive(Debug, Clone)]
pub struct ElfRelocation {
pub offset: u64,
pub symbol_index: u32,
pub reloc_type: u32,
pub addend: i64,
}
pub mod x86_64_reloc {
pub const R_X86_64_NONE: u32 = 0;
pub const R_X86_64_64: u32 = 1;
pub const R_X86_64_PC32: u32 = 2;
pub const R_X86_64_GOT32: u32 = 3;
pub const R_X86_64_PLT32: u32 = 4;
pub const R_X86_64_32: u32 = 10;
pub const R_X86_64_32S: u32 = 11;
pub const R_X86_64_PC64: u32 = 24;
pub const R_X86_64_GOTPCREL: u32 = 9;
pub const R_X86_64_REX_GOTPCRELX: u32 = 42;
}
pub mod aarch64_reloc {
pub const R_AARCH64_NONE: u32 = 0;
pub const R_AARCH64_ABS64: u32 = 257;
pub const R_AARCH64_ABS32: u32 = 258;
pub const R_AARCH64_CALL26: u32 = 283;
pub const R_AARCH64_ADR_PREL_PG_HI21: u32 = 275;
pub const R_AARCH64_ADD_ABS_LO12_NC: u32 = 277;
pub const R_AARCH64_LDST8_ABS_LO12_NC: u32 = 278;
pub const R_AARCH64_LDST32_ABS_LO12_NC: u32 = 280;
pub const R_AARCH64_LDST64_ABS_LO12_NC: u32 = 281;
pub const R_AARCH64_CONDBR19: u32 = 281;
pub const R_AARCH64_JUMP26: u32 = 282;
}
pub mod riscv64_reloc {
pub const R_RISCV_NONE: u32 = 0;
pub const R_RISCV_32: u32 = 1;
pub const R_RISCV_64: u32 = 2;
pub const R_RISCV_RELATIVE: u32 = 3;
pub const R_RISCV_BRANCH: u32 = 16;
pub const R_RISCV_JAL: u32 = 17;
pub const R_RISCV_CALL: u32 = 18;
pub const R_RISCV_CALL_PLT: u32 = 19;
pub const R_RISCV_GOT_HI20: u32 = 20;
pub const R_RISCV_PCREL_HI20: u32 = 23;
pub const R_RISCV_PCREL_LO12_I: u32 = 24;
pub const R_RISCV_PCREL_LO12_S: u32 = 25;
pub const R_RISCV_HI20: u32 = 26;
pub const R_RISCV_LO12_I: u32 = 27;
pub const R_RISCV_LO12_S: u32 = 28;
}
impl ObjectEmitter {
pub fn emit_x86_64_relocations(&self) -> Vec<u8> {
let mut rels = Vec::new();
if self.function_count > 0 {
rels.extend_from_slice(&5u64.to_le_bytes()); rels.extend_from_slice(&x86_64_reloc::R_X86_64_PC32.to_le_bytes()); rels.extend_from_slice(&(-4i64).to_le_bytes()); }
rels
}
pub fn emit_aarch64_relocations(&self) -> Vec<u8> {
let mut rels = Vec::new();
if self.function_count > 0 {
rels.extend_from_slice(&0u64.to_le_bytes());
rels.extend_from_slice(&aarch64_reloc::R_AARCH64_CALL26.to_le_bytes());
rels.extend_from_slice(&0i64.to_le_bytes());
}
rels
}
pub fn emit_riscv64_relocations(&self) -> Vec<u8> {
let mut rels = Vec::new();
if self.function_count > 0 {
rels.extend_from_slice(&0u64.to_le_bytes());
rels.extend_from_slice(&riscv64_reloc::R_RISCV_CALL.to_le_bytes());
rels.extend_from_slice(&0i64.to_le_bytes());
}
rels
}
}
impl ObjectEmitter {
pub fn emit_debug_abbrev(&self) -> Vec<u8> {
let mut d = Vec::new();
d.extend_from_slice(&encode_uleb128(1)); d.extend_from_slice(&encode_uleb128(0x11)); d.push(0x01); d.extend_from_slice(&encode_uleb128(0x25));
d.extend_from_slice(&encode_uleb128(0x08)); d.extend_from_slice(&encode_uleb128(0x0D));
d.extend_from_slice(&encode_uleb128(0x0B)); d.extend_from_slice(&encode_uleb128(0x03));
d.extend_from_slice(&encode_uleb128(0x08)); d.extend_from_slice(&encode_uleb128(0x11));
d.extend_from_slice(&encode_uleb128(0x01)); d.extend_from_slice(&[0, 0]);
d
}
pub fn emit_debug_info(&self) -> Vec<u8> {
let mut d = Vec::new();
d.extend_from_slice(&0u32.to_le_bytes());
d.extend_from_slice(&4u16.to_le_bytes());
d.extend_from_slice(&0u32.to_le_bytes());
d.push(8);
d.extend_from_slice(&encode_uleb128(1));
d.extend_from_slice(b"llvm-native-core 0.1\0");
d.push(12);
d.extend_from_slice(b"output.o\0");
d.extend_from_slice(&0u64.to_le_bytes());
d.push(0);
d
}
pub fn emit_debug_line(&self) -> Vec<u8> {
let mut d = Vec::new();
d.extend_from_slice(&0u32.to_le_bytes());
d.extend_from_slice(&4u16.to_le_bytes());
d.extend_from_slice(&0u32.to_le_bytes());
d.push(1);
d.push(1);
d.push(1);
d.push(-5i8 as u8);
d.push(14);
d.push(13);
d.extend_from_slice(&[0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1]);
d.push(0);
d.push(0);
d.extend_from_slice(&[0, 0, 0, 1]); d
}
pub fn emit_debug_frame(&self) -> Vec<u8> {
let mut d = Vec::new();
d.extend_from_slice(&0u32.to_le_bytes());
d.extend_from_slice(&0xFFFFFFFFu32.to_le_bytes());
d.push(4);
d.extend_from_slice(b"zR\0");
d.extend_from_slice(&encode_uleb128(8));
d.extend_from_slice(&encode_uleb128(0));
d.extend_from_slice(&encode_uleb128(1));
d.extend_from_slice(&encode_sleb128(-8));
d.extend_from_slice(&encode_uleb128(16));
d.push(1);
d.push(0x1B); d.push(0x0C); d.push(7);
d.push(8);
d.push(0x90);
d.push(1);
d.extend_from_slice(&0u32.to_le_bytes());
d.extend_from_slice(&0u32.to_le_bytes());
d.extend_from_slice(&0u64.to_le_bytes());
d.extend_from_slice(&(self.text_data.len() as u64).to_le_bytes());
d.extend_from_slice(&encode_uleb128(0));
d.push(0);
d
}
pub fn emit_debug_loc(&self) -> Vec<u8> {
let mut d = Vec::new();
d.extend_from_slice(&0u64.to_le_bytes()); d.extend_from_slice(&0u64.to_le_bytes()); d.extend_from_slice(&2u16.to_le_bytes()); d.push(0x55); d.push(0x00); d.extend_from_slice(&0u64.to_le_bytes());
d.extend_from_slice(&0u64.to_le_bytes());
d
}
}
pub fn encode_uleb128(mut val: u64) -> Vec<u8> {
let mut bytes = Vec::new();
loop {
let mut byte = (val & 0x7F) as u8;
val >>= 7;
if val != 0 {
byte |= 0x80;
}
bytes.push(byte);
if val == 0 {
break;
}
}
bytes
}
pub fn encode_sleb128(mut val: i64) -> Vec<u8> {
let mut bytes = Vec::new();
loop {
let mut byte = (val as u8) & 0x7F;
val >>= 7;
if (val == 0 && (byte & 0x40) == 0) || (val == -1 && (byte & 0x40) != 0) {
bytes.push(byte);
break;
}
byte |= 0x80;
bytes.push(byte);
}
bytes
}
impl ObjectEmitter {
pub fn encode_for_target(&mut self, func: &ValueRef, target: &str) {
match target {
"x86_64" | "x86-64" | "amd64" => self.encode_x86_64(func),
"aarch64" | "arm64" => self.encode_aarch64(func),
"riscv64" => self.encode_riscv64(func),
_ => self.encode_x86_64(func), }
}
fn encode_x86_64(&mut self, func: &ValueRef) {
let f = func.borrow();
for op in &f.operands {
let bb = op.borrow();
if bb.is_basic_block() {
for inst_val in &bb.operands {
let inst = inst_val.borrow();
if inst.is_instruction() {
if let Some(ref opc) = inst.opcode {
let mc_opc = match *opc {
Opcode::Ret => 0xC3u32,
Opcode::Add => 0x01,
Opcode::Sub => 0x29,
Opcode::Call => 0xE8,
Opcode::Br => 0xEB,
_ => 0x90,
};
let mc_inst = MCInst::new(mc_opc);
if let Some(encoded) = encode_x86_64(&mc_inst) {
self.text_data.extend_from_slice(&encoded);
}
}
}
}
}
}
self.function_count += 1;
}
fn encode_aarch64(&mut self, func: &ValueRef) {
let f = func.borrow();
for op in &f.operands {
let bb = op.borrow();
if bb.is_basic_block() {
for inst_val in &bb.operands {
let inst = inst_val.borrow();
if inst.is_instruction() {
if let Some(ref opc) = inst.opcode {
let encoded = match *opc {
Opcode::Ret => vec![0xC0, 0x03, 0x5F, 0xD6],
Opcode::Add => vec![0x00, 0x00, 0x00, 0x8B],
Opcode::Sub => vec![0x00, 0x00, 0x00, 0xCB],
Opcode::Br => vec![0x00, 0x00, 0x00, 0x14],
_ => vec![0x1F, 0x20, 0x03, 0xD5], };
self.text_data.extend_from_slice(&encoded);
}
}
}
}
}
self.function_count += 1;
}
fn encode_riscv64(&mut self, func: &ValueRef) {
let f = func.borrow();
for op in &f.operands {
let bb = op.borrow();
if bb.is_basic_block() {
for inst_val in &bb.operands {
let inst = inst_val.borrow();
if inst.is_instruction() {
if let Some(ref opc) = inst.opcode {
let encoded = match *opc {
Opcode::Ret => vec![0x67, 0x80, 0x00, 0x00], Opcode::Add => vec![0x33, 0x00, 0x00, 0x00],
Opcode::Sub => vec![0x33, 0x40, 0x00, 0x00],
Opcode::Br => vec![0x6F, 0x00, 0x00, 0x00], _ => vec![0x13, 0x00, 0x00, 0x00], };
self.text_data.extend_from_slice(&encoded);
}
}
}
}
}
self.function_count += 1;
}
}
pub fn detect_object_format(triple: &str) -> crate::object_writer::ObjectFormat {
let lower = triple.to_lowercase();
if lower.contains("wasm") {
return crate::object_writer::ObjectFormat::Wasm;
}
if lower.contains("apple")
|| lower.contains("darwin")
|| lower.contains("macos")
|| lower.contains("ios")
{
return crate::object_writer::ObjectFormat::MachO;
}
if lower.contains("windows")
|| lower.contains("mingw")
|| lower.contains("msvc")
|| lower.contains("cygwin")
{
return crate::object_writer::ObjectFormat::COFF;
}
crate::object_writer::ObjectFormat::ELF
}
pub fn default_entry_point(triple: &str) -> &str {
let lower = triple.to_lowercase();
if lower.contains("windows") && lower.contains("msvc") {
return "mainCRTStartup";
}
if lower.contains("windows") {
return "_mainCRTStartup";
}
if lower.contains("darwin") || lower.contains("macos") {
return "_main";
}
"_start"
}
pub fn code_section_name(triple: &str) -> &str {
let lower = triple.to_lowercase();
if lower.contains("apple")
|| lower.contains("darwin")
|| lower.contains("macos")
|| lower.contains("ios")
{
return "__TEXT,__text";
}
if lower.contains("windows") {
return ".text";
}
".text"
}
pub fn code_section_alignment(triple: &str) -> u64 {
let lower = triple.to_lowercase();
if lower.contains("x86_64") || lower.contains("amd64") {
return 16;
}
if lower.contains("aarch64") {
return 16;
}
if lower.contains("wasm") {
return 1;
}
16
}
pub fn target_supports_pic(triple: &str) -> bool {
let lower = triple.to_lowercase();
!lower.contains("wasm")
}
pub fn default_stack_alignment(triple: &str) -> u32 {
let lower = triple.to_lowercase();
if lower.contains("x86_64") || lower.contains("aarch64") {
return 16;
}
if lower.contains("x86") || lower.contains("i386") || lower.contains("arm") {
return 16;
}
if lower.contains("wasm") {
return 16;
}
16
}
pub fn validate_object_sections(data: &[u8], format: crate::object_writer::ObjectFormat) -> bool {
match format {
crate::object_writer::ObjectFormat::ELF => data.len() >= 64 && &data[0..4] == b"\x7fELF",
crate::object_writer::ObjectFormat::MachO => data.len() >= 32,
crate::object_writer::ObjectFormat::COFF => data.len() >= 20,
crate::object_writer::ObjectFormat::Wasm => data.len() >= 8 && &data[0..4] == b"\0asm",
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_empty_emitter() {
let emitter = ObjectEmitter::new(ObjectFormat::ELF, "x86_64-unknown-linux-gnu");
assert_eq!(emitter.function_count(), 0);
}
#[test]
fn test_add_global_data() {
let mut emitter = ObjectEmitter::new(ObjectFormat::ELF, "x86_64-unknown-linux-gnu");
emitter.add_global_data(&[0x42, 0x00, 0x00, 0x00]);
assert_eq!(emitter.global_count(), 1);
}
#[test]
fn test_format_helpers() {
let funcs: Vec<&ValueRef> = vec![];
assert!(compile_to_object(&funcs, "x86_64-unknown-linux-gnu").len() > 0);
assert!(compile_to_macho(&funcs, "x86_64-apple-macosx").len() > 0);
assert!(compile_to_coff(&funcs, "x86_64-pc-windows-msvc").len() > 0);
assert!(compile_to_wasm(&funcs, "wasm32-unknown-unknown").len() > 0);
}
}