atom_macho/load_command/
dysymtab.rs

1use crate::io::{Endian, ReadExt as _, WriteExt as _};
2use std::io::{Read, Write};
3
4/// This is the second set of the symbolic information which is used to support
5/// the data structures for the dynamically link editor.
6///
7/// The original set of symbolic information in the symtab_command which contains
8/// the symbol and string tables must also be present when this load command is
9/// present.  When this load command is present the symbol table is organized
10/// into three groups of symbols:
11/// * local symbols (static and debugging symbols) - grouped by module
12/// * defined external symbols - grouped by module (sorted by name if not lib)
13/// * undefined external symbols (sorted by name if MH_BINDATLOAD is not set,
14///   and in order the were seen by the static linker if MH_BINDATLOAD is set)
15///
16/// In this load command there are offsets and counts to each of the three groups of symbols.
17///
18/// This load command contains a the offsets and sizes of the following new
19/// symbolic information tables:
20/// * table of contents
21/// * module table
22/// * reference symbol table
23/// * indirect symbol table
24///
25/// The first three tables above (the table of contents, module table and
26/// reference symbol table) are only present if the file is a dynamically linked
27/// shared library.  For executable and object modules, which are files
28/// containing only one module, the information that would be in these three
29/// tables is determined as follows:
30/// * table of contents - the defined external symbols are sorted by name
31/// * module table - the file contains only one module so everything in the
32/// file is part of the module.
33/// * reference symbol table - is the defined and undefined external symbols
34///
35/// For dynamically linked shared library files this load command also contains
36/// offsets and sizes to the pool of relocation entries for all sections separated into two groups:
37/// * external relocation entries
38/// * local relocation entries
39///
40/// For executable and object modules the relocation entries continue to hang
41/// off the section structures.
42#[derive(Debug, Clone, PartialEq, Eq)]
43pub struct DysymtabCommand {
44    pub cmd: u32,
45    pub cmdsize: u32,
46    /// index to local symbols
47    pub ilocalsym: u32,
48    /// number of local symbols
49    pub nlocalsym: u32,
50    /// index to externally defined symbols
51    pub iextdefsym: u32,
52    /// number of externally defined symbols
53    pub nextdefsym: u32,
54    /// index to undefined symbols
55    pub iundefsym: u32,
56    /// number of undefined symbols
57    pub nundefsym: u32,
58    /// file offset to table of contents
59    pub tocoff: u32,
60    /// number of entries in table of contents
61    pub ntoc: u32,
62    /// file offset to module table
63    pub modtaboff: u32,
64    /// number of module table entries
65    pub nmodtab: u32,
66    /// offset to referenced symbol table
67    pub extrefsymoff: u32,
68    /// number of referenced symbol table entries
69    pub nextrefsyms: u32,
70    /// file offset to the indirect symbol table
71    pub indirectsymoff: u32,
72    /// number of indirect symbol table entries
73    pub nindirectsyms: u32,
74    /// offset to external relocation entries
75    pub extreloff: u32,
76    /// number of external relocation entries
77    pub nextrel: u32,
78    /// offset to local relocation entries
79    pub locreloff: u32,
80    /// number of local relocation entries
81    pub nlocrel: u32,
82}
83
84impl DysymtabCommand {
85    pub const TYPE: u32 = 0xB;
86
87    pub const SIZE: u32 = 0x50;
88
89    pub fn read_from_in<R: Read>(read: &mut R, endian: Endian) -> Self {
90        let cmd = read.read_u32_in(endian);
91        assert_eq!(cmd, Self::TYPE);
92
93        let cmdsize = read.read_u32_in(endian);
94        assert_eq!(cmdsize, Self::SIZE);
95
96        let ilocalsym = read.read_u32_in(endian);
97        let nlocalsym = read.read_u32_in(endian);
98        let iextdefsym = read.read_u32_in(endian);
99        let nextdefsym = read.read_u32_in(endian);
100        let iundefsym = read.read_u32_in(endian);
101        let nundefsym = read.read_u32_in(endian);
102        let tocoff = read.read_u32_in(endian);
103        let ntoc = read.read_u32_in(endian);
104        let modtaboff = read.read_u32_in(endian);
105        let nmodtab = read.read_u32_in(endian);
106        let extrefsymoff = read.read_u32_in(endian);
107        let nextrefsyms = read.read_u32_in(endian);
108        let indirectsymoff = read.read_u32_in(endian);
109        let nindirectsyms = read.read_u32_in(endian);
110        let extreloff = read.read_u32_in(endian);
111        let nextrel = read.read_u32_in(endian);
112        let locreloff = read.read_u32_in(endian);
113        let nlocrel = read.read_u32_in(endian);
114
115        DysymtabCommand {
116            cmd,
117            cmdsize,
118            ilocalsym,
119            nlocalsym,
120            iextdefsym,
121            nextdefsym,
122            iundefsym,
123            nundefsym,
124            tocoff,
125            ntoc,
126            modtaboff,
127            nmodtab,
128            extrefsymoff,
129            nextrefsyms,
130            indirectsymoff,
131            nindirectsyms,
132            extreloff,
133            nextrel,
134            locreloff,
135            nlocrel,
136        }
137    }
138
139    pub fn write_into<W: Write>(&self, write: &mut W) {
140        write.write_u32_native(self.cmd);
141        write.write_u32_native(self.cmdsize);
142        write.write_u32_native(self.ilocalsym);
143        write.write_u32_native(self.nlocalsym);
144        write.write_u32_native(self.iextdefsym);
145        write.write_u32_native(self.nextdefsym);
146        write.write_u32_native(self.iundefsym);
147        write.write_u32_native(self.nundefsym);
148        write.write_u32_native(self.tocoff);
149        write.write_u32_native(self.ntoc);
150        write.write_u32_native(self.modtaboff);
151        write.write_u32_native(self.nmodtab);
152        write.write_u32_native(self.extrefsymoff);
153        write.write_u32_native(self.nextrefsyms);
154        write.write_u32_native(self.indirectsymoff);
155        write.write_u32_native(self.nindirectsyms);
156        write.write_u32_native(self.extreloff);
157        write.write_u32_native(self.nextrel);
158        write.write_u32_native(self.locreloff);
159        write.write_u32_native(self.nlocrel);
160    }
161}
162
163#[cfg(test)]
164mod tests {
165    use super::*;
166
167    #[test]
168    fn write_and_read_dysymtab_command() {
169        let cmd = DysymtabCommand {
170            cmd: DysymtabCommand::TYPE,
171            cmdsize: DysymtabCommand::SIZE,
172            ilocalsym: 0,
173            nlocalsym: 2,
174            iextdefsym: 3,
175            nextdefsym: 4,
176            iundefsym: 5,
177            nundefsym: 9,
178            tocoff: 8,
179            ntoc: 5,
180            modtaboff: 8,
181            nmodtab: 5,
182            extrefsymoff: 0,
183            nextrefsyms: 2,
184            indirectsymoff: 3,
185            nindirectsyms: 6,
186            extreloff: 8,
187            nextrel: 9,
188            locreloff: 0,
189            nlocrel: 2,
190        };
191
192        let mut buf = Vec::new();
193
194        cmd.write_into(&mut buf);
195
196        assert_eq!(buf.len(), DysymtabCommand::SIZE as usize);
197
198        let read_cmd = DysymtabCommand::read_from_in(&mut buf.as_slice(), Endian::NATIVE);
199
200        assert_eq!(read_cmd, cmd);
201    }
202}