Musl uses hard-coded logic for iconv. This patch moves the logic out of C code, and implement a virtual machine for dynamically loading charsets at runtime and do conversion.
147 lines
4.3 KiB
Rust
147 lines
4.3 KiB
Rust
#[derive(Debug, Clone)]
|
|
struct Octo {
|
|
tag: Option<String>,
|
|
content: [u8; 8],
|
|
reloc: Vec<(usize, String)>,
|
|
}
|
|
|
|
fn main() {
|
|
let mut args = std::env::args().skip(1);
|
|
let src = args.next().expect("please specify source file");
|
|
let dst = args.next().expect("please specify output file");
|
|
|
|
let mut octos = Vec::new();
|
|
let src_content = std::fs::read_to_string(&src)
|
|
.expect("cannot read source file");
|
|
let mut current_tag = None;
|
|
for (nline, line) in src_content.lines().enumerate() {
|
|
let line = line.trim();
|
|
if line.is_empty() || line.starts_with("//") {
|
|
continue;
|
|
}
|
|
if let Some(tag) = line.strip_suffix(":") {
|
|
current_tag = Some(tag);
|
|
continue;
|
|
}
|
|
let Some((op, arglist)) = line.split_once(' ') else {
|
|
error(nline, "operation without arglist is currently disallowed");
|
|
};
|
|
let mut content = [0u8; 8];
|
|
content[0] = do_op(op).unwrap_or_else(|| error(nline, "unrecognized op"));
|
|
let mut cursor = 1;
|
|
if content[0] == 0 {
|
|
cursor = 0;
|
|
}
|
|
let reloc = do_arglist(arglist, &mut content, &mut cursor);
|
|
octos.push(Octo {
|
|
tag: current_tag.take().map(ToString::to_string),
|
|
content,
|
|
reloc,
|
|
});
|
|
}
|
|
|
|
let mut tags = std::collections::HashMap::new();
|
|
for (nocto, octo) in octos.iter().enumerate() {
|
|
if let Some(tag) = &octo.tag {
|
|
tags.insert(tag.to_string(), nocto * 8);
|
|
}
|
|
}
|
|
|
|
let mut content = Vec::new();
|
|
for octo in octos {
|
|
let mut current = octo.content.to_vec();
|
|
for (offset, tag) in octo.reloc {
|
|
let tag_addr = *tags.get(&tag).expect(&format!("tag {tag} undefined")) as u32;
|
|
current[offset..offset + 4].copy_from_slice(&tag_addr.to_be_bytes()[..]);
|
|
}
|
|
content.append(&mut current);
|
|
}
|
|
|
|
std::fs::write(dst, &content).expect("failed to write dst file");
|
|
}
|
|
|
|
fn error(line: usize, reason: &str) -> ! {
|
|
eprintln!("error: {reason} (source:{})", line + 1);
|
|
std::process::exit(1);
|
|
}
|
|
|
|
fn do_op(s: &str) -> Option<u8> {
|
|
match s {
|
|
"place64" => Some(0),
|
|
"input8" => Some(1),
|
|
"input16" => Some(2),
|
|
"input32" => Some(3),
|
|
"input64" => Some(4),
|
|
"output8" => Some(5),
|
|
"output16" => Some(6),
|
|
"output32" => Some(7),
|
|
"output64" => Some(8),
|
|
"xor" => Some(9),
|
|
"and" => Some(10),
|
|
"or" => Some(11),
|
|
"add" => Some(13),
|
|
"sub" => Some(14),
|
|
"smul" => Some(15),
|
|
"umul" => Some(17),
|
|
"eq" => Some(19),
|
|
"mt" => Some(20),
|
|
"lt" => Some(21),
|
|
"shl" => Some(29),
|
|
"shr" => Some(30),
|
|
"not" => Some(12),
|
|
"jnz" => Some(22),
|
|
"jmp" => Some(23),
|
|
"load8" => Some(24),
|
|
"load16" => Some(25),
|
|
"load32" => Some(26),
|
|
"load64" => Some(27),
|
|
"store64" => Some(28),
|
|
"ret" => Some(31),
|
|
"ptrload8" => Some(33),
|
|
"ptrload16" => Some(34),
|
|
"ptrload32" => Some(35),
|
|
"ptrload64" => Some(36),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
fn do_arglist(s: &str, content: &mut [u8; 8], cursor: &mut usize) -> Vec<(usize, String)> {
|
|
let mut reloc = Vec::new();
|
|
for arg in s.split(',') {
|
|
let arg = arg.trim();
|
|
if let Some(x) = do_arg(arg, content, cursor) {
|
|
reloc.push(x);
|
|
}
|
|
}
|
|
reloc
|
|
}
|
|
|
|
fn do_arg(s: &str, content: &mut [u8; 8], cursor: &mut usize) -> Option<(usize, String)> {
|
|
if let Ok(n) = s.parse::<u64>() {
|
|
*cursor = 8;
|
|
*content = n.to_be_bytes();
|
|
None
|
|
} else if let Some(digit) = s.strip_prefix('0') {
|
|
let radix = match digit.as_bytes()[0] {
|
|
b'x' => 16,
|
|
b'o' => 8,
|
|
b'b' => 2,
|
|
_ => panic!("unknown radix"),
|
|
};
|
|
*cursor = 8;
|
|
*content = u64::from_str_radix(&digit[1..], radix).unwrap().to_be_bytes();
|
|
None
|
|
} else if let Some(reg_id) = s.strip_prefix("&r") {
|
|
content[*cursor] = reg_id.parse::<u8>().unwrap();
|
|
*cursor += 1;
|
|
None
|
|
} else if s == "@sicv_magic_v1" {
|
|
*content = [b'S', b'I', b'C', b'V', 0, 0, 0, 1];
|
|
*cursor = 8;
|
|
None
|
|
} else {
|
|
*cursor += 4;
|
|
Some((*cursor - 4, s.into()))
|
|
}
|
|
}
|