@retrovm/nobj 0.1.3 → 0.1.5
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 +185 -160
- 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,90 @@ 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
|
+
// ARM64 ldr/str require 8-byte alignment; x64 works fine with 4-byte but 8 is harmless.
|
|
181
|
+
const rdataPtr = al(COFF_TOTAL_SZ + symd.length + tsd.length + tsed.length, 8);
|
|
182
|
+
const rdataFlags = arch === 'arm64' ? 0x40400040 : 0x40300040; // ALIGN_8BYTES vs ALIGN_4BYTES
|
|
166
183
|
setStr(hd, COFF_HDR_SZ + COFF_SECT_SZ, '.rdata', 8);
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
184
|
+
hddv.setUint32(COFF_HDR_SZ + COFF_SECT_SZ + 16, dsd.length, true);
|
|
185
|
+
hddv.setUint32(COFF_HDR_SZ + COFF_SECT_SZ + 20, rdataPtr, true);
|
|
186
|
+
hddv.setUint32(COFF_HDR_SZ + COFF_SECT_SZ + 36, rdataFlags, true);
|
|
170
187
|
|
|
171
188
|
// CoffSymbol: .rdata section symbol @ 100
|
|
172
189
|
setStr(hd, 100, '.rdata', 8);
|
|
173
|
-
|
|
174
|
-
hd
|
|
175
|
-
hd
|
|
190
|
+
hddv.setInt16(100 + 12, 2, true); // sectionNumber
|
|
191
|
+
hd[100 + 16] = 0x3; // storageClass: IMAGE_SYM_CLASS_STATIC
|
|
192
|
+
hd[100 + 17] = 1; // numberOfAuxSymbols
|
|
176
193
|
|
|
177
194
|
// CoffAuxSymbol for .rdata @ 118
|
|
178
|
-
|
|
179
|
-
|
|
195
|
+
hddv.setUint32(118 + 0, dsd.length, true); // length
|
|
196
|
+
hddv.setUint16(118 + 12, 2, true); // number (= section index)
|
|
180
197
|
|
|
181
198
|
// CoffSymbol: .drectve section symbol @ 136
|
|
182
199
|
setStr(hd, 136, '.drectve', 8);
|
|
183
|
-
|
|
184
|
-
hd
|
|
185
|
-
hd
|
|
200
|
+
hddv.setInt16(136 + 12, 1, true);
|
|
201
|
+
hd[136 + 16] = 0x3;
|
|
202
|
+
hd[136 + 17] = 1;
|
|
186
203
|
|
|
187
204
|
// CoffAuxSymbol for .drectve @ 154
|
|
188
|
-
|
|
189
|
-
|
|
205
|
+
hddv.setUint32(154 + 0, tsed.length, true);
|
|
206
|
+
hddv.setUint16(154 + 12, 1, true);
|
|
190
207
|
|
|
191
208
|
// CoffSymbol: @feat.00 @ 172
|
|
192
209
|
setStr(hd, 172, '@feat.00', 8);
|
|
193
|
-
|
|
194
|
-
hd
|
|
210
|
+
hddv.setInt16(172 + 12, -1, true); // IMAGE_SYM_ABSOLUTE
|
|
211
|
+
hd[172 + 16] = 0x3;
|
|
195
212
|
|
|
196
213
|
// Pad tsed to 8-byte boundary so .rdata starts aligned
|
|
197
214
|
const pad = rdataPtr - (COFF_TOTAL_SZ + symd.length + tsd.length + tsed.length);
|
|
198
|
-
const tsedFinal = pad > 0 ?
|
|
215
|
+
const tsedFinal = pad > 0 ? concat([tsed, new Uint8Array(pad)]) : tsed;
|
|
199
216
|
|
|
200
|
-
return
|
|
217
|
+
return concat([hd, symd, tsd, tsedFinal, dsd]);
|
|
201
218
|
}
|
|
202
219
|
|
|
203
220
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -230,22 +247,25 @@ const MMO = 264; // mach_minimun_os_command
|
|
|
230
247
|
const MSYM = 288; // mach_symtab_command
|
|
231
248
|
const MDYS = 312; // mach_symtab_info (LC_DYSYMTAB)
|
|
232
249
|
|
|
233
|
-
function doObjectMacOS(symbols: ObjSymbol[], arch: TargetArch):
|
|
250
|
+
function doObjectMacOS(symbols: ObjSymbol[], arch: TargetArch): Uint8Array {
|
|
234
251
|
let dataSz = 0, strTabSz = 1, symTabSz = 0;
|
|
235
252
|
|
|
236
253
|
for (const { name, obj } of symbols) {
|
|
237
|
-
if (obj instanceof Uint8Array)
|
|
238
|
-
else if (typeof obj === 'string')
|
|
239
|
-
else if (typeof obj === 'number')
|
|
254
|
+
if (obj instanceof Uint8Array) dataSz += al(obj.length, 16);
|
|
255
|
+
else if (typeof obj === 'string') dataSz += al(obj.length, 16); // raw bytes, no null
|
|
256
|
+
else if (typeof obj === 'number') dataSz += al(8, 16); // = 16
|
|
240
257
|
else throw new Error('Invalid symbol type');
|
|
241
258
|
strTabSz += name.length + 2; // '_' + name + '\0'
|
|
242
259
|
symTabSz += 16; // sizeof(mach_sym_entry)
|
|
243
260
|
}
|
|
244
261
|
strTabSz = al(strTabSz, 8);
|
|
245
262
|
|
|
246
|
-
const dt =
|
|
247
|
-
const nt =
|
|
248
|
-
const nti =
|
|
263
|
+
const dt = new Uint8Array(dataSz); // data section
|
|
264
|
+
const nt = new Uint8Array(strTabSz); // string table (first byte is '\0' by alloc)
|
|
265
|
+
const nti = new Uint8Array(symTabSz); // symbol entries
|
|
266
|
+
|
|
267
|
+
const dtdv = new DataView(dt.buffer);
|
|
268
|
+
const ntidv = new DataView(nti.buffer);
|
|
249
269
|
|
|
250
270
|
let dataOff = 0, strOff = 1;
|
|
251
271
|
|
|
@@ -257,88 +277,89 @@ function doObjectMacOS(symbols: ObjSymbol[], arch: TargetArch): Buffer {
|
|
|
257
277
|
dt.set(obj, dataOff);
|
|
258
278
|
dataOff += al(obj.length, 16);
|
|
259
279
|
} else if (typeof obj === 'string') {
|
|
260
|
-
dt.
|
|
280
|
+
dt.set(enc.encode(obj), dataOff);
|
|
261
281
|
dataOff += al(obj.length, 16);
|
|
262
282
|
} else if (typeof obj === 'number') {
|
|
263
|
-
|
|
283
|
+
dtdv.setFloat64(dataOff, obj, true);
|
|
264
284
|
dataOff += al(8, 16);
|
|
265
285
|
}
|
|
266
286
|
|
|
267
|
-
nt.
|
|
287
|
+
nt.set(enc.encode('_' + name), strOff); // null terminator from Uint8Array zero-fill
|
|
268
288
|
|
|
269
289
|
// mach_sym_entry @ k*16
|
|
270
290
|
const e = k * 16;
|
|
271
|
-
|
|
272
|
-
nti
|
|
273
|
-
nti
|
|
274
|
-
|
|
275
|
-
writeU64(
|
|
291
|
+
ntidv.setUint32(e + 0, strOff, true); // strx
|
|
292
|
+
nti[e + 4] = 0xf; // type: N_SECT | N_EXT
|
|
293
|
+
nti[e + 5] = 2; // sect: 2 = __const
|
|
294
|
+
ntidv.setUint16(e + 6, 0, true); // desc
|
|
295
|
+
writeU64(ntidv, e + 8, valueInSection); // value = offset within section
|
|
276
296
|
|
|
277
297
|
strOff += name.length + 2;
|
|
278
298
|
}
|
|
279
299
|
|
|
280
|
-
const hd
|
|
300
|
+
const hd = new Uint8Array(MACH_HDR_SZ);
|
|
301
|
+
const hddv = new DataView(hd.buffer);
|
|
281
302
|
|
|
282
303
|
// mach_header_64
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
304
|
+
hddv.setUint32(MH + 0, 0xfeedfacf, true); // MH_MAGIC_64
|
|
305
|
+
hddv.setUint32(MH + 4, arch === 'x64' ? 0x1000007 : 0x100000c, true); // cputype
|
|
306
|
+
hddv.setUint32(MH + 8, arch === 'x64' ? 0x3 : 0x0, true); // cpusubtype
|
|
307
|
+
hddv.setUint32(MH + 12, 0x1, true); // filetype: MH_OBJECT
|
|
308
|
+
hddv.setUint32(MH + 16, 4, true); // ncmds: 4 load commands
|
|
309
|
+
hddv.setUint32(MH + 20, 0x168, true); // sizeofcmds = 0xE8+0x18+0x18+0x50 = 360
|
|
310
|
+
hddv.setUint32(MH + 24, 0x200, true); // flags: MH_SUBSECTIONS_VIA_SYMBOLS
|
|
290
311
|
|
|
291
312
|
// LC_SEGMENT_64 (cmd=0x19, cmdsize=0xE8 = 72 + 80×2)
|
|
292
|
-
|
|
293
|
-
|
|
313
|
+
hddv.setUint32(MSEG + 0, 0x19, true);
|
|
314
|
+
hddv.setUint32(MSEG + 4, 0xE8, true);
|
|
294
315
|
// segname[16]: all zeros = unnamed segment (correct for .o files)
|
|
295
|
-
writeU64(
|
|
296
|
-
writeU64(
|
|
297
|
-
writeU64(
|
|
298
|
-
writeU64(
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
316
|
+
writeU64(hddv, MSEG + 24, 0); // vmaddr
|
|
317
|
+
writeU64(hddv, MSEG + 32, dataSz); // vmsize
|
|
318
|
+
writeU64(hddv, MSEG + 40, MACH_HDR_SZ); // fileoff
|
|
319
|
+
writeU64(hddv, MSEG + 48, dataSz); // filesize
|
|
320
|
+
hddv.setUint32(MSEG + 56, 0x7, true); // maxprot: PROT_READ|WRITE|EXEC
|
|
321
|
+
hddv.setUint32(MSEG + 60, 0x7, true); // initprot
|
|
322
|
+
hddv.setUint32(MSEG + 64, 2, true); // nsects
|
|
302
323
|
|
|
303
324
|
// mach_section_64[0]: __text (empty — placeholder for the TEXT segment)
|
|
304
325
|
setStr(hd, MS1 + 0, '__text', 16);
|
|
305
326
|
setStr(hd, MS1 + 16, '__TEXT', 16);
|
|
306
327
|
// addr=0, size=0 (zeroed)
|
|
307
|
-
|
|
328
|
+
hddv.setUint32(MS1 + 48, MACH_HDR_SZ, true); // offset
|
|
308
329
|
// align=0
|
|
309
|
-
|
|
330
|
+
hddv.setUint32(MS1 + 64, 0x80000000, true); // flags: S_ATTR_PURE_INSTRUCTIONS
|
|
310
331
|
|
|
311
332
|
// mach_section_64[1]: __const (actual exported data)
|
|
312
333
|
setStr(hd, MS2 + 0, '__const', 16);
|
|
313
334
|
setStr(hd, MS2 + 16, '__TEXT', 16);
|
|
314
335
|
// addr=0 (zeroed)
|
|
315
|
-
writeU64(
|
|
316
|
-
|
|
317
|
-
|
|
336
|
+
writeU64(hddv, MS2 + 40, dataSz); // size
|
|
337
|
+
hddv.setUint32(MS2 + 48, MACH_HDR_SZ, true); // offset
|
|
338
|
+
hddv.setUint32(MS2 + 52, 0x02, true); // align: 2^2 = 4 bytes
|
|
318
339
|
|
|
319
340
|
// LC_BUILD_VERSION (cmd=0x32)
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
341
|
+
hddv.setUint32(MMO + 0, 0x32, true);
|
|
342
|
+
hddv.setUint32(MMO + 4, 0x18, true);
|
|
343
|
+
hddv.setUint32(MMO + 8, 0x1, true); // platform: PLATFORM_MACOS
|
|
344
|
+
hddv.setUint32(MMO + 12, 0xa0900, true); // minos: 10.9.0
|
|
345
|
+
hddv.setUint32(MMO + 16, 0xa0900, true); // sdk: 10.9.0
|
|
325
346
|
|
|
326
347
|
// LC_SYMTAB (cmd=0x2)
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
348
|
+
hddv.setUint32(MSYM + 0, 0x2, true);
|
|
349
|
+
hddv.setUint32(MSYM + 4, 0x18, true);
|
|
350
|
+
hddv.setUint32(MSYM + 8, MACH_HDR_SZ + dataSz, true); // symoff
|
|
351
|
+
hddv.setUint32(MSYM + 12, symbols.length, true); // nsyms
|
|
352
|
+
hddv.setUint32(MSYM + 16, MACH_HDR_SZ + dataSz + symTabSz, true); // stroff
|
|
353
|
+
hddv.setUint32(MSYM + 20, strTabSz, true); // strsize
|
|
333
354
|
|
|
334
355
|
// LC_DYSYMTAB (cmd=0xb)
|
|
335
|
-
|
|
336
|
-
|
|
356
|
+
hddv.setUint32(MDYS + 0, 0xb, true);
|
|
357
|
+
hddv.setUint32(MDYS + 4, 0x50, true);
|
|
337
358
|
// localoff=0, nlocals=0 (zeroed)
|
|
338
|
-
|
|
339
|
-
|
|
359
|
+
hddv.setUint32(MDYS + 20, symbols.length, true); // nextdef
|
|
360
|
+
hddv.setUint32(MDYS + 24, symbols.length, true); // undefoff
|
|
340
361
|
|
|
341
|
-
return
|
|
362
|
+
return concat([hd, dt, nti, nt]);
|
|
342
363
|
}
|
|
343
364
|
|
|
344
365
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -377,7 +398,7 @@ const EY = { NAME:0, INFO:4, OTHER:5, SECTIDX:6, VALUE:8, SIZE:16 };
|
|
|
377
398
|
|
|
378
399
|
const sectOfs = (idx: number): number => ELF_HDR_SZ + idx * ELF_SECT_SZ;
|
|
379
400
|
|
|
380
|
-
function doObjectLinux(symbols: ObjSymbol[], arch: TargetArch):
|
|
401
|
+
function doObjectLinux(symbols: ObjSymbol[], arch: TargetArch): Uint8Array {
|
|
381
402
|
const SH_NAMES = '\0.symtab\0.strtab\0.rodata\0.note.GNU-stack\0';
|
|
382
403
|
// idx: 0 1 9 17 25
|
|
383
404
|
const I_SYMTAB = 1, I_STRTAB = 9, I_RODATA = 17, I_NOTE = 25;
|
|
@@ -386,18 +407,21 @@ function doObjectLinux(symbols: ObjSymbol[], arch: TargetArch): Buffer {
|
|
|
386
407
|
|
|
387
408
|
for (const { name, obj } of symbols) {
|
|
388
409
|
strTabSz += name.length + 1;
|
|
389
|
-
if (obj instanceof Uint8Array)
|
|
390
|
-
else if (typeof obj === 'string')
|
|
391
|
-
else if (typeof obj === 'number')
|
|
410
|
+
if (obj instanceof Uint8Array) dataSz += al(obj.length, 8);
|
|
411
|
+
else if (typeof obj === 'string') dataSz += al(obj.length + 1, 8);
|
|
412
|
+
else if (typeof obj === 'number') dataSz += 8;
|
|
392
413
|
else throw new Error('Invalid symbol type');
|
|
393
414
|
}
|
|
394
415
|
|
|
395
416
|
// Symbol table: one null entry (index 0) + one per export
|
|
396
|
-
const symd =
|
|
397
|
-
const ts =
|
|
398
|
-
const d =
|
|
417
|
+
const symd = new Uint8Array(al(ELF_SYM_SZ * (symbols.length + 1), 16));
|
|
418
|
+
const ts = new Uint8Array(al(strTabSz, 16));
|
|
419
|
+
const d = new Uint8Array(al(dataSz, 16));
|
|
420
|
+
|
|
421
|
+
const symdv = new DataView(symd.buffer);
|
|
422
|
+
const ddv = new DataView(d.buffer);
|
|
399
423
|
|
|
400
|
-
ts.
|
|
424
|
+
ts.set(enc.encode(SH_NAMES), 0);
|
|
401
425
|
|
|
402
426
|
let strOff = SH_NAMES.length, dataOff = 0;
|
|
403
427
|
|
|
@@ -405,52 +429,53 @@ function doObjectLinux(symbols: ObjSymbol[], arch: TargetArch): Buffer {
|
|
|
405
429
|
const { name, obj } = symbols[k]!;
|
|
406
430
|
const sb = (k + 1) * ELF_SYM_SZ; // skip null symbol at index 0
|
|
407
431
|
|
|
408
|
-
|
|
409
|
-
symd
|
|
410
|
-
symd
|
|
411
|
-
|
|
412
|
-
writeU64(
|
|
432
|
+
symdv.setUint32(sb + EY.NAME, strOff, true);
|
|
433
|
+
symd[sb + EY.INFO] = 0x11; // STB_GLOBAL|STT_OBJECT = (1<<4)|1
|
|
434
|
+
symd[sb + EY.OTHER] = 0;
|
|
435
|
+
symdv.setUint16(sb + EY.SECTIDX, 3, true); // .rodata = section 3
|
|
436
|
+
writeU64(symdv, sb + EY.VALUE, dataOff);
|
|
413
437
|
|
|
414
|
-
ts.
|
|
438
|
+
ts.set(enc.encode(name), strOff);
|
|
415
439
|
strOff += name.length + 1;
|
|
416
440
|
|
|
417
441
|
if (obj instanceof Uint8Array) {
|
|
418
442
|
d.set(obj, dataOff);
|
|
419
|
-
writeU64(
|
|
443
|
+
writeU64(symdv, sb + EY.SIZE, obj.length);
|
|
420
444
|
dataOff += al(obj.length, 8);
|
|
421
445
|
} else if (typeof obj === 'string') {
|
|
422
|
-
d.
|
|
423
|
-
writeU64(
|
|
446
|
+
d.set(enc.encode(obj), dataOff);
|
|
447
|
+
writeU64(symdv, sb + EY.SIZE, obj.length + 1);
|
|
424
448
|
dataOff += al(obj.length + 1, 8);
|
|
425
449
|
} else if (typeof obj === 'number') {
|
|
426
|
-
|
|
427
|
-
writeU64(
|
|
450
|
+
ddv.setFloat64(dataOff, obj, true);
|
|
451
|
+
writeU64(symdv, sb + EY.SIZE, 8);
|
|
428
452
|
dataOff += 8;
|
|
429
453
|
}
|
|
430
454
|
}
|
|
431
455
|
|
|
432
456
|
// ── ELF header + section headers ───────────────────────────────────────────
|
|
433
457
|
|
|
434
|
-
const hd
|
|
435
|
-
const
|
|
458
|
+
const hd = new Uint8Array(ELF_STRUCT_SZ);
|
|
459
|
+
const hddv = new DataView(hd.buffer);
|
|
460
|
+
const mach = arch === 'x64' ? 0x3e : 0xb7;
|
|
436
461
|
|
|
437
462
|
// ELF64Header @ 0
|
|
438
|
-
hd.
|
|
439
|
-
hd
|
|
440
|
-
hd
|
|
441
|
-
hd
|
|
463
|
+
hd.set([0x7f, 0x45, 0x4c, 0x46], 0); // \x7fELF
|
|
464
|
+
hd[4] = 2; // EI_CLASS: ELFCLASS64
|
|
465
|
+
hd[5] = 1; // EI_DATA: ELFDATA2LSB
|
|
466
|
+
hd[6] = 1; // EI_VERSION: EV_CURRENT
|
|
442
467
|
// osabi=0, abiversion=0, epad=0
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
468
|
+
hddv.setUint16(16, 1, true); // e_type: ET_REL
|
|
469
|
+
hddv.setUint16(18, mach, true); // e_machine
|
|
470
|
+
hddv.setUint32(20, 1, true); // e_version: EV_CURRENT
|
|
446
471
|
// e_entry=0, e_phoff=0 (zeroed)
|
|
447
|
-
writeU64(
|
|
472
|
+
writeU64(hddv, 40, ELF_HDR_SZ); // e_shoff: section headers right after hdr
|
|
448
473
|
// e_flags=0 (zeroed)
|
|
449
|
-
|
|
474
|
+
hddv.setUint16(52, ELF_HDR_SZ, true); // e_ehsize
|
|
450
475
|
// e_phentsize=0, e_phnum=0 (zeroed)
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
476
|
+
hddv.setUint16(58, ELF_SECT_SZ, true); // e_shentsize
|
|
477
|
+
hddv.setUint16(60, 6, true); // e_shnum
|
|
478
|
+
hddv.setUint16(62, 2, true); // e_shstrndx: .strtab = section 2
|
|
454
479
|
|
|
455
480
|
const symtabOfs = ELF_STRUCT_SZ;
|
|
456
481
|
const strtabOfs = ELF_STRUCT_SZ + symd.length;
|
|
@@ -461,38 +486,38 @@ function doObjectLinux(symbols: ObjSymbol[], arch: TargetArch): Buffer {
|
|
|
461
486
|
|
|
462
487
|
// Section[1]: .symtab
|
|
463
488
|
const s1 = sectOfs(1);
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
writeU64(
|
|
467
|
-
writeU64(
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
writeU64(
|
|
471
|
-
writeU64(
|
|
489
|
+
hddv.setUint32(s1 + ES.NAME, I_SYMTAB, true);
|
|
490
|
+
hddv.setUint32(s1 + ES.TYPE, 2, true); // SHT_SYMTAB
|
|
491
|
+
writeU64(hddv, s1 + ES.OFS, symtabOfs);
|
|
492
|
+
writeU64(hddv, s1 + ES.SIZE, symd.length);
|
|
493
|
+
hddv.setUint32(s1 + ES.LINK, 2, true); // associated .strtab = section 2
|
|
494
|
+
hddv.setUint32(s1 + ES.INFO, 1, true); // first global symbol index
|
|
495
|
+
writeU64(hddv, s1 + ES.ALIGN, 8);
|
|
496
|
+
writeU64(hddv, s1 + ES.ENTSZ, ELF_SYM_SZ);
|
|
472
497
|
|
|
473
498
|
// Section[2]: .strtab
|
|
474
499
|
const s2 = sectOfs(2);
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
writeU64(
|
|
478
|
-
writeU64(
|
|
500
|
+
hddv.setUint32(s2 + ES.NAME, I_STRTAB, true);
|
|
501
|
+
hddv.setUint32(s2 + ES.TYPE, 3, true); // SHT_STRTAB
|
|
502
|
+
writeU64(hddv, s2 + ES.OFS, strtabOfs);
|
|
503
|
+
writeU64(hddv, s2 + ES.SIZE, ts.length);
|
|
479
504
|
|
|
480
505
|
// Section[3]: .rodata
|
|
481
506
|
const s3 = sectOfs(3);
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
writeU64(
|
|
485
|
-
writeU64(
|
|
486
|
-
writeU64(
|
|
507
|
+
hddv.setUint32(s3 + ES.NAME, I_RODATA, true);
|
|
508
|
+
hddv.setUint32(s3 + ES.TYPE, 1, true); // SHT_PROGBITS
|
|
509
|
+
writeU64(hddv, s3 + ES.FLAGS, 2); // SHF_ALLOC
|
|
510
|
+
writeU64(hddv, s3 + ES.OFS, rodataOfs);
|
|
511
|
+
writeU64(hddv, s3 + ES.SIZE, d.length);
|
|
487
512
|
|
|
488
513
|
// Section[4]: .note.GNU-stack (empty; signals non-executable stack to linker)
|
|
489
514
|
const s4 = sectOfs(4);
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
writeU64(
|
|
515
|
+
hddv.setUint32(s4 + ES.NAME, I_NOTE, true);
|
|
516
|
+
hddv.setUint32(s4 + ES.TYPE, 1, true); // SHT_PROGBITS
|
|
517
|
+
writeU64(hddv, s4 + ES.OFS, noteOfs);
|
|
493
518
|
// size=0, flags=0 (zeroed)
|
|
494
519
|
|
|
495
|
-
return
|
|
520
|
+
return concat([hd, symd, ts, d]);
|
|
496
521
|
}
|
|
497
522
|
|
|
498
523
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -503,7 +528,7 @@ function dispatch(
|
|
|
503
528
|
symbols: ObjSymbol[],
|
|
504
529
|
arch: TargetArch = hostArch(),
|
|
505
530
|
platform: TargetPlatform = hostPlatform(),
|
|
506
|
-
):
|
|
531
|
+
): Uint8Array {
|
|
507
532
|
switch (platform) {
|
|
508
533
|
case 'win32': return doObjectWindows(symbols, arch);
|
|
509
534
|
case 'macos': return doObjectMacOS(symbols, arch);
|
|
@@ -518,7 +543,7 @@ export function encodeObject(
|
|
|
518
543
|
obj: SymbolValue,
|
|
519
544
|
arch?: TargetArch,
|
|
520
545
|
platform?: TargetPlatform,
|
|
521
|
-
):
|
|
546
|
+
): Uint8Array {
|
|
522
547
|
return dispatch([{ name, obj }], arch, platform);
|
|
523
548
|
}
|
|
524
549
|
|
|
@@ -527,6 +552,6 @@ export function encodeSymbols(
|
|
|
527
552
|
symbols: ObjSymbol[],
|
|
528
553
|
arch?: TargetArch,
|
|
529
554
|
platform?: TargetPlatform,
|
|
530
|
-
):
|
|
555
|
+
): Uint8Array {
|
|
531
556
|
return dispatch(symbols, arch, platform);
|
|
532
557
|
}
|
package/package.json
CHANGED