1use crate::Arch;
2use crate::common::{RelocEntry, SectionKind, SymbolDesc};
3use crate::dylib::data::DataMetaData;
4use crate::dylib::dynamic::DynamicMetadata;
5use crate::dylib::layout::ElfLayout;
6use crate::dylib::reloc::RelocMetaData;
7use crate::dylib::shdr::{SectionAllocator, ShdrManager};
8use crate::dylib::symtab::SymTabMetadata;
9use crate::dylib::text::CodeMetaData;
10use crate::dylib::tls::TlsMetaData;
11use anyhow::Result;
12use byteorder::{LittleEndian, WriteBytesExt};
13use object::elf::*;
14use std::path::Path;
15
16mod data;
17mod dynamic;
18mod layout;
19pub(crate) mod reloc;
20pub(crate) mod shdr;
21pub(crate) mod symtab;
22pub(crate) mod text;
23mod tls;
24
25fn align_up(val: u64, align: u64) -> u64 {
26 val.div_ceil(align) * align
27}
28
29pub(crate) struct StringTable {
30 data: Vec<u8>,
31}
32
33impl StringTable {
34 pub(crate) fn new() -> Self {
35 Self { data: vec![0u8] } }
37
38 pub(crate) fn add(&mut self, s: &str) -> u32 {
39 let idx = self.data.len() as u32;
40 self.data.extend_from_slice(s.as_bytes());
41 self.data.push(0);
42 idx
43 }
44
45 pub(crate) fn cur_idx(&self) -> u32 {
46 self.data.len() as u32
47 }
48
49 pub(crate) fn data(&self) -> &[u8] {
50 &self.data
51 }
52}
53
54#[derive(Clone)]
55pub struct ElfWriterConfig {
56 pub base_addr: u64,
58 pub page_size: u64,
60 pub ifunc_resolver_val: Option<u64>,
62}
63
64impl Default for ElfWriterConfig {
65 fn default() -> Self {
66 Self {
67 base_addr: 0,
68 page_size: 0x1000,
69 ifunc_resolver_val: None,
70 }
71 }
72}
73
74impl ElfWriterConfig {
75 pub fn with_base_addr(mut self, addr: u64) -> Self {
77 self.base_addr = addr;
78 self
79 }
80
81 pub fn with_page_size(mut self, size: u64) -> Self {
83 self.page_size = size;
84 self
85 }
86
87 pub fn with_ifunc_resolver_val(mut self, val: u64) -> Self {
89 self.ifunc_resolver_val = Some(val);
90 self
91 }
92}
93
94#[derive(Clone, Debug)]
97pub struct RelocationInfo {
98 pub vaddr: u64,
100 pub r_type: u32,
102 pub sym_idx: u64,
104 pub addend: i64,
106 pub sym_size: u64,
108}
109
110#[derive(Clone)]
112pub struct ElfWriteOutput {
113 pub data: Vec<u8>,
115 pub base_addr: u64,
117 pub data_vaddr: u64,
119 pub text_vaddr: u64,
121 pub relocations: Vec<RelocationInfo>,
123 pub ifunc_resolver_val: u64,
125}
126
127const EHDR_SIZE_64: u64 = 64;
129const EHDR_SIZE_32: u64 = 52;
130const PHDR_SIZE_64: u64 = 56;
131const PHDR_SIZE_32: u64 = 32;
132const SHDR_SIZE_64: u64 = 64;
133const SHDR_SIZE_32: u64 = 40;
134const SYM_SIZE_64: u64 = 24;
135const SYM_SIZE_32: u64 = 16;
136const RELA_SIZE_64: u64 = 24;
137const RELA_SIZE_32: u64 = 12;
138const REL_SIZE_64: u64 = 16;
139const REL_SIZE_32: u64 = 8;
140const DYN_SIZE_64: u64 = 16;
141const DYN_SIZE_32: u64 = 8;
142const HASH_SIZE: u64 = 4;
143
144pub struct DylibWriter {
146 arch: Arch,
147 config: ElfWriterConfig,
148}
149
150impl DylibWriter {
151 pub fn new(arch: Arch) -> Self {
153 let config = ElfWriterConfig::default();
154 Self { arch, config }
155 }
156
157 pub fn with_config(arch: Arch, config: ElfWriterConfig) -> Self {
159 Self { arch, config }
160 }
161
162 pub fn write_file(
164 &self,
165 out_path: &Path,
166 relocs: &[RelocEntry],
167 symbols: &[SymbolDesc],
168 ) -> Result<ElfWriteOutput> {
169 let output = self.write(relocs, symbols)?;
170 std::fs::write(out_path, &output.data)?;
171 Ok(output)
172 }
173
174 pub fn write(
176 &self,
177 raw_relocs: &[RelocEntry],
178 symbols: &[SymbolDesc],
179 ) -> Result<ElfWriteOutput> {
180 let is_64 = self.arch.is_64();
181
182 let final_relocs = RelocMetaData::preprocess(self.arch, raw_relocs);
184
185 let mut allocator = SectionAllocator::new();
186 let mut symtab = SymTabMetadata::new(self.arch, symbols, &final_relocs, &mut allocator);
187 let mut reloc = RelocMetaData::new(self.arch, &final_relocs, &symtab, &mut allocator)?;
188
189 let data = DataMetaData::new(&reloc, &symtab, &mut allocator);
190 let mut text = CodeMetaData::new(&symtab, &mut allocator);
191 let tls = TlsMetaData::new(&symtab, &mut allocator);
192
193 let mut sections = vec![];
195 text.create_sections(&mut sections);
196 data.create_sections(&mut sections);
197 tls.create_section(&mut sections);
198 symtab.create_sections(&mut sections);
199 reloc.create_sections(&mut sections)?;
200
201 let mut dyn_meta = DynamicMetadata::new(self.arch, §ions, &mut allocator);
203 dyn_meta.create_section(&mut sections);
204
205 let mut shdr_manager = ShdrManager::new();
207 for sec in sections {
208 shdr_manager.add_section(sec.header, sec.data);
209 }
210
211 shdr_manager.create_shstrtab_section(&mut allocator);
213
214 let mut layout = ElfLayout::new(&self.config);
216 let ehdr_size = if is_64 { EHDR_SIZE_64 } else { EHDR_SIZE_32 };
217 let ph_size =
218 (if is_64 { PHDR_SIZE_64 } else { PHDR_SIZE_32 }) * shdr_manager.get_phnum() as u64;
219 layout.add_header(ehdr_size, ph_size);
220 shdr_manager.layout(&mut layout);
221
222 let shdr_map = shdr_manager.get_shdr_map();
224 let plt_vaddr = shdr_manager.get_vaddr(SectionKind::Plt);
225 let text_vaddr = shdr_manager.get_vaddr(SectionKind::Text);
226 let data_vaddr = shdr_manager.get_vaddr(SectionKind::Data);
227 let got_plt_vaddr = shdr_manager.get_vaddr(SectionKind::GotPlt);
228
229 symtab.patch_symtab(plt_vaddr, text_vaddr, data_vaddr, &shdr_map, &mut allocator);
231
232 let resolver_val = self.config.ifunc_resolver_val.unwrap_or(plt_vaddr);
234 text.patch_text(
235 plt_vaddr,
236 text_vaddr,
237 got_plt_vaddr,
238 resolver_val,
239 &symtab,
240 &reloc,
241 &shdr_manager,
242 &mut allocator,
243 );
244
245 reloc.patch_all(&shdr_manager, &symtab, &mut allocator)?;
247
248 dyn_meta.patch_dynamic(&shdr_manager, &reloc, &mut allocator, got_plt_vaddr)?;
250
251 let mut out_bytes = vec![];
253 let ehdr = ElfHeader {
255 ident: self.get_ident(),
256 type_: ET_DYN,
257 machine: self.get_machine(),
258 version: EV_CURRENT as u32,
259 entry: 0,
260 phoff: ehdr_size,
261 shoff: layout.file_off,
262 flags: self.get_flags(),
263 ehsize: ehdr_size as u16,
264 phentsize: (if is_64 { PHDR_SIZE_64 } else { PHDR_SIZE_32 }) as u16,
265 phnum: shdr_manager.get_phnum(),
266 shentsize: (if is_64 { SHDR_SIZE_64 } else { SHDR_SIZE_32 }) as u16,
267 shnum: (shdr_manager.get_shdr_count() + 1) as u16,
268 shstrndx: *shdr_map.get(&SectionKind::ShStrTab).unwrap() as u16,
269 };
270 ehdr.write(&mut out_bytes, is_64)?;
271
272 shdr_manager.write_phdrs(&mut out_bytes, is_64, self.config.page_size)?;
274
275 for sec in shdr_manager.get_sections() {
277 self.write_at(&mut out_bytes, sec.header.offset, allocator.get(&sec.data));
278 }
279
280 let mut shdr_buf = vec![];
282 shdr_manager.write_shdrs(&mut shdr_buf, is_64)?;
283 self.write_at(&mut out_bytes, layout.file_off, &shdr_buf);
284
285 Ok(ElfWriteOutput {
286 data: out_bytes,
287 base_addr: self.config.base_addr,
288 data_vaddr,
289 text_vaddr,
290 relocations: reloc.get_relocation_infos(),
291 ifunc_resolver_val: resolver_val,
292 })
293 }
294
295 fn get_ident(&self) -> [u8; 16] {
296 let mut ident = [0u8; 16];
297 ident[0] = 0x7f;
298 ident[1] = b'E';
299 ident[2] = b'L';
300 ident[3] = b'F';
301 ident[4] = if self.arch.is_64() { 2 } else { 1 };
302 ident[5] = 1; ident[6] = 1; ident[7] = 0; ident
306 }
307
308 fn write_at(&self, buf: &mut Vec<u8>, offset: u64, data: &[u8]) {
309 let offset = offset as usize;
310 if buf.len() < offset + data.len() {
311 buf.resize(offset + data.len(), 0);
312 }
313 buf[offset..offset + data.len()].copy_from_slice(data);
314 }
315
316 fn get_flags(&self) -> u32 {
317 match self.arch {
318 Arch::Riscv64 | Arch::Riscv32 => {
319 0x0001 | 0x0004
321 }
322 Arch::Arm => {
323 0x05000000 | 0x00000400
325 }
326 _ => 0,
327 }
328 }
329
330 fn get_machine(&self) -> u16 {
331 match self.arch {
332 Arch::X86_64 => EM_X86_64,
333 Arch::X86 => EM_386,
334 Arch::Aarch64 => EM_AARCH64,
335 Arch::Riscv64 => EM_RISCV,
336 Arch::Riscv32 => EM_RISCV,
337 Arch::Arm => EM_ARM,
338 Arch::Loongarch64 => EM_LOONGARCH,
339 }
340 }
341}
342
343struct ElfHeader {
344 ident: [u8; 16],
345 type_: u16,
346 machine: u16,
347 version: u32,
348 entry: u64,
349 phoff: u64,
350 shoff: u64,
351 flags: u32,
352 ehsize: u16,
353 phentsize: u16,
354 phnum: u16,
355 shentsize: u16,
356 shnum: u16,
357 shstrndx: u16,
358}
359
360impl ElfHeader {
361 fn write(&self, buf: &mut Vec<u8>, is_64: bool) -> Result<()> {
362 buf.extend_from_slice(&self.ident);
363 buf.write_u16::<LittleEndian>(self.type_)?;
364 buf.write_u16::<LittleEndian>(self.machine)?;
365 buf.write_u32::<LittleEndian>(self.version)?;
366 if is_64 {
367 buf.write_u64::<LittleEndian>(self.entry)?;
368 buf.write_u64::<LittleEndian>(self.phoff)?;
369 buf.write_u64::<LittleEndian>(self.shoff)?;
370 } else {
371 buf.write_u32::<LittleEndian>(self.entry as u32)?;
372 buf.write_u32::<LittleEndian>(self.phoff as u32)?;
373 buf.write_u32::<LittleEndian>(self.shoff as u32)?;
374 }
375 buf.write_u32::<LittleEndian>(self.flags)?;
376 buf.write_u16::<LittleEndian>(self.ehsize)?;
377 buf.write_u16::<LittleEndian>(self.phentsize)?;
378 buf.write_u16::<LittleEndian>(self.phnum)?;
379 buf.write_u16::<LittleEndian>(self.shentsize)?;
380 buf.write_u16::<LittleEndian>(self.shnum)?;
381 buf.write_u16::<LittleEndian>(self.shstrndx)?;
382 Ok(())
383 }
384}