Skip to main content

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}