Skip to main content

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