use crate::mc_inst::{MCInst, MCOperand};
use std::collections::HashMap;
pub trait MCStreamer {
fn emit_instruction(&mut self, inst: &MCInst);
fn emit_label(&mut self, label: &str);
fn emit_directive(&mut self, directive: &str, args: &[String]);
fn emit_comment(&mut self, text: &str);
fn emit_blank_line(&mut self);
fn finish(&mut self);
}
pub struct MCAsmStreamer {
pub output: String,
indent: String,
current_section: String,
}
impl MCAsmStreamer {
pub fn new() -> Self {
Self {
output: String::new(),
indent: " ".into(),
current_section: ".text".into(),
}
}
pub fn switch_section(&mut self, section: &str) {
if section != self.current_section {
self.output.push_str(&format!("\n{}\n", section));
self.current_section = section.to_string();
}
}
pub fn emit_data_directive(&mut self, data: &[u8]) {
if data.is_empty() {
return;
}
for chunk in data.chunks(16) {
let bytes_str: Vec<String> = chunk.iter().map(|b| format!("0x{:02x}", b)).collect();
self.output
.push_str(&format!("{} .byte {}\n", self.indent, bytes_str.join(", ")));
}
}
pub fn emit_zero_fill(&mut self, size: u64) {
if size > 0 {
self.output
.push_str(&format!("{} .zero {}\n", self.indent, size));
}
}
pub fn emit_alignment(&mut self, align: u64) {
self.output
.push_str(&format!("{} .align {}\n", self.indent, align));
}
pub fn emit_symbol_directive(&mut self, name: &str, is_global: bool) {
if is_global {
self.output.push_str(&format!(".globl {}\n", name));
}
self.output.push_str(&format!("{}:\n", name));
}
fn format_operand(&self, op: &MCOperand) -> String {
match op {
MCOperand::Reg(r) => format!("%{}", x86_reg_name(*r)),
MCOperand::Imm(v) => format!("${}", v),
MCOperand::FpImm(v) => format!("{}", v),
MCOperand::Expr(e) => format!("{}", e),
MCOperand::Inst(_) => "<inst>".into(),
}
}
}
impl MCStreamer for MCAsmStreamer {
fn emit_instruction(&mut self, inst: &MCInst) {
let mnemonic = x86_mnemonic(inst.opcode);
let ops: Vec<String> = inst
.operands
.iter()
.map(|op| self.format_operand(op))
.collect();
self.output
.push_str(&format!("{}{} {}\n", self.indent, mnemonic, ops.join(", ")));
}
fn emit_label(&mut self, label: &str) {
self.output.push_str(&format!("{}:\n", label));
}
fn emit_directive(&mut self, directive: &str, args: &[String]) {
self.output
.push_str(&format!(".{} {}\n", directive, args.join(" ")));
}
fn emit_comment(&mut self, text: &str) {
self.output.push_str(&format!("# {}\n", text));
}
fn emit_blank_line(&mut self) {
self.output.push('\n');
}
fn finish(&mut self) {}
}
impl Default for MCAsmStreamer {
fn default() -> Self {
Self::new()
}
}
pub fn x86_reg_name(reg_id: u32) -> String {
let s: &str = match reg_id {
0 => "rax",
1 => "rcx",
2 => "rdx",
3 => "rbx",
4 => "rsp",
5 => "rbp",
6 => "rsi",
7 => "rdi",
8 => "r8",
9 => "r9",
10 => "r10",
11 => "r11",
12 => "r12",
13 => "r13",
14 => "r14",
15 => "r15",
16 => "eax",
17 => "ecx",
18 => "edx",
19 => "ebx",
20 => "esp",
21 => "ebp",
22 => "esi",
23 => "edi",
24 => "al",
25 => "cl",
26 => "dl",
27 => "bl",
28 => "ah",
29 => "ch",
30 => "dh",
31 => "bh",
32 => "spl",
33 => "bpl",
34 => "sil",
35 => "dil",
36 => "r8b",
37 => "r9b",
38 => "r10b",
39 => "r11b",
40 => "r12b",
41 => "r13b",
42 => "r14b",
43 => "r15b",
44 => "ax",
45 => "cx",
46 => "dx",
47 => "bx",
48 => "sp",
49 => "bp",
50 => "si",
51 => "di",
52 => "r8w",
53 => "r9w",
54 => "r10w",
55 => "r11w",
56 => "r12w",
57 => "r13w",
58 => "r14w",
59 => "r15w",
64 => "xmm0",
65 => "xmm1",
66 => "xmm2",
67 => "xmm3",
68 => "xmm4",
69 => "xmm5",
70 => "xmm6",
71 => "xmm7",
72 => "xmm8",
73 => "xmm9",
74 => "xmm10",
75 => "xmm11",
76 => "xmm12",
77 => "xmm13",
78 => "xmm14",
79 => "xmm15",
80 => "ymm0",
81 => "ymm1",
82 => "ymm2",
83 => "ymm3",
84 => "ymm4",
85 => "ymm5",
86 => "ymm6",
87 => "ymm7",
88 => "ymm8",
89 => "ymm9",
90 => "ymm10",
91 => "ymm11",
92 => "ymm12",
93 => "ymm13",
94 => "ymm14",
95 => "ymm15",
96 => "es",
97 => "cs",
98 => "ss",
99 => "ds",
100 => "fs",
101 => "gs",
_ => return format!("r{}", reg_id),
};
s.to_string()
}
pub fn x86_mnemonic(opcode: u32) -> &'static str {
match opcode {
0 => "nop",
1 => "mov",
2 => "add",
3 => "sub",
4 => "mul",
5 => "div",
6 => "and",
7 => "or",
8 => "xor",
9 => "shl",
10 => "shr",
11 => "push",
12 => "pop",
13 => "call",
14 => "ret",
15 => "jmp",
16 => "je",
17 => "jne",
18 => "cmp",
19 => "lea",
20 => "inc",
21 => "dec",
22 => "not",
23 => "neg",
24 => "adc",
25 => "sbb",
26 => "test",
27 => "imul",
28 => "idiv",
29 => "sar",
30 => "sal",
31 => "rol",
32 => "ror",
33 => "rcl",
34 => "rcr",
35 => "movsx",
36 => "movzx",
37 => "movsxd",
38 => "cmovo",
39 => "cmovno",
40 => "cmovb",
41 => "cmovae",
42 => "cmove",
43 => "cmovne",
44 => "cmovbe",
45 => "cmova",
46 => "cmovs",
47 => "cmovns",
48 => "cmovp",
49 => "cmovnp",
50 => "cmovl",
51 => "cmovge",
52 => "cmovle",
53 => "cmovg",
54 => "seto",
55 => "setno",
56 => "setb",
57 => "setae",
58 => "sete",
59 => "setne",
60 => "setbe",
61 => "seta",
62 => "sets",
63 => "setns",
64 => "setp",
65 => "setnp",
66 => "setl",
67 => "setge",
68 => "setle",
69 => "setg",
70 => "bswap",
71 => "xchg",
72 => "bt",
73 => "bts",
74 => "btr",
75 => "btc",
76 => "bsf",
77 => "bsr",
78 => "cbw",
79 => "cwde",
80 => "cdqe",
81 => "cwd",
82 => "cdq",
83 => "cqo",
84 => "lahf",
85 => "sahf",
86 => "cmc",
87 => "clc",
88 => "stc",
89 => "cli",
90 => "sti",
91 => "std",
92 => "cld",
93 => "pushf",
94 => "pushfq",
95 => "popf",
96 => "popfq",
97 => "syscall",
98 => "sysret",
99 => "hlt",
100 => "rdtsc",
101 => "cpuid",
102 => "jo",
103 => "jno",
104 => "jb",
105 => "jnb",
106 => "jbe",
107 => "ja",
108 => "js",
109 => "jns",
110 => "jp",
111 => "jnp",
112 => "jl",
113 => "jge",
114 => "jle",
115 => "jg",
116 => "movs",
117 => "stos",
118 => "lods",
119 => "scas",
120 => "load",
121 => "store",
122 => "addss",
123 => "addsd",
124 => "subss",
125 => "subsd",
126 => "mulss",
127 => "mulsd",
128 => "divss",
129 => "divsd",
130 => "ucomiss",
131 => "ucomisd",
132 => "movss",
133 => "movsd",
134 => "xorps",
135 => "xorpd",
136 => "cvtsi2ss",
137 => "cvtsi2sd",
138 => "cvttss2si",
139 => "cvttsd2si",
140 => "movd",
141 => "movq",
142 => "movd_from_xmm",
143 => "movq_from_xmm",
144 => "movss_load",
145 => "movsd_load",
146 => "movss_store",
147 => "movsd_store",
_ => "unknown",
}
}
pub mod x86_opcodes {
pub const NOP: u32 = 0;
pub const MOV: u32 = 1;
pub const ADD: u32 = 2;
pub const SUB: u32 = 3;
pub const MUL: u32 = 4;
pub const DIV: u32 = 5;
pub const AND: u32 = 6;
pub const OR: u32 = 7;
pub const XOR: u32 = 8;
pub const SHL: u32 = 9;
pub const SHR: u32 = 10;
pub const PUSH: u32 = 11;
pub const POP: u32 = 12;
pub const CALL: u32 = 13;
pub const RET: u32 = 14;
pub const JMP: u32 = 15;
pub const JE: u32 = 16;
pub const JNE: u32 = 17;
pub const CMP: u32 = 18;
pub const LEA: u32 = 19;
pub const INC: u32 = 20;
pub const DEC: u32 = 21;
pub const NOT: u32 = 22;
pub const NEG: u32 = 23;
pub const ADC: u32 = 24;
pub const SBB: u32 = 25;
pub const TEST: u32 = 26;
pub const IMUL: u32 = 27;
pub const IDIV: u32 = 28;
pub const SAR: u32 = 29;
pub const SAL: u32 = 30;
pub const ROL: u32 = 31;
pub const ROR: u32 = 32;
pub const RCL: u32 = 33;
pub const RCR: u32 = 34;
pub const MOVSX: u32 = 35;
pub const MOVZX: u32 = 36;
pub const MOVSXD: u32 = 37;
pub const CMOVO: u32 = 38;
pub const CMOVNO: u32 = 39;
pub const CMOVB: u32 = 40;
pub const CMOVAE: u32 = 41;
pub const CMOVE: u32 = 42;
pub const CMOVNE: u32 = 43;
pub const CMOVBE: u32 = 44;
pub const CMOVA: u32 = 45;
pub const CMOVS: u32 = 46;
pub const CMOVNS: u32 = 47;
pub const CMOVP: u32 = 48;
pub const CMOVNP: u32 = 49;
pub const CMOVL: u32 = 50;
pub const CMOVGE: u32 = 51;
pub const CMOVLE: u32 = 52;
pub const CMOVG: u32 = 53;
pub const SETO: u32 = 54;
pub const SETNO: u32 = 55;
pub const SETB: u32 = 56;
pub const SETAE: u32 = 57;
pub const SETE: u32 = 58;
pub const SETNE: u32 = 59;
pub const SETBE: u32 = 60;
pub const SETA: u32 = 61;
pub const SETS: u32 = 62;
pub const SETNS: u32 = 63;
pub const SETP: u32 = 64;
pub const SETNP: u32 = 65;
pub const SETL: u32 = 66;
pub const SETGE: u32 = 67;
pub const SETLE: u32 = 68;
pub const SETG: u32 = 69;
pub const BSWAP: u32 = 70;
pub const XCHG: u32 = 71;
pub const BT: u32 = 72;
pub const BTS: u32 = 73;
pub const BTR: u32 = 74;
pub const BTC: u32 = 75;
pub const BSF: u32 = 76;
pub const BSR: u32 = 77;
pub const CBW: u32 = 78;
pub const CWDE: u32 = 79;
pub const CDQE: u32 = 80;
pub const CWD: u32 = 81;
pub const CDQ: u32 = 82;
pub const CQO: u32 = 83;
pub const LAHF: u32 = 84;
pub const SAHF: u32 = 85;
pub const CMC: u32 = 86;
pub const CLC: u32 = 87;
pub const STC: u32 = 88;
pub const CLI: u32 = 89;
pub const STI: u32 = 90;
pub const STD: u32 = 91;
pub const CLD: u32 = 92;
pub const PUSHF: u32 = 93;
pub const PUSHFQ: u32 = 94;
pub const POPF: u32 = 95;
pub const POPFQ: u32 = 96;
pub const SYSCALL: u32 = 97;
pub const SYSRET: u32 = 98;
pub const HLT: u32 = 99;
pub const RDTSC: u32 = 100;
pub const CPUID: u32 = 101;
pub const JO: u32 = 102;
pub const JNO: u32 = 103;
pub const JB: u32 = 104;
pub const JNB: u32 = 105;
pub const JBE: u32 = 106;
pub const JA: u32 = 107;
pub const JS: u32 = 108;
pub const JNS: u32 = 109;
pub const JP: u32 = 110;
pub const JNP: u32 = 111;
pub const JL: u32 = 112;
pub const JGE: u32 = 113;
pub const JLE: u32 = 114;
pub const JG: u32 = 115;
pub const MOVS: u32 = 116;
pub const STOS: u32 = 117;
pub const LODS: u32 = 118;
pub const SCAS: u32 = 119;
pub const LOAD: u32 = 120;
pub const STORE: u32 = 121;
pub const ADDSS: u32 = 122;
pub const ADDSD: u32 = 123;
pub const SUBSS: u32 = 124;
pub const SUBSD: u32 = 125;
pub const MULSS: u32 = 126;
pub const MULSD: u32 = 127;
pub const DIVSS: u32 = 128;
pub const DIVSD: u32 = 129;
pub const UCOMISS: u32 = 130;
pub const UCOMISD: u32 = 131;
pub const MOVSS: u32 = 132;
pub const MOVSD: u32 = 133;
pub const XORPS: u32 = 134;
pub const XORPD: u32 = 135;
pub const CVTSI2SS: u32 = 136;
pub const CVTSI2SD: u32 = 137;
pub const CVTTSS2SI: u32 = 138;
pub const CVTTSD2SI: u32 = 139;
pub const MOVD: u32 = 140; pub const MOVQ: u32 = 141; pub const MOVD_FROM_XMM: u32 = 142; pub const MOVQ_FROM_XMM: u32 = 143; pub const MOVSS_LOAD: u32 = 144; pub const MOVSD_LOAD: u32 = 145; pub const MOVSS_STORE: u32 = 146; pub const MOVSD_STORE: u32 = 147; }
#[derive(Debug, Clone)]
pub struct MCObjectStreamer {
pub data: Vec<u8>,
pub current_section: String,
pub section_idx: u32,
pub fixups: Vec<MCFixup>,
pub symbols: Vec<MCSymbol>,
pub labels: HashMap<String, u64>,
pub offset: u64,
pub alignment: u32,
section_stack: Vec<SectionState>,
pub gen_dwarf: bool,
pub use_cfi: bool,
pub line_entries: Vec<LineEntry>,
}
#[derive(Debug, Clone)]
struct SectionState {
name: String,
idx: u32,
offset: u64,
alignment: u32,
}
#[derive(Debug, Clone)]
pub struct MCSymbol {
pub name: String,
pub value: u64,
pub section: String,
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 {
None,
Function,
Object,
Section,
File,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SymbolVisibility {
Default,
Hidden,
Protected,
}
#[derive(Debug, Clone)]
pub struct MCFixup {
pub kind: u32,
pub offset: u64,
pub symbol: String,
pub value: i64,
pub section: String,
}
#[derive(Debug, Clone)]
pub struct LineEntry {
pub address: u64,
pub file: String,
pub line: u32,
pub column: u32,
}
#[derive(Debug, Clone)]
pub enum MCFragment {
Data(Vec<u8>),
Align {
pow2: u32,
value: u8,
max_bytes: u64,
},
Fill { size: u64, value: u8 },
Org { address: u64 },
Instruction { bytes: Vec<u8>, mnemonic: String },
}
impl MCObjectStreamer {
pub fn new() -> Self {
Self {
data: Vec::new(),
current_section: String::from(".text"),
section_idx: 1,
fixups: Vec::new(),
symbols: Vec::new(),
labels: HashMap::new(),
offset: 0,
alignment: 4,
section_stack: Vec::new(),
gen_dwarf: false,
use_cfi: false,
line_entries: Vec::new(),
}
}
pub fn emit_instruction_bytes(&mut self, bytes: &[u8], mnemonic: &str) {
self.data.extend_from_slice(bytes);
self.offset += bytes.len() as u64;
}
pub fn emit_label(&mut self, name: &str) {
self.labels.insert(name.to_string(), self.offset);
}
pub fn emit_directive(&mut self, directive: &str, args: &[String]) {
match directive {
"align" => {
if let Some(a) = args.first() {
if let Ok(align) = a.parse::<u32>() {
self.emit_alignment(align, 0);
}
}
}
"p2align" => {
if let Some(a) = args.first() {
if let Ok(pow2) = a.parse::<u32>() {
self.emit_p2align(pow2, 0, 0);
}
}
}
"byte" => {
for a in args {
if let Ok(v) = a.parse::<u8>() {
self.data.push(v);
self.offset += 1;
}
}
}
"word" => {
for a in args {
if let Ok(v) = a.parse::<u16>() {
self.data.extend_from_slice(&v.to_le_bytes());
self.offset += 2;
}
}
}
"long" => {
for a in args {
if let Ok(v) = a.parse::<u32>() {
self.data.extend_from_slice(&v.to_le_bytes());
self.offset += 4;
}
}
}
"quad" => {
for a in args {
if let Ok(v) = a.parse::<u64>() {
self.data.extend_from_slice(&v.to_le_bytes());
self.offset += 8;
}
}
}
"ascii" => {
for a in args {
self.data.extend_from_slice(a.as_bytes());
self.offset += a.len() as u64;
}
}
"asciz" => {
for a in args {
self.data.extend_from_slice(a.as_bytes());
self.data.push(0);
self.offset += (a.len() + 1) as u64;
}
}
"skip" => {
if let Some(a) = args.first() {
if let Ok(count) = a.parse::<usize>() {
let fill = args.get(1).and_then(|s| s.parse::<u8>().ok()).unwrap_or(0);
self.data.resize(self.data.len() + count, fill);
self.offset += count as u64;
}
}
}
"balign" => {
if let Some(a) = args.first() {
if let Ok(align) = a.parse::<u64>() {
let fill = args.get(1).and_then(|s| s.parse::<u8>().ok()).unwrap_or(0);
self.emit_balign(align, fill);
}
}
}
"fill" => {
if args.len() >= 2 {
if let (Ok(size), Ok(val)) = (args[0].parse::<u64>(), args[1].parse::<u8>()) {
for _ in 0..size {
self.data.push(val);
}
self.offset += size;
}
}
}
"org" => {
if let Some(a) = args.first() {
if let Ok(addr) = a.parse::<u64>() {
self.emit_org(addr);
}
}
}
"section" => {
if let Some(name) = args.first() {
self.switch_section(name);
}
}
"global" | "globl" => {
for name in args {
self.emit_symbol_directive(name, SymbolBinding::Global);
}
}
"local" => {
for name in args {
self.emit_symbol_directive(name, SymbolBinding::Local);
}
}
"weak" => {
for name in args {
self.emit_symbol_directive(name, SymbolBinding::Weak);
}
}
"hidden" => {
for _name in args {
}
}
"protected" => {
for _name in args {
}
}
"data_region" => {
}
"end_data_region" => {
}
_ => {}
}
}
pub fn switch_section(&mut self, name: &str) {
self.current_section = name.to_string();
self.section_idx += 1;
self.offset = 0;
}
pub fn push_section(&mut self) {
self.section_stack.push(SectionState {
name: self.current_section.clone(),
idx: self.section_idx,
offset: self.offset,
alignment: self.alignment,
});
}
pub fn pop_section(&mut self) {
if let Some(state) = self.section_stack.pop() {
self.current_section = state.name;
self.section_idx = state.idx;
self.offset = state.offset;
self.alignment = state.alignment;
}
}
pub fn emit_alignment(&mut self, align: u32, fill: u8) {
let mask = align as u64 - 1;
let pad = (align as u64 - (self.offset & mask)) & mask;
for _ in 0..pad {
self.data.push(fill);
}
self.offset += pad;
}
pub fn emit_p2align(&mut self, pow2: u32, _max_bytes: u32, fill: u8) {
let align = 1u64 << pow2;
let mask = align - 1;
let pad = (align - (self.offset & mask)) & mask;
for _ in 0..pad {
self.data.push(fill);
}
self.offset += pad;
}
pub fn emit_balign(&mut self, align: u64, fill: u8) {
let pad = (align - (self.offset % align)) % align;
for _ in 0..pad {
self.data.push(fill);
}
self.offset += pad;
}
pub fn emit_org(&mut self, address: u64) {
if address > self.offset {
let pad = address - self.offset;
for _ in 0..pad {
self.data.push(0);
}
self.offset = address;
}
}
pub fn emit_symbol_directive(&mut self, name: &str, binding: SymbolBinding) {
self.symbols.push(MCSymbol {
name: name.to_string(),
value: self.offset,
section: self.current_section.clone(),
size: 0,
binding,
sym_type: SymbolType::None,
visibility: SymbolVisibility::Default,
});
}
pub fn emit_fixup(&mut self, kind: u32, symbol: &str, value: i64) {
self.fixups.push(MCFixup {
kind,
offset: self.offset,
symbol: symbol.to_string(),
value,
section: self.current_section.clone(),
});
}
pub fn emit_fragment(&mut self, fragment: &MCFragment) {
match fragment {
MCFragment::Data(bytes) => {
self.data.extend_from_slice(bytes);
self.offset += bytes.len() as u64;
}
MCFragment::Align {
pow2,
value,
max_bytes: _,
} => {
self.emit_p2align(*pow2, 0, *value);
}
MCFragment::Fill { size, value } => {
for _ in 0..*size {
self.data.push(*value);
}
self.offset += size;
}
MCFragment::Org { address } => {
self.emit_org(*address);
}
MCFragment::Instruction { bytes, mnemonic: _ } => {
self.data.extend_from_slice(bytes);
self.offset += bytes.len() as u64;
}
}
}
pub fn emit_dwarf_loc_directive(&mut self, file: &str, line: u32, column: u32) {
if self.gen_dwarf {
self.line_entries.push(LineEntry {
address: self.offset,
file: file.to_string(),
line,
column,
});
}
}
pub fn emit_dwarf_file_directive(&mut self, _idx: u32, _path: &str) {
}
pub fn emit_cfi_advance_loc(&mut self, _delta: u32) {
}
pub fn emit_cfi_offset(&mut self, _reg: u32, _offset: i32) {
}
pub fn emit_cfi_def_cfa(&mut self, _reg: u32, _offset: i32) {
}
pub fn emit_cfi_def_cfa_register(&mut self, _reg: u32) {
}
pub fn emit_cfi_def_cfa_offset(&mut self, _offset: i32) {
}
pub fn emit_cfi_remember_state(&mut self) {
}
pub fn emit_cfi_restore_state(&mut self) {
}
pub fn emit_cfi_restore(&mut self, _reg: u32) {
}
pub fn emit_cfi_undefined(&mut self, _reg: u32) {
}
pub fn emit_cfi_register(&mut self, _reg1: u32, _reg2: u32) {
}
pub fn emit_cfi_window_save(&mut self) {
}
pub fn emit_assembler_flag(&mut self, flag: AssemblerFlag) {
match flag {
AssemblerFlag::GenDwarfForAssembly => self.gen_dwarf = true,
AssemblerFlag::UseCFI => self.use_cfi = true,
AssemblerFlag::NoExecStack => {}
AssemblerFlag::SubsectionsViaSymbols => {}
AssemblerFlag::Code16 => {}
AssemblerFlag::Code32 => {}
AssemblerFlag::Code64 => {}
}
}
pub fn finish(self) -> Vec<u8> {
self.data
}
}
impl Default for MCObjectStreamer {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Default)]
pub struct MCNullStreamer {
pub instruction_count: u64,
pub label_count: u64,
pub directive_count: u64,
}
impl MCNullStreamer {
pub fn new() -> Self {
Self {
instruction_count: 0,
label_count: 0,
directive_count: 0,
}
}
pub fn emit_instruction_count(&mut self) {
self.instruction_count += 1;
}
pub fn emit_label_count(&mut self) {
self.label_count += 1;
}
pub fn emit_directive_count(&mut self) {
self.directive_count += 1;
}
pub fn finish(&self) {
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AssemblerFlag {
GenDwarfForAssembly,
UseCFI,
NoExecStack,
SubsectionsViaSymbols,
Code16,
Code32,
Code64,
}
impl AssemblerFlag {
pub fn as_str(&self) -> &'static str {
match self {
AssemblerFlag::GenDwarfForAssembly => "generate-dwarf",
AssemblerFlag::UseCFI => "use-cfi",
AssemblerFlag::NoExecStack => "no-exec-stack",
AssemblerFlag::SubsectionsViaSymbols => "subsections-via-symbols",
AssemblerFlag::Code16 => "code16",
AssemblerFlag::Code32 => "code32",
AssemblerFlag::Code64 => "code64",
}
}
}
#[derive(Debug, Clone)]
pub struct SectionFlags {
pub name: String,
pub section_type: String,
pub flags: Vec<String>,
pub alignment: u32,
pub entry_size: u32,
}
impl SectionFlags {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
section_type: "progbits".to_string(),
flags: Vec::new(),
alignment: 4,
entry_size: 0,
}
}
pub fn with_type(mut self, ty: &str) -> Self {
self.section_type = ty.to_string();
self
}
pub fn with_flag(mut self, flag: &str) -> Self {
self.flags.push(flag.to_string());
self
}
pub fn with_alignment(mut self, align: u32) -> Self {
self.alignment = align;
self
}
}
impl Default for SectionFlags {
fn default() -> Self {
Self::new(".text")
}
}
fn make_rex_byte(w: bool, r: bool, x: bool, b: bool) -> u8 {
0x40 | ((w as u8) << 3) | ((r as u8) << 2) | ((x as u8) << 1) | (b as u8)
}
fn emit_rex_64(bytes: &mut Vec<u8>, reg_field_reg: u32, rm_field_reg: u32) {
let rex = make_rex_byte(
true, (reg_field_reg >> 3) & 1 == 1, false, (rm_field_reg >> 3) & 1 == 1, );
if rex != 0x40 {
bytes.push(rex);
}
}
pub fn encode_x86_instruction(opcode: u32, operands: &[MCOperand]) -> Vec<u8> {
let mut bytes = Vec::new();
match opcode {
x86_opcodes::NOP => {
bytes.push(0x90);
}
x86_opcodes::RET => {
bytes.push(0xC3);
}
x86_opcodes::PUSH => {
if let Some(MCOperand::Reg(r)) = operands.first() {
match r {
5 => bytes.push(0x55), 4 => bytes.push(0x54), 0 => bytes.push(0x50), 1 => bytes.push(0x51), 2 => bytes.push(0x52), 3 => bytes.push(0x53), 6 => bytes.push(0x56), 7 => bytes.push(0x57), 8 => bytes.extend_from_slice(&[0x41, 0x50]), 9 => bytes.extend_from_slice(&[0x41, 0x51]), _ => {}
}
} else if let Some(MCOperand::Imm(v)) = operands.first() {
if *v <= 127 && *v >= -128 {
bytes.extend_from_slice(&[0x6A, *v as u8]);
} else {
bytes.push(0x68);
bytes.extend_from_slice(&(*v as i32).to_le_bytes());
}
}
}
x86_opcodes::POP => {
if let Some(MCOperand::Reg(r)) = operands.first() {
match r {
5 => bytes.push(0x5D), 4 => bytes.push(0x5C), 0 => bytes.push(0x58), 1 => bytes.push(0x59), 2 => bytes.push(0x5A), 3 => bytes.push(0x5B), 6 => bytes.push(0x5E), 7 => bytes.push(0x5F), 8 => bytes.extend_from_slice(&[0x41, 0x58]), 9 => bytes.extend_from_slice(&[0x41, 0x59]), _ => {}
}
}
}
x86_opcodes::MOV => {
if operands.len() >= 2 {
if let (MCOperand::Reg(dst), MCOperand::Reg(src)) = (&operands[0], &operands[1]) {
emit_rex_64(&mut bytes, *src, *dst);
bytes.push(0x89);
let modrm = (0xC0u32 | ((src & 0x07) << 3) | (dst & 0x07)) as u8;
bytes.push(modrm as u8);
} else if let (MCOperand::Reg(dst), MCOperand::Imm(val)) =
(&operands[0], &operands[1])
{
if *val <= i32::MAX as i64 && *val >= i32::MIN as i64 {
if *dst >= 8 {
bytes.push(make_rex_byte(false, false, false, true));
}
bytes.push((0xB8u32 | (dst & 0x07)) as u8);
bytes.extend_from_slice(&(*val as u32).to_le_bytes());
} else {
emit_rex_64(&mut bytes, 0, *dst);
bytes.push((0xB8u32 | (dst & 0x07)) as u8);
bytes.extend_from_slice(&val.to_le_bytes());
}
}
}
}
x86_opcodes::LOAD => {
if operands.len() >= 2 {
if let (MCOperand::Reg(dst), MCOperand::Reg(src)) = (&operands[0], &operands[1]) {
emit_rex_64(&mut bytes, *dst, *src);
bytes.push(0x8B);
let modrm = ((dst & 0x07) << 3) | (src & 0x07);
bytes.push(modrm as u8);
}
}
}
x86_opcodes::STORE => {
if operands.len() >= 2 {
if let (MCOperand::Reg(ptr), MCOperand::Reg(val)) = (&operands[0], &operands[1]) {
emit_rex_64(&mut bytes, *val, *ptr);
bytes.push(0x89);
let modrm = ((val & 0x07) << 3) | (ptr & 0x07);
bytes.push(modrm as u8);
}
}
}
x86_opcodes::ADD => {
if operands.len() >= 2 {
if let (MCOperand::Reg(dst), MCOperand::Imm(val)) = (&operands[0], &operands[1]) {
emit_rex_64(&mut bytes, 0, *dst);
if *val <= 127 && *val >= -128 {
bytes.push(0x83);
bytes.push((0xC0u32 | (dst & 0x07)) as u8);
bytes.push(*val as u8);
} else {
bytes.push(0x81);
bytes.push((0xC0u32 | (dst & 0x07)) as u8);
bytes.extend_from_slice(&(*val as u32).to_le_bytes());
}
}
}
}
x86_opcodes::SUB => {
if operands.len() >= 2 {
if let (MCOperand::Reg(dst), MCOperand::Imm(val)) = (&operands[0], &operands[1]) {
emit_rex_64(&mut bytes, 0, *dst);
if *val <= 127 && *val >= -128 {
bytes.push(0x83);
bytes.push((0xE8u32 | (dst & 0x07)) as u8);
bytes.push(*val as u8);
} else {
bytes.push(0x81);
bytes.push((0xE8u32 | (dst & 0x07)) as u8);
bytes.extend_from_slice(&(*val as u32).to_le_bytes());
}
}
}
}
x86_opcodes::CMP => {
if operands.len() >= 2 {
if let (MCOperand::Reg(dst), MCOperand::Reg(src)) = (&operands[0], &operands[1]) {
emit_rex_64(&mut bytes, *src, *dst);
bytes.push(0x39);
let modrm = (0xC0u32 | ((src & 0x07) << 3) | (dst & 0x07)) as u8;
bytes.push(modrm);
} else if let (MCOperand::Reg(dst), MCOperand::Imm(val)) =
(&operands[0], &operands[1])
{
emit_rex_64(&mut bytes, 0, *dst);
if *val <= 127 && *val >= -128 {
bytes.push(0x83);
bytes.push((0xF8u32 | (dst & 0x07)) as u8);
bytes.push(*val as u8);
} else {
bytes.push(0x81);
bytes.push((0xF8u32 | (dst & 0x07)) as u8);
bytes.extend_from_slice(&(*val as u32).to_le_bytes());
}
}
}
}
x86_opcodes::JMP => {
if let Some(MCOperand::Expr(_e)) = operands.first() {
bytes.extend_from_slice(&[0xE9, 0x00, 0x00, 0x00, 0x00]);
}
}
x86_opcodes::CALL => {
if let Some(MCOperand::Expr(_e)) = operands.first() {
bytes.extend_from_slice(&[0xE8, 0x00, 0x00, 0x00, 0x00]);
}
}
x86_opcodes::MOVZX => {
if operands.len() >= 2 {
if let (MCOperand::Reg(dst), MCOperand::Reg(src)) = (&operands[0], &operands[1]) {
if (*src >= 4 && *src < 8) || (*dst >= 4 && *dst < 8) {
bytes.push(0x40);
}
bytes.extend_from_slice(&[0x0F, 0xB6]);
let modrm = (0xC0u32 | ((src & 0x07) << 3) | (dst & 0x07)) as u8;
bytes.push(modrm);
}
}
}
x86_opcodes::SETO => {
if let Some(MCOperand::Reg(dst)) = operands.first() {
if *dst >= 4 && *dst < 8 {
bytes.push(0x40);
}
bytes.extend_from_slice(&[0x0F, 0x90]);
bytes.push((0xC0u32 | (dst & 0x07)) as u8);
}
}
x86_opcodes::SETNO => {
if let Some(MCOperand::Reg(dst)) = operands.first() {
if *dst >= 4 && *dst < 8 {
bytes.push(0x40);
}
bytes.extend_from_slice(&[0x0F, 0x91]);
bytes.push((0xC0u32 | (dst & 0x07)) as u8);
}
}
x86_opcodes::SETB => {
if let Some(MCOperand::Reg(dst)) = operands.first() {
if *dst >= 4 && *dst < 8 {
bytes.push(0x40);
}
bytes.extend_from_slice(&[0x0F, 0x92]);
bytes.push((0xC0u32 | (dst & 0x07)) as u8);
}
}
x86_opcodes::SETAE => {
if let Some(MCOperand::Reg(dst)) = operands.first() {
if *dst >= 4 && *dst < 8 {
bytes.push(0x40);
}
bytes.extend_from_slice(&[0x0F, 0x93]);
bytes.push((0xC0u32 | (dst & 0x07)) as u8);
}
}
x86_opcodes::SETE => {
if let Some(MCOperand::Reg(dst)) = operands.first() {
if *dst >= 4 && *dst < 8 {
bytes.push(0x40);
}
bytes.extend_from_slice(&[0x0F, 0x94]);
bytes.push((0xC0u32 | (dst & 0x07)) as u8);
}
}
x86_opcodes::SETNE => {
if let Some(MCOperand::Reg(dst)) = operands.first() {
if *dst >= 4 && *dst < 8 {
bytes.push(0x40);
}
bytes.extend_from_slice(&[0x0F, 0x95]);
bytes.push((0xC0u32 | (dst & 0x07)) as u8);
}
}
x86_opcodes::SETBE => {
if let Some(MCOperand::Reg(dst)) = operands.first() {
if *dst >= 4 && *dst < 8 {
bytes.push(0x40);
}
bytes.extend_from_slice(&[0x0F, 0x96]);
bytes.push((0xC0u32 | (dst & 0x07)) as u8);
}
}
x86_opcodes::SETA => {
if let Some(MCOperand::Reg(dst)) = operands.first() {
if *dst >= 4 && *dst < 8 {
bytes.push(0x40);
}
bytes.extend_from_slice(&[0x0F, 0x97]);
bytes.push((0xC0u32 | (dst & 0x07)) as u8);
}
}
x86_opcodes::SETS => {
if let Some(MCOperand::Reg(dst)) = operands.first() {
if *dst >= 4 && *dst < 8 {
bytes.push(0x40);
}
bytes.extend_from_slice(&[0x0F, 0x98]);
bytes.push((0xC0u32 | (dst & 0x07)) as u8);
}
}
x86_opcodes::SETNS => {
if let Some(MCOperand::Reg(dst)) = operands.first() {
if *dst >= 4 && *dst < 8 {
bytes.push(0x40);
}
bytes.extend_from_slice(&[0x0F, 0x99]);
bytes.push((0xC0u32 | (dst & 0x07)) as u8);
}
}
x86_opcodes::SETP => {
if let Some(MCOperand::Reg(dst)) = operands.first() {
if *dst >= 4 && *dst < 8 {
bytes.push(0x40);
}
bytes.extend_from_slice(&[0x0F, 0x9A]);
bytes.push((0xC0u32 | (dst & 0x07)) as u8);
}
}
x86_opcodes::SETNP => {
if let Some(MCOperand::Reg(dst)) = operands.first() {
if *dst >= 4 && *dst < 8 {
bytes.push(0x40);
}
bytes.extend_from_slice(&[0x0F, 0x9B]);
bytes.push((0xC0u32 | (dst & 0x07)) as u8);
}
}
x86_opcodes::SETL => {
if let Some(MCOperand::Reg(dst)) = operands.first() {
if *dst >= 4 && *dst < 8 {
bytes.push(0x40);
}
bytes.extend_from_slice(&[0x0F, 0x9C]);
bytes.push((0xC0u32 | (dst & 0x07)) as u8);
}
}
x86_opcodes::SETGE => {
if let Some(MCOperand::Reg(dst)) = operands.first() {
if *dst >= 4 && *dst < 8 {
bytes.push(0x40);
}
bytes.extend_from_slice(&[0x0F, 0x9D]);
bytes.push((0xC0u32 | (dst & 0x07)) as u8);
}
}
x86_opcodes::SETLE => {
if let Some(MCOperand::Reg(dst)) = operands.first() {
if *dst >= 4 && *dst < 8 {
bytes.push(0x40);
}
bytes.extend_from_slice(&[0x0F, 0x9E]);
bytes.push((0xC0u32 | (dst & 0x07)) as u8);
}
}
x86_opcodes::SETG => {
if let Some(MCOperand::Reg(dst)) = operands.first() {
if *dst >= 4 && *dst < 8 {
bytes.push(0x40);
}
bytes.extend_from_slice(&[0x0F, 0x9F]);
bytes.push((0xC0u32 | (dst & 0x07)) as u8);
}
}
_ => {
bytes.push(0x0F);
bytes.push(0x0B); }
}
bytes
}
#[allow(dead_code)]
pub fn emit_assembly_header(streamer: &mut MCAsmStreamer, triple: &str) {
streamer.emit_comment(&format!("Target: {}", triple));
streamer.emit_directive("file", &[format!("\"{}\"", triple)]);
}
#[allow(dead_code)]
pub fn emit_function_prologue(opcode: u32, streamer: &mut MCObjectStreamer) {
use x86_opcodes;
let push_rbp = encode_x86_instruction(x86_opcodes::PUSH, &[MCOperand::Reg(5)]);
let mov_rbp_rsp =
encode_x86_instruction(x86_opcodes::MOV, &[MCOperand::Reg(5), MCOperand::Reg(4)]);
streamer.emit_instruction_bytes(&push_rbp, "push");
streamer.emit_instruction_bytes(&mov_rbp_rsp, "mov");
let _ = opcode;
}
#[allow(dead_code)]
pub fn emit_function_epilogue(streamer: &mut MCObjectStreamer) {
use x86_opcodes;
let pop_rbp = encode_x86_instruction(x86_opcodes::POP, &[MCOperand::Reg(5)]);
let ret = encode_x86_instruction(x86_opcodes::RET, &[]);
streamer.emit_instruction_bytes(&pop_rbp, "pop");
streamer.emit_instruction_bytes(&ret, "ret");
}
#[allow(dead_code)]
pub mod x86_64_relocations {
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_COPY: u32 = 5;
pub const R_X86_64_GLOB_DAT: u32 = 6;
pub const R_X86_64_JUMP_SLOT: u32 = 7;
pub const R_X86_64_RELATIVE: u32 = 8;
pub const R_X86_64_GOTPCREL: u32 = 9;
pub const R_X86_64_32: u32 = 10;
pub const R_X86_64_32S: u32 = 11;
pub const R_X86_64_16: u32 = 12;
pub const R_X86_64_PC16: u32 = 13;
pub const R_X86_64_8: u32 = 14;
pub const R_X86_64_PC8: u32 = 15;
}
pub fn reloc_type_name(rel_type: u32) -> &'static str {
match rel_type {
0 => "R_X86_64_NONE",
1 => "R_X86_64_64",
2 => "R_X86_64_PC32",
3 => "R_X86_64_GOT32",
4 => "R_X86_64_PLT32",
5 => "R_X86_64_COPY",
6 => "R_X86_64_GLOB_DAT",
7 => "R_X86_64_JUMP_SLOT",
8 => "R_X86_64_RELATIVE",
9 => "R_X86_64_GOTPCREL",
10 => "R_X86_64_32",
11 => "R_X86_64_32S",
12 => "R_X86_64_16",
13 => "R_X86_64_PC16",
14 => "R_X86_64_8",
15 => "R_X86_64_PC8",
_ => "UNKNOWN",
}
}
#[derive(Debug, Clone)]
pub struct MCSymbolRefExpr {
pub name: String,
pub offset: i64,
}
impl MCSymbolRefExpr {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
offset: 0,
}
}
pub fn with_offset(mut self, offset: i64) -> Self {
self.offset = offset;
self
}
}
impl std::fmt::Display for MCSymbolRefExpr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.offset == 0 {
write!(f, "{}", self.name)
} else if self.offset > 0 {
write!(f, "{}+{}", self.name, self.offset)
} else {
write!(f, "{}-{}", self.name, -self.offset)
}
}
}
pub trait MCStreamerFactory {
fn create_asm_streamer(&self) -> MCAsmStreamer;
fn create_object_streamer(&self) -> MCObjectStreamer;
fn create_null_streamer(&self) -> MCNullStreamer;
}
#[derive(Debug, Clone, Default)]
pub struct DefaultMCStreamerFactory;
impl MCStreamerFactory for DefaultMCStreamerFactory {
fn create_asm_streamer(&self) -> MCAsmStreamer {
MCAsmStreamer::new()
}
fn create_object_streamer(&self) -> MCObjectStreamer {
MCObjectStreamer::new()
}
fn create_null_streamer(&self) -> MCNullStreamer {
MCNullStreamer::new()
}
}
#[derive(Debug, Clone)]
pub struct MCContext {
pub triple: String,
pub cpu: String,
pub flags: Vec<AssemblerFlag>,
pub pic: bool,
pub code_model: String,
}
impl MCContext {
pub fn new(triple: &str) -> Self {
Self {
triple: triple.to_string(),
cpu: String::new(),
flags: Vec::new(),
pic: false,
code_model: String::new(),
}
}
pub fn set_pic(&mut self, pic: bool) {
self.pic = pic;
}
pub fn add_flag(&mut self, flag: AssemblerFlag) {
self.flags.push(flag);
}
}
impl Default for MCContext {
fn default() -> Self {
Self::new("x86_64-unknown-linux-gnu")
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::mc_inst::MCInst;
#[test]
fn test_new_mnemonics_adc_sbb() {
assert_eq!(x86_mnemonic(x86_opcodes::ADC), "adc");
assert_eq!(x86_mnemonic(x86_opcodes::SBB), "sbb");
}
#[test]
fn test_new_mnemonics_shift_rotate() {
assert_eq!(x86_mnemonic(x86_opcodes::SAR), "sar");
assert_eq!(x86_mnemonic(x86_opcodes::SAL), "sal");
assert_eq!(x86_mnemonic(x86_opcodes::ROL), "rol");
assert_eq!(x86_mnemonic(x86_opcodes::ROR), "ror");
assert_eq!(x86_mnemonic(x86_opcodes::RCL), "rcl");
assert_eq!(x86_mnemonic(x86_opcodes::RCR), "rcr");
}
#[test]
fn test_new_mnemonics_mov_extensions() {
assert_eq!(x86_mnemonic(x86_opcodes::MOVSX), "movsx");
assert_eq!(x86_mnemonic(x86_opcodes::MOVZX), "movzx");
assert_eq!(x86_mnemonic(x86_opcodes::MOVSXD), "movsxd");
}
#[test]
fn test_new_mnemonics_cmov() {
assert_eq!(x86_mnemonic(x86_opcodes::CMOVE), "cmove");
assert_eq!(x86_mnemonic(x86_opcodes::CMOVNE), "cmovne");
assert_eq!(x86_mnemonic(x86_opcodes::CMOVL), "cmovl");
assert_eq!(x86_mnemonic(x86_opcodes::CMOVG), "cmovg");
}
#[test]
fn test_new_mnemonics_setcc() {
assert_eq!(x86_mnemonic(x86_opcodes::SETE), "sete");
assert_eq!(x86_mnemonic(x86_opcodes::SETNE), "setne");
assert_eq!(x86_mnemonic(x86_opcodes::SETL), "setl");
}
#[test]
fn test_new_mnemonics_bit_ops() {
assert_eq!(x86_mnemonic(x86_opcodes::BT), "bt");
assert_eq!(x86_mnemonic(x86_opcodes::BTS), "bts");
assert_eq!(x86_mnemonic(x86_opcodes::BTR), "btr");
assert_eq!(x86_mnemonic(x86_opcodes::BTC), "btc");
assert_eq!(x86_mnemonic(x86_opcodes::BSF), "bsf");
assert_eq!(x86_mnemonic(x86_opcodes::BSR), "bsr");
}
#[test]
fn test_new_mnemonics_misc() {
assert_eq!(x86_mnemonic(x86_opcodes::BSWAP), "bswap");
assert_eq!(x86_mnemonic(x86_opcodes::XCHG), "xchg");
assert_eq!(x86_mnemonic(x86_opcodes::SYSCALL), "syscall");
assert_eq!(x86_mnemonic(x86_opcodes::CPUID), "cpuid");
assert_eq!(x86_mnemonic(x86_opcodes::HLT), "hlt");
assert_eq!(x86_mnemonic(x86_opcodes::RDTSC), "rdtsc");
}
#[test]
fn test_reg_names_8bit() {
assert_eq!(x86_reg_name(28), "ah");
assert_eq!(x86_reg_name(29), "ch");
assert_eq!(x86_reg_name(30), "dh");
assert_eq!(x86_reg_name(31), "bh");
assert_eq!(x86_reg_name(32), "spl");
assert_eq!(x86_reg_name(36), "r8b");
assert_eq!(x86_reg_name(43), "r15b");
}
#[test]
fn test_reg_names_xmm() {
assert_eq!(x86_reg_name(64), "xmm0");
assert_eq!(x86_reg_name(72), "xmm8");
assert_eq!(x86_reg_name(79), "xmm15");
}
#[test]
fn test_reg_names_ymm() {
assert_eq!(x86_reg_name(80), "ymm0");
assert_eq!(x86_reg_name(88), "ymm8");
assert_eq!(x86_reg_name(95), "ymm15");
}
#[test]
fn test_reg_names_segment() {
assert_eq!(x86_reg_name(96), "es");
assert_eq!(x86_reg_name(97), "cs");
assert_eq!(x86_reg_name(100), "fs");
assert_eq!(x86_reg_name(101), "gs");
}
#[test]
fn test_emit_data_directive() {
let mut streamer = MCAsmStreamer::new();
streamer.emit_data_directive(&[0x90, 0xC3, 0xCC]);
assert!(streamer.output.contains(".byte"));
assert!(streamer.output.contains("0x90"));
assert!(streamer.output.contains("0xc3"));
assert!(streamer.output.contains("0xcc"));
}
#[test]
fn test_emit_zero_fill() {
let mut streamer = MCAsmStreamer::new();
streamer.emit_zero_fill(16);
assert!(streamer.output.contains(".zero 16"));
}
#[test]
fn test_emit_alignment() {
let mut streamer = MCAsmStreamer::new();
streamer.emit_alignment(8);
assert!(streamer.output.contains(".align 8"));
}
#[test]
fn test_emit_symbol_directive_local() {
let mut streamer = MCAsmStreamer::new();
streamer.emit_symbol_directive("my_func", false);
assert!(streamer.output.contains("my_func:"));
assert!(!streamer.output.contains(".globl"));
}
#[test]
fn test_emit_symbol_directive_global() {
let mut streamer = MCAsmStreamer::new();
streamer.emit_symbol_directive("main", true);
assert!(streamer.output.contains(".globl main"));
assert!(streamer.output.contains("main:"));
}
}