@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.
Files changed (2) hide show
  1. package/nobj.ts +185 -160
  2. 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(buf: Buffer, off: number, val: number): void {
41
- buf.writeUInt32LE(val >>> 0, off);
42
- buf.writeUInt32LE(Math.floor(val / 0x100000000), off + 4);
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: Buffer, off: number, str: string, len: number): void {
48
+ function setStr(buf: Uint8Array, off: number, str: string, len: number): void {
47
49
  buf.fill(0, off, off + len);
48
- buf.write(str.substring(0, len), off, 'ascii');
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): Buffer {
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) dataSz += al(obj.length, 8);
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 = Buffer.alloc(strTabSz + 4); // COFF string table
107
- const dsd = Buffer.alloc(dataSz); // .rdata data
108
- const tsed = Buffer.from(directives.join(''), 'ascii'); // .drectve content
109
- const symd = Buffer.alloc(COFF_SYM_SZ * symbols.length); // per-export symbols
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
- tsd.writeUInt32LE(strTabSz + 4, 0); // string table size prefix
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
- symd.writeUInt32LE(0, b + 0); // name.zeros
121
- symd.writeUInt32LE(strOff, b + 4); // name.offset → string table
122
- symd.writeUInt32LE(dataOff, b + 8); // value = offset in .rdata
123
- symd.writeInt16LE(2, b + 12); // sectionNumber: .rdata = 2
124
- symd.writeUInt16LE(0, b + 14); // type
125
- symd.writeUInt8(0x2, b + 16); // storageClass: IMAGE_SYM_CLASS_EXTERNAL
126
- symd.writeUInt8(0, b + 17); // numberOfAuxSymbols
127
-
128
- tsd.write(name, strOff, 'ascii');
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.write(obj, dataOff, 'ascii');
149
+ dsd.set(enc.encode(obj), dataOff);
136
150
  dataOff += al(obj.length + 1, 8);
137
151
  } else if (typeof obj === 'number') {
138
- dsd.writeDoubleLE(obj, dataOff);
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 = Buffer.alloc(COFF_TOTAL_SZ);
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
- hd.writeUInt16LE(machine, 0);
151
- hd.writeUInt16LE(2, 2); // numberOfSections
152
- hd.writeUInt32LE(ts, 4); // timeDateStamp
153
- hd.writeUInt32LE(COFF_OFFSETOF_RDATA, 8); // pointerToSymbolTable
154
- hd.writeUInt32LE(symbols.length + 5, 12); // numberOfSymbols (5 built-in + N exports)
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
- hd.writeUInt32LE(tsed.length, COFF_HDR_SZ + 16); // sizeOfRawData
161
- hd.writeUInt32LE(drectvePtr, COFF_HDR_SZ + 20); // pointerToRawData
162
- hd.writeUInt32LE(0x00100a00, COFF_HDR_SZ + 36); // flags
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
- const rdataPtr = al(COFF_TOTAL_SZ + symd.length + tsd.length + tsed.length, 8);
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
- hd.writeUInt32LE(dsd.length, COFF_HDR_SZ + COFF_SECT_SZ + 16);
168
- hd.writeUInt32LE(rdataPtr, COFF_HDR_SZ + COFF_SECT_SZ + 20);
169
- hd.writeUInt32LE(0x40300040, COFF_HDR_SZ + COFF_SECT_SZ + 36);
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
- hd.writeInt16LE(2, 100 + 12); // sectionNumber
174
- hd.writeUInt8(0x3, 100 + 16); // storageClass: IMAGE_SYM_CLASS_STATIC
175
- hd.writeUInt8(1, 100 + 17); // numberOfAuxSymbols
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
- hd.writeUInt32LE(dsd.length, 118 + 0); // length
179
- hd.writeUInt16LE(2, 118 + 12); // number (= section index)
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
- hd.writeInt16LE(1, 136 + 12);
184
- hd.writeUInt8(0x3, 136 + 16);
185
- hd.writeUInt8(1, 136 + 17);
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
- hd.writeUInt32LE(tsed.length, 154 + 0);
189
- hd.writeUInt16LE(1, 154 + 12);
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
- hd.writeInt16LE(-1, 172 + 12); // IMAGE_SYM_ABSOLUTE
194
- hd.writeUInt8(0x3, 172 + 16);
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 ? Buffer.concat([tsed, Buffer.alloc(pad)]) : tsed;
215
+ const tsedFinal = pad > 0 ? concat([tsed, new Uint8Array(pad)]) : tsed;
199
216
 
200
- return Buffer.concat([hd, symd, tsd, tsedFinal, dsd]);
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): Buffer {
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) dataSz += al(obj.length, 16);
238
- else if (typeof obj === 'string') dataSz += al(obj.length, 16); // raw bytes, no null
239
- else if (typeof obj === 'number') dataSz += al(8, 16); // = 16
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 = Buffer.alloc(dataSz); // data section
247
- const nt = Buffer.alloc(strTabSz); // string table (first byte is '\0' by alloc)
248
- const nti = Buffer.alloc(symTabSz); // symbol entries
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.write(obj, dataOff, 'ascii');
280
+ dt.set(enc.encode(obj), dataOff);
261
281
  dataOff += al(obj.length, 16);
262
282
  } else if (typeof obj === 'number') {
263
- dt.writeDoubleLE(obj, dataOff);
283
+ dtdv.setFloat64(dataOff, obj, true);
264
284
  dataOff += al(8, 16);
265
285
  }
266
286
 
267
- nt.write('_' + name, strOff, 'ascii'); // null terminator from Buffer.alloc
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
- nti.writeUInt32LE(strOff, e + 0); // strx
272
- nti.writeUInt8(0xf, e + 4); // type: N_SECT | N_EXT
273
- nti.writeUInt8(2, e + 5); // sect: 2 = __const
274
- nti.writeUInt16LE(0, e + 6); // desc
275
- writeU64(nti, e + 8, valueInSection); // value = offset within section
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 = Buffer.alloc(MACH_HDR_SZ);
300
+ const hd = new Uint8Array(MACH_HDR_SZ);
301
+ const hddv = new DataView(hd.buffer);
281
302
 
282
303
  // mach_header_64
283
- hd.writeUInt32LE(0xfeedfacf, MH + 0); // MH_MAGIC_64
284
- hd.writeUInt32LE(arch === 'x64' ? 0x1000007 : 0x100000c, MH + 4); // cputype
285
- hd.writeUInt32LE(arch === 'x64' ? 0x3 : 0x0, MH + 8); // cpusubtype
286
- hd.writeUInt32LE(0x1, MH + 12); // filetype: MH_OBJECT
287
- hd.writeUInt32LE(4, MH + 16); // ncmds: 4 load commands
288
- hd.writeUInt32LE(0x168, MH + 20); // sizeofcmds = 0xE8+0x18+0x18+0x50 = 360
289
- hd.writeUInt32LE(0x200, MH + 24); // flags: MH_SUBSECTIONS_VIA_SYMBOLS
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
- hd.writeUInt32LE(0x19, MSEG + 0);
293
- hd.writeUInt32LE(0xE8, MSEG + 4);
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(hd, MSEG + 24, 0); // vmaddr
296
- writeU64(hd, MSEG + 32, dataSz); // vmsize
297
- writeU64(hd, MSEG + 40, MACH_HDR_SZ); // fileoff
298
- writeU64(hd, MSEG + 48, dataSz); // filesize
299
- hd.writeUInt32LE(0x7, MSEG + 56); // maxprot: PROT_READ|WRITE|EXEC
300
- hd.writeUInt32LE(0x7, MSEG + 60); // initprot
301
- hd.writeUInt32LE(2, MSEG + 64); // nsects
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
- hd.writeUInt32LE(MACH_HDR_SZ, MS1 + 48); // offset
328
+ hddv.setUint32(MS1 + 48, MACH_HDR_SZ, true); // offset
308
329
  // align=0
309
- hd.writeUInt32LE(0x80000000, MS1 + 64); // flags: S_ATTR_PURE_INSTRUCTIONS
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(hd, MS2 + 40, dataSz); // size
316
- hd.writeUInt32LE(MACH_HDR_SZ, MS2 + 48); // offset
317
- hd.writeUInt32LE(0x02, MS2 + 52); // align: 2^2 = 4 bytes
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
- hd.writeUInt32LE(0x32, MMO + 0);
321
- hd.writeUInt32LE(0x18, MMO + 4);
322
- hd.writeUInt32LE(0x1, MMO + 8); // platform: PLATFORM_MACOS
323
- hd.writeUInt32LE(0xa0900, MMO + 12); // minos: 10.9.0
324
- hd.writeUInt32LE(0xa0900, MMO + 16); // sdk: 10.9.0
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
- hd.writeUInt32LE(0x2, MSYM + 0);
328
- hd.writeUInt32LE(0x18, MSYM + 4);
329
- hd.writeUInt32LE(MACH_HDR_SZ + dataSz, MSYM + 8); // symoff
330
- hd.writeUInt32LE(symbols.length, MSYM + 12); // nsyms
331
- hd.writeUInt32LE(MACH_HDR_SZ + dataSz + symTabSz, MSYM + 16); // stroff
332
- hd.writeUInt32LE(strTabSz, MSYM + 20); // strsize
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
- hd.writeUInt32LE(0xb, MDYS + 0);
336
- hd.writeUInt32LE(0x50, MDYS + 4);
356
+ hddv.setUint32(MDYS + 0, 0xb, true);
357
+ hddv.setUint32(MDYS + 4, 0x50, true);
337
358
  // localoff=0, nlocals=0 (zeroed)
338
- hd.writeUInt32LE(symbols.length, MDYS + 20); // nextdef
339
- hd.writeUInt32LE(symbols.length, MDYS + 24); // undefoff
359
+ hddv.setUint32(MDYS + 20, symbols.length, true); // nextdef
360
+ hddv.setUint32(MDYS + 24, symbols.length, true); // undefoff
340
361
 
341
- return Buffer.concat([hd, dt, nti, nt]);
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): Buffer {
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) dataSz += al(obj.length, 8);
390
- else if (typeof obj === 'string') dataSz += al(obj.length + 1, 8);
391
- else if (typeof obj === 'number') dataSz += 8;
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 = Buffer.alloc(al(ELF_SYM_SZ * (symbols.length + 1), 16));
397
- const ts = Buffer.alloc(al(strTabSz, 16));
398
- const d = Buffer.alloc(al(dataSz, 16));
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.write(SH_NAMES, 0, 'ascii');
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
- symd.writeUInt32LE(strOff, sb + EY.NAME);
409
- symd.writeUInt8(0x11, sb + EY.INFO); // STB_GLOBAL|STT_OBJECT = (1<<4)|1
410
- symd.writeUInt8(0, sb + EY.OTHER);
411
- symd.writeUInt16LE(3, sb + EY.SECTIDX); // .rodata = section 3
412
- writeU64(symd, sb + EY.VALUE, dataOff);
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.write(name, strOff, 'ascii');
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(symd, sb + EY.SIZE, obj.length);
443
+ writeU64(symdv, sb + EY.SIZE, obj.length);
420
444
  dataOff += al(obj.length, 8);
421
445
  } else if (typeof obj === 'string') {
422
- d.write(obj, dataOff, 'ascii');
423
- writeU64(symd, sb + EY.SIZE, obj.length + 1);
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
- d.writeDoubleLE(obj, dataOff);
427
- writeU64(symd, sb + EY.SIZE, 8);
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 = Buffer.alloc(ELF_STRUCT_SZ);
435
- const mach = arch === 'x64' ? 0x3e : 0xb7;
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.write('\x7fELF', 0, 'ascii');
439
- hd.writeUInt8(2, 4); // EI_CLASS: ELFCLASS64
440
- hd.writeUInt8(1, 5); // EI_DATA: ELFDATA2LSB
441
- hd.writeUInt8(1, 6); // EI_VERSION: EV_CURRENT
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
- hd.writeUInt16LE(1, 16); // e_type: ET_REL
444
- hd.writeUInt16LE(mach, 18); // e_machine
445
- hd.writeUInt32LE(1, 20); // e_version: EV_CURRENT
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(hd, 40, ELF_HDR_SZ); // e_shoff: section headers right after hdr
472
+ writeU64(hddv, 40, ELF_HDR_SZ); // e_shoff: section headers right after hdr
448
473
  // e_flags=0 (zeroed)
449
- hd.writeUInt16LE(ELF_HDR_SZ, 52); // e_ehsize
474
+ hddv.setUint16(52, ELF_HDR_SZ, true); // e_ehsize
450
475
  // e_phentsize=0, e_phnum=0 (zeroed)
451
- hd.writeUInt16LE(ELF_SECT_SZ, 58); // e_shentsize
452
- hd.writeUInt16LE(6, 60); // e_shnum
453
- hd.writeUInt16LE(2, 62); // e_shstrndx: .strtab = section 2
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
- hd.writeUInt32LE(I_SYMTAB, s1 + ES.NAME);
465
- hd.writeUInt32LE(2, s1 + ES.TYPE); // SHT_SYMTAB
466
- writeU64(hd, s1 + ES.OFS, symtabOfs);
467
- writeU64(hd, s1 + ES.SIZE, symd.length);
468
- hd.writeUInt32LE(2, s1 + ES.LINK); // associated .strtab = section 2
469
- hd.writeUInt32LE(1, s1 + ES.INFO); // first global symbol index
470
- writeU64(hd, s1 + ES.ALIGN, 8);
471
- writeU64(hd, s1 + ES.ENTSZ, ELF_SYM_SZ);
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
- hd.writeUInt32LE(I_STRTAB, s2 + ES.NAME);
476
- hd.writeUInt32LE(3, s2 + ES.TYPE); // SHT_STRTAB
477
- writeU64(hd, s2 + ES.OFS, strtabOfs);
478
- writeU64(hd, s2 + ES.SIZE, ts.length);
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
- hd.writeUInt32LE(I_RODATA, s3 + ES.NAME);
483
- hd.writeUInt32LE(1, s3 + ES.TYPE); // SHT_PROGBITS
484
- writeU64(hd, s3 + ES.FLAGS, 2); // SHF_ALLOC
485
- writeU64(hd, s3 + ES.OFS, rodataOfs);
486
- writeU64(hd, s3 + ES.SIZE, d.length);
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
- hd.writeUInt32LE(I_NOTE, s4 + ES.NAME);
491
- hd.writeUInt32LE(1, s4 + ES.TYPE); // SHT_PROGBITS
492
- writeU64(hd, s4 + ES.OFS, noteOfs);
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 Buffer.concat([hd, symd, ts, d]);
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
- ): Buffer {
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
- ): Buffer {
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
- ): Buffer {
555
+ ): Uint8Array {
531
556
  return dispatch(symbols, arch, platform);
532
557
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retrovm/nobj",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Generate native linkable object files (COFF, Mach-O, ELF64) from TypeScript/Bun — zero native dependencies",
5
5
  "license": "MIT",
6
6
  "author": "Juan Carlos González Amestoy",