object_lang/symbol.rs
1//! Symbols: named addresses that objects define for others and refer to from others.
2
3use alloc::string::String;
4
5use crate::model::SectionId;
6
7/// What a symbol names.
8///
9/// # Examples
10///
11/// ```
12/// use object_lang::{SectionId, Symbol, SymbolKind};
13///
14/// assert_eq!(Symbol::undefined("puts").kind, SymbolKind::NoType);
15/// ```
16#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
17#[non_exhaustive]
18pub enum SymbolKind {
19 /// Unspecified: a label, or a reference whose kind the object does not know.
20 NoType,
21 /// A function or other code entry point.
22 Function,
23 /// A data object: a variable, a constant, a table.
24 Data,
25 /// A thread-local variable; its value is an offset in the thread-local template.
26 Tls,
27 /// The name of the source file the object came from. Always local and
28 /// [`Absolute`](SymbolSection::Absolute), with value and size zero.
29 File,
30}
31
32/// Who can see a symbol: this object only, or every object in the link.
33///
34/// # Examples
35///
36/// ```
37/// use object_lang::{Binding, Symbol};
38///
39/// assert_eq!(Symbol::undefined("f").binding, Binding::Global);
40/// assert_eq!(Symbol::file("main.c").binding, Binding::Local);
41/// ```
42#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
43#[non_exhaustive]
44pub enum Binding {
45 /// Visible only inside this object.
46 Local,
47 /// Visible to every object in the link; two global definitions of one name clash.
48 Global,
49 /// Like global, but yields to a global definition of the same name, and an
50 /// undefined weak reference resolves to zero instead of failing the link.
51 Weak,
52}
53
54/// How far a global symbol is exported beyond the module it is linked into.
55///
56/// # Examples
57///
58/// ```
59/// use object_lang::{Symbol, Visibility};
60///
61/// let hidden = Symbol::undefined("helper").with_visibility(Visibility::Hidden);
62/// assert_eq!(hidden.visibility, Visibility::Hidden);
63/// ```
64#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
65#[non_exhaustive]
66pub enum Visibility {
67 /// Visibility follows the binding.
68 Default,
69 /// Not exported from the linked module (executable or shared library).
70 Hidden,
71 /// Exported, but references from inside the module always bind to this definition.
72 Protected,
73}
74
75/// Where a symbol is defined.
76///
77/// # Examples
78///
79/// ```
80/// use object_lang::{Symbol, SymbolSection};
81///
82/// assert_eq!(Symbol::undefined("x").section, SymbolSection::Undefined);
83/// assert_eq!(Symbol::absolute("PAGE", 4096).section, SymbolSection::Absolute);
84/// ```
85#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
86#[non_exhaustive]
87pub enum SymbolSection {
88 /// Not defined here: another object must define it (or, if weak, it may stay
89 /// undefined and resolve to zero).
90 Undefined,
91 /// A constant value that relocation does not change.
92 Absolute,
93 /// A tentative definition (a C "common" symbol): the linker allocates `size` bytes
94 /// of zeroed storage, aligned to the symbol's `value`, unless an object defines the
95 /// name properly. Only in relocatable objects.
96 Common,
97 /// Defined in this section of the object.
98 Section(SectionId),
99}
100
101/// One symbol: a name, what it names, where it is defined, and who can see it.
102///
103/// `value` is an offset within the symbol's section in a relocatable object, and an
104/// address in an executable. For a [`Common`](SymbolSection::Common) symbol it is the
105/// required alignment. `size` is the size in bytes of what the symbol names, or zero
106/// when unknown.
107///
108/// The fields are public; the constructors cover the common shapes. The struct is
109/// `#[non_exhaustive]`, so build one with a constructor and adjust fields or chain the
110/// `with_*` methods.
111///
112/// # Examples
113///
114/// ```
115/// use object_lang::{
116/// Architecture, Binding, Object, Section, SectionKind, Symbol, SymbolKind, Visibility,
117/// };
118///
119/// let mut obj = Object::relocatable(Architecture::X86_64);
120/// let text = obj.add_section(Section::new(".text", SectionKind::Text).with_data(vec![0xc3; 8]));
121/// let helper = Symbol::function("helper", text, 4, 4)
122/// .with_binding(Binding::Local);
123/// let api = Symbol::function("api", text, 0, 4).with_visibility(Visibility::Protected);
124/// obj.add_symbol(helper);
125/// obj.add_symbol(api);
126/// assert!(obj.validate().is_ok());
127/// assert_eq!(obj.symbols()[0].kind, SymbolKind::Function);
128/// ```
129#[derive(Clone, PartialEq, Eq, Hash, Debug)]
130#[non_exhaustive]
131pub struct Symbol {
132 /// The symbol's name. Must not contain a NUL byte.
133 pub name: String,
134 /// What the symbol names.
135 pub kind: SymbolKind,
136 /// Who can see the symbol.
137 pub binding: Binding,
138 /// How far a non-local symbol is exported.
139 pub visibility: Visibility,
140 /// Where the symbol is defined.
141 pub section: SymbolSection,
142 /// The offset in the section (relocatable), the address (executable), or the
143 /// alignment ([`Common`](SymbolSection::Common)).
144 pub value: u64,
145 /// The size in bytes of what the symbol names, or zero.
146 pub size: u64,
147}
148
149impl Symbol {
150 /// A symbol with every property given; the other constructors are shorthands.
151 /// Visibility is [`Default`](Visibility::Default).
152 ///
153 /// # Examples
154 ///
155 /// ```
156 /// use object_lang::{Binding, Symbol, SymbolKind, SymbolSection};
157 ///
158 /// let sym = Symbol::new("x", SymbolKind::Data, Binding::Weak, SymbolSection::Undefined, 0, 0);
159 /// assert_eq!(sym.binding, Binding::Weak);
160 /// ```
161 #[must_use]
162 pub fn new(
163 name: impl Into<String>,
164 kind: SymbolKind,
165 binding: Binding,
166 section: SymbolSection,
167 value: u64,
168 size: u64,
169 ) -> Self {
170 Symbol {
171 name: name.into(),
172 kind,
173 binding,
174 visibility: Visibility::Default,
175 section,
176 value,
177 size,
178 }
179 }
180
181 /// A global function defined at `value` in `section`, `size` bytes long.
182 ///
183 /// # Examples
184 ///
185 /// ```
186 /// use object_lang::{Architecture, Object, Section, SectionKind, Symbol, SymbolKind};
187 ///
188 /// let mut obj = Object::relocatable(Architecture::X86_64);
189 /// let text = obj.add_section(Section::new(".text", SectionKind::Text).with_data(vec![0xc3]));
190 /// let main = Symbol::function("main", text, 0, 1);
191 /// assert_eq!(main.kind, SymbolKind::Function);
192 /// ```
193 #[must_use]
194 pub fn function(name: impl Into<String>, section: SectionId, value: u64, size: u64) -> Self {
195 Symbol::new(
196 name,
197 SymbolKind::Function,
198 Binding::Global,
199 SymbolSection::Section(section),
200 value,
201 size,
202 )
203 }
204
205 /// A global data object defined at `value` in `section`, `size` bytes long.
206 ///
207 /// # Examples
208 ///
209 /// ```
210 /// use object_lang::{Architecture, Object, Section, SectionKind, Symbol, SymbolKind};
211 ///
212 /// let mut obj = Object::relocatable(Architecture::X86_64);
213 /// let data = obj.add_section(Section::new(".data", SectionKind::Data).with_data(vec![0; 4]));
214 /// assert_eq!(Symbol::data("counter", data, 0, 4).kind, SymbolKind::Data);
215 /// ```
216 #[must_use]
217 pub fn data(name: impl Into<String>, section: SectionId, value: u64, size: u64) -> Self {
218 Symbol::new(
219 name,
220 SymbolKind::Data,
221 Binding::Global,
222 SymbolSection::Section(section),
223 value,
224 size,
225 )
226 }
227
228 /// A global reference to a symbol another object defines.
229 ///
230 /// # Examples
231 ///
232 /// ```
233 /// use object_lang::{Symbol, SymbolSection};
234 ///
235 /// assert_eq!(Symbol::undefined("malloc").section, SymbolSection::Undefined);
236 /// ```
237 #[must_use]
238 pub fn undefined(name: impl Into<String>) -> Self {
239 Symbol::new(
240 name,
241 SymbolKind::NoType,
242 Binding::Global,
243 SymbolSection::Undefined,
244 0,
245 0,
246 )
247 }
248
249 /// A global constant `value` that relocation does not change.
250 ///
251 /// # Examples
252 ///
253 /// ```
254 /// use object_lang::Symbol;
255 ///
256 /// assert_eq!(Symbol::absolute("STACK_SIZE", 0x10_0000).value, 0x10_0000);
257 /// ```
258 #[must_use]
259 pub fn absolute(name: impl Into<String>, value: u64) -> Self {
260 Symbol::new(
261 name,
262 SymbolKind::NoType,
263 Binding::Global,
264 SymbolSection::Absolute,
265 value,
266 0,
267 )
268 }
269
270 /// A global [common](SymbolSection::Common) data symbol of `size` bytes aligned to
271 /// `align` (a power of two).
272 ///
273 /// # Examples
274 ///
275 /// ```
276 /// use object_lang::{Symbol, SymbolSection};
277 ///
278 /// let buffer = Symbol::common("buffer", 256, 16);
279 /// assert_eq!((buffer.section, buffer.value, buffer.size), (SymbolSection::Common, 16, 256));
280 /// ```
281 #[must_use]
282 pub fn common(name: impl Into<String>, size: u64, align: u64) -> Self {
283 Symbol::new(
284 name,
285 SymbolKind::Data,
286 Binding::Global,
287 SymbolSection::Common,
288 align,
289 size,
290 )
291 }
292
293 /// A [`File`](SymbolKind::File) symbol naming the source file.
294 ///
295 /// # Examples
296 ///
297 /// ```
298 /// use object_lang::{Binding, Symbol, SymbolKind};
299 ///
300 /// let file = Symbol::file("main.rs");
301 /// assert_eq!((file.kind, file.binding), (SymbolKind::File, Binding::Local));
302 /// ```
303 #[must_use]
304 pub fn file(name: impl Into<String>) -> Self {
305 Symbol::new(
306 name,
307 SymbolKind::File,
308 Binding::Local,
309 SymbolSection::Absolute,
310 0,
311 0,
312 )
313 }
314
315 /// `self` with a different binding.
316 ///
317 /// # Examples
318 ///
319 /// ```
320 /// use object_lang::{Binding, Symbol};
321 ///
322 /// assert_eq!(Symbol::undefined("f").with_binding(Binding::Weak).binding, Binding::Weak);
323 /// ```
324 #[must_use]
325 pub fn with_binding(mut self, binding: Binding) -> Self {
326 self.binding = binding;
327 self
328 }
329
330 /// `self` with a different visibility.
331 ///
332 /// # Examples
333 ///
334 /// ```
335 /// use object_lang::{Symbol, Visibility};
336 ///
337 /// let s = Symbol::undefined("f").with_visibility(Visibility::Hidden);
338 /// assert_eq!(s.visibility, Visibility::Hidden);
339 /// ```
340 #[must_use]
341 pub fn with_visibility(mut self, visibility: Visibility) -> Self {
342 self.visibility = visibility;
343 self
344 }
345
346 /// `self` with a different kind.
347 ///
348 /// # Examples
349 ///
350 /// ```
351 /// use object_lang::{Symbol, SymbolKind};
352 ///
353 /// assert_eq!(Symbol::undefined("f").with_kind(SymbolKind::Function).kind, SymbolKind::Function);
354 /// ```
355 #[must_use]
356 pub fn with_kind(mut self, kind: SymbolKind) -> Self {
357 self.kind = kind;
358 self
359 }
360}