1
// Copyright 2009 The Go Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
6
// http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
9
#include "../ld/dwarf.h"
10
#include "../ld/lib.h"
11
#include "../ld/macho.h"
15
static MachoLoad load[16];
16
static MachoSeg seg[16];
17
static MachoDebug xdebug[16];
18
static int nload, nseg, ndebug, nsect;
24
// 64-bit architectures
29
// 32-bit architectures
42
newMachoLoad(uint32 type, uint32 ndata)
46
if(nload >= nelem(load)) {
47
diag("too many loads");
51
if(macho64 && (ndata & 1))
57
l->data = mal(ndata*4);
62
newMachoSeg(char *name, int msect)
66
if(nseg >= nelem(seg)) {
67
diag("too many segs");
73
s->sect = mal(msect*sizeof s->sect[0]);
78
newMachoSect(MachoSeg *seg, char *name)
82
if(seg->nsect >= seg->msect) {
83
diag("too many sects in segment %s", seg->name);
86
s = &seg->sect[seg->nsect++];
95
if(ndebug >= nelem(xdebug)) {
96
diag("too many debugs");
99
return &xdebug[ndebug++];
103
// Generic linking code.
108
static vlong linkoff;
123
loadsize = 4*4*ndebug;
124
for(i=0; i<nload; i++)
125
loadsize += 4*(load[i].ndata+2);
127
loadsize += 18*4*nseg;
128
loadsize += 20*4*nsect;
130
loadsize += 14*4*nseg;
131
loadsize += 17*4*nsect;
140
LPUT(2); /* file type - mach executable */
141
LPUT(nload+nseg+ndebug);
143
LPUT(1); /* flags - no undefines */
145
LPUT(0); /* reserved */
147
for(i=0; i<nseg; i++) {
150
LPUT(25); /* segment 64 */
151
LPUT(72+80*s->nsect);
152
strnput(s->name, 16);
162
LPUT(1); /* segment 32 */
163
LPUT(56+68*s->nsect);
164
strnput(s->name, 16);
174
for(j=0; j<s->nsect; j++) {
177
strnput(t->name, 16);
178
strnput(s->name, 16);
186
LPUT(t->res1); /* reserved */
187
LPUT(t->res2); /* reserved */
188
LPUT(0); /* reserved */
190
strnput(t->name, 16);
191
strnput(s->name, 16);
199
LPUT(t->res1); /* reserved */
200
LPUT(t->res2); /* reserved */
205
for(i=0; i<nload; i++) {
208
LPUT(4*(l->ndata+2));
209
for(j=0; j<l->ndata; j++)
213
for(i=0; i<ndebug; i++) {
215
LPUT(3); /* obsolete gdb debug info */
216
LPUT(16); /* size of symseg command */
232
// empirically, string table must begin with " \x00".
233
s = lookup(".dynstr", 0);
234
s->type = SMACHODYNSTR;
239
s = lookup(".dynsym", 0);
240
s->type = SMACHODYNSYM;
243
s = lookup(".plt", 0); // will be __symbol_stub
247
s = lookup(".got", 0); // will be __nl_symbol_ptr
251
s = lookup(".linkedit.plt", 0); // indirect table for .plt
252
s->type = SMACHOINDIRECTPLT;
255
s = lookup(".linkedit.got", 0); // indirect table for .got
256
s->type = SMACHOINDIRECTGOT;
261
machoadddynlib(char *lib)
264
dylib = realloc(dylib, (ndylib+32)*sizeof dylib[0]);
266
diag("out of memory");
270
dylib[ndylib++] = lib;
287
va = INITTEXT - HEADR;
291
diag("unknown mach architecture");
294
mh->cpu = MACHO_CPU_AMD64;
295
mh->subcpu = MACHO_SUBCPU_X86;
298
mh->cpu = MACHO_CPU_386;
299
mh->subcpu = MACHO_SUBCPU_X86;
303
/* segment for zero page */
304
ms = newMachoSeg("__PAGEZERO", 0);
308
v = rnd(HEADR+segtext.len, INITRND);
309
ms = newMachoSeg("__TEXT", 2);
316
msect = newMachoSect(ms, "__text");
317
msect->addr = INITTEXT;
318
msect->size = segtext.sect->len;
319
msect->off = INITTEXT - va;
320
msect->flag = 0x400; /* flag - some instructions */
322
s = lookup(".plt", 0);
324
msect = newMachoSect(ms, "__symbol_stub1");
325
msect->addr = symaddr(s);
326
msect->size = s->size;
327
msect->off = ms->fileoffset + msect->addr - ms->vaddr;
328
msect->flag = 0x80000408; /* flag */
329
msect->res1 = 0; /* index into indirect symbol table */
330
msect->res2 = 6; /* size of stubs */
335
ms = newMachoSeg("__DATA", 3);
339
ms->filesize = segdata.filelen;
343
msect = newMachoSect(ms, "__data");
345
msect->size = symaddr(lookup(".got", 0)) - msect->addr;
348
s = lookup(".got", 0);
350
msect = newMachoSect(ms, "__nl_symbol_ptr");
351
msect->addr = symaddr(s);
352
msect->size = s->size;
353
msect->off = datoff(msect->addr);
355
msect->flag = 6; /* section with nonlazy symbol pointers */
356
msect->res1 = lookup(".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */
359
msect = newMachoSect(ms, "__bss");
360
msect->addr = va+v+segdata.filelen;
361
msect->size = segdata.len - segdata.filelen;
362
msect->flag = 1; /* flag - zero fill */
366
diag("unknown macho architecture");
369
ml = newMachoLoad(5, 42+2); /* unix thread */
370
ml->data[0] = 4; /* thread type */
371
ml->data[1] = 42; /* word count */
372
ml->data[2+32] = entryvalue(); /* start pc */
373
ml->data[2+32+1] = entryvalue()>>16>>16; // hide >>32 for 8l
376
ml = newMachoLoad(5, 16+2); /* unix thread */
377
ml->data[0] = 1; /* thread type */
378
ml->data[1] = 16; /* word count */
379
ml->data[2+10] = entryvalue(); /* start pc */
384
Sym *s1, *s2, *s3, *s4;
386
// must match domacholink below
387
s1 = lookup(".dynsym", 0);
388
s2 = lookup(".dynstr", 0);
389
s3 = lookup(".linkedit.plt", 0);
390
s4 = lookup(".linkedit.got", 0);
392
ms = newMachoSeg("__LINKEDIT", 0);
393
ms->vaddr = va+v+rnd(segdata.len, INITRND);
394
ms->vsize = s1->size + s2->size + s3->size + s4->size;
395
ms->fileoffset = linkoff;
396
ms->filesize = ms->vsize;
400
ml = newMachoLoad(2, 4); /* LC_SYMTAB */
401
ml->data[0] = linkoff; /* symoff */
402
ml->data[1] = s1->size / (macho64 ? 16 : 12); /* nsyms */
403
ml->data[2] = linkoff + s1->size; /* stroff */
404
ml->data[3] = s2->size; /* strsize */
406
ml = newMachoLoad(11, 18); /* LC_DYSYMTAB */
407
ml->data[0] = 0; /* ilocalsym */
408
ml->data[1] = 0; /* nlocalsym */
409
ml->data[2] = 0; /* iextdefsym */
410
ml->data[3] = ndynexp; /* nextdefsym */
411
ml->data[4] = ndynexp; /* iundefsym */
412
ml->data[5] = (s1->size / (macho64 ? 16 : 12)) - ndynexp; /* nundefsym */
413
ml->data[6] = 0; /* tocoffset */
414
ml->data[7] = 0; /* ntoc */
415
ml->data[8] = 0; /* modtaboff */
416
ml->data[9] = 0; /* nmodtab */
417
ml->data[10] = 0; /* extrefsymoff */
418
ml->data[11] = 0; /* nextrefsyms */
419
ml->data[12] = linkoff + s1->size + s2->size; /* indirectsymoff */
420
ml->data[13] = (s3->size + s4->size) / 4; /* nindirectsyms */
421
ml->data[14] = 0; /* extreloff */
422
ml->data[15] = 0; /* nextrel */
423
ml->data[16] = 0; /* locreloff */
424
ml->data[17] = 0; /* nlocrel */
426
ml = newMachoLoad(14, 6); /* LC_LOAD_DYLINKER */
427
ml->data[0] = 12; /* offset to string */
428
strcpy((char*)&ml->data[1], "/usr/lib/dyld");
430
for(i=0; i<ndylib; i++) {
431
ml = newMachoLoad(12, 4+(strlen(dylib[i])+1+7)/8*2); /* LC_LOAD_DYLIB */
432
ml->data[0] = 24; /* offset of string from beginning of load */
433
ml->data[1] = 0; /* time stamp */
434
ml->data[2] = 0; /* version */
435
ml->data[3] = 0; /* compatibility version */
436
strcpy((char*)&ml->data[4], dylib[i]);
443
md = newMachoDebug();
444
s = lookup("symtab", 0);
445
md->fileoffset = datoff(s->value);
446
md->filesize = s->size;
448
md = newMachoDebug();
449
s = lookup("pclntab", 0);
450
md->fileoffset = datoff(s->value);
451
md->filesize = s->size;
453
dwarfaddmachoheaders();
458
diag("MACHORESERVE too small: %d > %d", a, MACHORESERVE);
465
Sym *s1, *s2, *s3, *s4;
467
// write data that will be linkedit section
468
s1 = lookup(".dynsym", 0);
470
s2 = lookup(".dynstr", 0);
471
s3 = lookup(".linkedit.plt", 0);
472
s4 = lookup(".linkedit.got", 0);
477
size = s1->size + s2->size + s3->size + s4->size;
480
linkoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND);
481
seek(cout, linkoff, 0);
483
ewrite(cout, s1->p, s1->size);
484
ewrite(cout, s2->p, s2->size);
485
ewrite(cout, s3->p, s3->size);
486
ewrite(cout, s4->p, s4->size);
489
return rnd(size, INITRND);