1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
//! ELF64, little-endian, for x86-64 and AArch64: relocatable objects (`ET_REL`) and
//! static executables (`ET_EXEC`).
//!
//! - [`write()`] and [`write_into`] turn an [`Object`] into ELF bytes.
//! - [`read()`] and [`read_with_limits`] turn ELF bytes back into an [`Object`].
//! - [`executable`] is the one-call path from machine code to a runnable program.
//!
//! ## What the writer produces
//!
//! A **relocatable object** holds the object's sections in order (section header `i + 1`
//! is the model's section `i`), then one `.rela<name>` section per section with
//! relocations, an empty `.note.GNU-stack` marking whether the stack must be executable,
//! `.symtab` (with `.symtab_shndx` when a section index exceeds 16 bits), `.strtab`, and
//! `.shstrtab`. The symbol table starts with the null symbol, then one `STT_SECTION`
//! symbol for each section a relocation targets directly, then the object's local
//! symbols, then the rest, each group in model order; `sh_info` is the index of the
//! first non-local symbol. String tables share the bytes of names that are suffixes of
//! other names. Section counts and indices past 0xff00 use ELF's extended numbering.
//!
//! An **executable** maps its file headers read-only on the page(s) just below its
//! lowest section, then one `PT_LOAD` per run of sections with the same permissions,
//! each aligned to the [page size](crate::Architecture::page_size) with its file offset
//! congruent to its address. A `PT_GNU_STACK` header marks the stack non-executable
//! unless [`executable_stack`](Object::executable_stack) is set. There is no
//! interpreter and no dynamic section: the program is fully static. Section headers and
//! a symbol table are written too, so tools can name what they disassemble.
//!
//! The output depends only on the object: the same object always gives the same bytes.
//!
//! ## What the reader accepts
//!
//! Exactly the files the model can represent: ELF64 little-endian `ET_REL` or `ET_EXEC`
//! for x86-64 or AArch64, with `SHT_RELA` relocations of the kinds in
//! [`X86_64Reloc`](crate::X86_64Reloc) and [`Aarch64Reloc`](crate::Aarch64Reloc). It
//! drops what carries no meaning in the model (`STT_SECTION` symbols, which become
//! [`RelocationTarget::Section`](crate::RelocationTarget::Section); LLVM's
//! `.llvm_addrsig` hint) and refuses everything else it cannot represent exactly
//! (COMDAT groups, `SHT_REL`, dynamic sections, unknown section, symbol, or
//! relocation types) with a [`ReadError`].
use Vec;
use crate;
use crateLimits;
use crate;
use crate;
use crateSymbol;
/// Writes an object as an ELF file and returns the bytes.
///
/// The object is [validated](Object::validate) first. The output is deterministic.
///
/// # Errors
///
/// - [`WriteError::Invalid`] if the object breaks a rule of the model.
/// - [`WriteError::ReservedSectionName`] for a relocatable object with a section named
/// `.note.GNU-stack`, which the writer emits itself.
/// - For executables: [`WriteError::SegmentsSharePage`],
/// [`WriteError::NoRoomForHeaders`], and [`WriteError::Unsupported`] for
/// thread-local sections.
/// - [`WriteError::TooLarge`] if a table outgrows ELF's 32-bit fields.
///
/// # Examples
///
/// ```
/// use object_lang::{Architecture, Object, Section, SectionKind, Symbol};
///
/// let mut obj = Object::relocatable(Architecture::X86_64);
/// let text = obj.add_section(Section::new(".text", SectionKind::Text).with_data(vec![0xc3]));
/// obj.add_symbol(Symbol::function("ret", text, 0, 1));
///
/// let bytes = object_lang::elf::write(&obj)?;
/// assert_eq!(&bytes[..4], b"\x7fELF");
/// assert_eq!(object_lang::elf::read(&bytes)?, obj);
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
/// Writes an object as an ELF file, appending the bytes to `out`, so one buffer can be
/// reused across many objects. On error, `out` is left as it was.
///
/// # Errors
///
/// As [`write()`].
///
/// # Examples
///
/// ```
/// use object_lang::{Architecture, Object};
///
/// let mut buffer = Vec::new();
/// for arch in [Architecture::X86_64, Architecture::Aarch64] {
/// buffer.clear();
/// object_lang::elf::write_into(&Object::relocatable(arch), &mut buffer)?;
/// assert_eq!(object_lang::elf::read(&buffer)?.architecture(), arch);
/// }
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
/// Reads an ELF file into an object, with the default [`Limits`].
///
/// # Errors
///
/// A [`ReadError`] saying what is wrong: [`BadMagic`](ReadError::BadMagic) for bytes
/// that are not ELF, [`Truncated`](ReadError::Truncated) when a structure runs past the
/// input, [`Malformed`](ReadError::Malformed) when fields contradict the format or each
/// other, [`Unsupported`](ReadError::Unsupported) for valid ELF the model cannot
/// represent, [`LimitExceeded`](ReadError::LimitExceeded) when a budget is exceeded,
/// and [`Invalid`](ReadError::Invalid) when the decoded object breaks a model rule. It
/// never panics, whatever the bytes.
///
/// # Examples
///
/// ```
/// use object_lang::{Architecture, FileKind};
///
/// let exe = object_lang::elf::executable(Architecture::X86_64, &[0xeb, 0xfe])?; // jmp .
/// let obj = object_lang::elf::read(&exe)?;
/// assert_eq!(obj.kind(), FileKind::Executable);
/// assert_eq!(obj.sections()[0].data(), &[0xeb, 0xfe]);
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
/// Reads an ELF file into an object, with the given [`Limits`].
///
/// # Errors
///
/// As [`read()`], with [`ReadError::LimitExceeded`] naming the first budget exceeded.
///
/// # Examples
///
/// ```
/// use object_lang::{Architecture, Limits, Object, ReadError, Symbol};
///
/// let mut obj = Object::relocatable(Architecture::X86_64);
/// obj.add_symbol(Symbol::undefined("a_rather_long_symbol_name"));
/// let bytes = object_lang::elf::write(&obj)?;
///
/// let mut limits = Limits::default();
/// limits.max_name_len = 8;
/// assert_eq!(
/// object_lang::elf::read_with_limits(&bytes, &limits),
/// Err(ReadError::LimitExceeded { limit: "max_name_len" }),
/// );
/// # Ok::<(), object_lang::WriteError>(())
/// ```
/// The address [`executable`] loads its code at: one page above 4 MiB (`0x40_0000`), the
/// traditional base of a static Linux executable, with the file headers on the page(s)
/// below it.
///
/// # Examples
///
/// ```
/// use object_lang::{Architecture, elf};
///
/// assert_eq!(elf::code_address(Architecture::X86_64), 0x40_1000);
/// assert_eq!(elf::code_address(Architecture::Aarch64), 0x41_0000);
/// ```
pub const
/// Builds a static executable from machine code: the one-call path to a program the OS
/// can run.
///
/// `code` becomes a `.text` section at [`code_address`], 16-byte aligned, and execution
/// starts at its first byte, where a global `_start` symbol marks it. The code must not
/// need relocations or data of its own beyond what it carries; for anything more,
/// build an executable [`Object`] and [`write()`] it.
///
/// # Errors
///
/// [`WriteError::Invalid`] with [`EntryNotExecutable`](crate::ModelError::EntryNotExecutable)
/// if `code` is empty.
///
/// # Examples
///
/// `exit(42)` on Linux x86-64, hand-assembled:
///
/// ```
/// use object_lang::Architecture;
///
/// let code = [
/// 0xbf, 0x2a, 0x00, 0x00, 0x00, // mov edi, 42
/// 0xb8, 0x3c, 0x00, 0x00, 0x00, // mov eax, 60 (exit)
/// 0x0f, 0x05, // syscall
/// ];
/// let program = object_lang::elf::executable(Architecture::X86_64, &code)?;
/// // Write `program` to a file, mark it executable, run it: it exits with status 42.
/// assert_eq!(&program[..4], b"\x7fELF");
/// # Ok::<(), object_lang::WriteError>(())
/// ```