Blame


1 a84cbb2a 2004-04-19 devnull #include <u.h>
2 a84cbb2a 2004-04-19 devnull #include <libc.h>
3 a84cbb2a 2004-04-19 devnull #include <mach.h>
4 a84cbb2a 2004-04-19 devnull #include "macho.h"
5 a84cbb2a 2004-04-19 devnull
6 a84cbb2a 2004-04-19 devnull /*
7 fa325e9b 2020-01-10 cross http://www.channelu.com/NeXT/NeXTStep/3.3/nd/DevTools/14_MachO/MachO.htmld/
8 a84cbb2a 2004-04-19 devnull */
9 a84cbb2a 2004-04-19 devnull
10 a84cbb2a 2004-04-19 devnull Macho*
11 a84cbb2a 2004-04-19 devnull machoopen(char *name)
12 a84cbb2a 2004-04-19 devnull {
13 a84cbb2a 2004-04-19 devnull int fd;
14 a84cbb2a 2004-04-19 devnull Macho *m;
15 a84cbb2a 2004-04-19 devnull
16 a84cbb2a 2004-04-19 devnull if((fd = open(name, OREAD)) < 0)
17 a84cbb2a 2004-04-19 devnull return nil;
18 a84cbb2a 2004-04-19 devnull m = machoinit(fd);
19 a84cbb2a 2004-04-19 devnull if(m == nil)
20 a84cbb2a 2004-04-19 devnull close(fd);
21 a84cbb2a 2004-04-19 devnull return m;
22 a84cbb2a 2004-04-19 devnull }
23 a84cbb2a 2004-04-19 devnull
24 a84cbb2a 2004-04-19 devnull static int
25 873e5f50 2010-09-24 rsc unpackcmd(uchar *p, Macho *m, MachoCmd *c, uint type, uint sz)
26 a84cbb2a 2004-04-19 devnull {
27 873e5f50 2010-09-24 rsc uint32 (*e4)(uchar*);
28 873e5f50 2010-09-24 rsc uint64 (*e8)(uchar*);
29 873e5f50 2010-09-24 rsc MachoSect *s;
30 873e5f50 2010-09-24 rsc int i;
31 a84cbb2a 2004-04-19 devnull
32 a84cbb2a 2004-04-19 devnull e4 = m->e4;
33 873e5f50 2010-09-24 rsc e8 = m->e8;
34 a84cbb2a 2004-04-19 devnull
35 a84cbb2a 2004-04-19 devnull c->type = type;
36 a84cbb2a 2004-04-19 devnull c->size = sz;
37 a84cbb2a 2004-04-19 devnull switch(type){
38 a84cbb2a 2004-04-19 devnull default:
39 a84cbb2a 2004-04-19 devnull return -1;
40 a84cbb2a 2004-04-19 devnull case MachoCmdSegment:
41 a84cbb2a 2004-04-19 devnull if(sz < 56)
42 a84cbb2a 2004-04-19 devnull return -1;
43 a84cbb2a 2004-04-19 devnull strecpy(c->seg.name, c->seg.name+sizeof c->seg.name, (char*)p+8);
44 a84cbb2a 2004-04-19 devnull c->seg.vmaddr = e4(p+24);
45 a84cbb2a 2004-04-19 devnull c->seg.vmsize = e4(p+28);
46 a84cbb2a 2004-04-19 devnull c->seg.fileoff = e4(p+32);
47 a84cbb2a 2004-04-19 devnull c->seg.filesz = e4(p+36);
48 a84cbb2a 2004-04-19 devnull c->seg.maxprot = e4(p+40);
49 a84cbb2a 2004-04-19 devnull c->seg.initprot = e4(p+44);
50 a84cbb2a 2004-04-19 devnull c->seg.nsect = e4(p+48);
51 a84cbb2a 2004-04-19 devnull c->seg.flags = e4(p+52);
52 873e5f50 2010-09-24 rsc c->seg.sect = mallocz(c->seg.nsect * sizeof c->seg.sect[0], 1);
53 873e5f50 2010-09-24 rsc if(c->seg.sect == nil)
54 873e5f50 2010-09-24 rsc return -1;
55 873e5f50 2010-09-24 rsc if(sz < 56+c->seg.nsect*68)
56 873e5f50 2010-09-24 rsc return -1;
57 873e5f50 2010-09-24 rsc p += 56;
58 873e5f50 2010-09-24 rsc for(i=0; i<c->seg.nsect; i++) {
59 873e5f50 2010-09-24 rsc s = &c->seg.sect[i];
60 873e5f50 2010-09-24 rsc strecpy(s->name, s->name+sizeof s->name, (char*)p+0);
61 873e5f50 2010-09-24 rsc strecpy(s->segname, s->segname+sizeof s->segname, (char*)p+16);
62 873e5f50 2010-09-24 rsc s->addr = e4(p+32);
63 873e5f50 2010-09-24 rsc s->size = e4(p+36);
64 873e5f50 2010-09-24 rsc s->offset = e4(p+40);
65 873e5f50 2010-09-24 rsc s->align = e4(p+44);
66 873e5f50 2010-09-24 rsc s->reloff = e4(p+48);
67 873e5f50 2010-09-24 rsc s->nreloc = e4(p+52);
68 873e5f50 2010-09-24 rsc s->flags = e4(p+56);
69 873e5f50 2010-09-24 rsc // p+60 and p+64 are reserved
70 873e5f50 2010-09-24 rsc p += 68;
71 873e5f50 2010-09-24 rsc }
72 a84cbb2a 2004-04-19 devnull break;
73 873e5f50 2010-09-24 rsc case MachoCmdSegment64:
74 873e5f50 2010-09-24 rsc if(sz < 72)
75 873e5f50 2010-09-24 rsc return -1;
76 873e5f50 2010-09-24 rsc strecpy(c->seg.name, c->seg.name+sizeof c->seg.name, (char*)p+8);
77 873e5f50 2010-09-24 rsc c->seg.vmaddr = e8(p+24);
78 873e5f50 2010-09-24 rsc c->seg.vmsize = e8(p+32);
79 873e5f50 2010-09-24 rsc c->seg.fileoff = e8(p+40);
80 873e5f50 2010-09-24 rsc c->seg.filesz = e8(p+48);
81 873e5f50 2010-09-24 rsc c->seg.maxprot = e4(p+56);
82 873e5f50 2010-09-24 rsc c->seg.initprot = e4(p+60);
83 873e5f50 2010-09-24 rsc c->seg.nsect = e4(p+64);
84 873e5f50 2010-09-24 rsc c->seg.flags = e4(p+68);
85 873e5f50 2010-09-24 rsc c->seg.sect = mallocz(c->seg.nsect * sizeof c->seg.sect[0], 1);
86 873e5f50 2010-09-24 rsc if(c->seg.sect == nil)
87 873e5f50 2010-09-24 rsc return -1;
88 873e5f50 2010-09-24 rsc if(sz < 72+c->seg.nsect*80)
89 873e5f50 2010-09-24 rsc return -1;
90 873e5f50 2010-09-24 rsc p += 72;
91 873e5f50 2010-09-24 rsc for(i=0; i<c->seg.nsect; i++) {
92 873e5f50 2010-09-24 rsc s = &c->seg.sect[i];
93 873e5f50 2010-09-24 rsc strecpy(s->name, s->name+sizeof s->name, (char*)p+0);
94 873e5f50 2010-09-24 rsc strecpy(s->segname, s->segname+sizeof s->segname, (char*)p+16);
95 873e5f50 2010-09-24 rsc s->addr = e8(p+32);
96 873e5f50 2010-09-24 rsc s->size = e8(p+40);
97 873e5f50 2010-09-24 rsc s->offset = e4(p+48);
98 873e5f50 2010-09-24 rsc s->align = e4(p+52);
99 873e5f50 2010-09-24 rsc s->reloff = e4(p+56);
100 873e5f50 2010-09-24 rsc s->nreloc = e4(p+60);
101 873e5f50 2010-09-24 rsc s->flags = e4(p+64);
102 873e5f50 2010-09-24 rsc // p+68, p+72, and p+76 are reserved
103 873e5f50 2010-09-24 rsc p += 80;
104 873e5f50 2010-09-24 rsc }
105 873e5f50 2010-09-24 rsc break;
106 a84cbb2a 2004-04-19 devnull case MachoCmdSymtab:
107 a84cbb2a 2004-04-19 devnull if(sz < 24)
108 a84cbb2a 2004-04-19 devnull return -1;
109 a84cbb2a 2004-04-19 devnull c->sym.symoff = e4(p+8);
110 873e5f50 2010-09-24 rsc c->sym.nsym = e4(p+12);
111 a84cbb2a 2004-04-19 devnull c->sym.stroff = e4(p+16);
112 a84cbb2a 2004-04-19 devnull c->sym.strsize = e4(p+20);
113 a84cbb2a 2004-04-19 devnull break;
114 873e5f50 2010-09-24 rsc case MachoCmdDysymtab:
115 873e5f50 2010-09-24 rsc if(sz < 80)
116 873e5f50 2010-09-24 rsc return -1;
117 873e5f50 2010-09-24 rsc c->dsym.ilocalsym = e4(p+8);
118 873e5f50 2010-09-24 rsc c->dsym.nlocalsym = e4(p+12);
119 873e5f50 2010-09-24 rsc c->dsym.iextdefsym = e4(p+16);
120 873e5f50 2010-09-24 rsc c->dsym.nextdefsym = e4(p+20);
121 873e5f50 2010-09-24 rsc c->dsym.iundefsym = e4(p+24);
122 873e5f50 2010-09-24 rsc c->dsym.nundefsym = e4(p+28);
123 873e5f50 2010-09-24 rsc c->dsym.tocoff = e4(p+32);
124 873e5f50 2010-09-24 rsc c->dsym.ntoc = e4(p+36);
125 873e5f50 2010-09-24 rsc c->dsym.modtaboff = e4(p+40);
126 873e5f50 2010-09-24 rsc c->dsym.nmodtab = e4(p+44);
127 873e5f50 2010-09-24 rsc c->dsym.extrefsymoff = e4(p+48);
128 873e5f50 2010-09-24 rsc c->dsym.nextrefsyms = e4(p+52);
129 873e5f50 2010-09-24 rsc c->dsym.indirectsymoff = e4(p+56);
130 873e5f50 2010-09-24 rsc c->dsym.nindirectsyms = e4(p+60);
131 873e5f50 2010-09-24 rsc c->dsym.extreloff = e4(p+64);
132 873e5f50 2010-09-24 rsc c->dsym.nextrel = e4(p+68);
133 873e5f50 2010-09-24 rsc c->dsym.locreloff = e4(p+72);
134 873e5f50 2010-09-24 rsc c->dsym.nlocrel = e4(p+76);
135 873e5f50 2010-09-24 rsc break;
136 a84cbb2a 2004-04-19 devnull }
137 a84cbb2a 2004-04-19 devnull return 0;
138 a84cbb2a 2004-04-19 devnull }
139 a84cbb2a 2004-04-19 devnull
140 873e5f50 2010-09-24 rsc int
141 873e5f50 2010-09-24 rsc macholoadrel(Macho *m, MachoSect *sect)
142 873e5f50 2010-09-24 rsc {
143 873e5f50 2010-09-24 rsc MachoRel *rel, *r;
144 873e5f50 2010-09-24 rsc uchar *buf, *p;
145 873e5f50 2010-09-24 rsc int i, n;
146 873e5f50 2010-09-24 rsc uint32 v;
147 fa325e9b 2020-01-10 cross
148 873e5f50 2010-09-24 rsc if(sect->rel != nil || sect->nreloc == 0)
149 873e5f50 2010-09-24 rsc return 0;
150 873e5f50 2010-09-24 rsc rel = mallocz(sect->nreloc * sizeof r[0], 1);
151 873e5f50 2010-09-24 rsc if(rel == nil)
152 873e5f50 2010-09-24 rsc return -1;
153 873e5f50 2010-09-24 rsc n = sect->nreloc * 8;
154 873e5f50 2010-09-24 rsc buf = mallocz(n, 1);
155 873e5f50 2010-09-24 rsc if(buf == nil) {
156 873e5f50 2010-09-24 rsc free(rel);
157 873e5f50 2010-09-24 rsc return -1;
158 873e5f50 2010-09-24 rsc }
159 873e5f50 2010-09-24 rsc if(seek(m->fd, sect->reloff, 0) < 0 || readn(m->fd, buf, n) != n) {
160 873e5f50 2010-09-24 rsc free(rel);
161 873e5f50 2010-09-24 rsc free(buf);
162 873e5f50 2010-09-24 rsc return -1;
163 873e5f50 2010-09-24 rsc }
164 873e5f50 2010-09-24 rsc for(i=0; i<sect->nreloc; i++) {
165 873e5f50 2010-09-24 rsc r = &rel[i];
166 873e5f50 2010-09-24 rsc p = buf+i*8;
167 873e5f50 2010-09-24 rsc r->addr = m->e4(p);
168 fa325e9b 2020-01-10 cross
169 873e5f50 2010-09-24 rsc // TODO(rsc): Wrong interpretation for big-endian bitfields?
170 873e5f50 2010-09-24 rsc v = m->e4(p+4);
171 873e5f50 2010-09-24 rsc r->symnum = v & 0xFFFFFF;
172 873e5f50 2010-09-24 rsc v >>= 24;
173 873e5f50 2010-09-24 rsc r->pcrel = v&1;
174 873e5f50 2010-09-24 rsc v >>= 1;
175 873e5f50 2010-09-24 rsc r->length = 1<<(v&3);
176 873e5f50 2010-09-24 rsc v >>= 2;
177 873e5f50 2010-09-24 rsc r->extrn = v&1;
178 873e5f50 2010-09-24 rsc v >>= 1;
179 873e5f50 2010-09-24 rsc r->type = v;
180 873e5f50 2010-09-24 rsc }
181 873e5f50 2010-09-24 rsc sect->rel = rel;
182 873e5f50 2010-09-24 rsc free(buf);
183 873e5f50 2010-09-24 rsc return 0;
184 873e5f50 2010-09-24 rsc }
185 a84cbb2a 2004-04-19 devnull
186 fa325e9b 2020-01-10 cross int
187 873e5f50 2010-09-24 rsc macholoadsym(Macho *m, MachoSymtab *symtab)
188 873e5f50 2010-09-24 rsc {
189 873e5f50 2010-09-24 rsc char *strbuf;
190 873e5f50 2010-09-24 rsc uchar *symbuf, *p;
191 873e5f50 2010-09-24 rsc int i, n, symsize;
192 873e5f50 2010-09-24 rsc MachoSym *sym, *s;
193 873e5f50 2010-09-24 rsc uint32 v;
194 873e5f50 2010-09-24 rsc
195 873e5f50 2010-09-24 rsc if(symtab->sym != nil)
196 873e5f50 2010-09-24 rsc return 0;
197 873e5f50 2010-09-24 rsc
198 873e5f50 2010-09-24 rsc strbuf = mallocz(symtab->strsize, 1);
199 873e5f50 2010-09-24 rsc if(strbuf == nil)
200 873e5f50 2010-09-24 rsc return -1;
201 873e5f50 2010-09-24 rsc if(seek(m->fd, symtab->stroff, 0) < 0 || readn(m->fd, strbuf, symtab->strsize) != symtab->strsize) {
202 873e5f50 2010-09-24 rsc free(strbuf);
203 873e5f50 2010-09-24 rsc return -1;
204 873e5f50 2010-09-24 rsc }
205 fa325e9b 2020-01-10 cross
206 873e5f50 2010-09-24 rsc symsize = 12;
207 873e5f50 2010-09-24 rsc if(m->is64)
208 873e5f50 2010-09-24 rsc symsize = 16;
209 873e5f50 2010-09-24 rsc n = symtab->nsym * symsize;
210 873e5f50 2010-09-24 rsc symbuf = mallocz(n, 1);
211 873e5f50 2010-09-24 rsc if(symbuf == nil) {
212 873e5f50 2010-09-24 rsc free(strbuf);
213 873e5f50 2010-09-24 rsc return -1;
214 873e5f50 2010-09-24 rsc }
215 873e5f50 2010-09-24 rsc if(seek(m->fd, symtab->symoff, 0) < 0 || readn(m->fd, symbuf, n) != n) {
216 873e5f50 2010-09-24 rsc free(strbuf);
217 873e5f50 2010-09-24 rsc free(symbuf);
218 873e5f50 2010-09-24 rsc return -1;
219 873e5f50 2010-09-24 rsc }
220 873e5f50 2010-09-24 rsc sym = mallocz(symtab->nsym * sizeof sym[0], 1);
221 873e5f50 2010-09-24 rsc if(sym == nil) {
222 873e5f50 2010-09-24 rsc free(strbuf);
223 873e5f50 2010-09-24 rsc free(symbuf);
224 873e5f50 2010-09-24 rsc return -1;
225 873e5f50 2010-09-24 rsc }
226 873e5f50 2010-09-24 rsc p = symbuf;
227 873e5f50 2010-09-24 rsc for(i=0; i<symtab->nsym; i++) {
228 873e5f50 2010-09-24 rsc s = &sym[i];
229 873e5f50 2010-09-24 rsc v = m->e4(p);
230 873e5f50 2010-09-24 rsc if(v >= symtab->strsize) {
231 873e5f50 2010-09-24 rsc free(strbuf);
232 873e5f50 2010-09-24 rsc free(symbuf);
233 873e5f50 2010-09-24 rsc free(sym);
234 873e5f50 2010-09-24 rsc return -1;
235 873e5f50 2010-09-24 rsc }
236 873e5f50 2010-09-24 rsc s->name = strbuf + v;
237 873e5f50 2010-09-24 rsc s->type = p[4];
238 873e5f50 2010-09-24 rsc s->sectnum = p[5];
239 873e5f50 2010-09-24 rsc s->desc = m->e2(p+6);
240 873e5f50 2010-09-24 rsc if(m->is64)
241 873e5f50 2010-09-24 rsc s->value = m->e8(p+8);
242 873e5f50 2010-09-24 rsc else
243 873e5f50 2010-09-24 rsc s->value = m->e4(p+8);
244 873e5f50 2010-09-24 rsc p += symsize;
245 873e5f50 2010-09-24 rsc }
246 873e5f50 2010-09-24 rsc symtab->str = strbuf;
247 873e5f50 2010-09-24 rsc symtab->sym = sym;
248 873e5f50 2010-09-24 rsc free(symbuf);
249 873e5f50 2010-09-24 rsc return 0;
250 873e5f50 2010-09-24 rsc }
251 873e5f50 2010-09-24 rsc
252 a84cbb2a 2004-04-19 devnull Macho*
253 a84cbb2a 2004-04-19 devnull machoinit(int fd)
254 a84cbb2a 2004-04-19 devnull {
255 873e5f50 2010-09-24 rsc int i, is64;
256 a84cbb2a 2004-04-19 devnull uchar hdr[7*4], *cmdp;
257 873e5f50 2010-09-24 rsc uchar tmp[4];
258 873e5f50 2010-09-24 rsc uint16 (*e2)(uchar*);
259 873e5f50 2010-09-24 rsc uint32 (*e4)(uchar*);
260 873e5f50 2010-09-24 rsc uint64 (*e8)(uchar*);
261 a84cbb2a 2004-04-19 devnull ulong ncmd, cmdsz, ty, sz, off;
262 a84cbb2a 2004-04-19 devnull Macho *m;
263 a84cbb2a 2004-04-19 devnull
264 a84cbb2a 2004-04-19 devnull if(seek(fd, 0, 0) < 0 || readn(fd, hdr, sizeof hdr) != sizeof hdr)
265 a84cbb2a 2004-04-19 devnull return nil;
266 a84cbb2a 2004-04-19 devnull
267 873e5f50 2010-09-24 rsc if((beload4(hdr)&~1) == 0xFEEDFACE){
268 873e5f50 2010-09-24 rsc e2 = beload2;
269 a84cbb2a 2004-04-19 devnull e4 = beload4;
270 873e5f50 2010-09-24 rsc e8 = beload8;
271 873e5f50 2010-09-24 rsc }else if((leload4(hdr)&~1) == 0xFEEDFACE){
272 873e5f50 2010-09-24 rsc e2 = leload2;
273 a84cbb2a 2004-04-19 devnull e4 = leload4;
274 873e5f50 2010-09-24 rsc e8 = leload8;
275 873e5f50 2010-09-24 rsc }else{
276 a84cbb2a 2004-04-19 devnull werrstr("bad magic - not mach-o file");
277 a84cbb2a 2004-04-19 devnull return nil;
278 a84cbb2a 2004-04-19 devnull }
279 873e5f50 2010-09-24 rsc is64 = e4(hdr) == 0xFEEDFACF;
280 a84cbb2a 2004-04-19 devnull ncmd = e4(hdr+4*4);
281 a84cbb2a 2004-04-19 devnull cmdsz = e4(hdr+5*4);
282 a84cbb2a 2004-04-19 devnull if(ncmd > 0x10000 || cmdsz >= 0x01000000){
283 a84cbb2a 2004-04-19 devnull werrstr("implausible mach-o header ncmd=%lud cmdsz=%lud", ncmd, cmdsz);
284 a84cbb2a 2004-04-19 devnull return nil;
285 a84cbb2a 2004-04-19 devnull }
286 873e5f50 2010-09-24 rsc if(is64)
287 873e5f50 2010-09-24 rsc readn(fd, tmp, 4); // skip reserved word in header
288 a84cbb2a 2004-04-19 devnull
289 a84cbb2a 2004-04-19 devnull m = mallocz(sizeof(*m)+ncmd*sizeof(MachoCmd)+cmdsz, 1);
290 a84cbb2a 2004-04-19 devnull if(m == nil)
291 a84cbb2a 2004-04-19 devnull return nil;
292 a84cbb2a 2004-04-19 devnull
293 a84cbb2a 2004-04-19 devnull m->fd = fd;
294 873e5f50 2010-09-24 rsc m->e2 = e2;
295 a84cbb2a 2004-04-19 devnull m->e4 = e4;
296 873e5f50 2010-09-24 rsc m->e8 = e8;
297 a84cbb2a 2004-04-19 devnull m->cputype = e4(hdr+1*4);
298 a84cbb2a 2004-04-19 devnull m->subcputype = e4(hdr+2*4);
299 a84cbb2a 2004-04-19 devnull m->filetype = e4(hdr+3*4);
300 a84cbb2a 2004-04-19 devnull m->ncmd = ncmd;
301 a84cbb2a 2004-04-19 devnull m->flags = e4(hdr+6*4);
302 873e5f50 2010-09-24 rsc m->is64 = is64;
303 a84cbb2a 2004-04-19 devnull
304 a84cbb2a 2004-04-19 devnull m->cmd = (MachoCmd*)(m+1);
305 a84cbb2a 2004-04-19 devnull off = sizeof hdr;
306 a84cbb2a 2004-04-19 devnull cmdp = (uchar*)(m->cmd+ncmd);
307 a84cbb2a 2004-04-19 devnull if(readn(fd, cmdp, cmdsz) != cmdsz){
308 a84cbb2a 2004-04-19 devnull werrstr("reading cmds: %r");
309 a84cbb2a 2004-04-19 devnull free(m);
310 a84cbb2a 2004-04-19 devnull return nil;
311 a84cbb2a 2004-04-19 devnull }
312 a84cbb2a 2004-04-19 devnull
313 a84cbb2a 2004-04-19 devnull for(i=0; i<ncmd; i++){
314 a84cbb2a 2004-04-19 devnull ty = e4(cmdp);
315 a84cbb2a 2004-04-19 devnull sz = e4(cmdp+4);
316 a84cbb2a 2004-04-19 devnull m->cmd[i].off = off;
317 873e5f50 2010-09-24 rsc unpackcmd(cmdp, m, &m->cmd[i], ty, sz);
318 a84cbb2a 2004-04-19 devnull cmdp += sz;
319 a84cbb2a 2004-04-19 devnull off += sz;
320 a84cbb2a 2004-04-19 devnull }
321 a84cbb2a 2004-04-19 devnull return m;
322 a84cbb2a 2004-04-19 devnull }
323 a84cbb2a 2004-04-19 devnull
324 a84cbb2a 2004-04-19 devnull void
325 a84cbb2a 2004-04-19 devnull machoclose(Macho *m)
326 a84cbb2a 2004-04-19 devnull {
327 a84cbb2a 2004-04-19 devnull close(m->fd);
328 a84cbb2a 2004-04-19 devnull free(m);
329 a84cbb2a 2004-04-19 devnull }