1use crate::Arch;
2use crate::common::{
3 RelocEntry, SectionKind, SymbolDesc, SymbolScope as CommonSymbolScope, SymbolType,
4};
5use anyhow::Result;
6use object::{
7 Architecture, BinaryFormat, Endianness, SectionKind as ObjectSectionKind, SymbolKind,
8 SymbolScope,
9 write::{Object, Relocation, Symbol, SymbolSection},
10};
11use std::collections::HashMap;
12
13pub struct ObjectElfOutput {
15 pub data: Vec<u8>,
17 pub reloc_offsets: Vec<u64>,
19}
20
21pub struct ObjectWriter {
23 arch: Arch,
24}
25
26impl ObjectWriter {
27 pub fn new(arch: Arch) -> Self {
29 Self { arch }
30 }
31
32 pub fn write(&self, symbols: &[SymbolDesc], relocs: &[RelocEntry]) -> Result<ObjectElfOutput> {
34 gen_static_elf(self.arch, symbols, relocs)
35 }
36
37 pub fn write_file(
39 &self,
40 out_path: &std::path::Path,
41 symbols: &[SymbolDesc],
42 relocs: &[RelocEntry],
43 ) -> Result<ObjectElfOutput> {
44 let output = self.write(symbols, relocs)?;
45 std::fs::write(out_path, &output.data)?;
46 Ok(output)
47 }
48}
49
50fn gen_static_elf(
51 arch: Arch,
52 symbols: &[SymbolDesc],
53 relocs: &[RelocEntry],
54) -> Result<ObjectElfOutput> {
55 let obj_arch: Architecture = arch.into();
56 let mut obj = Object::new(BinaryFormat::Elf, obj_arch, Endianness::Little);
57
58 let mut section_map = HashMap::new();
59 let mut symbol_map = HashMap::new();
60 let mut reloc_offsets = Vec::new();
61
62 for sym_desc in symbols {
64 if let Some(content) = &sym_desc.content {
65 let section_id = *section_map.entry(content.kind).or_insert_with(|| {
66 let (name, kind) = match content.kind {
67 SectionKind::Text => (".text", ObjectSectionKind::Text),
68 SectionKind::Data => (".data", ObjectSectionKind::Data),
69 SectionKind::Plt => (".plt", ObjectSectionKind::Text),
70 SectionKind::Tls => (".tdata", ObjectSectionKind::Tls),
71 _ => (".data", ObjectSectionKind::Data),
72 };
73 obj.add_section(vec![], name.as_bytes().to_vec(), kind)
74 });
75
76 let offset = obj.append_section_data(section_id, &content.data, 8);
77
78 let symbol_id = obj.add_symbol(Symbol {
79 name: sym_desc.name.as_bytes().to_vec(),
80 value: offset,
81 size: content.data.len() as u64,
82 kind: match sym_desc.sym_type {
83 SymbolType::Func => SymbolKind::Text,
84 SymbolType::Object => SymbolKind::Data,
85 SymbolType::Tls => SymbolKind::Tls,
86 },
87 scope: match sym_desc.scope {
88 CommonSymbolScope::Global => SymbolScope::Dynamic,
89 CommonSymbolScope::Local => SymbolScope::Compilation,
90 CommonSymbolScope::Weak => SymbolScope::Dynamic,
91 },
92 weak: sym_desc.scope == CommonSymbolScope::Weak,
93 section: SymbolSection::Section(section_id),
94 flags: object::SymbolFlags::None,
95 });
96 symbol_map.insert(sym_desc.name.clone(), symbol_id);
97 }
98 }
99
100 for sym_desc in symbols {
102 if sym_desc.content.is_none() {
103 let symbol_id = obj.add_symbol(Symbol {
104 name: sym_desc.name.as_bytes().to_vec(),
105 value: 0,
106 size: 0,
107 kind: match sym_desc.sym_type {
108 SymbolType::Func => SymbolKind::Text,
109 SymbolType::Object => SymbolKind::Data,
110 SymbolType::Tls => SymbolKind::Tls,
111 },
112 scope: SymbolScope::Dynamic,
113 weak: sym_desc.scope == CommonSymbolScope::Weak,
114 section: SymbolSection::Undefined,
115 flags: object::SymbolFlags::None,
116 });
117 symbol_map.insert(sym_desc.name.clone(), symbol_id);
118 }
119 }
120
121 let target_section_id = section_map
128 .get(&SectionKind::Text)
129 .or_else(|| section_map.get(&SectionKind::Data))
130 .copied();
131
132 if let Some(section_id) = target_section_id {
133 let word_size = if arch.is_64() { 8 } else { 4 };
134 for (idx, reloc) in relocs.iter().enumerate() {
135 let symbol_id = if reloc.symbol_name.is_empty() {
136 obj.section_symbol(section_id)
138 } else {
139 *symbol_map.get(&reloc.symbol_name).ok_or_else(|| {
140 anyhow::anyhow!("Symbol not found for relocation: {}", reloc.symbol_name)
141 })?
142 };
143
144 let offset = 0x10 + (idx as u64 * word_size);
147 reloc_offsets.push(offset);
148
149 let flags = object::write::RelocationFlags::Elf {
150 r_type: reloc.r_type.0,
151 };
152
153 obj.add_relocation(
154 section_id,
155 Relocation {
156 offset,
157 symbol: symbol_id,
158 addend: 0, flags,
160 },
161 )?;
162 }
163 }
164
165 let elf_data = obj.write()?;
167
168 Ok(ObjectElfOutput {
169 data: elf_data,
170 reloc_offsets,
171 })
172}