@retrovm/nobj 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/nobj.ts +182 -159
- package/package.json +1 -1
package/nobj.ts
CHANGED
|
@@ -33,19 +33,29 @@ export type TargetArch = 'x64' | 'arm64';
|
|
|
33
33
|
/** Align v up to the next multiple of a (a must be a power of two). */
|
|
34
34
|
const al = (v: number, a: number): number => (v + a - 1) & -a;
|
|
35
35
|
|
|
36
|
+
const enc = new TextEncoder();
|
|
37
|
+
|
|
36
38
|
/**
|
|
37
39
|
* Write a 64-bit LE uint using two 32-bit writes.
|
|
38
40
|
* Safe for values ≤ 2^53 (all realistic file offsets and sizes).
|
|
39
41
|
*/
|
|
40
|
-
function writeU64(
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
function writeU64(dv: DataView, off: number, val: number): void {
|
|
43
|
+
dv.setUint32(off, val >>> 0, true);
|
|
44
|
+
dv.setUint32(off + 4, Math.floor(val / 0x100000000), true);
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
/** Zero a char[len] field and write an ASCII string (no overflow). */
|
|
46
|
-
function setStr(buf:
|
|
48
|
+
function setStr(buf: Uint8Array, off: number, str: string, len: number): void {
|
|
47
49
|
buf.fill(0, off, off + len);
|
|
48
|
-
buf.
|
|
50
|
+
buf.set(enc.encode(str.substring(0, len)), off);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function concat(arrays: Uint8Array[]): Uint8Array {
|
|
54
|
+
const total = arrays.reduce((n, a) => n + a.length, 0);
|
|
55
|
+
const out = new Uint8Array(total);
|
|
56
|
+
let ofs = 0;
|
|
57
|
+
for (const a of arrays) { out.set(a, ofs); ofs += a.length; }
|
|
58
|
+
return out;
|
|
49
59
|
}
|
|
50
60
|
|
|
51
61
|
function hostArch(): TargetArch {
|
|
@@ -90,25 +100,29 @@ const COFF_SYM_SZ = 18;
|
|
|
90
100
|
const COFF_HDR_SZ = 20;
|
|
91
101
|
const COFF_SECT_SZ = 40;
|
|
92
102
|
|
|
93
|
-
function doObjectWindows(symbols: ObjSymbol[], arch: TargetArch):
|
|
103
|
+
function doObjectWindows(symbols: ObjSymbol[], arch: TargetArch): Uint8Array {
|
|
94
104
|
let strTabSz = 0, dataSz = 0;
|
|
95
105
|
const directives: string[] = [];
|
|
96
106
|
|
|
97
107
|
for (const { name, obj } of symbols) {
|
|
98
108
|
strTabSz += name.length + 1;
|
|
99
109
|
directives.push(` /EXPORT:${name},DATA`);
|
|
100
|
-
if (obj instanceof Uint8Array)
|
|
110
|
+
if (obj instanceof Uint8Array) dataSz += al(obj.length, 8);
|
|
101
111
|
else if (typeof obj === 'string') dataSz += al(obj.length + 1, 8);
|
|
102
112
|
else if (typeof obj === 'number') dataSz += 8;
|
|
103
113
|
else throw new Error('Invalid symbol type');
|
|
104
114
|
}
|
|
105
115
|
|
|
106
|
-
const tsd =
|
|
107
|
-
const dsd =
|
|
108
|
-
const tsed =
|
|
109
|
-
const symd =
|
|
116
|
+
const tsd = new Uint8Array(strTabSz + 4); // COFF string table
|
|
117
|
+
const dsd = new Uint8Array(dataSz); // .rdata data
|
|
118
|
+
const tsed = enc.encode(directives.join('')); // .drectve content
|
|
119
|
+
const symd = new Uint8Array(COFF_SYM_SZ * symbols.length); // per-export symbols
|
|
120
|
+
|
|
121
|
+
const tsddv = new DataView(tsd.buffer);
|
|
122
|
+
const dsddv = new DataView(dsd.buffer);
|
|
123
|
+
const symdv = new DataView(symd.buffer);
|
|
110
124
|
|
|
111
|
-
|
|
125
|
+
tsddv.setUint32(0, strTabSz + 4, true); // string table size prefix
|
|
112
126
|
|
|
113
127
|
let strOff = 4, dataOff = 0;
|
|
114
128
|
|
|
@@ -117,87 +131,88 @@ function doObjectWindows(symbols: ObjSymbol[], arch: TargetArch): Buffer {
|
|
|
117
131
|
const b = i * COFF_SYM_SZ;
|
|
118
132
|
|
|
119
133
|
// CoffSymbol: long name (zeros=0 means use string table, offset=strOff)
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
symd
|
|
126
|
-
symd
|
|
127
|
-
|
|
128
|
-
tsd.
|
|
134
|
+
symdv.setUint32(b + 0, 0, true); // name.zeros
|
|
135
|
+
symdv.setUint32(b + 4, strOff, true); // name.offset → string table
|
|
136
|
+
symdv.setUint32(b + 8, dataOff, true); // value = offset in .rdata
|
|
137
|
+
symdv.setInt16( b + 12, 2, true); // sectionNumber: .rdata = 2
|
|
138
|
+
symdv.setUint16(b + 14, 0, true); // type
|
|
139
|
+
symd[b + 16] = 0x2; // storageClass: IMAGE_SYM_CLASS_EXTERNAL
|
|
140
|
+
symd[b + 17] = 0; // numberOfAuxSymbols
|
|
141
|
+
|
|
142
|
+
tsd.set(enc.encode(name), strOff);
|
|
129
143
|
strOff += name.length + 1;
|
|
130
144
|
|
|
131
145
|
if (obj instanceof Uint8Array) {
|
|
132
146
|
dsd.set(obj, dataOff);
|
|
133
147
|
dataOff += al(obj.length, 8);
|
|
134
148
|
} else if (typeof obj === 'string') {
|
|
135
|
-
dsd.
|
|
149
|
+
dsd.set(enc.encode(obj), dataOff);
|
|
136
150
|
dataOff += al(obj.length + 1, 8);
|
|
137
151
|
} else if (typeof obj === 'number') {
|
|
138
|
-
|
|
152
|
+
dsddv.setFloat64(dataOff, obj, true);
|
|
139
153
|
dataOff += 8;
|
|
140
154
|
}
|
|
141
155
|
}
|
|
142
156
|
|
|
143
157
|
// ── Coff header struct ──────────────────────────────────────────────────────
|
|
144
158
|
|
|
145
|
-
const hd
|
|
159
|
+
const hd = new Uint8Array(COFF_TOTAL_SZ);
|
|
160
|
+
const hddv = new DataView(hd.buffer);
|
|
146
161
|
const machine = arch === 'x64' ? 0x8664 : 0xaa64;
|
|
147
162
|
const ts = Math.floor(Date.now() / 1000);
|
|
148
163
|
|
|
149
164
|
// CoffHeader @ 0
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
165
|
+
hddv.setUint16(0, machine, true);
|
|
166
|
+
hddv.setUint16(2, 2, true); // numberOfSections
|
|
167
|
+
hddv.setUint32(4, ts, true); // timeDateStamp
|
|
168
|
+
hddv.setUint32(8, COFF_OFFSETOF_RDATA, true); // pointerToSymbolTable
|
|
169
|
+
hddv.setUint32(12, symbols.length + 5, true); // numberOfSymbols (5 built-in + N exports)
|
|
155
170
|
// sizeOfOptionalHeader=0, flags=0 (zeroed)
|
|
156
171
|
|
|
157
172
|
// CoffSection[0]: .drectve @ 20
|
|
158
173
|
const drectvePtr = COFF_TOTAL_SZ + symd.length + tsd.length;
|
|
159
174
|
setStr(hd, COFF_HDR_SZ, '.drectve', 8);
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
175
|
+
hddv.setUint32(COFF_HDR_SZ + 16, tsed.length, true); // sizeOfRawData
|
|
176
|
+
hddv.setUint32(COFF_HDR_SZ + 20, drectvePtr, true); // pointerToRawData
|
|
177
|
+
hddv.setUint32(COFF_HDR_SZ + 36, 0x00100a00, true); // flags
|
|
163
178
|
|
|
164
179
|
// CoffSection[1]: .rdata @ 60
|
|
165
180
|
const rdataPtr = al(COFF_TOTAL_SZ + symd.length + tsd.length + tsed.length, 8);
|
|
166
181
|
setStr(hd, COFF_HDR_SZ + COFF_SECT_SZ, '.rdata', 8);
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
182
|
+
hddv.setUint32(COFF_HDR_SZ + COFF_SECT_SZ + 16, dsd.length, true);
|
|
183
|
+
hddv.setUint32(COFF_HDR_SZ + COFF_SECT_SZ + 20, rdataPtr, true);
|
|
184
|
+
hddv.setUint32(COFF_HDR_SZ + COFF_SECT_SZ + 36, 0x40300040, true);
|
|
170
185
|
|
|
171
186
|
// CoffSymbol: .rdata section symbol @ 100
|
|
172
187
|
setStr(hd, 100, '.rdata', 8);
|
|
173
|
-
|
|
174
|
-
hd
|
|
175
|
-
hd
|
|
188
|
+
hddv.setInt16(100 + 12, 2, true); // sectionNumber
|
|
189
|
+
hd[100 + 16] = 0x3; // storageClass: IMAGE_SYM_CLASS_STATIC
|
|
190
|
+
hd[100 + 17] = 1; // numberOfAuxSymbols
|
|
176
191
|
|
|
177
192
|
// CoffAuxSymbol for .rdata @ 118
|
|
178
|
-
|
|
179
|
-
|
|
193
|
+
hddv.setUint32(118 + 0, dsd.length, true); // length
|
|
194
|
+
hddv.setUint16(118 + 12, 2, true); // number (= section index)
|
|
180
195
|
|
|
181
196
|
// CoffSymbol: .drectve section symbol @ 136
|
|
182
197
|
setStr(hd, 136, '.drectve', 8);
|
|
183
|
-
|
|
184
|
-
hd
|
|
185
|
-
hd
|
|
198
|
+
hddv.setInt16(136 + 12, 1, true);
|
|
199
|
+
hd[136 + 16] = 0x3;
|
|
200
|
+
hd[136 + 17] = 1;
|
|
186
201
|
|
|
187
202
|
// CoffAuxSymbol for .drectve @ 154
|
|
188
|
-
|
|
189
|
-
|
|
203
|
+
hddv.setUint32(154 + 0, tsed.length, true);
|
|
204
|
+
hddv.setUint16(154 + 12, 1, true);
|
|
190
205
|
|
|
191
206
|
// CoffSymbol: @feat.00 @ 172
|
|
192
207
|
setStr(hd, 172, '@feat.00', 8);
|
|
193
|
-
|
|
194
|
-
hd
|
|
208
|
+
hddv.setInt16(172 + 12, -1, true); // IMAGE_SYM_ABSOLUTE
|
|
209
|
+
hd[172 + 16] = 0x3;
|
|
195
210
|
|
|
196
211
|
// Pad tsed to 8-byte boundary so .rdata starts aligned
|
|
197
212
|
const pad = rdataPtr - (COFF_TOTAL_SZ + symd.length + tsd.length + tsed.length);
|
|
198
|
-
const tsedFinal = pad > 0 ?
|
|
213
|
+
const tsedFinal = pad > 0 ? concat([tsed, new Uint8Array(pad)]) : tsed;
|
|
199
214
|
|
|
200
|
-
return
|
|
215
|
+
return concat([hd, symd, tsd, tsedFinal, dsd]);
|
|
201
216
|
}
|
|
202
217
|
|
|
203
218
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -230,22 +245,25 @@ const MMO = 264; // mach_minimun_os_command
|
|
|
230
245
|
const MSYM = 288; // mach_symtab_command
|
|
231
246
|
const MDYS = 312; // mach_symtab_info (LC_DYSYMTAB)
|
|
232
247
|
|
|
233
|
-
function doObjectMacOS(symbols: ObjSymbol[], arch: TargetArch):
|
|
248
|
+
function doObjectMacOS(symbols: ObjSymbol[], arch: TargetArch): Uint8Array {
|
|
234
249
|
let dataSz = 0, strTabSz = 1, symTabSz = 0;
|
|
235
250
|
|
|
236
251
|
for (const { name, obj } of symbols) {
|
|
237
|
-
if (obj instanceof Uint8Array)
|
|
238
|
-
else if (typeof obj === 'string')
|
|
239
|
-
else if (typeof obj === 'number')
|
|
252
|
+
if (obj instanceof Uint8Array) dataSz += al(obj.length, 16);
|
|
253
|
+
else if (typeof obj === 'string') dataSz += al(obj.length, 16); // raw bytes, no null
|
|
254
|
+
else if (typeof obj === 'number') dataSz += al(8, 16); // = 16
|
|
240
255
|
else throw new Error('Invalid symbol type');
|
|
241
256
|
strTabSz += name.length + 2; // '_' + name + '\0'
|
|
242
257
|
symTabSz += 16; // sizeof(mach_sym_entry)
|
|
243
258
|
}
|
|
244
259
|
strTabSz = al(strTabSz, 8);
|
|
245
260
|
|
|
246
|
-
const dt =
|
|
247
|
-
const nt =
|
|
248
|
-
const nti =
|
|
261
|
+
const dt = new Uint8Array(dataSz); // data section
|
|
262
|
+
const nt = new Uint8Array(strTabSz); // string table (first byte is '\0' by alloc)
|
|
263
|
+
const nti = new Uint8Array(symTabSz); // symbol entries
|
|
264
|
+
|
|
265
|
+
const dtdv = new DataView(dt.buffer);
|
|
266
|
+
const ntidv = new DataView(nti.buffer);
|
|
249
267
|
|
|
250
268
|
let dataOff = 0, strOff = 1;
|
|
251
269
|
|
|
@@ -257,88 +275,89 @@ function doObjectMacOS(symbols: ObjSymbol[], arch: TargetArch): Buffer {
|
|
|
257
275
|
dt.set(obj, dataOff);
|
|
258
276
|
dataOff += al(obj.length, 16);
|
|
259
277
|
} else if (typeof obj === 'string') {
|
|
260
|
-
dt.
|
|
278
|
+
dt.set(enc.encode(obj), dataOff);
|
|
261
279
|
dataOff += al(obj.length, 16);
|
|
262
280
|
} else if (typeof obj === 'number') {
|
|
263
|
-
|
|
281
|
+
dtdv.setFloat64(dataOff, obj, true);
|
|
264
282
|
dataOff += al(8, 16);
|
|
265
283
|
}
|
|
266
284
|
|
|
267
|
-
nt.
|
|
285
|
+
nt.set(enc.encode('_' + name), strOff); // null terminator from Uint8Array zero-fill
|
|
268
286
|
|
|
269
287
|
// mach_sym_entry @ k*16
|
|
270
288
|
const e = k * 16;
|
|
271
|
-
|
|
272
|
-
nti
|
|
273
|
-
nti
|
|
274
|
-
|
|
275
|
-
writeU64(
|
|
289
|
+
ntidv.setUint32(e + 0, strOff, true); // strx
|
|
290
|
+
nti[e + 4] = 0xf; // type: N_SECT | N_EXT
|
|
291
|
+
nti[e + 5] = 2; // sect: 2 = __const
|
|
292
|
+
ntidv.setUint16(e + 6, 0, true); // desc
|
|
293
|
+
writeU64(ntidv, e + 8, valueInSection); // value = offset within section
|
|
276
294
|
|
|
277
295
|
strOff += name.length + 2;
|
|
278
296
|
}
|
|
279
297
|
|
|
280
|
-
const hd
|
|
298
|
+
const hd = new Uint8Array(MACH_HDR_SZ);
|
|
299
|
+
const hddv = new DataView(hd.buffer);
|
|
281
300
|
|
|
282
301
|
// mach_header_64
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
302
|
+
hddv.setUint32(MH + 0, 0xfeedfacf, true); // MH_MAGIC_64
|
|
303
|
+
hddv.setUint32(MH + 4, arch === 'x64' ? 0x1000007 : 0x100000c, true); // cputype
|
|
304
|
+
hddv.setUint32(MH + 8, arch === 'x64' ? 0x3 : 0x0, true); // cpusubtype
|
|
305
|
+
hddv.setUint32(MH + 12, 0x1, true); // filetype: MH_OBJECT
|
|
306
|
+
hddv.setUint32(MH + 16, 4, true); // ncmds: 4 load commands
|
|
307
|
+
hddv.setUint32(MH + 20, 0x168, true); // sizeofcmds = 0xE8+0x18+0x18+0x50 = 360
|
|
308
|
+
hddv.setUint32(MH + 24, 0x200, true); // flags: MH_SUBSECTIONS_VIA_SYMBOLS
|
|
290
309
|
|
|
291
310
|
// LC_SEGMENT_64 (cmd=0x19, cmdsize=0xE8 = 72 + 80×2)
|
|
292
|
-
|
|
293
|
-
|
|
311
|
+
hddv.setUint32(MSEG + 0, 0x19, true);
|
|
312
|
+
hddv.setUint32(MSEG + 4, 0xE8, true);
|
|
294
313
|
// segname[16]: all zeros = unnamed segment (correct for .o files)
|
|
295
|
-
writeU64(
|
|
296
|
-
writeU64(
|
|
297
|
-
writeU64(
|
|
298
|
-
writeU64(
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
314
|
+
writeU64(hddv, MSEG + 24, 0); // vmaddr
|
|
315
|
+
writeU64(hddv, MSEG + 32, dataSz); // vmsize
|
|
316
|
+
writeU64(hddv, MSEG + 40, MACH_HDR_SZ); // fileoff
|
|
317
|
+
writeU64(hddv, MSEG + 48, dataSz); // filesize
|
|
318
|
+
hddv.setUint32(MSEG + 56, 0x7, true); // maxprot: PROT_READ|WRITE|EXEC
|
|
319
|
+
hddv.setUint32(MSEG + 60, 0x7, true); // initprot
|
|
320
|
+
hddv.setUint32(MSEG + 64, 2, true); // nsects
|
|
302
321
|
|
|
303
322
|
// mach_section_64[0]: __text (empty — placeholder for the TEXT segment)
|
|
304
323
|
setStr(hd, MS1 + 0, '__text', 16);
|
|
305
324
|
setStr(hd, MS1 + 16, '__TEXT', 16);
|
|
306
325
|
// addr=0, size=0 (zeroed)
|
|
307
|
-
|
|
326
|
+
hddv.setUint32(MS1 + 48, MACH_HDR_SZ, true); // offset
|
|
308
327
|
// align=0
|
|
309
|
-
|
|
328
|
+
hddv.setUint32(MS1 + 64, 0x80000000, true); // flags: S_ATTR_PURE_INSTRUCTIONS
|
|
310
329
|
|
|
311
330
|
// mach_section_64[1]: __const (actual exported data)
|
|
312
331
|
setStr(hd, MS2 + 0, '__const', 16);
|
|
313
332
|
setStr(hd, MS2 + 16, '__TEXT', 16);
|
|
314
333
|
// addr=0 (zeroed)
|
|
315
|
-
writeU64(
|
|
316
|
-
|
|
317
|
-
|
|
334
|
+
writeU64(hddv, MS2 + 40, dataSz); // size
|
|
335
|
+
hddv.setUint32(MS2 + 48, MACH_HDR_SZ, true); // offset
|
|
336
|
+
hddv.setUint32(MS2 + 52, 0x02, true); // align: 2^2 = 4 bytes
|
|
318
337
|
|
|
319
338
|
// LC_BUILD_VERSION (cmd=0x32)
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
339
|
+
hddv.setUint32(MMO + 0, 0x32, true);
|
|
340
|
+
hddv.setUint32(MMO + 4, 0x18, true);
|
|
341
|
+
hddv.setUint32(MMO + 8, 0x1, true); // platform: PLATFORM_MACOS
|
|
342
|
+
hddv.setUint32(MMO + 12, 0xa0900, true); // minos: 10.9.0
|
|
343
|
+
hddv.setUint32(MMO + 16, 0xa0900, true); // sdk: 10.9.0
|
|
325
344
|
|
|
326
345
|
// LC_SYMTAB (cmd=0x2)
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
346
|
+
hddv.setUint32(MSYM + 0, 0x2, true);
|
|
347
|
+
hddv.setUint32(MSYM + 4, 0x18, true);
|
|
348
|
+
hddv.setUint32(MSYM + 8, MACH_HDR_SZ + dataSz, true); // symoff
|
|
349
|
+
hddv.setUint32(MSYM + 12, symbols.length, true); // nsyms
|
|
350
|
+
hddv.setUint32(MSYM + 16, MACH_HDR_SZ + dataSz + symTabSz, true); // stroff
|
|
351
|
+
hddv.setUint32(MSYM + 20, strTabSz, true); // strsize
|
|
333
352
|
|
|
334
353
|
// LC_DYSYMTAB (cmd=0xb)
|
|
335
|
-
|
|
336
|
-
|
|
354
|
+
hddv.setUint32(MDYS + 0, 0xb, true);
|
|
355
|
+
hddv.setUint32(MDYS + 4, 0x50, true);
|
|
337
356
|
// localoff=0, nlocals=0 (zeroed)
|
|
338
|
-
|
|
339
|
-
|
|
357
|
+
hddv.setUint32(MDYS + 20, symbols.length, true); // nextdef
|
|
358
|
+
hddv.setUint32(MDYS + 24, symbols.length, true); // undefoff
|
|
340
359
|
|
|
341
|
-
return
|
|
360
|
+
return concat([hd, dt, nti, nt]);
|
|
342
361
|
}
|
|
343
362
|
|
|
344
363
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -377,7 +396,7 @@ const EY = { NAME:0, INFO:4, OTHER:5, SECTIDX:6, VALUE:8, SIZE:16 };
|
|
|
377
396
|
|
|
378
397
|
const sectOfs = (idx: number): number => ELF_HDR_SZ + idx * ELF_SECT_SZ;
|
|
379
398
|
|
|
380
|
-
function doObjectLinux(symbols: ObjSymbol[], arch: TargetArch):
|
|
399
|
+
function doObjectLinux(symbols: ObjSymbol[], arch: TargetArch): Uint8Array {
|
|
381
400
|
const SH_NAMES = '\0.symtab\0.strtab\0.rodata\0.note.GNU-stack\0';
|
|
382
401
|
// idx: 0 1 9 17 25
|
|
383
402
|
const I_SYMTAB = 1, I_STRTAB = 9, I_RODATA = 17, I_NOTE = 25;
|
|
@@ -386,18 +405,21 @@ function doObjectLinux(symbols: ObjSymbol[], arch: TargetArch): Buffer {
|
|
|
386
405
|
|
|
387
406
|
for (const { name, obj } of symbols) {
|
|
388
407
|
strTabSz += name.length + 1;
|
|
389
|
-
if (obj instanceof Uint8Array)
|
|
390
|
-
else if (typeof obj === 'string')
|
|
391
|
-
else if (typeof obj === 'number')
|
|
408
|
+
if (obj instanceof Uint8Array) dataSz += al(obj.length, 8);
|
|
409
|
+
else if (typeof obj === 'string') dataSz += al(obj.length + 1, 8);
|
|
410
|
+
else if (typeof obj === 'number') dataSz += 8;
|
|
392
411
|
else throw new Error('Invalid symbol type');
|
|
393
412
|
}
|
|
394
413
|
|
|
395
414
|
// Symbol table: one null entry (index 0) + one per export
|
|
396
|
-
const symd =
|
|
397
|
-
const ts =
|
|
398
|
-
const d =
|
|
415
|
+
const symd = new Uint8Array(al(ELF_SYM_SZ * (symbols.length + 1), 16));
|
|
416
|
+
const ts = new Uint8Array(al(strTabSz, 16));
|
|
417
|
+
const d = new Uint8Array(al(dataSz, 16));
|
|
418
|
+
|
|
419
|
+
const symdv = new DataView(symd.buffer);
|
|
420
|
+
const ddv = new DataView(d.buffer);
|
|
399
421
|
|
|
400
|
-
ts.
|
|
422
|
+
ts.set(enc.encode(SH_NAMES), 0);
|
|
401
423
|
|
|
402
424
|
let strOff = SH_NAMES.length, dataOff = 0;
|
|
403
425
|
|
|
@@ -405,52 +427,53 @@ function doObjectLinux(symbols: ObjSymbol[], arch: TargetArch): Buffer {
|
|
|
405
427
|
const { name, obj } = symbols[k]!;
|
|
406
428
|
const sb = (k + 1) * ELF_SYM_SZ; // skip null symbol at index 0
|
|
407
429
|
|
|
408
|
-
|
|
409
|
-
symd
|
|
410
|
-
symd
|
|
411
|
-
|
|
412
|
-
writeU64(
|
|
430
|
+
symdv.setUint32(sb + EY.NAME, strOff, true);
|
|
431
|
+
symd[sb + EY.INFO] = 0x11; // STB_GLOBAL|STT_OBJECT = (1<<4)|1
|
|
432
|
+
symd[sb + EY.OTHER] = 0;
|
|
433
|
+
symdv.setUint16(sb + EY.SECTIDX, 3, true); // .rodata = section 3
|
|
434
|
+
writeU64(symdv, sb + EY.VALUE, dataOff);
|
|
413
435
|
|
|
414
|
-
ts.
|
|
436
|
+
ts.set(enc.encode(name), strOff);
|
|
415
437
|
strOff += name.length + 1;
|
|
416
438
|
|
|
417
439
|
if (obj instanceof Uint8Array) {
|
|
418
440
|
d.set(obj, dataOff);
|
|
419
|
-
writeU64(
|
|
441
|
+
writeU64(symdv, sb + EY.SIZE, obj.length);
|
|
420
442
|
dataOff += al(obj.length, 8);
|
|
421
443
|
} else if (typeof obj === 'string') {
|
|
422
|
-
d.
|
|
423
|
-
writeU64(
|
|
444
|
+
d.set(enc.encode(obj), dataOff);
|
|
445
|
+
writeU64(symdv, sb + EY.SIZE, obj.length + 1);
|
|
424
446
|
dataOff += al(obj.length + 1, 8);
|
|
425
447
|
} else if (typeof obj === 'number') {
|
|
426
|
-
|
|
427
|
-
writeU64(
|
|
448
|
+
ddv.setFloat64(dataOff, obj, true);
|
|
449
|
+
writeU64(symdv, sb + EY.SIZE, 8);
|
|
428
450
|
dataOff += 8;
|
|
429
451
|
}
|
|
430
452
|
}
|
|
431
453
|
|
|
432
454
|
// ── ELF header + section headers ───────────────────────────────────────────
|
|
433
455
|
|
|
434
|
-
const hd
|
|
435
|
-
const
|
|
456
|
+
const hd = new Uint8Array(ELF_STRUCT_SZ);
|
|
457
|
+
const hddv = new DataView(hd.buffer);
|
|
458
|
+
const mach = arch === 'x64' ? 0x3e : 0xb7;
|
|
436
459
|
|
|
437
460
|
// ELF64Header @ 0
|
|
438
|
-
hd.
|
|
439
|
-
hd
|
|
440
|
-
hd
|
|
441
|
-
hd
|
|
461
|
+
hd.set([0x7f, 0x45, 0x4c, 0x46], 0); // \x7fELF
|
|
462
|
+
hd[4] = 2; // EI_CLASS: ELFCLASS64
|
|
463
|
+
hd[5] = 1; // EI_DATA: ELFDATA2LSB
|
|
464
|
+
hd[6] = 1; // EI_VERSION: EV_CURRENT
|
|
442
465
|
// osabi=0, abiversion=0, epad=0
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
466
|
+
hddv.setUint16(16, 1, true); // e_type: ET_REL
|
|
467
|
+
hddv.setUint16(18, mach, true); // e_machine
|
|
468
|
+
hddv.setUint32(20, 1, true); // e_version: EV_CURRENT
|
|
446
469
|
// e_entry=0, e_phoff=0 (zeroed)
|
|
447
|
-
writeU64(
|
|
470
|
+
writeU64(hddv, 40, ELF_HDR_SZ); // e_shoff: section headers right after hdr
|
|
448
471
|
// e_flags=0 (zeroed)
|
|
449
|
-
|
|
472
|
+
hddv.setUint16(52, ELF_HDR_SZ, true); // e_ehsize
|
|
450
473
|
// e_phentsize=0, e_phnum=0 (zeroed)
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
474
|
+
hddv.setUint16(58, ELF_SECT_SZ, true); // e_shentsize
|
|
475
|
+
hddv.setUint16(60, 6, true); // e_shnum
|
|
476
|
+
hddv.setUint16(62, 2, true); // e_shstrndx: .strtab = section 2
|
|
454
477
|
|
|
455
478
|
const symtabOfs = ELF_STRUCT_SZ;
|
|
456
479
|
const strtabOfs = ELF_STRUCT_SZ + symd.length;
|
|
@@ -461,38 +484,38 @@ function doObjectLinux(symbols: ObjSymbol[], arch: TargetArch): Buffer {
|
|
|
461
484
|
|
|
462
485
|
// Section[1]: .symtab
|
|
463
486
|
const s1 = sectOfs(1);
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
writeU64(
|
|
467
|
-
writeU64(
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
writeU64(
|
|
471
|
-
writeU64(
|
|
487
|
+
hddv.setUint32(s1 + ES.NAME, I_SYMTAB, true);
|
|
488
|
+
hddv.setUint32(s1 + ES.TYPE, 2, true); // SHT_SYMTAB
|
|
489
|
+
writeU64(hddv, s1 + ES.OFS, symtabOfs);
|
|
490
|
+
writeU64(hddv, s1 + ES.SIZE, symd.length);
|
|
491
|
+
hddv.setUint32(s1 + ES.LINK, 2, true); // associated .strtab = section 2
|
|
492
|
+
hddv.setUint32(s1 + ES.INFO, 1, true); // first global symbol index
|
|
493
|
+
writeU64(hddv, s1 + ES.ALIGN, 8);
|
|
494
|
+
writeU64(hddv, s1 + ES.ENTSZ, ELF_SYM_SZ);
|
|
472
495
|
|
|
473
496
|
// Section[2]: .strtab
|
|
474
497
|
const s2 = sectOfs(2);
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
writeU64(
|
|
478
|
-
writeU64(
|
|
498
|
+
hddv.setUint32(s2 + ES.NAME, I_STRTAB, true);
|
|
499
|
+
hddv.setUint32(s2 + ES.TYPE, 3, true); // SHT_STRTAB
|
|
500
|
+
writeU64(hddv, s2 + ES.OFS, strtabOfs);
|
|
501
|
+
writeU64(hddv, s2 + ES.SIZE, ts.length);
|
|
479
502
|
|
|
480
503
|
// Section[3]: .rodata
|
|
481
504
|
const s3 = sectOfs(3);
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
writeU64(
|
|
485
|
-
writeU64(
|
|
486
|
-
writeU64(
|
|
505
|
+
hddv.setUint32(s3 + ES.NAME, I_RODATA, true);
|
|
506
|
+
hddv.setUint32(s3 + ES.TYPE, 1, true); // SHT_PROGBITS
|
|
507
|
+
writeU64(hddv, s3 + ES.FLAGS, 2); // SHF_ALLOC
|
|
508
|
+
writeU64(hddv, s3 + ES.OFS, rodataOfs);
|
|
509
|
+
writeU64(hddv, s3 + ES.SIZE, d.length);
|
|
487
510
|
|
|
488
511
|
// Section[4]: .note.GNU-stack (empty; signals non-executable stack to linker)
|
|
489
512
|
const s4 = sectOfs(4);
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
writeU64(
|
|
513
|
+
hddv.setUint32(s4 + ES.NAME, I_NOTE, true);
|
|
514
|
+
hddv.setUint32(s4 + ES.TYPE, 1, true); // SHT_PROGBITS
|
|
515
|
+
writeU64(hddv, s4 + ES.OFS, noteOfs);
|
|
493
516
|
// size=0, flags=0 (zeroed)
|
|
494
517
|
|
|
495
|
-
return
|
|
518
|
+
return concat([hd, symd, ts, d]);
|
|
496
519
|
}
|
|
497
520
|
|
|
498
521
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -503,7 +526,7 @@ function dispatch(
|
|
|
503
526
|
symbols: ObjSymbol[],
|
|
504
527
|
arch: TargetArch = hostArch(),
|
|
505
528
|
platform: TargetPlatform = hostPlatform(),
|
|
506
|
-
):
|
|
529
|
+
): Uint8Array {
|
|
507
530
|
switch (platform) {
|
|
508
531
|
case 'win32': return doObjectWindows(symbols, arch);
|
|
509
532
|
case 'macos': return doObjectMacOS(symbols, arch);
|
|
@@ -518,7 +541,7 @@ export function encodeObject(
|
|
|
518
541
|
obj: SymbolValue,
|
|
519
542
|
arch?: TargetArch,
|
|
520
543
|
platform?: TargetPlatform,
|
|
521
|
-
):
|
|
544
|
+
): Uint8Array {
|
|
522
545
|
return dispatch([{ name, obj }], arch, platform);
|
|
523
546
|
}
|
|
524
547
|
|
|
@@ -527,6 +550,6 @@ export function encodeSymbols(
|
|
|
527
550
|
symbols: ObjSymbol[],
|
|
528
551
|
arch?: TargetArch,
|
|
529
552
|
platform?: TargetPlatform,
|
|
530
|
-
):
|
|
553
|
+
): Uint8Array {
|
|
531
554
|
return dispatch(symbols, arch, platform);
|
|
532
555
|
}
|
package/package.json
CHANGED