rucc_object/section.rs
1//! What an object writer is given, which is a section of bytes and what the linker has to be
2//! told about them.
3//!
4//! Design: `spec/11-asm-objects-debug.md` sections 11.1 and 11.3.
5//!
6//! These types are here rather than beside the assembler that fills them in because they are what
7//! an object file is made of, and because a writer cannot depend on the thing that produces its
8//! input without the graph going the wrong way round. The assembler at layer rank 10 reaches down
9//! to these at rank 8, which is the direction `spec/18-package-layout.md` asks for.
10
11/// A text section, and what the linker has to be told about it.
12#[derive(Debug, Clone, Default, PartialEq, Eq)]
13pub struct Text {
14 /// The instructions, in the order they were laid out.
15 pub bytes: Vec<u8>,
16 /// Where each function starts and how long it is, in the order they were written.
17 pub funcs: Vec<Extent>,
18 /// Every place in the bytes that names something the linker has to find.
19 pub relocs: Vec<Reloc>,
20}
21
22/// Where one function ended up.
23///
24/// How long a function is is a fact ELF records and Mach-O has no way to, so it is handed over
25/// rather than worked out again: the writer that wants it has it and the one that does not
26/// ignores it.
27#[derive(Debug, Clone, PartialEq, Eq)]
28pub struct Extent {
29 /// The function's name, as the C program spelled it. The underscore an Apple symbol carries
30 /// is the object writer's business, not this one's.
31 pub name: String,
32 /// Where its first instruction is.
33 pub start: usize,
34 /// How many bytes of instructions it is, not counting the padding in front of the next one.
35 pub len: usize,
36}
37
38/// The variables a file defines, and what the linker has to be told about them.
39///
40/// One entry per variable rather than one section of everything, because where a variable goes is
41/// worked out from what it is and two of them that land in one section still have their own
42/// alignment, their own size and their own symbol. Putting them together is the writer's job and
43/// is the one part of it the three formats disagree about.
44#[derive(Debug, Clone, Default, PartialEq, Eq)]
45pub struct Data {
46 /// Every variable this file defines, in the order the module held them.
47 pub objects: Vec<Object>,
48}
49
50/// One global variable, laid out.
51#[derive(Debug, Clone, PartialEq, Eq)]
52pub struct Object {
53 /// Its name, as the C program spelled it. The underscore an Apple symbol carries is the
54 /// object writer's business, not this one's.
55 pub name: String,
56 /// Its image, and nothing at all when it is zero filled and the file carries none of it.
57 pub bytes: Vec<u8>,
58 /// How many bytes it occupies, which is the length of the image except when there is none.
59 pub size: u64,
60 /// What it has to be aligned to, always a power of two.
61 pub align: u64,
62 /// Which section it goes in.
63 pub place: Place,
64 /// How the linker sees the name.
65 pub binding: Binding,
66 /// Every place in its image that holds the address of a symbol, counted from the start of
67 /// the image rather than from the start of the section it lands in.
68 pub relocs: Vec<Reloc>,
69}
70
71/// Which section a variable goes in.
72///
73/// Worked out from what the variable is rather than named by it, except in the one case where the
74/// program named it. A reader who wants to know why a variable is in `.rodata` should be able to
75/// find the answer in the variable.
76#[derive(Debug, Clone, PartialEq, Eq)]
77pub enum Place {
78 /// Written to, and its image is not all zeros. `.data`.
79 Written,
80 /// Never written to, so it can go in a page the loader maps read only and every process
81 /// running the program can share. `.rodata`.
82 ReadOnly,
83 /// All zeros, so the file says how big it is and carries none of it. `.bss`.
84 Zero,
85 /// A tentative definition, which is not in a section at all: the linker is asked for that
86 /// much zeroed space and merges every definition of the name into one. `.comm`.
87 Merged,
88 /// The section the program named, from `__attribute__((section(...)))`.
89 Named(String),
90}
91
92/// How the linker sees a name.
93///
94/// Three of the five linkages the IR has, because that is how many an object file can say. Which
95/// of the two weak ones a symbol had is a fact the optimizer needs and the linker does not.
96#[derive(Debug, Clone, Copy, PartialEq, Eq)]
97pub enum Binding {
98 /// Visible to every other object, and the definition here is the definition.
99 Global,
100 /// Invisible outside this object, which is what `static` at file scope means.
101 Local,
102 /// Visible, and allowed to lose to a definition in another object.
103 Weak,
104}
105
106/// One reference to something this file does not contain.
107#[derive(Debug, Clone, PartialEq, Eq)]
108pub struct Reloc {
109 /// Where the bytes the linker writes over begin.
110 pub at: usize,
111 /// What is wanted, as the C program spelled it.
112 pub symbol: String,
113 /// What the linker is being asked for.
114 pub kind: Reference,
115 /// What to add to the distance, which is the constant the instruction already meant plus the
116 /// bytes between the hole and the end of the instruction, negated. An instruction counts from
117 /// where it ends and a relocation counts from where it starts, and this is the difference.
118 pub addend: i64,
119}
120
121/// What kind of thing a relocation is asking the linker for.
122///
123/// The first two are the distance from the end of an instruction to something, which is what every
124/// reference the code makes is, because this compiler generates position independent code and
125/// nothing else. They are told apart because the linker may answer one of them with a stub and may
126/// not answer the other one that way. The third is not a distance at all and is the only kind an
127/// image asks for, since an initializer holding the address of something holds the address itself.
128#[derive(Debug, Clone, Copy, PartialEq, Eq)]
129pub enum Reference {
130 /// A call, which the linker may satisfy with a stub that reaches further than the four bytes
131 /// would. `R_X86_64_PLT32` on ELF, and the same relocation a branch gets on the other two.
132 Call,
133 /// A datum, reached from the instruction pointer. `R_X86_64_PC32` on ELF.
134 Data,
135 /// The address itself, written into an image. `int *p = &y;` and nothing else in C.
136 Address {
137 /// How many bytes of it are written, which is the pointer width except on a target with
138 /// a narrower relocation for it. `R_X86_64_64` and `R_X86_64_32` on ELF.
139 bytes: u8,
140 },
141}