1use object::write::{
29 Object as Writer, Relocation, StandardSection, Symbol, SymbolId, SymbolSection,
30};
31use object::{
32 Architecture, BinaryFormat, Endianness, RelocationFlags, SectionKind, SymbolFlags, SymbolKind,
33 SymbolScope, elf,
34};
35use rucc_target::{ObjectFormat, TargetInfo};
36use rucc_tuple::Arch;
37
38use crate::section::{
39 Alias, Binding, Data, Object, Place, Reference, Reloc, Sections, Text, Visibility,
40};
41
42#[derive(Debug, Clone, PartialEq, Eq)]
44pub enum Error {
45 Format {
47 triple: String,
49 },
50 Refused {
52 why: String,
54 },
55}
56
57impl std::fmt::Display for Error {
58 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59 match self {
60 Error::Format { triple } => {
61 write!(f, "there is no object writer for {triple} in this compiler yet")
62 }
63 Error::Refused { why } => {
64 write!(f, "the object writer refused what it was given: {why}")
65 }
66 }
67 }
68}
69
70impl std::error::Error for Error {}
71
72pub fn write(
81 text: &Text,
82 data: &Data,
83 aliases: &[Alias],
84 target: &TargetInfo,
85 sections: Sections,
86) -> Result<Vec<u8>, Error> {
87 if target.tuple.arch() != Arch::X86_64 || target.object_format != ObjectFormat::Elf {
88 return Err(Error::Format { triple: target.tuple.to_string() });
89 }
90 let mut obj = Writer::new(BinaryFormat::Elf, Architecture::X86_64, Endianness::Little);
91 let whole = obj.section_id(StandardSection::Text);
95 if !sections.functions {
96 obj.append_section_data(whole, &text.bytes, u64::from(text.align));
97 }
98
99 let mut symbols = std::collections::BTreeMap::new();
103 let mut split = Vec::with_capacity(text.funcs.len());
107 for func in &text.funcs {
108 let (section, at) = if sections.functions {
113 let name = format!(".text.{}", func.name).into_bytes();
114 let id = obj.add_section(Vec::new(), name, SectionKind::Text);
115 let bytes = &text.bytes[func.start..func.start + func.len];
116 obj.append_section_data(id, bytes, u64::from(func.align.max(1)));
117 (id, 0)
118 } else {
119 (whole, func.start as u64)
120 };
121 let id = obj.add_symbol(Symbol {
122 name: func.name.clone().into_bytes(),
123 value: at,
124 size: func.len as u64,
125 kind: SymbolKind::Text,
126 scope: scope_of(func.binding),
127 weak: func.binding == Binding::Weak,
128 section: SymbolSection::Section(section),
129 flags: SymbolFlags::None,
130 });
131 see(&mut obj, id, func.binding, func.visibility);
132 symbols.insert(func.name.clone(), id);
133 split.push(section);
134 }
135
136 let mut placed = Vec::with_capacity(data.objects.len());
141 let mut local = None;
145 for object in &data.objects {
146 let (section, offset) = put(&mut obj, object, &mut local, sections);
147 let id = obj.add_symbol(Symbol {
148 name: object.name.clone().into_bytes(),
149 value: if object.place == Place::Merged { object.align } else { offset },
152 size: object.size,
153 kind: SymbolKind::Data,
154 scope: scope_of(object.binding),
155 weak: object.binding == Binding::Weak,
156 section,
157 flags: SymbolFlags::None,
158 });
159 see(&mut obj, id, object.binding, object.visibility);
160 symbols.insert(object.name.clone(), id);
161 placed.push((section.id(), offset));
162 }
163
164 for alias in aliases {
170 let Some(&id) = symbols.get(&alias.target) else {
171 let why =
172 format!("'{}' is aliased to '{}', which is not here", alias.name, alias.target);
173 return Err(Error::Refused { why });
174 };
175 let (value, size) = (obj.symbol(id).value, obj.symbol(id).size);
176 let (kind, section) = (obj.symbol(id).kind, obj.symbol(id).section);
177 let id = obj.add_symbol(Symbol {
178 name: alias.name.clone().into_bytes(),
179 value,
180 size,
181 kind,
182 scope: scope_of(alias.binding),
183 weak: alias.binding == Binding::Weak,
184 section,
185 flags: SymbolFlags::None,
186 });
187 see(&mut obj, id, alias.binding, alias.visibility);
188 symbols.insert(alias.name.clone(), id);
189 }
190
191 let wanted = text
192 .relocs
193 .iter()
194 .chain(text.unwind.relocs.iter())
195 .chain(data.objects.iter().flat_map(|object| &object.relocs));
196 for reloc in wanted {
197 if symbols.contains_key(&reloc.symbol) {
198 continue;
199 }
200 let id = obj.add_symbol(Symbol {
201 name: reloc.symbol.clone().into_bytes(),
202 value: 0,
203 size: 0,
204 kind: SymbolKind::Unknown,
208 scope: SymbolScope::Dynamic,
209 weak: false,
210 section: SymbolSection::Undefined,
211 flags: SymbolFlags::None,
212 });
213 symbols.insert(reloc.symbol.clone(), id);
214 }
215
216 for reloc in &text.relocs {
217 let (section, at) = if sections.functions {
222 let after = text.funcs.partition_point(|func| func.start <= reloc.at);
223 let Some(func) = after.checked_sub(1).map(|i| &text.funcs[i]) else {
224 let why = format!("a relocation at {} is in front of every function", reloc.at);
225 return Err(Error::Refused { why });
226 };
227 (split[after - 1], (reloc.at - func.start) as u64)
228 } else {
229 (whole, reloc.at as u64)
230 };
231 add(&mut obj, section, at, reloc, &symbols)?;
232 }
233
234 if !text.unwind.bytes.is_empty() {
240 let frames = obj.add_section(Vec::new(), b".eh_frame".to_vec(), SectionKind::ReadOnlyData);
241 obj.append_section_data(frames, &text.unwind.bytes, 8);
242 for reloc in &text.unwind.relocs {
243 add(&mut obj, frames, reloc.at as u64, reloc, &symbols)?;
244 }
245 }
246 for (object, &(section, offset)) in data.objects.iter().zip(&placed) {
247 let Some(section) = section else { continue };
248 for reloc in &object.relocs {
249 add(&mut obj, section, offset + reloc.at as u64, reloc, &symbols)?;
250 }
251 }
252
253 obj.add_section(Vec::new(), b".note.GNU-stack".to_vec(), SectionKind::Metadata);
256
257 obj.write().map_err(|why| Error::Refused { why: why.to_string() })
258}
259
260fn put(
267 obj: &mut Writer<'_>,
268 object: &Object,
269 local: &mut Option<object::write::SectionId>,
270 sections: Sections,
271) -> (SymbolSection, u64) {
272 if sections.data {
278 if let Some(name) = object.place.split(&object.name) {
279 let section = obj.add_section(Vec::new(), name.into_bytes(), kind_of(&object.place));
280 let offset = if object.place == Place::Zero {
281 obj.append_section_bss(section, object.size, object.align)
282 } else {
283 obj.append_section_data(section, &object.bytes, object.align)
284 };
285 return (SymbolSection::Section(section), offset);
286 }
287 }
288 let section = match &object.place {
289 Place::Written => obj.section_id(StandardSection::Data),
290 Place::ReadOnly => obj.section_id(StandardSection::ReadOnlyData),
291 Place::RelocReadOnly { local: false } => {
297 obj.section_id(StandardSection::ReadOnlyDataWithRel)
298 }
299 Place::RelocReadOnly { local: true } => *local.get_or_insert_with(|| {
300 obj.add_section(
301 Vec::new(),
302 b".data.rel.ro.local".to_vec(),
303 SectionKind::ReadOnlyDataWithRel,
304 )
305 }),
306 Place::Zero => obj.section_id(StandardSection::UninitializedData),
307 Place::Merged => return (SymbolSection::Common, 0),
308 Place::Named(name) => {
312 obj.add_section(Vec::new(), name.clone().into_bytes(), SectionKind::Data)
313 }
314 };
315 let offset = if object.place == Place::Zero {
316 obj.append_section_bss(section, object.size, object.align)
317 } else {
318 obj.append_section_data(section, &object.bytes, object.align)
319 };
320 (SymbolSection::Section(section), offset)
321}
322
323fn kind_of(place: &Place) -> SectionKind {
332 match place {
333 Place::ReadOnly => SectionKind::ReadOnlyData,
334 Place::RelocReadOnly { .. } => SectionKind::ReadOnlyDataWithRel,
335 Place::Zero => SectionKind::UninitializedData,
336 Place::Written | Place::Merged | Place::Named(_) => SectionKind::Data,
337 }
338}
339
340fn add(
347 obj: &mut Writer<'_>,
348 section: object::write::SectionId,
349 at: u64,
350 reloc: &Reloc,
351 symbols: &std::collections::BTreeMap<String, SymbolId>,
352) -> Result<(), Error> {
353 let r_type = r_type(reloc.kind)
354 .ok_or_else(|| Error::Refused { why: format!("no relocation is {:?}", reloc.kind) })?;
355 obj.add_relocation(
356 section,
357 Relocation {
358 offset: at,
359 symbol: symbols[&reloc.symbol],
360 addend: reloc.addend,
361 flags: RelocationFlags::Elf { r_type },
362 },
363 )
364 .map_err(|why| Error::Refused { why: why.to_string() })
365}
366
367fn scope_of(binding: Binding) -> SymbolScope {
380 match binding {
381 Binding::Local => SymbolScope::Compilation,
382 Binding::Global | Binding::Weak => SymbolScope::Dynamic,
383 }
384}
385
386fn see(obj: &mut Writer<'_>, id: SymbolId, binding: Binding, visibility: Visibility) {
398 if binding == Binding::Local {
399 return;
400 }
401 let wanted = match visibility {
402 Visibility::Default => elf::STV_DEFAULT,
403 Visibility::Hidden => elf::STV_HIDDEN,
404 Visibility::Protected => elf::STV_PROTECTED,
405 };
406 if let SymbolFlags::Elf { st_other, .. } = obj.symbol_flags_mut(id) {
407 *st_other = st_other.with_visibility(wanted);
408 }
409}
410
411fn r_type(reference: Reference) -> Option<elf::RelocationType> {
422 Some(match reference {
423 Reference::Call => elf::R_X86_64_PLT32,
424 Reference::Data => elf::R_X86_64_PC32,
425 Reference::Got => elf::R_X86_64_REX_GOTPCRELX,
426 Reference::Address { bytes: 8 } => elf::R_X86_64_64,
427 Reference::Address { bytes: 4 } => elf::R_X86_64_32,
428 Reference::Address { .. } => return None,
429 })
430}
431
432#[cfg(test)]
433mod tests {
434 use super::*;
435
436 use object::read::elf::Sym as _;
437 use object::read::{Object as _, ObjectSection as _, ObjectSymbol as _};
438 use rucc_target::{Arch, Env, Os, Triple};
439
440 use crate::section::{Extent, Reloc};
441
442 fn target() -> TargetInfo {
444 TargetInfo::new(Triple::new(Arch::X86_64, Os::Linux, Env::Gnu))
445 }
446
447 fn extent(name: String, start: usize, len: usize, binding: Binding) -> Extent {
452 Extent {
453 name,
454 start,
455 len,
456 align: crate::FUNC_ALIGN,
457 binding,
458 visibility: Visibility::Default,
459 }
460 }
461
462 fn calling(name: &str) -> Text {
464 Text {
465 bytes: vec![0xe8, 0, 0, 0, 0, 0xc3],
466 funcs: vec![extent("f".to_owned(), 0, 6, Binding::Global)],
467 relocs: vec![Reloc {
468 at: 1,
469 symbol: name.to_owned(),
470 kind: Reference::Call,
471 addend: -4,
472 }],
473 ..Text::default()
474 }
475 }
476
477 #[test]
478 fn the_bytes_come_back_out_of_the_section_they_went_into() {
479 let text = calling("puts");
480 let bytes =
481 write(&text, &Data::default(), &[], &target(), Sections::default()).expect("an object");
482 let file = object::File::parse(&bytes[..]).expect("a readable object");
483 let section = file.section_by_name(".text").expect("a text section");
484 assert_eq!(section.data().expect("the bytes"), &text.bytes[..]);
485 }
486
487 #[test]
488 fn a_function_is_a_symbol_that_says_where_it_is_and_how_long_it_is() {
489 let mut text = calling("puts");
490 text.funcs.push(extent("g".to_owned(), 16, 1, Binding::Global));
491 text.bytes.resize(17, 0x90);
492 let bytes =
493 write(&text, &Data::default(), &[], &target(), Sections::default()).expect("an object");
494 let file = object::File::parse(&bytes[..]).expect("a readable object");
495 let g = file.symbols().find(|s| s.name() == Ok("g")).expect("the second function");
496 assert_eq!(g.address(), 16);
497 assert_eq!(g.size(), 1);
498 assert_eq!(g.kind(), SymbolKind::Text);
499 assert!(g.is_global(), "nothing said otherwise about this one");
500 }
501
502 #[test]
503 fn a_function_no_other_file_can_see_is_a_local_symbol() {
504 let mut text = calling("puts");
505 text.funcs.push(extent("hidden".to_owned(), 16, 1, Binding::Local));
506 text.funcs.push(extent("shared".to_owned(), 32, 1, Binding::Weak));
507 text.bytes.resize(33, 0x90);
508 let bytes =
509 write(&text, &Data::default(), &[], &target(), Sections::default()).expect("an object");
510 let file = object::File::parse(&bytes[..]).expect("a readable object");
511 let hidden = file.symbols().find(|s| s.name() == Ok("hidden")).expect("the static one");
512 assert!(hidden.is_local(), "a static function must not be offered to the linker");
515 assert!(!hidden.is_weak());
516 let shared = file.symbols().find(|s| s.name() == Ok("shared")).expect("the weak one");
517 assert!(shared.is_weak(), "a weak function has to be able to lose");
518 assert!(shared.is_global());
519 }
520
521 #[test]
532 fn a_global_is_visible_to_the_dynamic_linker_and_a_static_one_is_not_a_symbol_at_all() {
533 let mut text = calling("puts");
534 text.funcs.push(extent("g".to_owned(), 16, 1, Binding::Global));
535 text.funcs.push(extent("w".to_owned(), 32, 1, Binding::Weak));
536 text.funcs.push(extent("s".to_owned(), 48, 1, Binding::Local));
537 text.bytes.resize(49, 0x90);
538 let bytes =
539 write(&text, &Data::default(), &[], &target(), Sections::default()).expect("an object");
540 let file = object::read::elf::ElfFile64::<Endianness>::parse(&bytes[..]).expect("readable");
541 let visibility = |name: &str| {
542 file.symbols()
543 .find(|s| s.name() == Ok(name))
544 .expect("the function")
545 .elf_symbol()
546 .st_visibility()
547 };
548 assert_eq!(visibility("g"), elf::STV_DEFAULT);
550 assert_eq!(visibility("w"), elf::STV_DEFAULT, "a weak one is still a name others may use");
551 assert_eq!(visibility("s"), elf::STV_DEFAULT);
554 }
555
556 #[test]
566 fn a_name_that_asked_to_be_hidden_is_hidden_and_a_protected_one_is_protected() {
567 let mut text = calling("puts");
568 for (index, (name, seen)) in
569 [("h", Visibility::Hidden), ("p", Visibility::Protected)].into_iter().enumerate()
570 {
571 let mut func = extent(name.to_owned(), 16 + index * 16, 1, Binding::Global);
572 func.visibility = seen;
573 text.funcs.push(func);
574 }
575 text.bytes.resize(49, 0x90);
576 let mut data = Data::default();
577 for (name, seen) in [("vh", Visibility::Hidden), ("vp", Visibility::Protected)] {
578 let mut object = variable(name, Place::Written);
579 object.visibility = seen;
580 data.objects.push(object);
581 }
582 let bytes = write(&text, &data, &[], &target(), Sections::default()).expect("an object");
583 let file = object::read::elf::ElfFile64::<Endianness>::parse(&bytes[..]).expect("readable");
584 let visibility = |name: &str| {
585 file.symbols()
586 .find(|s| s.name() == Ok(name))
587 .expect("the symbol")
588 .elf_symbol()
589 .st_visibility()
590 };
591 assert_eq!(visibility("h"), elf::STV_HIDDEN);
592 assert_eq!(visibility("p"), elf::STV_PROTECTED);
593 assert_eq!(visibility("vh"), elf::STV_HIDDEN, "a variable goes through a second loop");
594 assert_eq!(visibility("vp"), elf::STV_PROTECTED);
595 let h = file.symbols().find(|s| s.name() == Ok("h")).expect("the function");
598 assert!(h.is_global(), "hidden is about the dynamic linker and not about the binding");
599 assert_eq!(h.size(), 1, "and it is still a function of the length it was");
600 }
601
602 #[test]
603 fn a_name_this_file_does_not_define_is_left_for_the_linker_to_find() {
604 let bytes = write(&calling("puts"), &Data::default(), &[], &target(), Sections::default())
605 .expect("an object");
606 let file = object::File::parse(&bytes[..]).expect("a readable object");
607 let puts = file.symbols().find(|s| s.name() == Ok("puts")).expect("the callee");
608 assert!(puts.is_undefined(), "the file does not define it and must not claim to");
609 }
610
611 #[test]
612 fn a_call_asks_for_the_relocation_a_stub_may_answer_and_a_load_asks_for_the_one_that_may_not() {
613 for (reference, wanted) in [
614 (Reference::Call, elf::R_X86_64_PLT32),
615 (Reference::Data, elf::R_X86_64_PC32),
616 (Reference::Got, elf::R_X86_64_REX_GOTPCRELX),
617 ] {
618 let mut text = calling("puts");
619 text.relocs[0].kind = reference;
620 let bytes = write(&text, &Data::default(), &[], &target(), Sections::default())
621 .expect("an object");
622 let file = object::File::parse(&bytes[..]).expect("a readable object");
623 let section = file.section_by_name(".text").expect("a text section");
624 let (offset, reloc) = section.relocations().next().expect("one relocation");
625 assert_eq!(offset, 1);
626 assert_eq!(reloc.addend(), -4);
627 assert_eq!(reloc.flags(), RelocationFlags::Elf { r_type: wanted });
628 }
629 }
630
631 #[test]
632 fn a_name_wanted_twice_is_one_symbol_rather_than_two() {
633 let mut text = calling("puts");
634 text.relocs.push(Reloc {
635 at: 1,
636 symbol: "puts".to_owned(),
637 kind: Reference::Call,
638 addend: -4,
639 });
640 let bytes =
641 write(&text, &Data::default(), &[], &target(), Sections::default()).expect("an object");
642 let file = object::File::parse(&bytes[..]).expect("a readable object");
643 assert_eq!(file.symbols().filter(|s| s.name() == Ok("puts")).count(), 1);
644 }
645
646 #[test]
647 fn a_function_that_is_also_called_is_not_a_second_symbol() {
648 let text = calling("f");
649 let bytes =
650 write(&text, &Data::default(), &[], &target(), Sections::default()).expect("an object");
651 let file = object::File::parse(&bytes[..]).expect("a readable object");
652 let mut found = file.symbols().filter(|s| s.name() == Ok("f"));
653 let f = found.next().expect("the function");
654 assert!(!f.is_undefined(), "the file defines it");
655 assert!(found.next().is_none(), "and defines it once");
656 }
657
658 #[test]
659 fn the_marker_that_says_the_stack_is_not_executable_is_written() {
660 let bytes = write(&calling("puts"), &Data::default(), &[], &target(), Sections::default())
661 .expect("an object");
662 let file = object::File::parse(&bytes[..]).expect("a readable object");
663 let note = file.section_by_name(".note.GNU-stack").expect("the marker");
664 assert!(note.data().expect("no bytes").is_empty());
665 }
666
667 #[test]
676 fn an_unwind_record_names_the_function_it_is_about_and_not_the_first_one() {
677 let mut text = calling("puts");
678 text.funcs.push(extent("g".to_owned(), 16, 1, Binding::Global));
679 text.bytes.resize(17, 0x90);
680 text.unwind.bytes = vec![0; 64];
683 for (at, name) in [(32usize, "f"), (48usize, "g")] {
684 text.unwind.relocs.push(Reloc {
685 at,
686 symbol: name.to_owned(),
687 kind: Reference::Address { bytes: 8 },
688 addend: 0,
689 });
690 }
691 let bytes =
692 write(&text, &Data::default(), &[], &target(), Sections::default()).expect("an object");
693 let file = object::File::parse(&bytes[..]).expect("a readable object");
694 let frames = file.section_by_name(".eh_frame").expect("the table");
695 let mut at = frames.relocations().map(|(offset, _)| offset).collect::<Vec<_>>();
696 at.sort_unstable();
697 assert_eq!(at, [32, 48]);
698 }
699
700 fn lives_in<'a>(file: &'a object::File<'a>, name: &str) -> String {
702 let symbol = file.symbols().find(|s| s.name() == Ok(name)).expect("the symbol");
703 let index = symbol.section_index().expect("a section to be defined in");
704 let section = file.section_by_index(index).expect("a readable section");
705 section.name().expect("a named section").to_owned()
706 }
707
708 fn two() -> Text {
710 let mut text = calling("puts");
711 text.bytes.resize(16, 0x90);
714 text.bytes.extend_from_slice(&[0xe8, 0, 0, 0, 0, 0xc3]);
715 text.funcs.push(extent("g".to_owned(), 16, 6, Binding::Global));
716 text.relocs.push(Reloc {
717 at: 17,
718 symbol: "puts".to_owned(),
719 kind: Reference::Call,
720 addend: -4,
721 });
722 text
723 }
724
725 #[test]
732 fn every_function_gets_a_section_of_its_own_when_that_is_what_was_asked_for() {
733 let sections = Sections { functions: true, data: false };
734 let bytes = write(&two(), &Data::default(), &[], &target(), sections).expect("an object");
735 let file = object::File::parse(&bytes[..]).expect("a readable object");
736 assert_eq!(lives_in(&file, "f"), ".text.f");
737 assert_eq!(lives_in(&file, "g"), ".text.g");
738 assert!(file.section_by_name(".text").expect("the empty one").size() == 0);
739 for name in ["f", "g"] {
742 let symbol = file.symbols().find(|s| s.name() == Ok(name)).expect("the function");
743 assert_eq!(symbol.address(), 0, "{name}");
744 assert_eq!(symbol.size(), 6, "{name}");
745 }
746 let section = file.section_by_name(".text.g").expect("the second function");
747 assert_eq!(section.data().expect("the bytes"), &[0xe8, 0, 0, 0, 0, 0xc3]);
748 assert_eq!(section.align(), u64::from(crate::FUNC_ALIGN));
751 }
752
753 #[test]
759 fn a_relocation_moves_with_the_function_whose_bytes_it_is_in() {
760 let sections = Sections { functions: true, data: false };
761 let bytes = write(&two(), &Data::default(), &[], &target(), sections).expect("an object");
762 let file = object::File::parse(&bytes[..]).expect("a readable object");
763 for name in [".text.f", ".text.g"] {
764 let section = file.section_by_name(name).expect("a function");
765 let (offset, _) = section.relocations().next().expect("the call in it");
766 assert_eq!(offset, 1, "{name}");
769 assert_eq!(section.relocations().count(), 1, "{name}");
770 }
771 }
772
773 fn variable(name: &str, place: Place) -> Object {
775 Object {
776 name: name.to_owned(),
777 bytes: if place == Place::Zero { Vec::new() } else { vec![1, 0, 0, 0] },
778 size: 4,
779 align: 4,
780 place,
781 binding: Binding::Global,
782 visibility: Visibility::Default,
783 relocs: Vec::new(),
784 }
785 }
786
787 fn holding(object: Object) -> Vec<u8> {
789 let data = Data { objects: vec![object] };
790 write(&Text::default(), &data, &[], &target(), Sections::default()).expect("an object")
791 }
792
793 #[test]
794 fn what_a_variable_is_decides_which_section_it_goes_in() {
795 for (place, wanted) in [
796 (Place::Written, ".data"),
797 (Place::ReadOnly, ".rodata"),
798 (Place::RelocReadOnly { local: false }, ".data.rel.ro"),
799 (Place::RelocReadOnly { local: true }, ".data.rel.ro.local"),
800 (Place::Zero, ".bss"),
801 (Place::Named(".init_array".to_owned()), ".init_array"),
802 ] {
803 let bytes = holding(variable("x", place.clone()));
804 let file = object::File::parse(&bytes[..]).expect("a readable object");
805 let section = file.section_by_name(wanted).unwrap_or_else(|| panic!("{place:?}"));
806 assert_eq!(section.size(), 4, "{place:?}");
807 let carried = section.data().expect("the bytes").len();
810 assert_eq!(carried, if place == Place::Zero { 0 } else { 4 }, "{place:?}");
811 }
812 }
813
814 #[test]
818 fn every_variable_gets_a_section_of_its_own_when_that_is_what_was_asked_for() {
819 let sections = Sections { functions: false, data: true };
820 for (place, wanted) in [
821 (Place::Written, ".data.x"),
822 (Place::ReadOnly, ".rodata.x"),
823 (Place::RelocReadOnly { local: false }, ".data.rel.ro.x"),
824 (Place::RelocReadOnly { local: true }, ".data.rel.ro.local.x"),
825 (Place::Zero, ".bss.x"),
826 ] {
827 let data = Data { objects: vec![variable("x", place.clone())] };
828 let bytes = write(&Text::default(), &data, &[], &target(), sections).expect("object");
829 let file = object::File::parse(&bytes[..]).expect("a readable object");
830 assert_eq!(lives_in(&file, "x"), wanted, "{place:?}");
831 let section = file.section_by_name(wanted).expect("the section it named");
832 assert_eq!(section.size(), 4, "{place:?}");
833 let carried = section.data().expect("the bytes").len();
836 assert_eq!(carried, if place == Place::Zero { 0 } else { 4 }, "{place:?}");
837 }
838 }
839
840 #[test]
844 fn a_variable_that_has_no_section_of_its_own_to_be_given_is_left_where_it_was() {
845 let sections = Sections { functions: false, data: true };
846 let named = Place::Named(".init_array".to_owned());
847 let objects = vec![variable("m", Place::Merged), variable("n", named)];
848 let bytes =
849 write(&Text::default(), &Data { objects }, &[], &target(), sections).expect("object");
850 let file = object::File::parse(&bytes[..]).expect("a readable object");
851 let m = file.symbols().find(|s| s.name() == Ok("m")).expect("the tentative one");
852 assert!(m.is_common(), "still the linker's to merge and not in a section at all");
853 assert_eq!(lives_in(&file, "n"), ".init_array");
854 assert!(file.section_by_name(".init_array.n").is_none(), "the source already answered");
855 }
856
857 #[test]
861 fn a_relocation_in_an_image_moves_with_the_variable_whose_image_it_is_in() {
862 let sections = Sections { functions: false, data: true };
863 let pointer = Object {
864 bytes: vec![0; 8],
865 size: 8,
866 align: 8,
867 relocs: vec![Reloc {
868 at: 0,
869 symbol: "y".to_owned(),
870 kind: Reference::Address { bytes: 8 },
871 addend: 0,
872 }],
873 ..variable("p", Place::Written)
874 };
875 let objects = vec![variable("first", Place::Written), pointer];
876 let bytes =
877 write(&Text::default(), &Data { objects }, &[], &target(), sections).expect("object");
878 let file = object::File::parse(&bytes[..]).expect("a readable object");
879 let section = file.section_by_name(".data.p").expect("the pointer's own section");
880 let (offset, reloc) = section.relocations().next().expect("one relocation");
881 assert_eq!(offset, 0);
884 assert_eq!(reloc.flags(), RelocationFlags::Elf { r_type: elf::R_X86_64_64 });
885 }
886
887 #[test]
895 fn every_variable_that_wants_the_local_relocated_section_shares_one() {
896 let place = Place::RelocReadOnly { local: true };
897 let data =
898 Data { objects: vec![variable("first", place.clone()), variable("second", place)] };
899 let bytes =
900 write(&Text::default(), &data, &[], &target(), Sections::default()).expect("an object");
901 let file = object::File::parse(&bytes[..]).expect("a readable object");
902 let named = file.sections().filter(|s| s.name() == Ok(".data.rel.ro.local")).count();
903 assert_eq!(named, 1, "one section holding both, not one each");
904 }
905
906 #[test]
907 fn a_variable_is_a_symbol_that_says_where_it_is_and_how_long_it_is() {
908 let mut data = Data { objects: vec![variable("first", Place::Written)] };
909 data.objects.push(Object { align: 16, ..variable("second", Place::Written) });
910 let bytes =
911 write(&Text::default(), &data, &[], &target(), Sections::default()).expect("an object");
912 let file = object::File::parse(&bytes[..]).expect("a readable object");
913 let second = file.symbols().find(|s| s.name() == Ok("second")).expect("the second one");
914 assert_eq!(second.kind(), SymbolKind::Data);
915 assert_eq!(second.size(), 4);
916 assert_eq!(second.address(), 16);
920 }
921
922 #[test]
923 fn the_linkage_a_variable_had_is_the_binding_the_symbol_gets() {
924 for (binding, global, weak) in [
925 (Binding::Global, true, false),
926 (Binding::Local, false, false),
927 (Binding::Weak, true, true),
928 ] {
929 let bytes = holding(Object { binding, ..variable("x", Place::Written) });
930 let file = object::File::parse(&bytes[..]).expect("a readable object");
931 let x = file.symbols().find(|s| s.name() == Ok("x")).expect("the variable");
932 assert_eq!(x.is_global(), global, "{binding:?}");
933 assert_eq!(x.is_weak(), weak, "{binding:?}");
934 }
935 }
936
937 #[test]
938 fn a_tentative_definition_asks_the_linker_for_space_rather_than_naming_any() {
939 let bytes = holding(Object { align: 8, ..variable("x", Place::Merged) });
940 let file = object::read::elf::ElfFile64::<Endianness>::parse(&bytes[..]).expect("readable");
941 let x = file.symbols().find(|s| s.name() == Ok("x")).expect("the variable");
942 assert!(x.is_common(), "the linker merges every definition of this name into one");
943 assert_eq!(x.size(), 4);
944 assert_eq!(x.address(), 0);
948 assert_eq!(x.elf_symbol().st_value(Endianness::Little), 8);
949 }
950
951 #[test]
952 fn an_address_in_an_image_is_the_address_and_not_a_distance_to_it() {
953 let object = Object {
954 bytes: vec![0; 8],
955 size: 8,
956 align: 8,
957 relocs: vec![Reloc {
958 at: 0,
959 symbol: "y".to_owned(),
960 kind: Reference::Address { bytes: 8 },
961 addend: 16,
962 }],
963 ..variable("p", Place::Written)
964 };
965 let bytes = holding(object);
966 let file = object::File::parse(&bytes[..]).expect("a readable object");
967 let section = file.section_by_name(".data").expect("a data section");
968 let (offset, reloc) = section.relocations().next().expect("one relocation");
969 assert_eq!(offset, 0);
970 assert_eq!(reloc.addend(), 16);
971 assert_eq!(reloc.flags(), RelocationFlags::Elf { r_type: elf::R_X86_64_64 });
972 let y = file.symbols().find(|s| s.name() == Ok("y")).expect("what it points at");
973 assert!(y.is_undefined(), "nothing here defines it and the linker is being asked for it");
974 }
975
976 #[test]
978 fn a_relocation_counts_from_the_start_of_the_section_and_not_of_the_image_it_is_in() {
979 let mut data = Data { objects: vec![variable("first", Place::Written)] };
980 data.objects.push(Object {
981 bytes: vec![0; 16],
982 size: 16,
983 align: 8,
984 relocs: vec![Reloc {
985 at: 8,
986 symbol: "y".to_owned(),
987 kind: Reference::Address { bytes: 8 },
988 addend: 0,
989 }],
990 ..variable("second", Place::Written)
991 });
992 let bytes =
993 write(&Text::default(), &data, &[], &target(), Sections::default()).expect("an object");
994 let file = object::File::parse(&bytes[..]).expect("a readable object");
995 let section = file.section_by_name(".data").expect("a data section");
996 let (offset, _) = section.relocations().next().expect("one relocation");
997 assert_eq!(offset, 16);
1000 }
1001
1002 #[test]
1003 fn a_second_name_is_a_second_symbol_at_the_first_one_s_address_and_no_second_image() {
1004 let data = Data {
1005 objects: vec![Object { binding: Binding::Local, ..variable("a", Place::Written) }],
1006 };
1007 let aliases = [Alias {
1008 name: "b".to_owned(),
1009 target: "a".to_owned(),
1010 binding: Binding::Global,
1011 visibility: Visibility::Default,
1012 }];
1013 let bytes = write(&Text::default(), &data, &aliases, &target(), Sections::default())
1014 .expect("an object");
1015 let file = object::File::parse(&bytes[..]).expect("a readable object");
1016 let a = file.symbols().find(|s| s.name() == Ok("a")).expect("the variable");
1017 let b = file.symbols().find(|s| s.name() == Ok("b")).expect("the second name");
1018 assert_eq!(b.address(), a.address(), "the same place");
1019 assert_eq!(b.size(), a.size());
1020 assert_eq!(b.section_index(), a.section_index());
1021 assert!(a.is_local(), "the target was written `static`");
1024 assert!(b.is_global(), "and the name given to it was not");
1025 assert_eq!(file.section_by_name(".data").expect("a data section").size(), 4);
1027 }
1028
1029 #[test]
1030 fn a_function_can_be_given_a_second_name_the_same_way_a_variable_can() {
1031 let text = calling("puts");
1032 let aliases = [Alias {
1033 name: "g".to_owned(),
1034 target: "f".to_owned(),
1035 binding: Binding::Weak,
1036 visibility: Visibility::Default,
1037 }];
1038 let bytes = write(&text, &Data::default(), &aliases, &target(), Sections::default())
1039 .expect("an object");
1040 let file = object::File::parse(&bytes[..]).expect("a readable object");
1041 let f = file.symbols().find(|s| s.name() == Ok("f")).expect("the function");
1042 let g = file.symbols().find(|s| s.name() == Ok("g")).expect("the second name");
1043 assert_eq!(g.address(), f.address());
1044 assert_eq!(g.size(), f.size());
1045 assert_eq!(g.kind(), f.kind(), "a second name for a function is a function");
1046 assert!(g.is_weak(), "so that a program may define the name itself instead");
1047 }
1048
1049 #[test]
1052 fn a_second_name_for_something_this_file_does_not_define_is_refused() {
1053 let aliases = [Alias {
1054 name: "b".to_owned(),
1055 target: "a".to_owned(),
1056 binding: Binding::Global,
1057 visibility: Visibility::Default,
1058 }];
1059 let error =
1060 write(&Text::default(), &Data::default(), &aliases, &target(), Sections::default())
1061 .expect_err("nothing to point at");
1062 assert!(matches!(error, Error::Refused { .. }), "{error:?}");
1063 }
1064
1065 #[test]
1066 fn a_platform_this_does_not_write_is_said_so_rather_than_written_as_elf() {
1067 let text = calling("puts");
1068 for triple in [
1069 Triple::new(Arch::Aarch64, Os::Linux, Env::Gnu),
1070 Triple::new(Arch::X86_64, Os::Darwin, Env::Gnu),
1071 ] {
1072 let error =
1073 write(&text, &Data::default(), &[], &TargetInfo::new(triple), Sections::default())
1074 .expect_err("no writer");
1075 assert!(matches!(error, Error::Format { .. }), "{error:?}");
1076 }
1077 }
1078}