Skip to content

Commit 75cddc6

Browse files
committed
Update host_runtime_shim.rs
1 parent b508a2c commit 75cddc6

1 file changed

Lines changed: 241 additions & 0 deletions

File tree

crates/dust_codegen/src/host_runtime_shim.rs

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ const SHF_WRITE: u64 = 0x1;
3636
const SHF_EXECINSTR: u64 = 0x4;
3737
const SHT_NOBITS: u32 = 8;
3838
const SHT_PROGBITS: u32 = 1;
39+
const SHT_DYNSYM: u32 = 11;
3940
const PT_LOAD: u32 = 1;
4041
const PT_DYNAMIC: u32 = 2;
4142
const PT_INTERP: u32 = 3;
@@ -180,6 +181,7 @@ struct LinkerState {
180181
link_pie: bool,
181182
link_static: bool,
182183
link_as_needed: bool,
184+
no_undefined: bool,
183185
dynamic_linker_path: u64,
184186
soname: u64,
185187
needed_shared_libs: Vec<u64>,
@@ -1590,6 +1592,7 @@ fn reset_linker_state_defaults(state: &mut LinkerState) {
15901592
state.entry = 0x0010_0000;
15911593
state.image_base = 0x0001_0000;
15921594
state.link_as_needed = false;
1595+
state.no_undefined = false;
15931596
state.link_pie = false;
15941597
state.link_shared = false;
15951598
state.link_static = false;
@@ -1625,6 +1628,172 @@ fn probe_object_format_path(path: &Path) -> u32 {
16251628
probe_object_format_bytes(&raw)
16261629
}
16271630

1631+
fn dynstr_symbol_name(raw: &[u8], dynstr_off: usize, dynstr_size: usize, st_name: u32) -> Option<String> {
1632+
let name_off = st_name as usize;
1633+
if name_off >= dynstr_size {
1634+
return None;
1635+
}
1636+
let start = dynstr_off.checked_add(name_off)?;
1637+
let end_limit = dynstr_off.checked_add(dynstr_size)?;
1638+
if start >= raw.len() || start >= end_limit {
1639+
return None;
1640+
}
1641+
let mut end = start;
1642+
while end < end_limit && end < raw.len() {
1643+
if raw[end] == 0 {
1644+
break;
1645+
}
1646+
end += 1;
1647+
}
1648+
if end <= start {
1649+
return None;
1650+
}
1651+
Some(String::from_utf8_lossy(&raw[start..end]).to_string())
1652+
}
1653+
1654+
fn ingest_shared_elf_symbols(state: &mut LinkerState, raw: &[u8]) -> u32 {
1655+
if raw.len() < 64 || &raw[0..4] != b"\x7fELF" {
1656+
return ERR_INVALID_FORMAT;
1657+
}
1658+
if raw.get(4).copied().unwrap_or(0) != 2 || raw.get(5).copied().unwrap_or(0) != 1 {
1659+
return ERR_INVALID_FORMAT;
1660+
}
1661+
1662+
let shoff = match read_u64_le_at(raw, 40) {
1663+
Some(v) => v as usize,
1664+
None => return ERR_INVALID_FORMAT,
1665+
};
1666+
let shentsize = match read_u16_le_at(raw, 58) {
1667+
Some(v) if v >= 64 => v as usize,
1668+
_ => return ERR_INVALID_FORMAT,
1669+
};
1670+
let shnum = match read_u16_le_at(raw, 60) {
1671+
Some(v) if v > 0 => v as usize,
1672+
_ => return ERR_INVALID_FORMAT,
1673+
};
1674+
1675+
let mut dynsym_index: Option<usize> = None;
1676+
for index in 0..shnum {
1677+
let base = match shoff.checked_add(index.saturating_mul(shentsize)) {
1678+
Some(v) => v,
1679+
None => return ERR_INVALID_FORMAT,
1680+
};
1681+
let sh_type = match read_u32_le_at(raw, base + 4) {
1682+
Some(v) => v,
1683+
None => return ERR_INVALID_FORMAT,
1684+
};
1685+
if sh_type == SHT_DYNSYM {
1686+
dynsym_index = Some(index);
1687+
break;
1688+
}
1689+
}
1690+
1691+
let dynsym_index = match dynsym_index {
1692+
Some(v) => v,
1693+
None => return ERR_OK,
1694+
};
1695+
let dynsym_base = match shoff.checked_add(dynsym_index.saturating_mul(shentsize)) {
1696+
Some(v) => v,
1697+
None => return ERR_INVALID_FORMAT,
1698+
};
1699+
let dynsym_off = match read_u64_le_at(raw, dynsym_base + 24) {
1700+
Some(v) => v as usize,
1701+
None => return ERR_INVALID_FORMAT,
1702+
};
1703+
let dynsym_size = match read_u64_le_at(raw, dynsym_base + 32) {
1704+
Some(v) => v as usize,
1705+
None => return ERR_INVALID_FORMAT,
1706+
};
1707+
let dynsym_link = match read_u32_le_at(raw, dynsym_base + 40) {
1708+
Some(v) => v as usize,
1709+
None => return ERR_INVALID_FORMAT,
1710+
};
1711+
let dynsym_entsize = match read_u64_le_at(raw, dynsym_base + 56) {
1712+
Some(v) if v >= 24 => v as usize,
1713+
_ => return ERR_INVALID_FORMAT,
1714+
};
1715+
1716+
if dynsym_off.saturating_add(dynsym_size) > raw.len() {
1717+
return ERR_INVALID_FORMAT;
1718+
}
1719+
if dynsym_link >= shnum {
1720+
return ERR_INVALID_FORMAT;
1721+
}
1722+
1723+
let dynstr_base = match shoff.checked_add(dynsym_link.saturating_mul(shentsize)) {
1724+
Some(v) => v,
1725+
None => return ERR_INVALID_FORMAT,
1726+
};
1727+
let dynstr_off = match read_u64_le_at(raw, dynstr_base + 24) {
1728+
Some(v) => v as usize,
1729+
None => return ERR_INVALID_FORMAT,
1730+
};
1731+
let dynstr_size = match read_u64_le_at(raw, dynstr_base + 32) {
1732+
Some(v) => v as usize,
1733+
None => return ERR_INVALID_FORMAT,
1734+
};
1735+
if dynstr_off.saturating_add(dynstr_size) > raw.len() {
1736+
return ERR_INVALID_FORMAT;
1737+
}
1738+
1739+
let symbol_count = dynsym_size / dynsym_entsize;
1740+
for index in 0..symbol_count {
1741+
let sym_off = dynsym_off + index.saturating_mul(dynsym_entsize);
1742+
let st_name = match read_u32_le_at(raw, sym_off) {
1743+
Some(v) if v != 0 => v,
1744+
_ => continue,
1745+
};
1746+
let st_info = *raw.get(sym_off + 4).unwrap_or(&0);
1747+
let st_bind = st_info >> 4;
1748+
if st_bind != 1 && st_bind != 2 {
1749+
continue;
1750+
}
1751+
let st_shndx = match read_u16_le_at(raw, sym_off + 6) {
1752+
Some(v) => v,
1753+
None => continue,
1754+
};
1755+
if st_shndx == SHN_UNDEF {
1756+
continue;
1757+
}
1758+
let name = match dynstr_symbol_name(raw, dynstr_off, dynstr_size, st_name) {
1759+
Some(v) if !v.is_empty() => v,
1760+
_ => continue,
1761+
};
1762+
let name_hash = fnv1a64(&name);
1763+
let should_insert = match state.globals.get(&name_hash) {
1764+
Some(existing) if existing.defined == 1 && existing.bind == 1 => false,
1765+
_ => true,
1766+
};
1767+
if should_insert {
1768+
state.globals.insert(
1769+
name_hash,
1770+
GlobalSymbol {
1771+
object_index: 0,
1772+
symbol_index: 0,
1773+
bind: 2,
1774+
defined: 1,
1775+
address: 0,
1776+
},
1777+
);
1778+
}
1779+
}
1780+
1781+
ERR_OK
1782+
}
1783+
1784+
fn ingest_shared_object_symbols(state: &mut LinkerState, path: &Path) -> u32 {
1785+
let raw = match fs::read(path) {
1786+
Ok(v) => v,
1787+
Err(_) => return ERR_FILE_NOT_FOUND,
1788+
};
1789+
match probe_object_format_bytes(&raw) {
1790+
OBJECT_FORMAT_ELF64 => ingest_shared_elf_symbols(state, &raw),
1791+
OBJECT_FORMAT_COFF64 | OBJECT_FORMAT_MACHO64 => ERR_OK,
1792+
OBJECT_FORMAT_UNKNOWN => ERR_OK,
1793+
_ => ERR_OK,
1794+
}
1795+
}
1796+
16281797
fn coff_characteristics_to_flags(characteristics: u32, section_name: &str) -> (u32, u64) {
16291798
let mut sh_flags = SHF_ALLOC;
16301799
if characteristics & 0x8000_0000 != 0 {
@@ -2293,6 +2462,13 @@ fn apply_linker_script_statement(
22932462
return ERR_OK;
22942463
}
22952464

2465+
if let Some(arg) = extract_directive_arg(statement, "OUTPUT_ARCH") {
2466+
if let Some(target) = parse_target_value(&arg) {
2467+
state.target = target;
2468+
}
2469+
return ERR_OK;
2470+
}
2471+
22962472
if let Some(arg) = extract_directive_arg(statement, "OUTPUT") {
22972473
if !arg.is_empty() {
22982474
let output_path = resolve_script_path(script_dir, &arg);
@@ -2361,6 +2537,32 @@ fn apply_linker_script_statement(
23612537
return ERR_OK;
23622538
}
23632539

2540+
if let Some(arg) = extract_directive_arg(statement, "AS_NEEDED") {
2541+
let prior = state.link_as_needed;
2542+
state.link_as_needed = true;
2543+
for token in tokenize_script_args(&arg) {
2544+
let path = resolve_script_path(script_dir, &token);
2545+
state
2546+
.inputs
2547+
.push(intern_string(path.to_string_lossy().to_string()));
2548+
}
2549+
state.link_as_needed = prior;
2550+
return ERR_OK;
2551+
}
2552+
2553+
if let Some(arg) = extract_directive_arg(statement, "NO_AS_NEEDED") {
2554+
let prior = state.link_as_needed;
2555+
state.link_as_needed = false;
2556+
for token in tokenize_script_args(&arg) {
2557+
let path = resolve_script_path(script_dir, &token);
2558+
state
2559+
.inputs
2560+
.push(intern_string(path.to_string_lossy().to_string()));
2561+
}
2562+
state.link_as_needed = prior;
2563+
return ERR_OK;
2564+
}
2565+
23642566
if let Some(arg) = extract_directive_arg(statement, "INCLUDE") {
23652567
if depth >= 32 {
23662568
return ERR_INVALID_FORMAT;
@@ -3127,6 +3329,34 @@ pub extern "C" fn host_linker_get_as_needed() -> u32 {
31273329
if state.link_as_needed { 1 } else { 0 }
31283330
}
31293331

3332+
#[no_mangle]
3333+
pub extern "C" fn host_linker_set_no_undefined(enabled: u32) -> u32 {
3334+
let mut state = linker().lock().expect("linker mutex poisoned");
3335+
state.no_undefined = enabled != 0;
3336+
set_last_error(&mut state, ERR_OK)
3337+
}
3338+
3339+
#[no_mangle]
3340+
pub extern "C" fn host_linker_get_no_undefined() -> u32 {
3341+
let state = linker().lock().expect("linker mutex poisoned");
3342+
if state.no_undefined { 1 } else { 0 }
3343+
}
3344+
3345+
#[no_mangle]
3346+
pub extern "C" fn host_linker_allow_dynamic_unresolved() -> u32 {
3347+
let state = linker().lock().expect("linker mutex poisoned");
3348+
if state.no_undefined {
3349+
return 0;
3350+
}
3351+
if state.link_static {
3352+
return 0;
3353+
}
3354+
if state.needed_shared_libs.is_empty() {
3355+
return 0;
3356+
}
3357+
1
3358+
}
3359+
31303360
#[no_mangle]
31313361
pub extern "C" fn host_linker_set_dynamic_linker(path: u64) -> u32 {
31323362
let mut state = linker().lock().expect("linker mutex poisoned");
@@ -3278,6 +3508,17 @@ pub extern "C" fn host_linker_ingest_macho_object(path: u64) -> u32 {
32783508
set_last_error(&mut state, ERR_OK)
32793509
}
32803510

3511+
#[no_mangle]
3512+
pub extern "C" fn host_linker_ingest_shared_object(path: u64) -> u32 {
3513+
let p = match to_path(path) {
3514+
Some(v) => v,
3515+
None => return ERR_FILE_NOT_FOUND,
3516+
};
3517+
let mut state = linker().lock().expect("linker mutex poisoned");
3518+
let status = ingest_shared_object_symbols(&mut state, &p);
3519+
set_last_error(&mut state, status)
3520+
}
3521+
32813522
#[no_mangle]
32823523
pub extern "C" fn host_linker_object_begin(path: u64, file_size: u64, elf_type: u16, machine: u16) -> u32 {
32833524
let mut state = linker().lock().expect("linker mutex poisoned");

0 commit comments

Comments
 (0)