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/// Answers with nothing to do with each other, together because they arrive together: none of
92/// them can be worked out from a function, and the listing and the byte writer have to be handed
93/// the same ones 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 /// The extensions the unit is built for, which is what `-march=` said. Only the listing reads
101 /// it, since an assembler reading the file has to be told about an extension whose
102 /// instructions are in it, and bytes need no telling.
103 pub isa: rucc_target::Isa,
104 /// What the file says made it, which ELF keeps in `.comment` and gcc writes as `.ident`.
105 /// Nothing under `-fno-ident`, and nothing on the formats with no such section.
106 pub ident: Option<&'static str>,
107}
108
109/// A text section, and what the linker has to be told about it.
110#[derive(Debug, Clone, PartialEq, Eq)]
111pub struct Text {
112 /// The instructions, in the order they were laid out.
113 pub bytes: Vec<u8>,
114 /// Where each function starts and how long it is, in the order they were written.
115 pub funcs: Vec<Extent>,
116 /// Every place in the bytes that names something the linker has to find.
117 pub relocs: Vec<Reloc>,
118 /// Every place inside a function that has a name of its own, in the order they were written.
119 pub labels: Vec<Marker>,
120 /// What the whole section has to be aligned to, which is the largest alignment any function
121 /// in it asked for.
122 ///
123 /// A function is at a fixed offset inside the section, so a function at a multiple of two
124 /// hundred and fifty six is one only if the section itself is at one. The padding between the
125 /// functions is the assembler's half of the same job and this is the linker's.
126 pub align: u32,
127 /// What an unwinder is told about the functions, which is empty for a format that has no such
128 /// section or a build that asked for none.
129 pub unwind: Unwind,
130 /// The jump tables that are read rather than run, and so go in a read only section of data
131 /// rather than in these bytes. Empty on a format that keeps its tables after the function.
132 pub tables: Vec<Table>,
133 /// Where each call to the profiler's hook that `-mrecord-mcount` lists is, in the order they
134 /// were written, as offsets into [`Text::bytes`]. Empty unless the flag was given.
135 ///
136 /// The writer puts one eight byte address per call in a section called `__mcount_loc`, which
137 /// is what gcc writes and what a kernel before objtool took this over reads at boot to find
138 /// every call it can turn into a nop.
139 pub mcount: Vec<usize>,
140}
141
142/// The section `-mrecord-mcount` lists the calls in. See [`Text::mcount`].
143pub const MCOUNT_LOC: &str = "__mcount_loc";
144
145impl Default for Text {
146 fn default() -> Self {
147 Self {
148 bytes: Vec::new(),
149 funcs: Vec::new(),
150 relocs: Vec::new(),
151 labels: Vec::new(),
152 align: FUNC_ALIGN,
153 unwind: Unwind::default(),
154 tables: Vec::new(),
155 mcount: Vec::new(),
156 }
157 }
158}
159
160/// The unwind table, as the bytes of the section or two it goes in and what the linker has to be
161/// told about them.
162///
163/// Bytes rather than rows, because what a record is is the platform's answer rather than the object
164/// writer's, and the layer that knows what a frame did is the one that can say it in the fewest of
165/// them. What is left for the writer is where the sections go and what their relocations are.
166///
167/// Two of them, because the two platforms lay the same facts out differently. ELF writes one section
168/// of records, each a little program an unwinder runs to rebuild the frame at an address, and each
169/// carrying its own codes, so [`Self::info`] is empty there. Windows writes a table of fixed rows
170/// sorted by address, one per function, each pointing at the description of that function's prologue
171/// in a second section, which is what [`Self::info`] holds.
172///
173/// Every record says where its function is, and where a function is is a number no compilation
174/// knows: a function is at a fixed offset inside its own section and the section is placed by the
175/// linker. So there are relocations, and which kind they are is the format's answer too.
176#[derive(Debug, Clone, Default, PartialEq, Eq)]
177pub struct Unwind {
178 /// The records: one shared header and one per function on ELF, and one row per function on
179 /// Windows.
180 pub bytes: Vec<u8>,
181 /// Every place in them that names something the linker has to place, which is the functions
182 /// they are about and, where there is a second section, the description each row points at.
183 pub relocs: Vec<Reloc>,
184 /// What those records point at, on the format that keeps the two apart, and nothing at all on
185 /// the one whose records carry their own.
186 pub info: Vec<u8>,
187 /// The names inside [`Self::info`], one per function that has a description there, which are
188 /// what the relocations above ask for.
189 ///
190 /// Names rather than offsets because a relocation names a symbol, and the record and the thing
191 /// it points at are in two different sections, so there is no distance either of them can be
192 /// written with instead.
193 pub labels: Vec<Marker>,
194 /// The table of where each call an unwind lands from goes, which is `.gcc_except_table` and
195 /// is empty in a file with no landing pad in it. One header per function that has any, each
196 /// found by the record of its function through a relocation against this section, which is
197 /// what the name [`EXCEPT_TABLE`] in a relocation of [`Self::relocs`] stands for.
198 pub except: Vec<u8>,
199}
200
201/// The name of the section the call site tables go in, which is also what a relocation against it
202/// names. See [`Unwind::except`].
203pub const EXCEPT_TABLE: &str = ".gcc_except_table";
204
205/// The debug information, as the bytes of the sections it goes in.
206///
207/// Bytes rather than anything shaped like DWARF, for the reason [`Unwind`] is bytes: what a record
208/// is is the format's answer and the layer that knows what the program was doing is the one that
209/// can say it, and what is left for the writer is where the sections go and what their relocations
210/// are. The difference between the two is only that there are more than two sections here and that
211/// their names are not the writer's to choose, so each one carries its own.
212#[derive(Debug, Clone, Default, PartialEq, Eq)]
213pub struct Info {
214 /// One entry per section that has anything in it, in the order they are to be written.
215 ///
216 /// The order matters because a relocation in one of them can name another, and a name is
217 /// resolved against the sections this file already has. Writing them in the order the producer
218 /// hands them over keeps that a property of the list rather than of the writer.
219 pub chunks: Vec<Chunk>,
220 /// How the sections are stored in an ELF file, which is what `-gz` asks. Every other format
221 /// gets them as they are.
222 pub compress: Compress,
223}
224
225/// How an ELF file stores its debug sections.
226///
227/// A debug section is much larger than the code it describes and is read by a debugger rather than
228/// by the program, so it can be stored compressed and unpacked by whatever reads it. A section
229/// that would come out no smaller is left as it is, the way gas leaves one.
230#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
231pub enum Compress {
232 /// As they are.
233 #[default]
234 None,
235 /// `-gz=zlib`: the section keeps its name, gains `SHF_COMPRESSED`, and starts with an
236 /// `Elf_Chdr` saying it is zlib and how large it was.
237 Zlib,
238 /// `-gz=zlib-gnu`: the older layout, where `.debug_info` becomes `.zdebug_info` and starts with
239 /// `ZLIB` and its size as eight big endian bytes.
240 ZlibGnu,
241 /// `-gz=zstd`: as `Zlib`, with the `Elf_Chdr` saying zstd and a zstd frame after it.
242 Zstd,
243}
244
245/// One debug section, with the name it goes in the file under.
246///
247/// A relocation here names either a function this file defines or another section in the same
248/// list, and the two are told apart by looking the name up among the sections first. That is safe
249/// rather than lucky: every section name in DWARF begins with `.debug_`, which is not the spelling
250/// of any name a C program can define.
251#[derive(Debug, Clone, PartialEq, Eq)]
252pub struct Chunk {
253 /// What the section is called, which is the name DWARF gives it.
254 pub name: String,
255 /// Its contents.
256 pub bytes: Vec<u8>,
257 /// Every place in them that names something this file does not place itself.
258 pub relocs: Vec<Reloc>,
259}
260
261/// Where the room a patcher was promised at the top of a function ended up.
262///
263/// What `-fpatchable-function-entry=` asks for, once it is bytes rather than instructions. Two
264/// numbers because the writer has two questions: where the address it records points, and how much
265/// of the function is in front of the symbol.
266///
267/// They are not the same number. The room can be split by the landing pad a function opens with,
268/// since the pad has to be the first instruction after the label and the room does not, so the part
269/// in front of the label and the part after it are not always next to each other. What is recorded
270/// is the front of the whole thing, which is the part in front of the label when there is one.
271#[derive(Debug, Clone, Copy, PartialEq, Eq)]
272pub struct Patch {
273 /// Where the room begins, as an offset into the same bytes [`Extent::start`] is one into.
274 pub at: usize,
275 /// How many bytes of the function are in front of [`Extent::start`], which is where its symbol
276 /// is and where an unwinder is told the function begins.
277 pub before: usize,
278}
279
280/// Where a place inside a function that has a name of its own ended up.
281///
282/// What asks for one is GNU's address of a label in the initializer of an object with static
283/// storage duration. A label is somewhere a jump goes and a jump is a distance the assembler works
284/// out, so no ordinary label is in the symbol table at all. An image is the other case: it is in
285/// another section, so what it holds is a relocation, and a relocation names a symbol.
286///
287/// The name is never one the program wrote, so nothing outside this file looks it up and it is
288/// always local: it is here for a relocation in this same file to resolve against, and a linker
289/// that offered it to another file would be offering the middle of a function.
290#[derive(Debug, Clone, PartialEq, Eq)]
291pub struct Marker {
292 /// The name, which is whatever the compiler minted for it.
293 pub name: String,
294 /// Where it is, as an offset into the same bytes [`Extent::start`] is one into.
295 pub at: usize,
296}
297
298/// One jump table of one function, kept out of the instructions.
299///
300/// A table is data the function reads, and gcc and clang put it in `.rodata` rather than in the
301/// code. Keeping it there keeps data out of the lines the instruction fetcher reads and keeps the
302/// executable sections to what is executed, which is also what a size counted by section is
303/// measuring. The cost is that the two ends of every cell are now in different sections, so each
304/// cell is a relocation the linker fills in rather than a number the assembler writes, which is
305/// what gas does with the same `.long .L3-.L4` when the `.L4` is in `.rodata`.
306///
307/// Each cell is still the distance from the front of the table to a block, so the code that reads
308/// one is the same code wherever the table is.
309#[derive(Debug, Clone, PartialEq, Eq)]
310pub struct Table {
311 /// The name the instruction that reads it gives it, which is local to this file.
312 pub name: String,
313 /// Which of [`Text::funcs`] it belongs to.
314 pub func: usize,
315 /// Where each cell's block is, counted from [`Extent::start`] of that function.
316 pub cells: Vec<usize>,
317 /// Whether each cell is the block's address in eight bytes rather than its distance from the
318 /// table in four, which is the table the kernel code model reads.
319 pub absolute: bool,
320}
321
322/// Where one function ended up.
323///
324/// How long a function is is a fact ELF records and Mach-O has no way to, so it is handed over
325/// rather than worked out again: the writer that wants it has it and the one that does not
326/// ignores it.
327#[derive(Debug, Clone, PartialEq, Eq)]
328pub struct Extent {
329 /// The function's name, as the C program spelled it. The underscore an Apple symbol carries
330 /// is the object writer's business, not this one's.
331 pub name: String,
332 /// Where its first instruction is.
333 pub start: usize,
334 /// How many bytes of instructions it is, not counting the padding in front of the next one.
335 pub len: usize,
336 /// What this one function asked to be aligned to, which is not always what the section it is
337 /// in was aligned to.
338 ///
339 /// The two are the same number only when this function is the one that asked for the most.
340 /// Under [`Sections::functions`] each function is a section of its own and this is what that
341 /// section is aligned to, so the number has to survive the trip rather than be recovered from
342 /// the offset, which says nothing once the function is at zero in a section of its own.
343 pub align: u32,
344 /// How the linker sees the name, which is what the C `static` reaches the object file as.
345 pub binding: Binding,
346 /// How far outside a shared library holding this the name reaches.
347 pub visibility: Visibility,
348 /// Where the room a patcher was promised is, or `None` in a function promised none, which is
349 /// every function on a command line that did not ask. See [`Patch`].
350 pub patch: Option<Patch>,
351 /// Each call an unwind lands somewhere from, in the order they are in the function, which is
352 /// empty in every function with no cleanup handler to run on the way out. See [`Site`].
353 pub landings: Vec<Site>,
354}
355
356/// One call an unwind out of lands in a pad, as distances from [`Extent::start`].
357///
358/// What a row of the call site table in `.gcc_except_table` says, which is the bytes of the call
359/// and where the pad is. An unwinder looking up a return address finds the call it is the end of,
360/// so the range is the call's own bytes and nothing around it.
361#[derive(Debug, Clone, Copy, PartialEq, Eq)]
362pub struct Site {
363 /// Where the call begins.
364 pub start: usize,
365 /// How many bytes it is.
366 pub len: usize,
367 /// Where the pad begins.
368 pub pad: usize,
369}
370
371/// The variables a file defines, and what the linker has to be told about them.
372///
373/// One entry per variable rather than one section of everything, because where a variable goes is
374/// worked out from what it is and two of them that land in one section still have their own
375/// alignment, their own size and their own symbol. Putting them together is the writer's job and
376/// is the one part of it the three formats disagree about.
377#[derive(Debug, Clone, Default, PartialEq, Eq)]
378pub struct Data {
379 /// Every variable this file defines, in the order the module held them.
380 pub objects: Vec<Object>,
381 /// Every name this file declares weak and does not define, in the order the module held them.
382 ///
383 /// Each becomes an undefined symbol the linker is allowed to leave undefined, whose references
384 /// then read a zero address. A name here is not an object and carries no bytes, which is why
385 /// it is a list of names beside the objects rather than one of them.
386 pub weak: Vec<String>,
387 /// Every distance between two labels an image holds, which the writer fills in once it knows
388 /// where the labels are. See [`Apart`].
389 pub apart: Vec<Apart>,
390 /// Every name this file offers to other DLLs, functions first and then variables, each in the
391 /// order the module held them. Only COFF has anywhere to say it and every other format is
392 /// handed an empty list. See [`Export`].
393 pub exports: Vec<Export>,
394}
395
396/// One name the DLL this file is linked into offers to others, which is `dllexport`, or one it
397/// is told to keep to itself, which is a hidden definition.
398///
399/// What a COFF object says either with is an option for the linker, ` -export:name`, in a section
400/// called `.drectve` that holds nothing but options and that the linker reads and then drops. A
401/// variable is ` -export:name,data`, which keeps the import library from writing a stub under the
402/// plain name for it, since a jump is no use to somebody reading a variable. The list is in the
403/// order clang writes it and the options are spelled the way it spells them, which is also what
404/// gcc's are, apart from the quotes gcc puts round each name.
405#[derive(Debug, Clone, PartialEq, Eq)]
406pub struct Export {
407 /// The name as the linker sees it.
408 pub name: String,
409 /// What the linker is told about it.
410 pub kind: Offer,
411}
412
413/// What an [`Export`] tells the linker about its name.
414#[derive(Debug, Clone, Copy, PartialEq, Eq)]
415pub enum Offer {
416 /// A function other DLLs may call.
417 Function,
418 /// A variable other DLLs may read.
419 Variable,
420 /// A name that is left out when the linker exports every name a DLL defines, which is what it
421 /// does for a DLL with no `dllexport` and no `.def` file. `-exclude-symbols:name`, which clang
422 /// writes for a hidden definition on a mingw-w64 target and which both lld and GNU ld read.
423 /// gcc ignores hidden visibility there. This is how the runtime routines of our own that a
424 /// DLL links in stay out of its export table, the way libgcc's do by being named libgcc.
425 Hidden,
426 /// Not a name at all but a whole option, which [`Export::name`] holds as the linker reads it.
427 /// What `#pragma comment(lib)` and `#pragma comment(linker)` ask for, such as
428 /// `/DEFAULTLIB:ws2_32.lib`, which goes in the same section for the same linker to read.
429 Verbatim,
430}
431
432impl Export {
433 /// The option the linker is handed for it, with the space in front that holds it apart from
434 /// the one before.
435 #[must_use]
436 pub fn option(&self) -> String {
437 match self.kind {
438 Offer::Function => format!(" -export:{}", self.name),
439 Offer::Variable => format!(" -export:{},data", self.name),
440 Offer::Hidden => format!(" -exclude-symbols:{}", self.name),
441 Offer::Verbatim => format!(" {}", self.name),
442 }
443 }
444}
445
446/// How far one label is from another, written into a variable's image.
447///
448/// What `static int b[] = { &&l1 - &&l0 };` asks for. Neither label has an address until the
449/// link, and yet both are in the one function's code and the code moves as one piece, so the
450/// distance is known as soon as the code is laid out. That makes it a number the writer puts in
451/// the bytes itself rather than a relocation it asks the linker for, which is what gas does with
452/// `.long .L1-.L0` too, and it is why a label in another function is refused: the two could land
453/// in different sections and then no number is right.
454#[derive(Debug, Clone, PartialEq, Eq)]
455pub struct Apart {
456 /// Which of [`Data::objects`] the distance is written into.
457 pub object: usize,
458 /// How far into that object's image.
459 pub at: usize,
460 /// The label measured to, as the image named it.
461 pub to: String,
462 /// The label measured from.
463 pub from: String,
464 /// What to add to the distance.
465 pub addend: i64,
466 /// How many bytes the distance is written in.
467 pub bytes: u8,
468}
469
470/// A second name for something the same file defines.
471///
472/// Not a section and not a byte of anything, which is the whole point of it: an alias is a symbol
473/// table entry pointing at an address something else already occupies, so a file with one in it is
474/// no larger than the same file without. `.set b, a` is what an assembler is told and a second
475/// entry at the first one's section, value and size is what a writer produces, and the two say the
476/// same thing.
477///
478/// The target is a name rather than an index into anything above, because the two output paths
479/// find it in different places: a listing hands the name to an assembler that resolves it, and a
480/// writer looks it up among the symbols it has already added.
481#[derive(Debug, Clone, PartialEq, Eq)]
482pub struct Alias {
483 /// The name being defined, as the C program spelled it.
484 pub name: String,
485 /// The name it stands for, which has to be something this same file defines.
486 pub target: String,
487 /// How the linker sees the new name, which is not always how it sees the old one: the target
488 /// of `extern int b __attribute__((alias("a")))` may be a `static`.
489 pub binding: Binding,
490 /// How far outside a shared library holding this the new name reaches, which is its own
491 /// answer for the same reason the binding is: the attribute is written on the alias.
492 pub visibility: Visibility,
493 /// Whether the new name is an indirect function, `STT_GNU_IFUNC`, rather than a second name
494 /// for the target. The target is then a resolver, which the dynamic loader calls once and
495 /// whose answer is the address every call to the new name reaches. ELF is the only format with
496 /// the type, and a writer for another one refuses it rather than write an ordinary name.
497 pub ifunc: bool,
498}
499
500/// One global variable, laid out.
501#[derive(Debug, Clone, PartialEq, Eq)]
502pub struct Object {
503 /// Its name, as the C program spelled it. The underscore an Apple symbol carries is the
504 /// object writer's business, not this one's.
505 pub name: String,
506 /// Its image, and nothing at all when it is zero filled and the file carries none of it.
507 pub bytes: Vec<u8>,
508 /// How many bytes it occupies, which is the length of the image except when there is none.
509 pub size: u64,
510 /// What it has to be aligned to, always a power of two.
511 pub align: u64,
512 /// Which section it goes in.
513 pub place: Place,
514 /// How the linker sees the name.
515 pub binding: Binding,
516 /// How far outside a shared library holding this the name reaches.
517 pub visibility: Visibility,
518 /// Every place in its image that holds the address of a symbol, counted from the start of
519 /// the image rather than from the start of the section it lands in.
520 pub relocs: Vec<Reloc>,
521}
522
523/// Which section a variable goes in.
524///
525/// Worked out from what the variable is rather than named by it, except in the one case where the
526/// program named it. A reader who wants to know why a variable is in `.rodata` should be able to
527/// find the answer in the variable.
528#[derive(Debug, Clone, PartialEq, Eq)]
529pub enum Place {
530 /// Written to, and its image is not all zeros. `.data`.
531 Written,
532 /// Never written to, so it can go in a page the loader maps read only and every process
533 /// running the program can share. `.rodata`.
534 ReadOnly,
535 /// Never written to by the program, but written once by the dynamic linker, because its image
536 /// holds the address of something and an address is not known until the image is loaded.
537 /// `.data.rel.ro`.
538 ///
539 /// The section has to be writable for that one write and read only afterwards, which is what
540 /// the `PT_GNU_RELRO` segment is: the loader maps it, the relocations are applied, and then it
541 /// is turned read only before the program starts. Putting the variable in `.rodata` instead
542 /// means asking the linker to leave a relocation in a section that is never writable, and what
543 /// it does about that is give the whole image `DT_TEXTREL`, which gives up the protection the
544 /// section was for. Some hardened toolchains refuse the link outright.
545 RelocReadOnly {
546 /// Whether every address in the image is of something this file defines and does not
547 /// export, which means the link can resolve them all and none can be interposed.
548 ///
549 /// Those go in `.data.rel.ro.local`, which the linker puts in the first pages of the
550 /// segment, so the pages holding them are the ones the loader is done with soonest. It is
551 /// a hint about layout rather than a difference in what the section is.
552 local: bool,
553 },
554 /// All zeros, so the file says how big it is and carries none of it. `.bss`.
555 Zero,
556 /// One copy per thread rather than one copy per program. `.tdata` and `.tbss`.
557 ///
558 /// What the loader does with these two sections is what makes them different from every other
559 /// section here. Their contents are the template of a thread's own block of storage rather than
560 /// the storage itself: the image is laid out once, and every thread that starts gets a fresh
561 /// copy of it, so the address of a variable in one of them is a different address in every
562 /// thread and there is no single address for the link to write down. That is why a reference to
563 /// one is not the ordinary distance from the instruction pointer, and why the symbol is marked
564 /// as being of this kind so a linker refuses one that is.
565 ///
566 /// The pair is the same split as `.data` and `.bss` for the same reason, so an image that is
567 /// all zeros costs its size in the file and not its bytes.
568 Thread {
569 /// Whether the image is all zeros, which puts it in `.tbss` rather than `.tdata`.
570 zero: bool,
571 },
572 /// A tentative definition, which is not in a section at all: the linker is asked for that
573 /// much zeroed space and merges every definition of the name into one. `.comm`.
574 Merged,
575 /// The section the program named, from `__attribute__((section(...)))`, and what the
576 /// variable put there holds, which is what the section's flags have to say.
577 Named(String, Holds),
578 /// A pointer to a variable this file only declares, in a read only section of its own that
579 /// the linker keeps one copy of whichever objects wrote it. COFF only, where it is called
580 /// `.rdata$` and the pointer's name, and every object that reads the variable writes the same
581 /// one with the same name, which is why a copy has to be allowed to lose to another.
582 ///
583 /// What the pointer is for is `rucc_codegen::elsewhere::Slot::Referred`. The runtime may write
584 /// it once the DLL the variable turns out to be in is loaded, which is why the section is not
585 /// merely read only: the runtime unprotects the page for that one write.
586 Pointer,
587 /// A string literal, in the section of them the linker keeps one copy of each string in,
588 /// whichever objects it came from. `.rodata.str1.` and the alignment, which is where gcc puts
589 /// one, flagged `SHF_MERGE` and `SHF_STRINGS` with entries a byte wide.
590 ///
591 /// Only for a literal of one byte characters whose first zero is its last byte. The linker
592 /// reads the section as a run of strings each ended by a zero, so one with a zero inside it
593 /// would be cut in two, and a wide one is entries of a different width, which goes in a
594 /// section of its own name that nothing here writes yet.
595 Strings {
596 /// What it is aligned to, which is in the name because two literals aligned differently
597 /// cannot be in one run the linker merges.
598 align: u64,
599 },
600}
601
602/// What a variable in a section the program named holds, which is the one thing about the section
603/// the name does not say.
604///
605/// The answers are the ones gcc gives, which a kernel's linker script and `readelf` both see: a
606/// section is writable unless the variable is constant and holds no address, and it carries no
607/// bytes only when its name is one of the names that always mean zeros and the variable is zeros.
608#[derive(Debug, Clone, Copy, PartialEq, Eq)]
609pub enum Holds {
610 /// Bytes the program or the loader may write. `"aw"` on ELF.
611 Written,
612 /// Bytes nothing writes, which a loader maps read only. `"a"` on ELF.
613 ReadOnly,
614 /// Zeros, in a section named for holding nothing else, so the file carries none of them.
615 /// `"aw",@nobits` on ELF.
616 Zero,
617}
618
619impl Holds {
620 /// Whether a section of this name is one gcc makes carry no bytes, which is `.bss` and the
621 /// names under it, the small data one and the old COMDAT spellings of both. A kernel puts
622 /// its page aligned zeros in `.bss..page_aligned` and relies on this.
623 #[must_use]
624 pub fn nobits(name: &str) -> bool {
625 name == ".bss"
626 || name.starts_with(".bss.")
627 || name.starts_with(".gnu.linkonce.b.")
628 || name == ".sbss"
629 || name.starts_with(".sbss.")
630 || name.starts_with(".gnu.linkonce.sb.")
631 }
632}
633
634impl Place {
635 /// What the section this variable goes in is called under [`Sections::data`], and nothing at
636 /// all for a variable that has no section of its own to be given.
637 ///
638 /// The name is the section it would otherwise have shared with a dot and the variable's name
639 /// after it, which is what gcc writes and is not merely a convention: `--gc-sections`, the
640 /// linker scripts a kernel and an embedded image are linked with, and the default placement
641 /// rules all match on the part in front of the dot, so a section called anything else would be
642 /// placed by whatever the catch all rule is.
643 ///
644 /// Two kinds of variable are left alone. A merged one is a request to the linker for that much
645 /// zeroed space rather than an image, so there is no section to split, and one the program put
646 /// a name on already has the answer the source gave, which this must not overrule.
647 /// A string literal is left alone too, as gcc leaves it: the linker merges the strings of the
648 /// section they share, and a section per literal would give it nothing to merge them with.
649 ///
650 /// Here rather than beside either output path, so that the listing `-S` writes and the object
651 /// `-c` writes cannot come to disagree about where a variable went.
652 #[must_use]
653 pub fn split(&self, name: &str) -> Option<String> {
654 Some(format!("{}.{name}", self.base()?))
655 }
656
657 /// The section this variable goes in when nothing is being split up, and nothing at all for
658 /// the two kinds that are not in one.
659 #[must_use]
660 pub fn base(&self) -> Option<&'static str> {
661 Some(match self {
662 Place::Written => ".data",
663 Place::ReadOnly => ".rodata",
664 Place::RelocReadOnly { local: false } => ".data.rel.ro",
665 Place::RelocReadOnly { local: true } => ".data.rel.ro.local",
666 Place::Zero => ".bss",
667 Place::Thread { zero: false } => ".tdata",
668 Place::Thread { zero: true } => ".tbss",
669 Place::Merged | Place::Named(..) | Place::Pointer | Place::Strings { .. } => {
670 return None;
671 }
672 })
673 }
674
675 /// The section a string literal of that alignment goes in.
676 #[must_use]
677 pub fn strings(align: u64) -> String {
678 format!(".rodata.str1.{align}")
679 }
680}
681
682/// A section holding function addresses for a C runtime to call rather than data for the program
683/// to read.
684///
685/// ELF has a type for each of the three, and a section of that type is what the startup code walks:
686/// the linker gathers every input section of the kind into one run and the CRT calls what it finds
687/// between the two ends. A section of the ordinary type with the same name would be gathered the
688/// same way and called by nothing, which is why the type is worth writing down rather than leaving
689/// to the default.
690///
691/// Only ELF says it this way. COFF sorts by what follows the `$` in a section name and Mach-O has
692/// a section attribute for it, so on those two the name carries the whole of the answer and there
693/// is nothing for this to be.
694#[derive(Debug, Clone, Copy, PartialEq, Eq)]
695pub enum Array {
696 /// Run on the way to `main`, in the order the linker sorted the sections into.
697 Init,
698 /// Run after `main` returns, in the reverse of that order.
699 Fini,
700 /// Run ahead of `.init_array` and ahead of the shared libraries a program is linked against,
701 /// which is a thing only the C library itself has a use for.
702 Preinit,
703}
704
705impl Array {
706 /// Which of them a section of this name is, and [`None`] for a name that is not one of them.
707 ///
708 /// The name itself or the name with a dot and a priority after it. A numbered `constructor` is
709 /// written as the second of those and is the same kind of section as the first: the number is
710 /// there so that the linker sorts it, not to make it a different thing.
711 #[must_use]
712 pub fn of(name: &str) -> Option<Array> {
713 let kinds = [
714 (".init_array", Array::Init),
715 (".fini_array", Array::Fini),
716 (".preinit_array", Array::Preinit),
717 ];
718 kinds.into_iter().find_map(|(base, array)| {
719 let rest = name.strip_prefix(base)?;
720 (rest.is_empty() || rest.starts_with('.')).then_some(array)
721 })
722 }
723
724 /// How the type is spelled in a `.section` directive.
725 #[must_use]
726 pub const fn asm(self) -> &'static str {
727 match self {
728 Array::Init => "@init_array",
729 Array::Fini => "@fini_array",
730 Array::Preinit => "@preinit_array",
731 }
732 }
733}
734
735/// How the linker sees a name.
736///
737/// Three of the five linkages the IR has, because that is how many an object file can say. Which
738/// of the two weak ones a symbol had is a fact the optimizer needs and the linker does not.
739#[derive(Debug, Clone, Copy, PartialEq, Eq)]
740pub enum Binding {
741 /// Visible to every other object, and the definition here is the definition.
742 Global,
743 /// Invisible outside this object, which is what `static` at file scope means.
744 Local,
745 /// Visible, and allowed to lose to a definition in another object.
746 Weak,
747}
748
749/// How far outside a shared library a name reaches.
750///
751/// A different question from [`Binding`] and asked of a different linker. The binding is what the
752/// static linker does with a name while it is building the output, and this is what the dynamic
753/// linker may do with it once the output is a shared library and is being loaded. A hidden name is
754/// still global to the static link, so two files in the same library can call each other by it; it
755/// is simply not in the dynamic symbol table afterwards, so nothing outside can name it.
756///
757/// Written down here as its own thing rather than folded into the binding because it is the
758/// mistake tamnd/rucc#733 was: a writer that has one word for both ends up saying something about
759/// visibility while it thinks it is saying something about linkage, and what it said was hidden.
760///
761/// It means nothing for a [`Binding::Local`] name. `static` is already invisible to the whole
762/// world outside the file, and ELF records `STV_DEFAULT` for one, which is what gcc writes.
763#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
764pub enum Visibility {
765 /// In the dynamic symbol table, and a reference from inside the library may be satisfied by a
766 /// definition somewhere else, which is what makes `LD_PRELOAD` work. What a name gets when
767 /// nothing said otherwise.
768 #[default]
769 Default,
770 /// Not in the dynamic symbol table at all, so nothing outside the library can name it and
771 /// every reference to it from inside binds here. `__attribute__((visibility("hidden")))`.
772 Hidden,
773 /// In the dynamic symbol table, so something outside can name it, but a reference from inside
774 /// the library binds to the definition inside it and cannot be interposed.
775 Protected,
776}
777
778/// One reference to something this file does not contain.
779#[derive(Debug, Clone, PartialEq, Eq)]
780pub struct Reloc {
781 /// Where the bytes the linker writes over begin.
782 pub at: usize,
783 /// What is wanted, as the C program spelled it.
784 pub symbol: String,
785 /// What the linker is being asked for.
786 pub kind: Reference,
787 /// What to add to the distance, which is the constant the instruction already meant plus the
788 /// bytes between the hole and the end of the instruction, negated. An instruction counts from
789 /// where it ends and a relocation counts from where it starts, and this is the difference.
790 pub addend: i64,
791 /// How many bytes of the instruction come after the four the linker writes over, which is zero
792 /// for everything except an instruction carrying an immediate behind its displacement.
793 ///
794 /// Already inside [`Self::addend`] and written down again because the two formats disagree about
795 /// which of the two numbers they want. ELF takes the one number and counts from where the hole
796 /// starts, so the difference between that and where the instruction ends is the writer's to fold
797 /// in and nothing after it ever has to be told apart again. COFF counts from where the
798 /// instruction ends and says how far that is in the relocation type itself, which is what
799 /// `IMAGE_REL_AMD64_REL32_1` through `REL32_5` are, so it needs the two apart. A writer cannot
800 /// recover one from the other, since a displacement of minus four and no trailing bytes and a
801 /// displacement of zero and four of them are the same sum.
802 ///
803 /// Zero for a relocation in an image, where there is no instruction and the question does not
804 /// arise.
805 pub after: u8,
806}
807
808/// Which of the i386 thread-local relocations a [`Reference::Tls`] is, named after what the four
809/// bytes end up holding.
810///
811/// The suffix gcc writes for each is beside it. The linker may rewrite the instruction around the
812/// first three into a cheaper model once it knows where the variable ends up, which is why each
813/// kind is kept apart from the others rather than folded into an address or an offset.
814#[derive(Debug, Clone, Copy, PartialEq, Eq)]
815pub enum Tls {
816 /// The pair of slots of the global offset table `___tls_get_addr` takes, as a distance from the
817 /// table. `@TLSGD`, `R_386_TLS_GD`.
818 General,
819 /// The same pair for the module as a whole rather than one variable. `@TLSLDM`,
820 /// `R_386_TLS_LDM`.
821 Module,
822 /// How far into its module's block a variable is, which is what goes with the address
823 /// [`Tls::Module`] found. `@DTPOFF`, `R_386_TLS_LDO_32`.
824 InModule,
825 /// A slot of the global offset table holding where the variable is from the thread pointer, as
826 /// a distance from the table. `@GOTNTPOFF`, `R_386_TLS_GOTIE`.
827 Slot,
828 /// The same slot by its address, for code that is not position independent. `@INDNTPOFF`,
829 /// `R_386_TLS_IE`.
830 SlotAddress,
831 /// A slot holding the distance the other way round, from the variable up to the thread
832 /// pointer, as a distance from the table. `@GOTTPOFF`, `R_386_TLS_IE_32`.
833 SlotNegated,
834 /// Where the variable is from the thread pointer, which is below it and so negative.
835 /// `@NTPOFF`, `R_386_TLS_LE`.
836 Offset,
837 /// The same distance the other way round, which is positive. `@TPOFF`, `R_386_TLS_LE_32`.
838 Negated,
839}
840
841/// What kind of thing a relocation is asking the linker for.
842///
843/// The first four are the distance from the end of an instruction to something, which is what every
844/// reference the code makes is, because this compiler generates position independent code and
845/// nothing else. They are told apart by what the linker is allowed to do about each one. The last
846/// two are not distances from an instruction at all and are what a table of data asks for: the
847/// address itself, which is what an initializer holding the address of something holds, and how far
848/// something is from the front of the image, which is what a table the runtime reads holds.
849#[derive(Debug, Clone, Copy, PartialEq, Eq)]
850pub enum Reference {
851 /// A call, which the linker may satisfy with a stub that reaches further than the four bytes
852 /// would. `R_X86_64_PLT32` on ELF, and the same relocation a branch gets on the other two.
853 Call,
854 /// A datum, reached from the instruction pointer. `R_X86_64_PC32` on ELF.
855 Data,
856 /// A slot of the global offset table, reached from the instruction pointer, holding the
857 /// address of something another object may be the one that defines.
858 ///
859 /// The distance to the slot rather than to the thing, which is the whole difference: the
860 /// distance to the thing is a number only a link that puts the thing in this program can
861 /// work out, and a shared library is a link that does not. `R_X86_64_REX_GOTPCRELX` on ELF,
862 /// which says the instruction is a `mov` with a REX prefix and lets the linker turn it back
863 /// into the `lea` it would have been if the symbol had been here all along.
864 Got,
865 /// A slot of the global offset table read by an instruction the linker may rewrite that has
866 /// no REX prefix, `call *f@GOTPCREL(%rip)` or a 32 bit `mov`. `R_X86_64_GOTPCRELX` on ELF.
867 GotBare,
868 /// A slot of the global offset table read by an instruction the linker has to leave as it is,
869 /// because it is not one of the few it knows how to rewrite: a store into the slot, or a load
870 /// into a vector register. `R_X86_64_GOTPCREL` on ELF.
871 GotKept,
872 /// A slot of the global offset table, reached from the instruction pointer, holding how far
873 /// into a thread's own block of storage a thread-local variable sits.
874 ///
875 /// An offset and not an address, which is what makes it a different relocation from the one
876 /// above rather than the same one against a different symbol: a thread-local variable has one
877 /// copy per thread and therefore no address for a link to write down, and what every copy has
878 /// in common is where it sits inside the block. Adding the block's own address, which the
879 /// machine keeps in a segment register, is what turns one into the other, and that addition is
880 /// in the code rather than in the relocation. `R_X86_64_GOTTPOFF` on ELF, which the linker
881 /// turns into a constant in the instruction when it is making an executable and therefore
882 /// knows how the blocks are laid out.
883 Thread,
884 /// The address itself, written into an image. `int *p = &y;` and nothing else in C.
885 Address {
886 /// How many bytes of it are written, which is the pointer width except on a target with
887 /// a narrower relocation for it. `R_X86_64_64` and `R_X86_64_32` on ELF.
888 bytes: u8,
889 },
890 /// The address itself in four bytes of an x86-64 instruction that sign extends them to eight,
891 /// which is an immediate on sixty four bits and a displacement. `R_X86_64_32S` on ELF, which
892 /// is what code that is not position independent reaches its data with: `table(,%rax,4)` and
893 /// `movq $.LC0, %rdi`. The linker checks the address fits in the lower two gigabytes, where
894 /// `R_X86_64_32` would let one between two and four through to come out negative.
895 Signed,
896 /// How far the thing is from where the four bytes holding the answer are, written into an
897 /// image rather than reached by an instruction. `.long target - .` in an `asm` at file scope,
898 /// which is how a table of places in a program says where each of them is in four bytes rather
899 /// than eight and says it without anything having to be written into the table at startup.
900 ///
901 /// The same relocation a load makes, with nothing after the hole, because what a load asks is
902 /// the same question about the same four bytes. It is a kind of its own here all the same, and
903 /// not [`Reference::Data`] with `after` left at zero, because the two formats count the answer
904 /// from different ends: ELF counts from the front of the hole, which is what this wants, and
905 /// COFF counts from the byte after it, which is what an instruction wants. Saying which is
906 /// meant is what lets each writer answer for itself rather than one of them be quietly four
907 /// out.
908 Away,
909 /// The same distance written into eight bytes, which is `.quad target - .`. The kernel's jump
910 /// label table says where each key is that way on x86-64, and the key is in another section
911 /// from the table, so it is a relocation. `R_X86_64_PC64` on ELF.
912 AwayWide,
913 /// How far the thing is from the front of the loaded image, written into four bytes.
914 ///
915 /// What every field of a Windows unwind table is. The table is read at run time by code that
916 /// already has the image's own address, so four bytes of distance from it reach anything in an
917 /// image a linker will build, which eight bytes of address would have cost twice as much to say
918 /// and a distance from the table itself could not have said at all: a row is looked up by
919 /// address in a sorted table, and a row whose meaning depended on where the row was would not
920 /// sort. `IMAGE_REL_AMD64_ADDR32NB`.
921 ///
922 /// ELF has no relocation of this kind because nothing it writes asks the question. Its unwind
923 /// records are found by walking rather than by binary search, and what they hold is the ordinary
924 /// distance from the record to the function.
925 Image,
926 /// How far the thing is from the front of the section it is in, written into the four bytes
927 /// of displacement of an address that is counted from a register.
928 ///
929 /// What a Windows thread finds its copy of a thread-local variable with. Every thread has a
930 /// copy of the image's `.tls` section, the register holds where this thread's copy is, and the
931 /// variable is as far into the copy as it is into the section. `IMAGE_REL_AMD64_SECREL`, and
932 /// nothing on ELF or Mach-O, which reach thread-local storage through a table slot instead.
933 Section,
934 /// How far the thing is from the front of the global offset table, in four bytes.
935 ///
936 /// What position independent code on i386 reaches its own data with. That machine has no
937 /// addressing from the instruction pointer, so a function finds the table once, keeps its
938 /// address in a register, and reaches everything this file defines as that register plus a
939 /// constant: `leal .LC0@GOTOFF(%ebx), %eax`. `R_386_GOTOFF` on ELF.
940 GotOffset,
941 /// How far the front of the global offset table is from the four bytes themselves, which is how
942 /// i386 code finds the table in the first place.
943 ///
944 /// `addl $_GLOBAL_OFFSET_TABLE_, %ebx` straight after a call that left its own return address
945 /// in `%ebx`. The addend makes up the difference between where the four bytes are and where the
946 /// instruction starts, which is the address the call left behind. `R_386_GOTPC` on ELF.
947 GotFront,
948 /// Where a slot of the global offset table is, as a distance from the front of the table, read
949 /// by an instruction the linker may rewrite into one that does not go through the slot at all.
950 ///
951 /// The i386 counterpart of [`Reference::Got`], counted from the register holding the table
952 /// rather than from the instruction pointer: `movl foo@GOT(%ebx), %eax` and
953 /// `call *foo@GOT(%ebx)`. `R_386_GOT32X` on ELF.
954 Slot,
955 /// The same slot read or written by an instruction the linker has to leave as it is, because it
956 /// is not one of the few it knows how to rewrite. `R_386_GOT32` on ELF.
957 SlotKept,
958 /// One of the ways i386 code reaches a thread-local variable, which the model says which.
959 ///
960 /// Apart from [`Reference::Thread`] because this machine has a relocation for each step of each
961 /// model rather than the one x86-64 needs from a compiler that only writes one of them, and a
962 /// file of assembly may use any of them. See [`Tls`].
963 Tls(Tls),
964 /// Some bits of an AArch64 instruction, which the fixup says which and how to fill in.
965 ///
966 /// Its own kind rather than one of the above, because on this machine a reference is not four
967 /// bytes of distance: it is a field of a word, and a name takes two instructions to reach,
968 /// `adrp` for its page and an `add` or a load for the low twelve bits of it. Each of those is
969 /// its own relocation, and the fixup is already the name of one.
970 Field(rucc_target::aarch64::Fixup),
971}