]> git.proxmox.com Git - rustc.git/blame - vendor/object-0.22.0/src/write/elf.rs
New upstream version 1.55.0+dfsg1
[rustc.git] / vendor / object-0.22.0 / src / write / elf.rs
CommitLineData
f035d41b
XL
1use std::mem;
2use std::vec::Vec;
3
4use crate::elf;
5use crate::endian::*;
fc512014 6use crate::pod::{bytes_of, BytesMut, WritableBuffer};
f035d41b
XL
7use crate::write::string::*;
8use crate::write::util::*;
9use crate::write::*;
10
fc512014
XL
11#[derive(Default, Clone, Copy)]
12struct ComdatOffsets {
13 offset: usize,
14 str_id: Option<StringId>,
15 len: usize,
16}
17
f035d41b
XL
18#[derive(Default, Clone, Copy)]
19struct SectionOffsets {
20 index: usize,
21 offset: usize,
22 str_id: Option<StringId>,
23 reloc_index: usize,
24 reloc_offset: usize,
25 reloc_len: usize,
26 reloc_str_id: Option<StringId>,
27}
28
29#[derive(Default, Clone, Copy)]
30struct SymbolOffsets {
31 index: usize,
32 str_id: Option<StringId>,
33}
34
35impl Object {
36 pub(crate) fn elf_section_info(
37 &self,
38 section: StandardSection,
39 ) -> (&'static [u8], &'static [u8], SectionKind) {
40 match section {
41 StandardSection::Text => (&[], &b".text"[..], SectionKind::Text),
42 StandardSection::Data => (&[], &b".data"[..], SectionKind::Data),
43 StandardSection::ReadOnlyData | StandardSection::ReadOnlyString => {
44 (&[], &b".rodata"[..], SectionKind::ReadOnlyData)
45 }
46 StandardSection::ReadOnlyDataWithRel => (&[], b".data.rel.ro", SectionKind::Data),
47 StandardSection::UninitializedData => {
48 (&[], &b".bss"[..], SectionKind::UninitializedData)
49 }
50 StandardSection::Tls => (&[], &b".tdata"[..], SectionKind::Tls),
51 StandardSection::UninitializedTls => {
52 (&[], &b".tbss"[..], SectionKind::UninitializedTls)
53 }
54 StandardSection::TlsVariables => {
55 // Unsupported section.
56 (&[], &[], SectionKind::TlsVariables)
57 }
58 StandardSection::Common => {
59 // Unsupported section.
60 (&[], &[], SectionKind::Common)
61 }
62 }
63 }
64
65 pub(crate) fn elf_subsection_name(&self, section: &[u8], value: &[u8]) -> Vec<u8> {
66 let mut name = section.to_vec();
67 name.push(b'.');
68 name.extend(value);
69 name
70 }
71
72 fn elf_has_relocation_addend(&self) -> Result<bool> {
73 Ok(match self.architecture {
74 Architecture::Arm => false,
75 Architecture::Aarch64 => true,
76 Architecture::I386 => false,
77 Architecture::X86_64 => true,
fc512014 78 Architecture::S390x => true,
f035d41b
XL
79 _ => {
80 return Err(Error(format!(
81 "unimplemented architecture {:?}",
82 self.architecture
83 )));
84 }
85 })
86 }
87
88 pub(crate) fn elf_fixup_relocation(&mut self, mut relocation: &mut Relocation) -> Result<i64> {
89 // Return true if we should use a section symbol to avoid preemption.
90 fn want_section_symbol(relocation: &Relocation, symbol: &Symbol) -> bool {
91 if symbol.scope != SymbolScope::Dynamic {
92 // Only dynamic symbols can be preemptible.
93 return false;
94 }
95 match symbol.kind {
96 SymbolKind::Text | SymbolKind::Data => {}
97 _ => return false,
98 }
99 match relocation.kind {
100 // Anything using GOT or PLT is preemptible.
101 // We also require that `Other` relocations must already be correct.
102 RelocationKind::Got
103 | RelocationKind::GotRelative
104 | RelocationKind::GotBaseRelative
105 | RelocationKind::PltRelative
106 | RelocationKind::Elf(_) => return false,
107 // Absolute relocations are preemptible for non-local data.
108 // TODO: not sure if this rule is exactly correct
109 // This rule was added to handle global data references in debuginfo.
110 // Maybe this should be a new relocation kind so that the caller can decide.
111 RelocationKind::Absolute => {
112 if symbol.kind == SymbolKind::Data {
113 return false;
114 }
115 }
116 _ => {}
117 }
118 true
119 }
120
121 // Use section symbols for relocations where required to avoid preemption.
122 // Otherwise, the linker will fail with:
123 // relocation R_X86_64_PC32 against symbol `SomeSymbolName' can not be used when
124 // making a shared object; recompile with -fPIC
125 let symbol = &self.symbols[relocation.symbol.0];
126 if want_section_symbol(relocation, symbol) {
127 if let Some(section) = symbol.section.id() {
128 relocation.addend += symbol.value as i64;
129 relocation.symbol = self.section_symbol(section);
130 }
131 }
132
133 // Determine whether the addend is stored in the relocation or the data.
134 if self.elf_has_relocation_addend()? {
135 Ok(0)
136 } else {
137 let constant = relocation.addend;
138 relocation.addend = 0;
139 Ok(constant)
140 }
141 }
142
fc512014 143 pub(crate) fn elf_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> {
f035d41b
XL
144 let address_size = self.architecture.address_size().unwrap();
145 let endian = self.endian;
146 let elf32 = Elf32 { endian };
147 let elf64 = Elf64 { endian };
148 let elf: &dyn Elf = match address_size {
149 AddressSize::U32 => &elf32,
150 AddressSize::U64 => &elf64,
151 };
152 let pointer_align = address_size.bytes() as usize;
153
154 // Calculate offsets of everything.
155 let mut offset = 0;
156
157 // ELF header.
158 let e_ehsize = elf.file_header_size();
159 offset += e_ehsize;
160
161 // Create reloc section header names.
162 let is_rela = self.elf_has_relocation_addend()?;
163 let reloc_names: Vec<_> = self
164 .sections
165 .iter()
166 .map(|section| {
167 let mut reloc_name = Vec::new();
168 if !section.relocations.is_empty() {
169 reloc_name.extend_from_slice(if is_rela {
170 &b".rela"[..]
171 } else {
172 &b".rel"[..]
173 });
174 reloc_name.extend_from_slice(&section.name);
175 }
176 reloc_name
177 })
178 .collect();
179
180 // Calculate size of section data.
181 let mut shstrtab = StringTable::default();
fc512014 182 let mut comdat_offsets = vec![ComdatOffsets::default(); self.comdats.len()];
f035d41b
XL
183 let mut section_offsets = vec![SectionOffsets::default(); self.sections.len()];
184 // Null section.
185 let mut section_num = 1;
fc512014
XL
186 for (index, comdat) in self.comdats.iter().enumerate() {
187 if comdat.kind != ComdatKind::Any {
188 return Err(Error(format!(
189 "unsupported COMDAT symbol `{}` kind {:?}",
190 self.symbols[comdat.symbol.0].name().unwrap_or(""),
191 comdat.kind
192 )));
193 }
194
195 comdat_offsets[index].str_id = Some(shstrtab.add(b".group"));
196 section_num += 1;
197 offset = align(offset, 4);
198 comdat_offsets[index].offset = offset;
199 let len = (comdat.sections.len() + 1) * 4;
200 comdat_offsets[index].len = len;
201 offset += len;
202 }
f035d41b
XL
203 for (index, section) in self.sections.iter().enumerate() {
204 section_offsets[index].str_id = Some(shstrtab.add(&section.name));
205 section_offsets[index].index = section_num;
206 section_num += 1;
207
208 let len = section.data.len();
209 if len != 0 {
210 offset = align(offset, section.align as usize);
211 section_offsets[index].offset = offset;
212 offset += len;
213 } else {
214 section_offsets[index].offset = offset;
215 }
216
217 if !section.relocations.is_empty() {
218 section_offsets[index].reloc_str_id = Some(shstrtab.add(&reloc_names[index]));
219 section_offsets[index].reloc_index = section_num;
220 section_num += 1;
221 }
222 }
223
224 // Calculate index of symbols and add symbol strings to strtab.
225 let mut strtab = StringTable::default();
226 let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()];
227 // Null symbol.
228 let mut symtab_count = 1;
229 // Local symbols must come before global.
230 for (index, symbol) in self.symbols.iter().enumerate() {
231 if symbol.is_local() {
232 symbol_offsets[index].index = symtab_count;
233 symtab_count += 1;
234 }
235 }
236 let symtab_count_local = symtab_count;
237 for (index, symbol) in self.symbols.iter().enumerate() {
238 if !symbol.is_local() {
239 symbol_offsets[index].index = symtab_count;
240 symtab_count += 1;
241 }
242 }
243 for (index, symbol) in self.symbols.iter().enumerate() {
244 if symbol.kind != SymbolKind::Section {
245 symbol_offsets[index].str_id = Some(strtab.add(&symbol.name));
246 }
247 }
248
249 // Calculate size of symtab.
250 let symtab_str_id = shstrtab.add(&b".symtab"[..]);
251 offset = align(offset, pointer_align);
252 let symtab_offset = offset;
253 let symtab_len = symtab_count * elf.symbol_size();
254 offset += symtab_len;
255 let symtab_index = section_num;
256 section_num += 1;
257
258 // Calculate size of symtab_shndx.
259 let mut need_symtab_shndx = false;
260 for symbol in &self.symbols {
261 let index = symbol
262 .section
263 .id()
264 .map(|s| section_offsets[s.0].index)
265 .unwrap_or(0);
266 if index >= elf::SHN_LORESERVE as usize {
267 need_symtab_shndx = true;
268 break;
269 }
270 }
271 let symtab_shndx_offset = offset;
272 let mut symtab_shndx_str_id = None;
273 let mut symtab_shndx_len = 0;
274 if need_symtab_shndx {
275 symtab_shndx_str_id = Some(shstrtab.add(&b".symtab_shndx"[..]));
276 symtab_shndx_len = symtab_count * 4;
277 offset += symtab_shndx_len;
278 section_num += 1;
279 }
280
281 // Calculate size of strtab.
282 let strtab_str_id = shstrtab.add(&b".strtab"[..]);
283 let strtab_offset = offset;
284 let mut strtab_data = Vec::new();
285 // Null name.
286 strtab_data.push(0);
287 strtab.write(1, &mut strtab_data);
288 offset += strtab_data.len();
289 let strtab_index = section_num;
290 section_num += 1;
291
292 // Calculate size of relocations.
293 for (index, section) in self.sections.iter().enumerate() {
294 let count = section.relocations.len();
295 if count != 0 {
296 offset = align(offset, pointer_align);
297 section_offsets[index].reloc_offset = offset;
298 let len = count * elf.rel_size(is_rela);
299 section_offsets[index].reloc_len = len;
300 offset += len;
301 }
302 }
303
304 // Calculate size of shstrtab.
305 let shstrtab_str_id = shstrtab.add(&b".shstrtab"[..]);
306 let shstrtab_offset = offset;
307 let mut shstrtab_data = Vec::new();
308 // Null section name.
309 shstrtab_data.push(0);
310 shstrtab.write(1, &mut shstrtab_data);
311 offset += shstrtab_data.len();
312 let shstrtab_index = section_num;
313 section_num += 1;
314
315 // Calculate size of section headers.
316 offset = align(offset, pointer_align);
317 let e_shoff = offset;
318 let e_shentsize = elf.section_header_size();
319 offset += section_num * e_shentsize;
320
321 // Start writing.
fc512014
XL
322 buffer
323 .reserve(offset)
324 .map_err(|_| Error(String::from("Cannot allocate buffer")))?;
f035d41b
XL
325
326 // Write file header.
327 let e_ident = elf::Ident {
328 magic: elf::ELFMAG,
329 class: match address_size {
330 AddressSize::U32 => elf::ELFCLASS32,
331 AddressSize::U64 => elf::ELFCLASS64,
332 },
333 data: if endian.is_little_endian() {
334 elf::ELFDATA2LSB
335 } else {
336 elf::ELFDATA2MSB
337 },
338 version: elf::EV_CURRENT,
339 os_abi: elf::ELFOSABI_NONE,
340 abi_version: 0,
341 padding: [0; 7],
342 };
343 let e_type = elf::ET_REL;
344 let e_machine = match self.architecture {
345 Architecture::Arm => elf::EM_ARM,
346 Architecture::Aarch64 => elf::EM_AARCH64,
347 Architecture::I386 => elf::EM_386,
348 Architecture::X86_64 => elf::EM_X86_64,
fc512014 349 Architecture::S390x => elf::EM_S390,
f035d41b
XL
350 _ => {
351 return Err(Error(format!(
352 "unimplemented architecture {:?}",
353 self.architecture
354 )));
355 }
356 };
357 let e_flags = if let FileFlags::Elf { e_flags } = self.flags {
358 e_flags
359 } else {
360 0
361 };
362 let e_shnum = if section_num >= elf::SHN_LORESERVE as usize {
363 0
364 } else {
365 section_num as u16
366 };
367 let e_shstrndx = if shstrtab_index >= elf::SHN_LORESERVE as usize {
368 elf::SHN_XINDEX
369 } else {
370 shstrtab_index as u16
371 };
372
373 elf.write_file_header(
fc512014 374 buffer,
f035d41b
XL
375 FileHeader {
376 e_ident,
377 e_type,
378 e_machine,
379 e_version: elf::EV_CURRENT.into(),
380 e_entry: 0,
381 e_phoff: 0,
382 e_shoff: e_shoff as u64,
383 e_flags,
384 e_ehsize: e_ehsize as u16,
385 e_phentsize: 0,
386 e_phnum: 0,
387 e_shentsize: e_shentsize as u16,
388 e_shnum,
389 e_shstrndx,
390 },
391 );
392
393 // Write section data.
fc512014
XL
394 for (index, comdat) in self.comdats.iter().enumerate() {
395 let mut data = BytesMut::new();
396 data.write(&U32::new(endian, elf::GRP_COMDAT));
397 for section in &comdat.sections {
398 data.write(&U32::new(endian, section_offsets[section.0].index as u32));
399 }
400
401 write_align(buffer, 4);
402 debug_assert_eq!(comdat_offsets[index].offset, buffer.len());
403 debug_assert_eq!(comdat_offsets[index].len, data.len());
404 buffer.extend(data.as_slice());
405 }
f035d41b
XL
406 for (index, section) in self.sections.iter().enumerate() {
407 let len = section.data.len();
408 if len != 0 {
fc512014 409 write_align(buffer, section.align as usize);
f035d41b 410 debug_assert_eq!(section_offsets[index].offset, buffer.len());
fc512014 411 buffer.extend(section.data.as_slice());
f035d41b
XL
412 }
413 }
414
415 // Write symbols.
fc512014 416 write_align(buffer, pointer_align);
f035d41b
XL
417 debug_assert_eq!(symtab_offset, buffer.len());
418 elf.write_symbol(
fc512014 419 buffer,
f035d41b
XL
420 Sym {
421 st_name: 0,
422 st_info: 0,
423 st_other: 0,
424 st_shndx: 0,
425 st_value: 0,
426 st_size: 0,
427 },
428 );
429 let mut symtab_shndx = BytesMut::new();
430 if need_symtab_shndx {
431 symtab_shndx.write(&U32::new(endian, 0));
432 }
433 let mut write_symbol = |index: usize, symbol: &Symbol| -> Result<()> {
434 let st_info = if let SymbolFlags::Elf { st_info, .. } = symbol.flags {
435 st_info
436 } else {
437 let st_type = match symbol.kind {
438 SymbolKind::Null => elf::STT_NOTYPE,
439 SymbolKind::Text => {
440 if symbol.is_undefined() {
441 elf::STT_NOTYPE
442 } else {
443 elf::STT_FUNC
444 }
445 }
446 SymbolKind::Data => {
447 if symbol.is_undefined() {
448 elf::STT_NOTYPE
449 } else if symbol.is_common() {
450 elf::STT_COMMON
451 } else {
452 elf::STT_OBJECT
453 }
454 }
455 SymbolKind::Section => elf::STT_SECTION,
456 SymbolKind::File => elf::STT_FILE,
457 SymbolKind::Tls => elf::STT_TLS,
458 SymbolKind::Label => elf::STT_NOTYPE,
459 SymbolKind::Unknown => {
460 if symbol.is_undefined() {
461 elf::STT_NOTYPE
462 } else {
463 return Err(Error(format!(
464 "unimplemented symbol `{}` kind {:?}",
465 symbol.name().unwrap_or(""),
466 symbol.kind
467 )));
468 }
469 }
470 };
fc512014
XL
471 let st_bind = if symbol.weak {
472 elf::STB_WEAK
473 } else if symbol.is_undefined() {
f035d41b
XL
474 elf::STB_GLOBAL
475 } else if symbol.is_local() {
476 elf::STB_LOCAL
f035d41b
XL
477 } else {
478 elf::STB_GLOBAL
479 };
480 (st_bind << 4) + st_type
481 };
482 let st_other = if let SymbolFlags::Elf { st_other, .. } = symbol.flags {
483 st_other
484 } else if symbol.scope == SymbolScope::Linkage {
485 elf::STV_HIDDEN
486 } else {
487 elf::STV_DEFAULT
488 };
489 let (st_shndx, xindex) = match symbol.section {
490 SymbolSection::None => {
491 debug_assert_eq!(symbol.kind, SymbolKind::File);
492 (elf::SHN_ABS, 0)
493 }
494 SymbolSection::Undefined => (elf::SHN_UNDEF, 0),
495 SymbolSection::Absolute => (elf::SHN_ABS, 0),
496 SymbolSection::Common => (elf::SHN_COMMON, 0),
497 SymbolSection::Section(id) => {
498 let index = section_offsets[id.0].index as u32;
499 (
500 if index >= elf::SHN_LORESERVE as u32 {
501 elf::SHN_XINDEX
502 } else {
503 index as u16
504 },
505 index,
506 )
507 }
508 };
509 let st_name = symbol_offsets[index]
510 .str_id
511 .map(|id| strtab.get_offset(id))
512 .unwrap_or(0) as u32;
513 elf.write_symbol(
fc512014 514 buffer,
f035d41b
XL
515 Sym {
516 st_name,
517 st_info,
518 st_other,
519 st_shndx,
520 st_value: symbol.value,
521 st_size: symbol.size,
522 },
523 );
524 if need_symtab_shndx {
525 symtab_shndx.write(&U32::new(endian, xindex));
526 }
527 Ok(())
528 };
529 for (index, symbol) in self.symbols.iter().enumerate() {
530 if symbol.is_local() {
531 write_symbol(index, symbol)?;
532 }
533 }
534 for (index, symbol) in self.symbols.iter().enumerate() {
535 if !symbol.is_local() {
536 write_symbol(index, symbol)?;
537 }
538 }
539 if need_symtab_shndx {
540 debug_assert_eq!(symtab_shndx_offset, buffer.len());
541 debug_assert_eq!(symtab_shndx_len, symtab_shndx.len());
fc512014 542 buffer.extend(symtab_shndx.as_slice());
f035d41b
XL
543 }
544
545 // Write strtab section.
546 debug_assert_eq!(strtab_offset, buffer.len());
547 buffer.extend(&strtab_data);
548
549 // Write relocations.
550 for (index, section) in self.sections.iter().enumerate() {
551 if !section.relocations.is_empty() {
fc512014 552 write_align(buffer, pointer_align);
f035d41b
XL
553 debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len());
554 for reloc in &section.relocations {
555 let r_type = match self.architecture {
556 Architecture::I386 => match (reloc.kind, reloc.size) {
557 (RelocationKind::Absolute, 32) => elf::R_386_32,
558 (RelocationKind::Relative, 32) => elf::R_386_PC32,
559 (RelocationKind::Got, 32) => elf::R_386_GOT32,
560 (RelocationKind::PltRelative, 32) => elf::R_386_PLT32,
561 (RelocationKind::GotBaseOffset, 32) => elf::R_386_GOTOFF,
562 (RelocationKind::GotBaseRelative, 32) => elf::R_386_GOTPC,
563 (RelocationKind::Absolute, 16) => elf::R_386_16,
564 (RelocationKind::Relative, 16) => elf::R_386_PC16,
565 (RelocationKind::Absolute, 8) => elf::R_386_8,
566 (RelocationKind::Relative, 8) => elf::R_386_PC8,
567 (RelocationKind::Elf(x), _) => x,
568 _ => {
569 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
570 }
571 },
572 Architecture::X86_64 => match (reloc.kind, reloc.encoding, reloc.size) {
573 (RelocationKind::Absolute, RelocationEncoding::Generic, 64) => {
574 elf::R_X86_64_64
575 }
576 (RelocationKind::Relative, _, 32) => elf::R_X86_64_PC32,
577 (RelocationKind::Got, _, 32) => elf::R_X86_64_GOT32,
578 (RelocationKind::PltRelative, _, 32) => elf::R_X86_64_PLT32,
579 (RelocationKind::GotRelative, _, 32) => elf::R_X86_64_GOTPCREL,
580 (RelocationKind::Absolute, RelocationEncoding::Generic, 32) => {
581 elf::R_X86_64_32
582 }
583 (RelocationKind::Absolute, RelocationEncoding::X86Signed, 32) => {
584 elf::R_X86_64_32S
585 }
586 (RelocationKind::Absolute, _, 16) => elf::R_X86_64_16,
587 (RelocationKind::Relative, _, 16) => elf::R_X86_64_PC16,
588 (RelocationKind::Absolute, _, 8) => elf::R_X86_64_8,
589 (RelocationKind::Relative, _, 8) => elf::R_X86_64_PC8,
590 (RelocationKind::Elf(x), _, _) => x,
591 _ => {
592 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
593 }
594 },
595 Architecture::Aarch64 => match (reloc.kind, reloc.encoding, reloc.size) {
596 (RelocationKind::Absolute, RelocationEncoding::Generic, 32) => {
597 elf::R_AARCH64_ABS32
598 }
599 (RelocationKind::Absolute, RelocationEncoding::Generic, 64) => {
600 elf::R_AARCH64_ABS64
601 }
602 (RelocationKind::Elf(x), _, _) => x,
603 _ => {
604 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
605 }
606 },
fc512014
XL
607 Architecture::S390x => match (reloc.kind, reloc.encoding, reloc.size) {
608 (RelocationKind::Absolute, RelocationEncoding::Generic, 8) => {
609 elf::R_390_8
610 }
611 (RelocationKind::Absolute, RelocationEncoding::Generic, 16) => {
612 elf::R_390_16
613 }
614 (RelocationKind::Absolute, RelocationEncoding::Generic, 32) => {
615 elf::R_390_32
616 }
617 (RelocationKind::Absolute, RelocationEncoding::Generic, 64) => {
618 elf::R_390_64
619 }
620 (RelocationKind::Relative, RelocationEncoding::Generic, 16) => {
621 elf::R_390_PC16
622 }
623 (RelocationKind::Relative, RelocationEncoding::Generic, 32) => {
624 elf::R_390_PC32
625 }
626 (RelocationKind::Relative, RelocationEncoding::Generic, 64) => {
627 elf::R_390_PC64
628 }
629 (RelocationKind::Relative, RelocationEncoding::S390xDbl, 16) => {
630 elf::R_390_PC16DBL
631 }
632 (RelocationKind::Relative, RelocationEncoding::S390xDbl, 32) => {
633 elf::R_390_PC32DBL
634 }
635 (RelocationKind::PltRelative, RelocationEncoding::S390xDbl, 16) => {
636 elf::R_390_PLT16DBL
637 }
638 (RelocationKind::PltRelative, RelocationEncoding::S390xDbl, 32) => {
639 elf::R_390_PLT32DBL
640 }
641 (RelocationKind::Got, RelocationEncoding::Generic, 16) => {
642 elf::R_390_GOT16
643 }
644 (RelocationKind::Got, RelocationEncoding::Generic, 32) => {
645 elf::R_390_GOT32
646 }
647 (RelocationKind::Got, RelocationEncoding::Generic, 64) => {
648 elf::R_390_GOT64
649 }
650 (RelocationKind::GotRelative, RelocationEncoding::S390xDbl, 32) => {
651 elf::R_390_GOTENT
652 }
653 (RelocationKind::GotBaseOffset, RelocationEncoding::Generic, 16) => {
654 elf::R_390_GOTOFF16
655 }
656 (RelocationKind::GotBaseOffset, RelocationEncoding::Generic, 32) => {
657 elf::R_390_GOTOFF32
658 }
659 (RelocationKind::GotBaseOffset, RelocationEncoding::Generic, 64) => {
660 elf::R_390_GOTOFF64
661 }
662 (RelocationKind::GotBaseRelative, RelocationEncoding::Generic, 64) => {
663 elf::R_390_GOTPC
664 }
665 (RelocationKind::GotBaseRelative, RelocationEncoding::S390xDbl, 32) => {
666 elf::R_390_GOTPCDBL
667 }
668 (RelocationKind::Elf(x), _, _) => x,
669 _ => {
670 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
671 }
672 },
f035d41b
XL
673 _ => {
674 return Err(Error(format!(
675 "unimplemented architecture {:?}",
676 self.architecture
677 )));
678 }
679 };
680 let r_sym = symbol_offsets[reloc.symbol.0].index as u32;
681 elf.write_rel(
fc512014 682 buffer,
f035d41b
XL
683 is_rela,
684 Rel {
685 r_offset: reloc.offset,
686 r_sym,
687 r_type,
688 r_addend: reloc.addend,
689 },
690 );
691 }
692 }
693 }
694
695 // Write shstrtab section.
696 debug_assert_eq!(shstrtab_offset, buffer.len());
697 buffer.extend(&shstrtab_data);
698
699 // Write section headers.
fc512014 700 write_align(buffer, pointer_align);
f035d41b
XL
701 debug_assert_eq!(e_shoff, buffer.len());
702 elf.write_section_header(
fc512014 703 buffer,
f035d41b
XL
704 SectionHeader {
705 sh_name: 0,
706 sh_type: 0,
707 sh_flags: 0,
708 sh_addr: 0,
709 sh_offset: 0,
710 sh_size: if section_num >= elf::SHN_LORESERVE as usize {
711 section_num as u64
712 } else {
713 0
714 },
715 sh_link: if shstrtab_index >= elf::SHN_LORESERVE as usize {
716 shstrtab_index as u32
717 } else {
718 0
719 },
720 // TODO: e_phnum overflow
721 sh_info: 0,
722 sh_addralign: 0,
723 sh_entsize: 0,
724 },
725 );
fc512014
XL
726 for (index, comdat) in self.comdats.iter().enumerate() {
727 let sh_name = comdat_offsets[index]
728 .str_id
729 .map(|id| shstrtab.get_offset(id))
730 .unwrap_or(0) as u32;
731 elf.write_section_header(
732 buffer,
733 SectionHeader {
734 sh_name,
735 sh_type: elf::SHT_GROUP,
736 sh_flags: 0,
737 sh_addr: 0,
738 sh_offset: comdat_offsets[index].offset as u64,
739 sh_size: comdat_offsets[index].len as u64,
740 sh_link: symtab_index as u32,
741 sh_info: symbol_offsets[comdat.symbol.0].index as u32,
742 sh_addralign: 4,
743 sh_entsize: 4,
744 },
745 );
746 }
f035d41b
XL
747 for (index, section) in self.sections.iter().enumerate() {
748 let sh_type = match section.kind {
749 SectionKind::UninitializedData | SectionKind::UninitializedTls => elf::SHT_NOBITS,
750 SectionKind::Note => elf::SHT_NOTE,
751 _ => elf::SHT_PROGBITS,
752 };
753 let sh_flags = if let SectionFlags::Elf { sh_flags } = section.flags {
754 sh_flags
755 } else {
756 match section.kind {
757 SectionKind::Text => elf::SHF_ALLOC | elf::SHF_EXECINSTR,
758 SectionKind::Data => elf::SHF_ALLOC | elf::SHF_WRITE,
759 SectionKind::Tls => elf::SHF_ALLOC | elf::SHF_WRITE | elf::SHF_TLS,
760 SectionKind::UninitializedData => elf::SHF_ALLOC | elf::SHF_WRITE,
761 SectionKind::UninitializedTls => elf::SHF_ALLOC | elf::SHF_WRITE | elf::SHF_TLS,
762 SectionKind::ReadOnlyData => elf::SHF_ALLOC,
763 SectionKind::ReadOnlyString => {
764 elf::SHF_ALLOC | elf::SHF_STRINGS | elf::SHF_MERGE
765 }
766 SectionKind::OtherString => elf::SHF_STRINGS | elf::SHF_MERGE,
767 SectionKind::Other
768 | SectionKind::Debug
769 | SectionKind::Metadata
770 | SectionKind::Linker
771 | SectionKind::Note => 0,
772 SectionKind::Unknown | SectionKind::Common | SectionKind::TlsVariables => {
773 return Err(Error(format!(
774 "unimplemented section `{}` kind {:?}",
775 section.name().unwrap_or(""),
776 section.kind
777 )));
778 }
779 }
780 .into()
781 };
782 // TODO: not sure if this is correct, maybe user should determine this
783 let sh_entsize = match section.kind {
784 SectionKind::ReadOnlyString | SectionKind::OtherString => 1,
785 _ => 0,
786 };
787 let sh_name = section_offsets[index]
788 .str_id
789 .map(|id| shstrtab.get_offset(id))
790 .unwrap_or(0) as u32;
791 elf.write_section_header(
fc512014 792 buffer,
f035d41b
XL
793 SectionHeader {
794 sh_name,
795 sh_type,
796 sh_flags,
797 sh_addr: 0,
798 sh_offset: section_offsets[index].offset as u64,
799 sh_size: section.size,
800 sh_link: 0,
801 sh_info: 0,
802 sh_addralign: section.align,
803 sh_entsize,
804 },
805 );
806
807 if !section.relocations.is_empty() {
808 let sh_name = section_offsets[index]
809 .reloc_str_id
810 .map(|id| shstrtab.get_offset(id))
811 .unwrap_or(0);
812 elf.write_section_header(
fc512014 813 buffer,
f035d41b
XL
814 SectionHeader {
815 sh_name: sh_name as u32,
816 sh_type: if is_rela { elf::SHT_RELA } else { elf::SHT_REL },
817 sh_flags: elf::SHF_INFO_LINK.into(),
818 sh_addr: 0,
819 sh_offset: section_offsets[index].reloc_offset as u64,
820 sh_size: section_offsets[index].reloc_len as u64,
821 sh_link: symtab_index as u32,
822 sh_info: section_offsets[index].index as u32,
823 sh_addralign: pointer_align as u64,
824 sh_entsize: elf.rel_size(is_rela) as u64,
825 },
826 );
827 }
828 }
829
830 // Write symtab section header.
831 elf.write_section_header(
fc512014 832 buffer,
f035d41b
XL
833 SectionHeader {
834 sh_name: shstrtab.get_offset(symtab_str_id) as u32,
835 sh_type: elf::SHT_SYMTAB,
836 sh_flags: 0,
837 sh_addr: 0,
838 sh_offset: symtab_offset as u64,
839 sh_size: symtab_len as u64,
840 sh_link: strtab_index as u32,
841 sh_info: symtab_count_local as u32,
842 sh_addralign: pointer_align as u64,
843 sh_entsize: elf.symbol_size() as u64,
844 },
845 );
846
847 // Write symtab_shndx section header.
848 if need_symtab_shndx {
849 elf.write_section_header(
fc512014 850 buffer,
f035d41b
XL
851 SectionHeader {
852 sh_name: shstrtab.get_offset(symtab_shndx_str_id.unwrap()) as u32,
853 sh_type: elf::SHT_SYMTAB_SHNDX,
854 sh_flags: 0,
855 sh_addr: 0,
856 sh_offset: symtab_shndx_offset as u64,
857 sh_size: symtab_shndx_len as u64,
858 sh_link: symtab_index as u32,
859 sh_info: symtab_count_local as u32,
860 sh_addralign: 4,
861 sh_entsize: 4,
862 },
863 );
864 }
865
866 // Write strtab section header.
867 elf.write_section_header(
fc512014 868 buffer,
f035d41b
XL
869 SectionHeader {
870 sh_name: shstrtab.get_offset(strtab_str_id) as u32,
871 sh_type: elf::SHT_STRTAB,
872 sh_flags: 0,
873 sh_addr: 0,
874 sh_offset: strtab_offset as u64,
875 sh_size: strtab_data.len() as u64,
876 sh_link: 0,
877 sh_info: 0,
878 sh_addralign: 1,
879 sh_entsize: 0,
880 },
881 );
882
883 // Write shstrtab section header.
884 elf.write_section_header(
fc512014 885 buffer,
f035d41b
XL
886 SectionHeader {
887 sh_name: shstrtab.get_offset(shstrtab_str_id) as u32,
888 sh_type: elf::SHT_STRTAB,
889 sh_flags: 0,
890 sh_addr: 0,
891 sh_offset: shstrtab_offset as u64,
892 sh_size: shstrtab_data.len() as u64,
893 sh_link: 0,
894 sh_info: 0,
895 sh_addralign: 1,
896 sh_entsize: 0,
897 },
898 );
899
fc512014
XL
900 debug_assert_eq!(offset, buffer.len());
901
902 Ok(())
f035d41b
XL
903 }
904}
905
906/// Native endian version of `FileHeader64`.
907struct FileHeader {
908 e_ident: elf::Ident,
909 e_type: u16,
910 e_machine: u16,
911 e_version: u32,
912 e_entry: u64,
913 e_phoff: u64,
914 e_shoff: u64,
915 e_flags: u32,
916 e_ehsize: u16,
917 e_phentsize: u16,
918 e_phnum: u16,
919 e_shentsize: u16,
920 e_shnum: u16,
921 e_shstrndx: u16,
922}
923
924/// Native endian version of `SectionHeader64`.
925struct SectionHeader {
926 sh_name: u32,
927 sh_type: u32,
928 sh_flags: u64,
929 sh_addr: u64,
930 sh_offset: u64,
931 sh_size: u64,
932 sh_link: u32,
933 sh_info: u32,
934 sh_addralign: u64,
935 sh_entsize: u64,
936}
937
938/// Native endian version of `Sym64`.
939struct Sym {
940 st_name: u32,
941 st_info: u8,
942 st_other: u8,
943 st_shndx: u16,
944 st_value: u64,
945 st_size: u64,
946}
947
948/// Unified native endian version of `Rel*`.
949struct Rel {
950 r_offset: u64,
951 r_sym: u32,
952 r_type: u32,
953 r_addend: i64,
954}
955
956trait Elf {
957 fn file_header_size(&self) -> usize;
958 fn section_header_size(&self) -> usize;
959 fn symbol_size(&self) -> usize;
960 fn rel_size(&self, is_rela: bool) -> usize;
fc512014
XL
961 fn write_file_header(&self, buffer: &mut dyn WritableBuffer, section: FileHeader);
962 fn write_section_header(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader);
963 fn write_symbol(&self, buffer: &mut dyn WritableBuffer, symbol: Sym);
964 fn write_rel(&self, buffer: &mut dyn WritableBuffer, is_rela: bool, rel: Rel);
f035d41b
XL
965}
966
967struct Elf32<E> {
968 endian: E,
969}
970
971impl<E: Endian> Elf for Elf32<E> {
972 fn file_header_size(&self) -> usize {
973 mem::size_of::<elf::FileHeader32<E>>()
974 }
975
976 fn section_header_size(&self) -> usize {
977 mem::size_of::<elf::SectionHeader32<E>>()
978 }
979
980 fn symbol_size(&self) -> usize {
981 mem::size_of::<elf::Sym32<E>>()
982 }
983
984 fn rel_size(&self, is_rela: bool) -> usize {
985 if is_rela {
986 mem::size_of::<elf::Rela32<E>>()
987 } else {
988 mem::size_of::<elf::Rel32<E>>()
989 }
990 }
991
fc512014 992 fn write_file_header(&self, buffer: &mut dyn WritableBuffer, file: FileHeader) {
f035d41b
XL
993 let endian = self.endian;
994 let file = elf::FileHeader32 {
995 e_ident: file.e_ident,
996 e_type: U16::new(endian, file.e_type),
997 e_machine: U16::new(endian, file.e_machine),
998 e_version: U32::new(endian, file.e_version),
999 e_entry: U32::new(endian, file.e_entry as u32),
1000 e_phoff: U32::new(endian, file.e_phoff as u32),
1001 e_shoff: U32::new(endian, file.e_shoff as u32),
1002 e_flags: U32::new(endian, file.e_flags),
1003 e_ehsize: U16::new(endian, file.e_ehsize),
1004 e_phentsize: U16::new(endian, file.e_phentsize),
1005 e_phnum: U16::new(endian, file.e_phnum),
1006 e_shentsize: U16::new(endian, file.e_shentsize),
1007 e_shnum: U16::new(endian, file.e_shnum),
1008 e_shstrndx: U16::new(endian, file.e_shstrndx),
1009 };
fc512014 1010 buffer.extend(bytes_of(&file));
f035d41b
XL
1011 }
1012
fc512014 1013 fn write_section_header(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader) {
f035d41b
XL
1014 let endian = self.endian;
1015 let section = elf::SectionHeader32 {
1016 sh_name: U32::new(endian, section.sh_name),
1017 sh_type: U32::new(endian, section.sh_type),
1018 sh_flags: U32::new(endian, section.sh_flags as u32),
1019 sh_addr: U32::new(endian, section.sh_addr as u32),
1020 sh_offset: U32::new(endian, section.sh_offset as u32),
1021 sh_size: U32::new(endian, section.sh_size as u32),
1022 sh_link: U32::new(endian, section.sh_link),
1023 sh_info: U32::new(endian, section.sh_info),
1024 sh_addralign: U32::new(endian, section.sh_addralign as u32),
1025 sh_entsize: U32::new(endian, section.sh_entsize as u32),
1026 };
fc512014 1027 buffer.extend(bytes_of(&section));
f035d41b
XL
1028 }
1029
fc512014 1030 fn write_symbol(&self, buffer: &mut dyn WritableBuffer, symbol: Sym) {
f035d41b
XL
1031 let endian = self.endian;
1032 let symbol = elf::Sym32 {
1033 st_name: U32::new(endian, symbol.st_name),
1034 st_info: symbol.st_info,
1035 st_other: symbol.st_other,
1036 st_shndx: U16::new(endian, symbol.st_shndx),
1037 st_value: U32::new(endian, symbol.st_value as u32),
1038 st_size: U32::new(endian, symbol.st_size as u32),
1039 };
fc512014 1040 buffer.extend(bytes_of(&symbol));
f035d41b
XL
1041 }
1042
fc512014 1043 fn write_rel(&self, buffer: &mut dyn WritableBuffer, is_rela: bool, rel: Rel) {
f035d41b
XL
1044 let endian = self.endian;
1045 if is_rela {
1046 let rel = elf::Rela32 {
1047 r_offset: U32::new(endian, rel.r_offset as u32),
1048 r_info: elf::Rel32::r_info(endian, rel.r_sym, rel.r_type as u8),
1049 r_addend: I32::new(endian, rel.r_addend as i32),
1050 };
fc512014 1051 buffer.extend(bytes_of(&rel));
f035d41b
XL
1052 } else {
1053 let rel = elf::Rel32 {
1054 r_offset: U32::new(endian, rel.r_offset as u32),
1055 r_info: elf::Rel32::r_info(endian, rel.r_sym, rel.r_type as u8),
1056 };
fc512014 1057 buffer.extend(bytes_of(&rel));
f035d41b
XL
1058 }
1059 }
1060}
1061
1062struct Elf64<E> {
1063 endian: E,
1064}
1065
1066impl<E: Endian> Elf for Elf64<E> {
1067 fn file_header_size(&self) -> usize {
1068 mem::size_of::<elf::FileHeader64<E>>()
1069 }
1070
1071 fn section_header_size(&self) -> usize {
1072 mem::size_of::<elf::SectionHeader64<E>>()
1073 }
1074
1075 fn symbol_size(&self) -> usize {
1076 mem::size_of::<elf::Sym64<E>>()
1077 }
1078
1079 fn rel_size(&self, is_rela: bool) -> usize {
1080 if is_rela {
1081 mem::size_of::<elf::Rela64<E>>()
1082 } else {
1083 mem::size_of::<elf::Rel64<E>>()
1084 }
1085 }
1086
fc512014 1087 fn write_file_header(&self, buffer: &mut dyn WritableBuffer, file: FileHeader) {
f035d41b
XL
1088 let endian = self.endian;
1089 let file = elf::FileHeader64 {
1090 e_ident: file.e_ident,
1091 e_type: U16::new(endian, file.e_type),
1092 e_machine: U16::new(endian, file.e_machine),
1093 e_version: U32::new(endian, file.e_version),
1094 e_entry: U64::new(endian, file.e_entry),
1095 e_phoff: U64::new(endian, file.e_phoff),
1096 e_shoff: U64::new(endian, file.e_shoff),
1097 e_flags: U32::new(endian, file.e_flags),
1098 e_ehsize: U16::new(endian, file.e_ehsize),
1099 e_phentsize: U16::new(endian, file.e_phentsize),
1100 e_phnum: U16::new(endian, file.e_phnum),
1101 e_shentsize: U16::new(endian, file.e_shentsize),
1102 e_shnum: U16::new(endian, file.e_shnum),
1103 e_shstrndx: U16::new(endian, file.e_shstrndx),
1104 };
fc512014 1105 buffer.extend(bytes_of(&file))
f035d41b
XL
1106 }
1107
fc512014 1108 fn write_section_header(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader) {
f035d41b
XL
1109 let endian = self.endian;
1110 let section = elf::SectionHeader64 {
1111 sh_name: U32::new(endian, section.sh_name),
1112 sh_type: U32::new(endian, section.sh_type),
1113 sh_flags: U64::new(endian, section.sh_flags),
1114 sh_addr: U64::new(endian, section.sh_addr),
1115 sh_offset: U64::new(endian, section.sh_offset),
1116 sh_size: U64::new(endian, section.sh_size),
1117 sh_link: U32::new(endian, section.sh_link),
1118 sh_info: U32::new(endian, section.sh_info),
1119 sh_addralign: U64::new(endian, section.sh_addralign),
1120 sh_entsize: U64::new(endian, section.sh_entsize),
1121 };
fc512014 1122 buffer.extend(bytes_of(&section));
f035d41b
XL
1123 }
1124
fc512014 1125 fn write_symbol(&self, buffer: &mut dyn WritableBuffer, symbol: Sym) {
f035d41b
XL
1126 let endian = self.endian;
1127 let symbol = elf::Sym64 {
1128 st_name: U32::new(endian, symbol.st_name),
1129 st_info: symbol.st_info,
1130 st_other: symbol.st_other,
1131 st_shndx: U16::new(endian, symbol.st_shndx),
1132 st_value: U64::new(endian, symbol.st_value),
1133 st_size: U64::new(endian, symbol.st_size),
1134 };
fc512014 1135 buffer.extend(bytes_of(&symbol));
f035d41b
XL
1136 }
1137
fc512014 1138 fn write_rel(&self, buffer: &mut dyn WritableBuffer, is_rela: bool, rel: Rel) {
f035d41b
XL
1139 let endian = self.endian;
1140 if is_rela {
1141 let rel = elf::Rela64 {
1142 r_offset: U64::new(endian, rel.r_offset),
1143 r_info: elf::Rela64::r_info(endian, rel.r_sym, rel.r_type),
1144 r_addend: I64::new(endian, rel.r_addend),
1145 };
fc512014 1146 buffer.extend(bytes_of(&rel));
f035d41b
XL
1147 } else {
1148 let rel = elf::Rel64 {
1149 r_offset: U64::new(endian, rel.r_offset),
1150 r_info: elf::Rel64::r_info(endian, rel.r_sym, rel.r_type),
1151 };
fc512014 1152 buffer.extend(bytes_of(&rel));
f035d41b
XL
1153 }
1154 }
1155}