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