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
227
228
229
230
231
232
233
234
|
package com.seaofnodes.simple.codegen;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.type.TypeMemPtr;
import com.seaofnodes.simple.type.TypeStruct;
import com.seaofnodes.simple.util.Ary;
import com.seaofnodes.simple.util.BAOS;
import com.seaofnodes.simple.util.Utils;
import java.io.*;
import java.nio.file.Files;
import java.util.HashMap;
public class ElfReader {
public final File _file;
public final byte[] _buf;
int _x; // Cursor into buffer
// ELF Header
public final ElfHeader _header;
// All sections
public final Section[] _sections;
// Simple section, if available
public final Section _simple;
// Byte array in/out stream - used as a reader
public final BAOS _bais;
// Compilation unit; written into FunNodes
public final CompUnit _compunit;
// Strings from the Simple section, either small public set or whole set
public String[] _strs;
// Dependent file names
public String[] _deps;
// Only published symbol this file
public TypeStruct _clz;
// Canonical named types, distinct from optimized same-named graph states.
public TypeStruct[] _pubTypes;
// Nodes read in this Elf
public Ary<Node> _nodes;
// Load an Elf file (mostly lazily)
public static ElfReader load( File f, CompUnit cu ) {
try { return new ElfReader(f,cu); }
catch( IOException ioe ) { return null; }
}
// Load the Simple section from the ELF file
private ElfReader( File f, CompUnit cu ) throws IOException {
_file = f;
_compunit = cu;
_buf = Files.readAllBytes(f.toPath());
_header = new ElfHeader();
// No attempt is made to parse the program header table.
_sections = new Section[_header._shnum];
for( int i=0; i<_header._shnum; i++ )
_sections[i] = new Section(i);
// Load section names
Section secstr = _sections[_header._shstrndx];
for( Section sec : _sections )
if( sec._type != 0 )
sec._name = secstr.str(sec._noff);
Section simple = null;
for( Section sec : _sections )
if( ".simple".equals(sec._name) )
simple = sec;
_simple = simple;
_bais = new BAOS(_buf, (int)_simple._offset);
}
// For Serialize self-test
ElfReader( BAOS bais ) {
_file = null;
_compunit = null;
_buf = bais.buf();
_header = null;
_sections = null;
_simple = null;
_bais = bais;
}
// Load the public symbols and dependent objs, but not the whole IR
void loadPublicSymbols() {
// Check already loaded and cached
if( _strs == null && _simple != null )
// Read only the published public strings, for speed purposes when
// scanning a large count of ELF files but getting hits in only a
// few of them. i.e. optimizing (prematurely?) for the traditional
// case of linking a small file against a large library
Serialize.read_public_strs(this);
}
// Loads the entire IR
public TypeStruct loadSimple(CodeGen code) {
Serialize.readAll(code, this, code._aliases, code._fidxs, code._rpcs);
return _clz;
}
// Loads strings, mappings, and types, but not Nodes. Used after the
// public-string scan finds a matching Simple ELF, so parsing can resolve
// imported field/array aliases before the full graph is linked in later.
public TypeStruct loadPublicTypes(CodeGen code) {
Serialize.readTypes(code, this, code._aliases, code._fidxs, code._rpcs);
return _clz;
}
int u1() { return _buf[_x++]&0xFF; }
int magic() { // Big endian
return (u1() << 24) | (u1() << 16) | (u1() << 8) | u1();
}
int u2() { return u1() | (u1()<<8); } // Little endian
int u4() { // Little endian
return u1() | (u1() << 8) | (u1() << 16) | (u1() << 24);
}
long u8() { return u4() | ((long)u4()<<32); }
void skip(int skip) { _x += skip; }
public class ElfHeader {
final int _magic;
final boolean _format32; // Format32 or format64
final byte _osabi;
final boolean _little; // True if little endian, false if big endian
final char _type;
final char _machine;
final long _entry; // Process entry point
final long _phoff; // Program header table offset, from file start
final long _shoff; // Section header table offset, from file start
final int _flags; // Flags
final int _phnum; // Number of program header entries
final int _shentsize;
final int _shnum; // Number of section header entries
final int _shstrndx; // Section header index contains section names
ElfHeader() throws IOException {
_x = 0;
if( (_magic = magic()) != 0x7F454C46 ) bad("magic number",_magic);
byte EI_CLASS = (byte)u1();
if( EI_CLASS != 1 && EI_CLASS != 2 ) bad("EI_CLASS",EI_CLASS);
_format32 = (EI_CLASS==1);
byte EI_DATA = (byte)u1();
if( EI_DATA != 1 && EI_DATA != 2 ) bad("EI_DATA",EI_DATA);
_little = EI_DATA == 1;
if( u1() != 1 ) bad("version",1);
if( (_osabi=(byte)u1()) != 0 ) bad("EI_VERSION",_osabi);
byte abiversion = (byte)u1();
if( abiversion != 0 ) bad("EI_ABIVERSION",abiversion);
skip(7); // Pad
// Endian matters now
if( !_little ) throw new IOException("TODO: Big endian");
if( (_type = (char)u2()) != 1 ) bad("ET_REL",_type);
if( (_machine = (char)u2()) != 0x3E ) bad("AMD x86-64",_machine);
int ver = u4();
if( ver != 1 ) bad("Version",ver);
// Format32 matters now
if( _format32 ) bad("Format",1);
_entry = u8(); // Process entry point
_phoff = u8(); // Program header table offset
_shoff = u8(); // Section header table offset
_flags = u4(); // Flags
int ehsize = u2();
if( ehsize != 0x40 ) bad("EHSIZE",ehsize);
int phentsize = u2();
if( phentsize != 0x38 && phentsize != 0 ) bad("PHENTSIZE",phentsize);
_phnum = u2();
_shentsize = u2();
if( _shentsize != 0x40 ) bad("SHENTSIZE",_shentsize);
_shnum = u2();
// String section
_shstrndx = u2();
assert _x == ehsize;
}
}
public class Section {
final int _noff; // Offset in string section for name
final int _type; // Section type
final long _flags;
final long _addr; // Offset in virtual mem, if loaded
final long _offset; // Offset in file
final long _size; // Size in bytes
final int _link; // Associated section index, varies
final int _info; // Varies
final byte _align; // Log2 alignment
final int _esize; // Element size, if non-zero
String _name;
Section(int sidx) throws IOException {
_x = (int)(_header._shoff + (sidx * _header._shentsize));
_noff = u4();
_type = u4();
_flags = u8();
_addr = u8();
_offset= u8();
_size = u8();
_link = u4();
_info = u4();
long align = u8();
if( align==0 ) align=1;
_align = (byte)Long.numberOfTrailingZeros(align);
if( (1L << _align ) != align )
throw new IOException("Bad section alignment: "+align);
_esize = (int)u8();
}
String str(int off) {
assert _type == 3/*SHT_STRTAB*/; // String table section header
int start = (int)(_offset+off);
int x = start;
while( _buf[x++] !=0 ) ;
return new String(_buf,start,x-start-1);
}
}
private static void bad(String msg, int val) throws IOException {
throw new IOException("Bad "+msg+": "+val);
}
//public TypeMemPtr lookup( String name ) {
// if( _simple == null ) return null;
// BAOS baos = new BAOS(_buf, (int)_simple._offset);
// Ary<String> strs = Serialize.read_strs(baos);
//
//
//
// Ary<Node> nodes = Serialize.read_types(baos);
//
// throw Utils.TODO("Elf load symbol "+name);
//}
}
|