~john-koepi/ubuntu/trusty/golang/default

« back to all changes in this revision

Viewing changes to src/cmd/ld/macho.c

  • Committer: Bazaar Package Importer
  • Author(s): Ondřej Surý
  • Date: 2011-04-20 17:36:48 UTC
  • Revision ID: james.westby@ubuntu.com-20110420173648-ifergoxyrm832trd
Tags: upstream-2011.03.07.1
Import upstream version 2011.03.07.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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.
 
4
 
 
5
// Mach-O file writing
 
6
// http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
 
7
 
 
8
#include "l.h"
 
9
#include "../ld/dwarf.h"
 
10
#include "../ld/lib.h"
 
11
#include "../ld/macho.h"
 
12
 
 
13
static  int     macho64;
 
14
static  MachoHdr        hdr;
 
15
static  MachoLoad       load[16];
 
16
static  MachoSeg        seg[16];
 
17
static  MachoDebug      xdebug[16];
 
18
static  int     nload, nseg, ndebug, nsect;
 
19
 
 
20
void
 
21
machoinit(void)
 
22
{
 
23
        switch(thechar) {
 
24
        // 64-bit architectures
 
25
        case '6':
 
26
                macho64 = 1;
 
27
                break;
 
28
 
 
29
        // 32-bit architectures
 
30
        default:
 
31
                break;
 
32
        }
 
33
}
 
34
 
 
35
MachoHdr*
 
36
getMachoHdr(void)
 
37
{
 
38
        return &hdr;
 
39
}
 
40
 
 
41
MachoLoad*
 
42
newMachoLoad(uint32 type, uint32 ndata)
 
43
{
 
44
        MachoLoad *l;
 
45
 
 
46
        if(nload >= nelem(load)) {
 
47
                diag("too many loads");
 
48
                errorexit();
 
49
        }
 
50
        
 
51
        if(macho64 && (ndata & 1))
 
52
                ndata++;
 
53
        
 
54
        l = &load[nload++];
 
55
        l->type = type;
 
56
        l->ndata = ndata;
 
57
        l->data = mal(ndata*4);
 
58
        return l;
 
59
}
 
60
 
 
61
MachoSeg*
 
62
newMachoSeg(char *name, int msect)
 
63
{
 
64
        MachoSeg *s;
 
65
 
 
66
        if(nseg >= nelem(seg)) {
 
67
                diag("too many segs");
 
68
                errorexit();
 
69
        }
 
70
        s = &seg[nseg++];
 
71
        s->name = name;
 
72
        s->msect = msect;
 
73
        s->sect = mal(msect*sizeof s->sect[0]);
 
74
        return s;
 
75
}
 
76
 
 
77
MachoSect*
 
78
newMachoSect(MachoSeg *seg, char *name)
 
79
{
 
80
        MachoSect *s;
 
81
 
 
82
        if(seg->nsect >= seg->msect) {
 
83
                diag("too many sects in segment %s", seg->name);
 
84
                errorexit();
 
85
        }
 
86
        s = &seg->sect[seg->nsect++];
 
87
        s->name = name;
 
88
        nsect++;
 
89
        return s;
 
90
}
 
91
 
 
92
MachoDebug*
 
93
newMachoDebug(void)
 
94
{
 
95
        if(ndebug >= nelem(xdebug)) {
 
96
                diag("too many debugs");
 
97
                errorexit();
 
98
        }
 
99
        return &xdebug[ndebug++];
 
100
}
 
101
 
 
102
 
 
103
// Generic linking code.
 
104
 
 
105
static char **dylib;
 
106
static int ndylib;
 
107
 
 
108
static vlong linkoff;
 
109
 
 
110
int
 
111
machowrite(void)
 
112
{
 
113
        vlong o1;
 
114
        int loadsize;
 
115
        int i, j;
 
116
        MachoSeg *s;
 
117
        MachoSect *t;
 
118
        MachoDebug *d;
 
119
        MachoLoad *l;
 
120
 
 
121
        o1 = cpos();
 
122
 
 
123
        loadsize = 4*4*ndebug;
 
124
        for(i=0; i<nload; i++)
 
125
                loadsize += 4*(load[i].ndata+2);
 
126
        if(macho64) {
 
127
                loadsize += 18*4*nseg;
 
128
                loadsize += 20*4*nsect;
 
129
        } else {
 
130
                loadsize += 14*4*nseg;
 
131
                loadsize += 17*4*nsect;
 
132
        }
 
133
 
 
134
        if(macho64)
 
135
                LPUT(0xfeedfacf);
 
136
        else
 
137
                LPUT(0xfeedface);
 
138
        LPUT(hdr.cpu);
 
139
        LPUT(hdr.subcpu);
 
140
        LPUT(2);        /* file type - mach executable */
 
141
        LPUT(nload+nseg+ndebug);
 
142
        LPUT(loadsize);
 
143
        LPUT(1);        /* flags - no undefines */
 
144
        if(macho64)
 
145
                LPUT(0);        /* reserved */
 
146
 
 
147
        for(i=0; i<nseg; i++) {
 
148
                s = &seg[i];
 
149
                if(macho64) {
 
150
                        LPUT(25);       /* segment 64 */
 
151
                        LPUT(72+80*s->nsect);
 
152
                        strnput(s->name, 16);
 
153
                        VPUT(s->vaddr);
 
154
                        VPUT(s->vsize);
 
155
                        VPUT(s->fileoffset);
 
156
                        VPUT(s->filesize);
 
157
                        LPUT(s->prot1);
 
158
                        LPUT(s->prot2);
 
159
                        LPUT(s->nsect);
 
160
                        LPUT(s->flag);
 
161
                } else {
 
162
                        LPUT(1);        /* segment 32 */
 
163
                        LPUT(56+68*s->nsect);
 
164
                        strnput(s->name, 16);
 
165
                        LPUT(s->vaddr);
 
166
                        LPUT(s->vsize);
 
167
                        LPUT(s->fileoffset);
 
168
                        LPUT(s->filesize);
 
169
                        LPUT(s->prot1);
 
170
                        LPUT(s->prot2);
 
171
                        LPUT(s->nsect);
 
172
                        LPUT(s->flag);
 
173
                }
 
174
                for(j=0; j<s->nsect; j++) {
 
175
                        t = &s->sect[j];
 
176
                        if(macho64) {
 
177
                                strnput(t->name, 16);
 
178
                                strnput(s->name, 16);
 
179
                                VPUT(t->addr);
 
180
                                VPUT(t->size);
 
181
                                LPUT(t->off);
 
182
                                LPUT(t->align);
 
183
                                LPUT(t->reloc);
 
184
                                LPUT(t->nreloc);
 
185
                                LPUT(t->flag);
 
186
                                LPUT(t->res1);  /* reserved */
 
187
                                LPUT(t->res2);  /* reserved */
 
188
                                LPUT(0);        /* reserved */
 
189
                        } else {
 
190
                                strnput(t->name, 16);
 
191
                                strnput(s->name, 16);
 
192
                                LPUT(t->addr);
 
193
                                LPUT(t->size);
 
194
                                LPUT(t->off);
 
195
                                LPUT(t->align);
 
196
                                LPUT(t->reloc);
 
197
                                LPUT(t->nreloc);
 
198
                                LPUT(t->flag);
 
199
                                LPUT(t->res1);  /* reserved */
 
200
                                LPUT(t->res2);  /* reserved */
 
201
                        }
 
202
                }
 
203
        }
 
204
 
 
205
        for(i=0; i<nload; i++) {
 
206
                l = &load[i];
 
207
                LPUT(l->type);
 
208
                LPUT(4*(l->ndata+2));
 
209
                for(j=0; j<l->ndata; j++)
 
210
                        LPUT(l->data[j]);
 
211
        }
 
212
 
 
213
        for(i=0; i<ndebug; i++) {
 
214
                d = &xdebug[i];
 
215
                LPUT(3);        /* obsolete gdb debug info */
 
216
                LPUT(16);       /* size of symseg command */
 
217
                LPUT(d->fileoffset);
 
218
                LPUT(d->filesize);
 
219
        }
 
220
 
 
221
        return cpos() - o1;
 
222
}
 
223
 
 
224
void
 
225
domacho(void)
 
226
{
 
227
        Sym *s;
 
228
 
 
229
        if(debug['d'])
 
230
                return;
 
231
 
 
232
        // empirically, string table must begin with " \x00".
 
233
        s = lookup(".dynstr", 0);
 
234
        s->type = SMACHODYNSTR;
 
235
        s->reachable = 1;
 
236
        adduint8(s, ' ');
 
237
        adduint8(s, '\0');
 
238
        
 
239
        s = lookup(".dynsym", 0);
 
240
        s->type = SMACHODYNSYM;
 
241
        s->reachable = 1;
 
242
        
 
243
        s = lookup(".plt", 0);  // will be __symbol_stub
 
244
        s->type = SMACHOPLT;
 
245
        s->reachable = 1;
 
246
        
 
247
        s = lookup(".got", 0);  // will be __nl_symbol_ptr
 
248
        s->type = SMACHOGOT;
 
249
        s->reachable = 1;
 
250
        
 
251
        s = lookup(".linkedit.plt", 0); // indirect table for .plt
 
252
        s->type = SMACHOINDIRECTPLT;
 
253
        s->reachable = 1;
 
254
        
 
255
        s = lookup(".linkedit.got", 0); // indirect table for .got
 
256
        s->type = SMACHOINDIRECTGOT;
 
257
        s->reachable = 1;
 
258
}
 
259
 
 
260
void
 
261
machoadddynlib(char *lib)
 
262
{
 
263
        if(ndylib%32 == 0) {
 
264
                dylib = realloc(dylib, (ndylib+32)*sizeof dylib[0]);
 
265
                if(dylib == nil) {
 
266
                        diag("out of memory");
 
267
                        errorexit();
 
268
                }
 
269
        }
 
270
        dylib[ndylib++] = lib;
 
271
}
 
272
 
 
273
void
 
274
asmbmacho(void)
 
275
{
 
276
        vlong v, w;
 
277
        vlong va;
 
278
        int a, i;
 
279
        MachoHdr *mh;
 
280
        MachoSect *msect;
 
281
        MachoSeg *ms;
 
282
        MachoDebug *md;
 
283
        MachoLoad *ml;
 
284
        Sym *s;
 
285
 
 
286
        /* apple MACH */
 
287
        va = INITTEXT - HEADR;
 
288
        mh = getMachoHdr();
 
289
        switch(thechar){
 
290
        default:
 
291
                diag("unknown mach architecture");
 
292
                errorexit();
 
293
        case '6':
 
294
                mh->cpu = MACHO_CPU_AMD64;
 
295
                mh->subcpu = MACHO_SUBCPU_X86;
 
296
                break;
 
297
        case '8':
 
298
                mh->cpu = MACHO_CPU_386;
 
299
                mh->subcpu = MACHO_SUBCPU_X86;
 
300
                break;
 
301
        }
 
302
 
 
303
        /* segment for zero page */
 
304
        ms = newMachoSeg("__PAGEZERO", 0);
 
305
        ms->vsize = va;
 
306
 
 
307
        /* text */
 
308
        v = rnd(HEADR+segtext.len, INITRND);
 
309
        ms = newMachoSeg("__TEXT", 2);
 
310
        ms->vaddr = va;
 
311
        ms->vsize = v;
 
312
        ms->filesize = v;
 
313
        ms->prot1 = 7;
 
314
        ms->prot2 = 5;
 
315
 
 
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 */
 
321
        
 
322
        s = lookup(".plt", 0);
 
323
        if(s->size > 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 */
 
331
        }
 
332
 
 
333
        /* data */
 
334
        w = segdata.len;
 
335
        ms = newMachoSeg("__DATA", 3);
 
336
        ms->vaddr = va+v;
 
337
        ms->vsize = w;
 
338
        ms->fileoffset = v;
 
339
        ms->filesize = segdata.filelen;
 
340
        ms->prot1 = 7;
 
341
        ms->prot2 = 3;
 
342
 
 
343
        msect = newMachoSect(ms, "__data");
 
344
        msect->addr = va+v;
 
345
        msect->size = symaddr(lookup(".got", 0)) - msect->addr;
 
346
        msect->off = v;
 
347
 
 
348
        s = lookup(".got", 0);
 
349
        if(s->size > 0) {
 
350
                msect = newMachoSect(ms, "__nl_symbol_ptr");
 
351
                msect->addr = symaddr(s);
 
352
                msect->size = s->size;
 
353
                msect->off = datoff(msect->addr);
 
354
                msect->align = 2;
 
355
                msect->flag = 6;        /* section with nonlazy symbol pointers */
 
356
                msect->res1 = lookup(".linkedit.plt", 0)->size / 4;     /* offset into indirect symbol table */
 
357
        }
 
358
 
 
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 */
 
363
 
 
364
        switch(thechar) {
 
365
        default:
 
366
                diag("unknown macho architecture");
 
367
                errorexit();
 
368
        case '6':
 
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
 
374
                break;
 
375
        case '8':
 
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 */
 
380
                break;
 
381
        }
 
382
 
 
383
        if(!debug['d']) {
 
384
                Sym *s1, *s2, *s3, *s4;
 
385
 
 
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);
 
391
 
 
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;
 
397
                ms->prot1 = 7;
 
398
                ms->prot2 = 3;
 
399
 
 
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 */
 
405
 
 
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 */
 
425
 
 
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");
 
429
 
 
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]);
 
437
                }
 
438
        }
 
439
 
 
440
        if(!debug['s']) {
 
441
                Sym *s;
 
442
 
 
443
                md = newMachoDebug();
 
444
                s = lookup("symtab", 0);
 
445
                md->fileoffset = datoff(s->value);
 
446
                md->filesize = s->size;
 
447
 
 
448
                md = newMachoDebug();
 
449
                s = lookup("pclntab", 0);
 
450
                md->fileoffset = datoff(s->value);
 
451
                md->filesize = s->size;
 
452
 
 
453
                dwarfaddmachoheaders();
 
454
        }
 
455
 
 
456
        a = machowrite();
 
457
        if(a > MACHORESERVE)
 
458
                diag("MACHORESERVE too small: %d > %d", a, MACHORESERVE);
 
459
}
 
460
 
 
461
vlong
 
462
domacholink(void)
 
463
{
 
464
        int size;
 
465
        Sym *s1, *s2, *s3, *s4;
 
466
 
 
467
        // write data that will be linkedit section
 
468
        s1 = lookup(".dynsym", 0);
 
469
        relocsym(s1);
 
470
        s2 = lookup(".dynstr", 0);
 
471
        s3 = lookup(".linkedit.plt", 0);
 
472
        s4 = lookup(".linkedit.got", 0);
 
473
 
 
474
        while(s2->size%4)
 
475
                adduint8(s2, 0);
 
476
        
 
477
        size = s1->size + s2->size + s3->size + s4->size;
 
478
 
 
479
        if(size > 0) {
 
480
                linkoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND);
 
481
                seek(cout, linkoff, 0);
 
482
 
 
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);
 
487
        }
 
488
 
 
489
        return rnd(size, INITRND);
 
490
}