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 11 reaches down
9//! to these at rank 9, which is the direction `spec/18-package-layout.md` asks for.
10
11/// What a function is aligned to when nothing asked for more.
12///
13/// Sixteen because that is what every x86-64 toolchain puts a function at, and because it is what
14/// keeps the loop inside one from straddling one more cache line than it has to. Here rather than
15/// beside the assembler because the assembler pads to it and the writer records it, and two
16/// copies of one number is how the padding and the record come apart.
17pub const FUNC_ALIGN: u32 = 16;
18
19/// Whether each function and each variable gets a section to itself.
20///
21/// Design: `spec/11-asm-objects-debug.md` section 11.3, and `spec/04-driver-and-cli.md` section 4.7
22/// for the flags that ask for it.
23///
24/// A linker can drop a section nothing reaches and cannot drop half of one, so a file whose
25/// functions share a section keeps every function that file defines in the output as soon as any
26/// one of them is called. Splitting them is what makes `--gc-sections` do anything, which is how an
27/// embedded image or a kernel gets small, and it is the whole of what these two flags are for. The
28/// cost is a section header per name, which is why it is asked for rather than always done.
29///
30/// Not one flag, because gcc has two and a build that wants one of them and not the other is a
31/// build that measured something. Splitting the code is nearly free at link time; splitting the
32/// data can defeat the linker's ordering of what is next to what.
33#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
34pub struct Sections {
35 /// `-ffunction-sections`. Each function in `.text.<name>` rather than all of them in `.text`.
36 pub functions: bool,
37 /// `-fdata-sections`. Each variable in a section named after it rather than in the one its
38 /// contents would otherwise have chosen.
39 pub data: bool,
40}
41
42impl Sections {
43 /// Whether either of them was asked for.
44 #[must_use]
45 pub const fn any(self) -> bool {
46 self.functions || self.data
47 }
48}
49
50/// What a file says it was built to have checked, which is what `-fcf-protection=` asks for.
51///
52/// Design: `spec/11-asm-objects-debug.md` section 11.3, and `spec/04-driver-and-cli.md` section 4.7
53/// for the flag.
54///
55/// A machine's control flow checks are turned on for a whole process or not at all, never for one
56/// function, so a program made of one object built with them and one built without has to be run
57/// one way or the other. What everybody settled on is that each object records what it was built
58/// for, the linker keeps only what every input agreed on, and the loader turns on what is left. So
59/// an object that records nothing turns the check off for every object it is linked with, which is
60/// why this is written even when the flag changed no instruction in the file.
61///
62/// One number rather than a pair of flags, because that is what the record holds: a word of bits
63/// whose meaning is the machine's, and a linker that has never heard of a bit still knows to drop
64/// it when one input does not have it.
65#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
66pub struct Property {
67 /// The bits of the x86 feature word, which are [`Self::IBT`] and [`Self::SHSTK`].
68 pub features: u32,
69}
70
71impl Property {
72 /// Which property the feature word is, which is the key the record is written under.
73 pub const X86_FEATURES: u32 = 0xc000_0002;
74 /// Indirect branch tracking: every indirect call and jump in the file arrives at a landing
75 /// pad, so the machine may fault on one that does not.
76 pub const IBT: u32 = 1;
77 /// The shadow stack: every return in the file goes where a second copy of the return address
78 /// says it should, so the machine may fault when the two disagree.
79 pub const SHSTK: u32 = 2;
80
81 /// Whether anything is recorded at all, which is whether the record is written.
82 #[must_use]
83 pub const fn any(self) -> bool {
84 self.features != 0
85 }
86}
87
88/// What the command line decided about the file being written, as against what the code in it
89/// decided.
90///
91/// Two answers with nothing to do with each other, together because they arrive together: neither
92/// can be worked out from a function, and the listing and the byte writer have to be handed the
93/// same pair or the two outputs of one command line would not be the same file.
94#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
95pub struct Output {
96 /// Whether each function and each variable gets a section to itself.
97 pub sections: Sections,
98 /// What the file says it was built to have checked.
99 pub property: Property,
100}
101
102/// A text section, and what the linker has to be told about it.
103#[derive(Debug, Clone, PartialEq, Eq)]
104pub struct Text {
105 /// The instructions, in the order they were laid out.
106 pub bytes: Vec<u8>,
107 /// Where each function starts and how long it is, in the order they were written.
108 pub funcs: Vec<Extent>,
109 /// Every place in the bytes that names something the linker has to find.
110 pub relocs: Vec<Reloc>,
111 /// What the whole section has to be aligned to, which is the largest alignment any function
112 /// in it asked for.
113 ///
114 /// A function is at a fixed offset inside the section, so a function at a multiple of two
115 /// hundred and fifty six is one only if the section itself is at one. The padding between the
116 /// functions is the assembler's half of the same job and this is the linker's.
117 pub align: u32,
118 /// What an unwinder is told about the functions, which is empty for a format that has no such
119 /// section or a build that asked for none.
120 pub unwind: Unwind,
121}
122
123impl Default for Text {
124 fn default() -> Self {
125 Self {
126 bytes: Vec::new(),
127 funcs: Vec::new(),
128 relocs: Vec::new(),
129 align: FUNC_ALIGN,
130 unwind: Unwind::default(),
131 }
132 }
133}
134
135/// The unwind table, as the bytes of its own section and what the linker has to be told about them.
136///
137/// Bytes rather than rows, because what a record is is DWARF's answer and not the object format's,
138/// and the layer that knows what a frame did is the one that can say it in the fewest of them. What
139/// is left for the writer is where the section goes and what its relocations are, which is the part
140/// the three formats disagree about.
141///
142/// Each record says where its function is as a distance from the record to the function, which is
143/// a number no compilation knows: a function is at a fixed offset inside its own section and the
144/// section is placed by the linker. So there is one relocation per record and it is the ordinary
145/// instruction pointer relative one, since the distance is between two things in the same file.
146#[derive(Debug, Clone, Default, PartialEq, Eq)]
147pub struct Unwind {
148 /// The records, one shared header and one per function.
149 pub bytes: Vec<u8>,
150 /// Every place in them that names a function the linker has to place.
151 pub relocs: Vec<Reloc>,
152}
153
154/// Where the room a patcher was promised at the top of a function ended up.
155///
156/// What `-fpatchable-function-entry=` asks for, once it is bytes rather than instructions. Two
157/// numbers because the writer has two questions: where the address it records points, and how much
158/// of the function is in front of the symbol.
159///
160/// They are not the same number. The room can be split by the landing pad a function opens with,
161/// since the pad has to be the first instruction after the label and the room does not, so the part
162/// in front of the label and the part after it are not always next to each other. What is recorded
163/// is the front of the whole thing, which is the part in front of the label when there is one.
164#[derive(Debug, Clone, Copy, PartialEq, Eq)]
165pub struct Patch {
166 /// Where the room begins, as an offset into the same bytes [`Extent::start`] is one into.
167 pub at: usize,
168 /// How many bytes of the function are in front of [`Extent::start`], which is where its symbol
169 /// is and where an unwinder is told the function begins.
170 pub before: usize,
171}
172
173/// Where one function ended up.
174///
175/// How long a function is is a fact ELF records and Mach-O has no way to, so it is handed over
176/// rather than worked out again: the writer that wants it has it and the one that does not
177/// ignores it.
178#[derive(Debug, Clone, PartialEq, Eq)]
179pub struct Extent {
180 /// The function's name, as the C program spelled it. The underscore an Apple symbol carries
181 /// is the object writer's business, not this one's.
182 pub name: String,
183 /// Where its first instruction is.
184 pub start: usize,
185 /// How many bytes of instructions it is, not counting the padding in front of the next one.
186 pub len: usize,
187 /// What this one function asked to be aligned to, which is not always what the section it is
188 /// in was aligned to.
189 ///
190 /// The two are the same number only when this function is the one that asked for the most.
191 /// Under [`Sections::functions`] each function is a section of its own and this is what that
192 /// section is aligned to, so the number has to survive the trip rather than be recovered from
193 /// the offset, which says nothing once the function is at zero in a section of its own.
194 pub align: u32,
195 /// How the linker sees the name, which is what the C `static` reaches the object file as.
196 pub binding: Binding,
197 /// How far outside a shared library holding this the name reaches.
198 pub visibility: Visibility,
199 /// Where the room a patcher was promised is, or `None` in a function promised none, which is
200 /// every function on a command line that did not ask. See [`Patch`].
201 pub patch: Option<Patch>,
202}
203
204/// The variables a file defines, and what the linker has to be told about them.
205///
206/// One entry per variable rather than one section of everything, because where a variable goes is
207/// worked out from what it is and two of them that land in one section still have their own
208/// alignment, their own size and their own symbol. Putting them together is the writer's job and
209/// is the one part of it the three formats disagree about.
210#[derive(Debug, Clone, Default, PartialEq, Eq)]
211pub struct Data {
212 /// Every variable this file defines, in the order the module held them.
213 pub objects: Vec<Object>,
214}
215
216/// A second name for something the same file defines.
217///
218/// Not a section and not a byte of anything, which is the whole point of it: an alias is a symbol
219/// table entry pointing at an address something else already occupies, so a file with one in it is
220/// no larger than the same file without. `.set b, a` is what an assembler is told and a second
221/// entry at the first one's section, value and size is what a writer produces, and the two say the
222/// same thing.
223///
224/// The target is a name rather than an index into anything above, because the two output paths
225/// find it in different places: a listing hands the name to an assembler that resolves it, and a
226/// writer looks it up among the symbols it has already added.
227#[derive(Debug, Clone, PartialEq, Eq)]
228pub struct Alias {
229 /// The name being defined, as the C program spelled it.
230 pub name: String,
231 /// The name it stands for, which has to be something this same file defines.
232 pub target: String,
233 /// How the linker sees the new name, which is not always how it sees the old one: the target
234 /// of `extern int b __attribute__((alias("a")))` may be a `static`.
235 pub binding: Binding,
236 /// How far outside a shared library holding this the new name reaches, which is its own
237 /// answer for the same reason the binding is: the attribute is written on the alias.
238 pub visibility: Visibility,
239}
240
241/// One global variable, laid out.
242#[derive(Debug, Clone, PartialEq, Eq)]
243pub struct Object {
244 /// Its name, as the C program spelled it. The underscore an Apple symbol carries is the
245 /// object writer's business, not this one's.
246 pub name: String,
247 /// Its image, and nothing at all when it is zero filled and the file carries none of it.
248 pub bytes: Vec<u8>,
249 /// How many bytes it occupies, which is the length of the image except when there is none.
250 pub size: u64,
251 /// What it has to be aligned to, always a power of two.
252 pub align: u64,
253 /// Which section it goes in.
254 pub place: Place,
255 /// How the linker sees the name.
256 pub binding: Binding,
257 /// How far outside a shared library holding this the name reaches.
258 pub visibility: Visibility,
259 /// Every place in its image that holds the address of a symbol, counted from the start of
260 /// the image rather than from the start of the section it lands in.
261 pub relocs: Vec<Reloc>,
262}
263
264/// Which section a variable goes in.
265///
266/// Worked out from what the variable is rather than named by it, except in the one case where the
267/// program named it. A reader who wants to know why a variable is in `.rodata` should be able to
268/// find the answer in the variable.
269#[derive(Debug, Clone, PartialEq, Eq)]
270pub enum Place {
271 /// Written to, and its image is not all zeros. `.data`.
272 Written,
273 /// Never written to, so it can go in a page the loader maps read only and every process
274 /// running the program can share. `.rodata`.
275 ReadOnly,
276 /// Never written to by the program, but written once by the dynamic linker, because its image
277 /// holds the address of something and an address is not known until the image is loaded.
278 /// `.data.rel.ro`.
279 ///
280 /// The section has to be writable for that one write and read only afterwards, which is what
281 /// the `PT_GNU_RELRO` segment is: the loader maps it, the relocations are applied, and then it
282 /// is turned read only before the program starts. Putting the variable in `.rodata` instead
283 /// means asking the linker to leave a relocation in a section that is never writable, and what
284 /// it does about that is give the whole image `DT_TEXTREL`, which gives up the protection the
285 /// section was for. Some hardened toolchains refuse the link outright.
286 RelocReadOnly {
287 /// Whether every address in the image is of something this file defines and does not
288 /// export, which means the link can resolve them all and none can be interposed.
289 ///
290 /// Those go in `.data.rel.ro.local`, which the linker puts in the first pages of the
291 /// segment, so the pages holding them are the ones the loader is done with soonest. It is
292 /// a hint about layout rather than a difference in what the section is.
293 local: bool,
294 },
295 /// All zeros, so the file says how big it is and carries none of it. `.bss`.
296 Zero,
297 /// One copy per thread rather than one copy per program. `.tdata` and `.tbss`.
298 ///
299 /// What the loader does with these two sections is what makes them different from every other
300 /// section here. Their contents are the template of a thread's own block of storage rather than
301 /// the storage itself: the image is laid out once, and every thread that starts gets a fresh
302 /// copy of it, so the address of a variable in one of them is a different address in every
303 /// thread and there is no single address for the link to write down. That is why a reference to
304 /// one is not the ordinary distance from the instruction pointer, and why the symbol is marked
305 /// as being of this kind so a linker refuses one that is.
306 ///
307 /// The pair is the same split as `.data` and `.bss` for the same reason, so an image that is
308 /// all zeros costs its size in the file and not its bytes.
309 Thread {
310 /// Whether the image is all zeros, which puts it in `.tbss` rather than `.tdata`.
311 zero: bool,
312 },
313 /// A tentative definition, which is not in a section at all: the linker is asked for that
314 /// much zeroed space and merges every definition of the name into one. `.comm`.
315 Merged,
316 /// The section the program named, from `__attribute__((section(...)))`.
317 Named(String),
318}
319
320impl Place {
321 /// What the section this variable goes in is called under [`Sections::data`], and nothing at
322 /// all for a variable that has no section of its own to be given.
323 ///
324 /// The name is the section it would otherwise have shared with a dot and the variable's name
325 /// after it, which is what gcc writes and is not merely a convention: `--gc-sections`, the
326 /// linker scripts a kernel and an embedded image are linked with, and the default placement
327 /// rules all match on the part in front of the dot, so a section called anything else would be
328 /// placed by whatever the catch all rule is.
329 ///
330 /// Two kinds of variable are left alone. A merged one is a request to the linker for that much
331 /// zeroed space rather than an image, so there is no section to split, and one the program put
332 /// a name on already has the answer the source gave, which this must not overrule.
333 ///
334 /// Here rather than beside either output path, so that the listing `-S` writes and the object
335 /// `-c` writes cannot come to disagree about where a variable went.
336 #[must_use]
337 pub fn split(&self, name: &str) -> Option<String> {
338 Some(format!("{}.{name}", self.base()?))
339 }
340
341 /// The section this variable goes in when nothing is being split up, and nothing at all for
342 /// the two kinds that are not in one.
343 #[must_use]
344 pub fn base(&self) -> Option<&'static str> {
345 Some(match self {
346 Place::Written => ".data",
347 Place::ReadOnly => ".rodata",
348 Place::RelocReadOnly { local: false } => ".data.rel.ro",
349 Place::RelocReadOnly { local: true } => ".data.rel.ro.local",
350 Place::Zero => ".bss",
351 Place::Thread { zero: false } => ".tdata",
352 Place::Thread { zero: true } => ".tbss",
353 Place::Merged | Place::Named(_) => return None,
354 })
355 }
356}
357
358/// A section holding function addresses for a C runtime to call rather than data for the program
359/// to read.
360///
361/// ELF has a type for each of the three, and a section of that type is what the startup code walks:
362/// the linker gathers every input section of the kind into one run and the CRT calls what it finds
363/// between the two ends. A section of the ordinary type with the same name would be gathered the
364/// same way and called by nothing, which is why the type is worth writing down rather than leaving
365/// to the default.
366///
367/// Only ELF says it this way. COFF sorts by what follows the `$` in a section name and Mach-O has
368/// a section attribute for it, so on those two the name carries the whole of the answer and there
369/// is nothing for this to be.
370#[derive(Debug, Clone, Copy, PartialEq, Eq)]
371pub enum Array {
372 /// Run on the way to `main`, in the order the linker sorted the sections into.
373 Init,
374 /// Run after `main` returns, in the reverse of that order.
375 Fini,
376 /// Run ahead of `.init_array` and ahead of the shared libraries a program is linked against,
377 /// which is a thing only the C library itself has a use for.
378 Preinit,
379}
380
381impl Array {
382 /// Which of them a section of this name is, and [`None`] for a name that is not one of them.
383 ///
384 /// The name itself or the name with a dot and a priority after it. A numbered `constructor` is
385 /// written as the second of those and is the same kind of section as the first: the number is
386 /// there so that the linker sorts it, not to make it a different thing.
387 #[must_use]
388 pub fn of(name: &str) -> Option<Array> {
389 let kinds = [
390 (".init_array", Array::Init),
391 (".fini_array", Array::Fini),
392 (".preinit_array", Array::Preinit),
393 ];
394 kinds.into_iter().find_map(|(base, array)| {
395 let rest = name.strip_prefix(base)?;
396 (rest.is_empty() || rest.starts_with('.')).then_some(array)
397 })
398 }
399
400 /// How the type is spelled in a `.section` directive.
401 #[must_use]
402 pub const fn asm(self) -> &'static str {
403 match self {
404 Array::Init => "@init_array",
405 Array::Fini => "@fini_array",
406 Array::Preinit => "@preinit_array",
407 }
408 }
409}
410
411/// How the linker sees a name.
412///
413/// Three of the five linkages the IR has, because that is how many an object file can say. Which
414/// of the two weak ones a symbol had is a fact the optimizer needs and the linker does not.
415#[derive(Debug, Clone, Copy, PartialEq, Eq)]
416pub enum Binding {
417 /// Visible to every other object, and the definition here is the definition.
418 Global,
419 /// Invisible outside this object, which is what `static` at file scope means.
420 Local,
421 /// Visible, and allowed to lose to a definition in another object.
422 Weak,
423}
424
425/// How far outside a shared library a name reaches.
426///
427/// A different question from [`Binding`] and asked of a different linker. The binding is what the
428/// static linker does with a name while it is building the output, and this is what the dynamic
429/// linker may do with it once the output is a shared library and is being loaded. A hidden name is
430/// still global to the static link, so two files in the same library can call each other by it; it
431/// is simply not in the dynamic symbol table afterwards, so nothing outside can name it.
432///
433/// Written down here as its own thing rather than folded into the binding because it is the
434/// mistake tamnd/rucc#733 was: a writer that has one word for both ends up saying something about
435/// visibility while it thinks it is saying something about linkage, and what it said was hidden.
436///
437/// It means nothing for a [`Binding::Local`] name. `static` is already invisible to the whole
438/// world outside the file, and ELF records `STV_DEFAULT` for one, which is what gcc writes.
439#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
440pub enum Visibility {
441 /// In the dynamic symbol table, and a reference from inside the library may be satisfied by a
442 /// definition somewhere else, which is what makes `LD_PRELOAD` work. What a name gets when
443 /// nothing said otherwise.
444 #[default]
445 Default,
446 /// Not in the dynamic symbol table at all, so nothing outside the library can name it and
447 /// every reference to it from inside binds here. `__attribute__((visibility("hidden")))`.
448 Hidden,
449 /// In the dynamic symbol table, so something outside can name it, but a reference from inside
450 /// the library binds to the definition inside it and cannot be interposed.
451 Protected,
452}
453
454/// One reference to something this file does not contain.
455#[derive(Debug, Clone, PartialEq, Eq)]
456pub struct Reloc {
457 /// Where the bytes the linker writes over begin.
458 pub at: usize,
459 /// What is wanted, as the C program spelled it.
460 pub symbol: String,
461 /// What the linker is being asked for.
462 pub kind: Reference,
463 /// What to add to the distance, which is the constant the instruction already meant plus the
464 /// bytes between the hole and the end of the instruction, negated. An instruction counts from
465 /// where it ends and a relocation counts from where it starts, and this is the difference.
466 pub addend: i64,
467}
468
469/// What kind of thing a relocation is asking the linker for.
470///
471/// The first three are the distance from the end of an instruction to something, which is what
472/// every reference the code makes is, because this compiler generates position independent code and
473/// nothing else. They are told apart by what the linker is allowed to do about each one. The fourth
474/// is not a distance at all and is the only kind an image asks for, since an initializer holding the
475/// address of something holds the address itself.
476#[derive(Debug, Clone, Copy, PartialEq, Eq)]
477pub enum Reference {
478 /// A call, which the linker may satisfy with a stub that reaches further than the four bytes
479 /// would. `R_X86_64_PLT32` on ELF, and the same relocation a branch gets on the other two.
480 Call,
481 /// A datum, reached from the instruction pointer. `R_X86_64_PC32` on ELF.
482 Data,
483 /// A slot of the global offset table, reached from the instruction pointer, holding the
484 /// address of something another object may be the one that defines.
485 ///
486 /// The distance to the slot rather than to the thing, which is the whole difference: the
487 /// distance to the thing is a number only a link that puts the thing in this program can
488 /// work out, and a shared library is a link that does not. `R_X86_64_REX_GOTPCRELX` on ELF,
489 /// which says the instruction is a `mov` with a REX prefix and lets the linker turn it back
490 /// into the `lea` it would have been if the symbol had been here all along.
491 Got,
492 /// A slot of the global offset table, reached from the instruction pointer, holding how far
493 /// into a thread's own block of storage a thread-local variable sits.
494 ///
495 /// An offset and not an address, which is what makes it a different relocation from the one
496 /// above rather than the same one against a different symbol: a thread-local variable has one
497 /// copy per thread and therefore no address for a link to write down, and what every copy has
498 /// in common is where it sits inside the block. Adding the block's own address, which the
499 /// machine keeps in a segment register, is what turns one into the other, and that addition is
500 /// in the code rather than in the relocation. `R_X86_64_GOTTPOFF` on ELF, which the linker
501 /// turns into a constant in the instruction when it is making an executable and therefore
502 /// knows how the blocks are laid out.
503 Thread,
504 /// The address itself, written into an image. `int *p = &y;` and nothing else in C.
505 Address {
506 /// How many bytes of it are written, which is the pointer width except on a target with
507 /// a narrower relocation for it. `R_X86_64_64` and `R_X86_64_32` on ELF.
508 bytes: u8,
509 },
510}