Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 1 | // Inferno libmach/executable.c |
| 2 | // http://code.google.com/p/inferno-os/source/browse/utils/libmach/executable.c |
| 3 | // |
Russ Cox | 133a158 | 2009-10-03 10:37:12 -0700 | [diff] [blame] | 4 | // Copyright © 1994-1999 Lucent Technologies Inc. |
| 5 | // Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net). |
| 6 | // Portions Copyright © 1997-1999 Vita Nuova Limited. |
| 7 | // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). |
| 8 | // Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others. |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 9 | // Portions Copyright © 2009 The Go Authors. All rights reserved. |
| 10 | // |
| 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy |
| 12 | // of this software and associated documentation files (the "Software"), to deal |
| 13 | // in the Software without restriction, including without limitation the rights |
| 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 15 | // copies of the Software, and to permit persons to whom the Software is |
| 16 | // furnished to do so, subject to the following conditions: |
| 17 | // |
| 18 | // The above copyright notice and this permission notice shall be included in |
| 19 | // all copies or substantial portions of the Software. |
| 20 | // |
| 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| 27 | // THE SOFTWARE. |
| 28 | |
| 29 | #include <u.h> |
| 30 | #include <libc.h> |
| 31 | #include <bio.h> |
| 32 | #include <bootexec.h> |
Rob Pike | 00274a1 | 2009-08-14 10:46:04 -0700 | [diff] [blame] | 33 | #include <mach.h> |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 34 | #include "elf.h" |
Rob Pike | 073486c | 2008-06-15 17:22:57 -0700 | [diff] [blame] | 35 | #include "macho.h" |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 36 | |
| 37 | /* |
| 38 | * All a.out header types. The dummy entry allows canonical |
Russ Cox | 9aad9fe | 2008-08-03 17:25:15 -0700 | [diff] [blame] | 39 | * processing of the union as a sequence of int32s |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 40 | */ |
| 41 | |
| 42 | typedef struct { |
| 43 | union{ |
| 44 | /*struct { */ |
| 45 | Exec exechdr; /* a.out.h */ |
| 46 | /* uvlong hdr[1];*/ |
| 47 | /*};*/ |
| 48 | Ehdr32 elfhdr32; /* elf.h */ |
| 49 | Ehdr64 elfhdr64; /* elf.h */ |
| 50 | struct mipsexec mips; /* bootexec.h */ |
| 51 | struct mips4kexec mipsk4; /* bootexec.h */ |
| 52 | struct sparcexec sparc; /* bootexec.h */ |
| 53 | struct nextexec next; /* bootexec.h */ |
Rob Pike | 073486c | 2008-06-15 17:22:57 -0700 | [diff] [blame] | 54 | Machhdr machhdr; /* macho.h */ |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 55 | } e; |
Russ Cox | 9aad9fe | 2008-08-03 17:25:15 -0700 | [diff] [blame] | 56 | int32 dummy; /* padding to ensure extra int32 */ |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 57 | } ExecHdr; |
| 58 | |
| 59 | static int nextboot(int, Fhdr*, ExecHdr*); |
| 60 | static int sparcboot(int, Fhdr*, ExecHdr*); |
| 61 | static int mipsboot(int, Fhdr*, ExecHdr*); |
| 62 | static int mips4kboot(int, Fhdr*, ExecHdr*); |
| 63 | static int common(int, Fhdr*, ExecHdr*); |
| 64 | static int commonllp64(int, Fhdr*, ExecHdr*); |
| 65 | static int adotout(int, Fhdr*, ExecHdr*); |
| 66 | static int elfdotout(int, Fhdr*, ExecHdr*); |
Rob Pike | 073486c | 2008-06-15 17:22:57 -0700 | [diff] [blame] | 67 | static int machdotout(int, Fhdr*, ExecHdr*); |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 68 | static int armdotout(int, Fhdr*, ExecHdr*); |
Mateusz Czapliński | eae0a48 | 2011-08-29 14:25:43 -0400 | [diff] [blame] | 69 | static int pedotout(int, Fhdr*, ExecHdr*); |
Russ Cox | 19fd5c7 | 2010-10-19 18:07:19 -0400 | [diff] [blame] | 70 | static void setsym(Fhdr*, vlong, int32, vlong, int32, vlong, int32); |
Russ Cox | 9aad9fe | 2008-08-03 17:25:15 -0700 | [diff] [blame] | 71 | static void setdata(Fhdr*, uvlong, int32, vlong, int32); |
| 72 | static void settext(Fhdr*, uvlong, uvlong, int32, vlong); |
| 73 | static void hswal(void*, int, uint32(*)(uint32)); |
| 74 | static uvlong _round(uvlong, uint32); |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 75 | |
| 76 | /* |
| 77 | * definition of per-executable file type structures |
| 78 | */ |
| 79 | |
| 80 | typedef struct Exectable{ |
Russ Cox | 9aad9fe | 2008-08-03 17:25:15 -0700 | [diff] [blame] | 81 | int32 magic; /* big-endian magic number of file */ |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 82 | char *name; /* executable identifier */ |
| 83 | char *dlmname; /* dynamically loadable module identifier */ |
| 84 | uchar type; /* Internal code */ |
| 85 | uchar _magic; /* _MAGIC() magic */ |
| 86 | Mach *mach; /* Per-machine data */ |
Russ Cox | 9aad9fe | 2008-08-03 17:25:15 -0700 | [diff] [blame] | 87 | int32 hsize; /* header size */ |
| 88 | uint32 (*swal)(uint32); /* beswal or leswal */ |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 89 | int (*hparse)(int, Fhdr*, ExecHdr*); |
| 90 | } ExecTable; |
| 91 | |
| 92 | extern Mach mmips; |
| 93 | extern Mach mmips2le; |
| 94 | extern Mach mmips2be; |
| 95 | extern Mach msparc; |
| 96 | extern Mach msparc64; |
| 97 | extern Mach m68020; |
| 98 | extern Mach mi386; |
| 99 | extern Mach mamd64; |
| 100 | extern Mach marm; |
| 101 | extern Mach mpower; |
| 102 | extern Mach mpower64; |
| 103 | extern Mach malpha; |
| 104 | |
| 105 | /* BUG: FIX THESE WHEN NEEDED */ |
| 106 | Mach mmips; |
| 107 | Mach mmips2le; |
| 108 | Mach mmips2be; |
| 109 | Mach msparc; |
| 110 | Mach msparc64; |
| 111 | Mach m68020; |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 112 | Mach mpower; |
| 113 | Mach mpower64; |
| 114 | Mach malpha; |
| 115 | |
| 116 | ExecTable exectab[] = |
| 117 | { |
| 118 | { V_MAGIC, /* Mips v.out */ |
| 119 | "mips plan 9 executable BE", |
| 120 | "mips plan 9 dlm BE", |
| 121 | FMIPS, |
| 122 | 1, |
| 123 | &mmips, |
| 124 | sizeof(Exec), |
| 125 | beswal, |
| 126 | adotout }, |
| 127 | { P_MAGIC, /* Mips 0.out (r3k le) */ |
| 128 | "mips plan 9 executable LE", |
| 129 | "mips plan 9 dlm LE", |
| 130 | FMIPSLE, |
| 131 | 1, |
| 132 | &mmips, |
| 133 | sizeof(Exec), |
| 134 | beswal, |
| 135 | adotout }, |
| 136 | { M_MAGIC, /* Mips 4.out */ |
| 137 | "mips 4k plan 9 executable BE", |
| 138 | "mips 4k plan 9 dlm BE", |
| 139 | FMIPS2BE, |
| 140 | 1, |
| 141 | &mmips2be, |
| 142 | sizeof(Exec), |
| 143 | beswal, |
| 144 | adotout }, |
| 145 | { N_MAGIC, /* Mips 0.out */ |
| 146 | "mips 4k plan 9 executable LE", |
| 147 | "mips 4k plan 9 dlm LE", |
| 148 | FMIPS2LE, |
| 149 | 1, |
| 150 | &mmips2le, |
| 151 | sizeof(Exec), |
| 152 | beswal, |
| 153 | adotout }, |
| 154 | { 0x160<<16, /* Mips boot image */ |
| 155 | "mips plan 9 boot image", |
| 156 | nil, |
| 157 | FMIPSB, |
| 158 | 0, |
| 159 | &mmips, |
| 160 | sizeof(struct mipsexec), |
| 161 | beswal, |
| 162 | mipsboot }, |
| 163 | { (0x160<<16)|3, /* Mips boot image */ |
| 164 | "mips 4k plan 9 boot image", |
| 165 | nil, |
| 166 | FMIPSB, |
| 167 | 0, |
| 168 | &mmips2be, |
| 169 | sizeof(struct mips4kexec), |
| 170 | beswal, |
| 171 | mips4kboot }, |
| 172 | { K_MAGIC, /* Sparc k.out */ |
| 173 | "sparc plan 9 executable", |
| 174 | "sparc plan 9 dlm", |
| 175 | FSPARC, |
| 176 | 1, |
| 177 | &msparc, |
| 178 | sizeof(Exec), |
| 179 | beswal, |
| 180 | adotout }, |
| 181 | { 0x01030107, /* Sparc boot image */ |
| 182 | "sparc plan 9 boot image", |
| 183 | nil, |
| 184 | FSPARCB, |
| 185 | 0, |
| 186 | &msparc, |
| 187 | sizeof(struct sparcexec), |
| 188 | beswal, |
| 189 | sparcboot }, |
| 190 | { U_MAGIC, /* Sparc64 u.out */ |
| 191 | "sparc64 plan 9 executable", |
| 192 | "sparc64 plan 9 dlm", |
| 193 | FSPARC64, |
| 194 | 1, |
| 195 | &msparc64, |
| 196 | sizeof(Exec), |
| 197 | beswal, |
| 198 | adotout }, |
| 199 | { A_MAGIC, /* 68020 2.out & boot image */ |
| 200 | "68020 plan 9 executable", |
| 201 | "68020 plan 9 dlm", |
| 202 | F68020, |
| 203 | 1, |
| 204 | &m68020, |
| 205 | sizeof(Exec), |
| 206 | beswal, |
| 207 | common }, |
| 208 | { 0xFEEDFACE, /* Next boot image */ |
| 209 | "next plan 9 boot image", |
| 210 | nil, |
| 211 | FNEXTB, |
| 212 | 0, |
| 213 | &m68020, |
| 214 | sizeof(struct nextexec), |
| 215 | beswal, |
| 216 | nextboot }, |
| 217 | { I_MAGIC, /* I386 8.out & boot image */ |
| 218 | "386 plan 9 executable", |
| 219 | "386 plan 9 dlm", |
| 220 | FI386, |
| 221 | 1, |
| 222 | &mi386, |
| 223 | sizeof(Exec), |
| 224 | beswal, |
| 225 | common }, |
| 226 | { S_MAGIC, /* amd64 6.out & boot image */ |
| 227 | "amd64 plan 9 executable", |
| 228 | "amd64 plan 9 dlm", |
| 229 | FAMD64, |
| 230 | 1, |
| 231 | &mamd64, |
| 232 | sizeof(Exec)+8, |
| 233 | nil, |
| 234 | commonllp64 }, |
| 235 | { Q_MAGIC, /* PowerPC q.out & boot image */ |
| 236 | "power plan 9 executable", |
| 237 | "power plan 9 dlm", |
| 238 | FPOWER, |
| 239 | 1, |
| 240 | &mpower, |
| 241 | sizeof(Exec), |
| 242 | beswal, |
| 243 | common }, |
| 244 | { T_MAGIC, /* power64 9.out & boot image */ |
| 245 | "power64 plan 9 executable", |
| 246 | "power64 plan 9 dlm", |
| 247 | FPOWER64, |
| 248 | 1, |
| 249 | &mpower64, |
| 250 | sizeof(Exec)+8, |
| 251 | nil, |
| 252 | commonllp64 }, |
| 253 | { ELF_MAG, /* any elf32 or elf64 */ |
| 254 | "elf executable", |
| 255 | nil, |
| 256 | FNONE, |
| 257 | 0, |
| 258 | &mi386, |
| 259 | sizeof(Ehdr64), |
| 260 | nil, |
| 261 | elfdotout }, |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 262 | { MACH64_MAG, /* 64-bit MACH (apple mac) */ |
Rob Pike | 073486c | 2008-06-15 17:22:57 -0700 | [diff] [blame] | 263 | "mach executable", |
| 264 | nil, |
| 265 | FAMD64, |
| 266 | 0, |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 267 | &mamd64, |
| 268 | sizeof(Machhdr), |
| 269 | nil, |
| 270 | machdotout }, |
Rob Pike | 00274a1 | 2009-08-14 10:46:04 -0700 | [diff] [blame] | 271 | { MACH32_MAG, /* 32-bit MACH (apple mac) */ |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 272 | "mach executable", |
| 273 | nil, |
| 274 | FI386, |
| 275 | 0, |
Rob Pike | 073486c | 2008-06-15 17:22:57 -0700 | [diff] [blame] | 276 | &mi386, |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 277 | sizeof(Machhdr), |
Rob Pike | 073486c | 2008-06-15 17:22:57 -0700 | [diff] [blame] | 278 | nil, |
| 279 | machdotout }, |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 280 | { E_MAGIC, /* Arm 5.out and boot image */ |
| 281 | "arm plan 9 executable", |
| 282 | "arm plan 9 dlm", |
| 283 | FARM, |
| 284 | 1, |
| 285 | &marm, |
| 286 | sizeof(Exec), |
| 287 | beswal, |
| 288 | common }, |
| 289 | { (143<<16)|0413, /* (Free|Net)BSD Arm */ |
| 290 | "arm *bsd executable", |
| 291 | nil, |
| 292 | FARM, |
| 293 | 0, |
| 294 | &marm, |
| 295 | sizeof(Exec), |
| 296 | leswal, |
| 297 | armdotout }, |
| 298 | { L_MAGIC, /* alpha 7.out */ |
| 299 | "alpha plan 9 executable", |
| 300 | "alpha plan 9 dlm", |
| 301 | FALPHA, |
| 302 | 1, |
| 303 | &malpha, |
| 304 | sizeof(Exec), |
| 305 | beswal, |
| 306 | common }, |
| 307 | { 0x0700e0c3, /* alpha boot image */ |
| 308 | "alpha plan 9 boot image", |
| 309 | nil, |
| 310 | FALPHA, |
| 311 | 0, |
| 312 | &malpha, |
| 313 | sizeof(Exec), |
| 314 | beswal, |
| 315 | common }, |
Mateusz Czapliński | eae0a48 | 2011-08-29 14:25:43 -0400 | [diff] [blame] | 316 | { 0x4d5a9000, /* see dosstub[] in pe.c */ |
| 317 | "windows PE executable", |
| 318 | nil, |
| 319 | FWINPE, |
| 320 | 0, |
| 321 | &mi386, |
| 322 | sizeof(Exec), /* TODO */ |
| 323 | nil, |
| 324 | pedotout }, |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 325 | { 0 }, |
| 326 | }; |
| 327 | |
| 328 | Mach *mach = &mi386; /* Global current machine table */ |
| 329 | |
| 330 | static ExecTable* |
| 331 | couldbe4k(ExecTable *mp) |
| 332 | { |
| 333 | Dir *d; |
| 334 | ExecTable *f; |
| 335 | |
| 336 | if((d=dirstat("/proc/1/regs")) == nil) |
| 337 | return mp; |
| 338 | if(d->length < 32*8){ /* R3000 */ |
| 339 | free(d); |
| 340 | return mp; |
| 341 | } |
| 342 | free(d); |
| 343 | for (f = exectab; f->magic; f++) |
| 344 | if(f->magic == M_MAGIC) { |
| 345 | f->name = "mips plan 9 executable on mips2 kernel"; |
| 346 | return f; |
| 347 | } |
| 348 | return mp; |
| 349 | } |
| 350 | |
| 351 | int |
| 352 | crackhdr(int fd, Fhdr *fp) |
| 353 | { |
| 354 | ExecTable *mp; |
| 355 | ExecHdr d; |
| 356 | int nb, ret; |
Russ Cox | 9aad9fe | 2008-08-03 17:25:15 -0700 | [diff] [blame] | 357 | uint32 magic; |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 358 | |
| 359 | fp->type = FNONE; |
| 360 | nb = read(fd, (char *)&d.e, sizeof(d.e)); |
| 361 | if (nb <= 0) |
| 362 | return 0; |
| 363 | |
| 364 | ret = 0; |
| 365 | magic = beswal(d.e.exechdr.magic); /* big-endian */ |
| 366 | for (mp = exectab; mp->magic; mp++) { |
| 367 | if (nb < mp->hsize) |
| 368 | continue; |
| 369 | |
| 370 | /* |
| 371 | * The magic number has morphed into something |
| 372 | * with fields (the straw was DYN_MAGIC) so now |
| 373 | * a flag is needed in Fhdr to distinguish _MAGIC() |
| 374 | * magic numbers from foreign magic numbers. |
| 375 | * |
| 376 | * This code is creaking a bit and if it has to |
| 377 | * be modified/extended much more it's probably |
| 378 | * time to step back and redo it all. |
| 379 | */ |
| 380 | if(mp->_magic){ |
| 381 | if(mp->magic != (magic & ~DYN_MAGIC)) |
| 382 | continue; |
| 383 | |
| 384 | if(mp->magic == V_MAGIC) |
| 385 | mp = couldbe4k(mp); |
| 386 | |
| 387 | if ((magic & DYN_MAGIC) && mp->dlmname != nil) |
| 388 | fp->name = mp->dlmname; |
| 389 | else |
| 390 | fp->name = mp->name; |
| 391 | } |
| 392 | else{ |
| 393 | if(mp->magic != magic) |
| 394 | continue; |
| 395 | fp->name = mp->name; |
| 396 | } |
| 397 | fp->type = mp->type; |
| 398 | fp->hdrsz = mp->hsize; /* will be zero on bootables */ |
| 399 | fp->_magic = mp->_magic; |
| 400 | fp->magic = magic; |
| 401 | |
| 402 | mach = mp->mach; |
| 403 | if(mp->swal != nil) |
Russ Cox | 9aad9fe | 2008-08-03 17:25:15 -0700 | [diff] [blame] | 404 | hswal(&d, sizeof(d.e)/sizeof(uint32), mp->swal); |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 405 | ret = mp->hparse(fd, fp, &d); |
| 406 | seek(fd, mp->hsize, 0); /* seek to end of header */ |
| 407 | break; |
| 408 | } |
| 409 | if(mp->magic == 0) |
| 410 | werrstr("unknown header type"); |
| 411 | return ret; |
| 412 | } |
| 413 | |
| 414 | /* |
| 415 | * Convert header to canonical form |
| 416 | */ |
| 417 | static void |
Russ Cox | 9aad9fe | 2008-08-03 17:25:15 -0700 | [diff] [blame] | 418 | hswal(void *v, int n, uint32 (*swap)(uint32)) |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 419 | { |
Russ Cox | 9aad9fe | 2008-08-03 17:25:15 -0700 | [diff] [blame] | 420 | uint32 *ulp; |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 421 | |
| 422 | for(ulp = v; n--; ulp++) |
| 423 | *ulp = (*swap)(*ulp); |
| 424 | } |
| 425 | |
| 426 | /* |
| 427 | * Crack a normal a.out-type header |
| 428 | */ |
| 429 | static int |
| 430 | adotout(int fd, Fhdr *fp, ExecHdr *hp) |
| 431 | { |
Russ Cox | 9aad9fe | 2008-08-03 17:25:15 -0700 | [diff] [blame] | 432 | int32 pgsize; |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 433 | |
| 434 | USED(fd); |
| 435 | pgsize = mach->pgsize; |
| 436 | settext(fp, hp->e.exechdr.entry, pgsize+sizeof(Exec), |
| 437 | hp->e.exechdr.text, sizeof(Exec)); |
| 438 | setdata(fp, _round(pgsize+fp->txtsz+sizeof(Exec), pgsize), |
| 439 | hp->e.exechdr.data, fp->txtsz+sizeof(Exec), hp->e.exechdr.bss); |
Russ Cox | 19fd5c7 | 2010-10-19 18:07:19 -0400 | [diff] [blame] | 440 | setsym(fp, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz); |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 441 | return 1; |
| 442 | } |
| 443 | |
| 444 | static void |
| 445 | commonboot(Fhdr *fp) |
| 446 | { |
| 447 | if (!(fp->entry & mach->ktmask)) |
| 448 | return; |
| 449 | |
| 450 | switch(fp->type) { /* boot image */ |
| 451 | case F68020: |
| 452 | fp->type = F68020B; |
| 453 | fp->name = "68020 plan 9 boot image"; |
| 454 | break; |
| 455 | case FI386: |
| 456 | fp->type = FI386B; |
| 457 | fp->txtaddr = (u32int)fp->entry; |
| 458 | fp->name = "386 plan 9 boot image"; |
| 459 | fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize); |
| 460 | break; |
| 461 | case FARM: |
| 462 | fp->type = FARMB; |
| 463 | fp->txtaddr = (u32int)fp->entry; |
| 464 | fp->name = "ARM plan 9 boot image"; |
| 465 | fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize); |
| 466 | return; |
| 467 | case FALPHA: |
| 468 | fp->type = FALPHAB; |
| 469 | fp->txtaddr = (u32int)fp->entry; |
| 470 | fp->name = "alpha plan 9 boot image"; |
| 471 | fp->dataddr = fp->txtaddr+fp->txtsz; |
| 472 | break; |
| 473 | case FPOWER: |
| 474 | fp->type = FPOWERB; |
| 475 | fp->txtaddr = (u32int)fp->entry; |
| 476 | fp->name = "power plan 9 boot image"; |
| 477 | fp->dataddr = fp->txtaddr+fp->txtsz; |
| 478 | break; |
| 479 | case FAMD64: |
| 480 | fp->type = FAMD64B; |
| 481 | fp->txtaddr = fp->entry; |
| 482 | fp->name = "amd64 plan 9 boot image"; |
| 483 | fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize); |
| 484 | break; |
| 485 | default: |
| 486 | return; |
| 487 | } |
| 488 | fp->hdrsz = 0; /* header stripped */ |
| 489 | } |
| 490 | |
| 491 | /* |
| 492 | * _MAGIC() style headers and |
| 493 | * alpha plan9-style bootable images for axp "headerless" boot |
| 494 | * |
| 495 | */ |
| 496 | static int |
| 497 | common(int fd, Fhdr *fp, ExecHdr *hp) |
| 498 | { |
| 499 | adotout(fd, fp, hp); |
| 500 | if(hp->e.exechdr.magic & DYN_MAGIC) { |
| 501 | fp->txtaddr = 0; |
| 502 | fp->dataddr = fp->txtsz; |
| 503 | return 1; |
| 504 | } |
| 505 | commonboot(fp); |
| 506 | return 1; |
| 507 | } |
| 508 | |
| 509 | static int |
| 510 | commonllp64(int unused, Fhdr *fp, ExecHdr *hp) |
| 511 | { |
Russ Cox | 9aad9fe | 2008-08-03 17:25:15 -0700 | [diff] [blame] | 512 | int32 pgsize; |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 513 | uvlong entry; |
| 514 | |
Russ Cox | 55db9fe | 2011-08-25 16:08:13 -0400 | [diff] [blame] | 515 | USED(unused); |
| 516 | |
Russ Cox | 9aad9fe | 2008-08-03 17:25:15 -0700 | [diff] [blame] | 517 | hswal(&hp->e, sizeof(Exec)/sizeof(int32), beswal); |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 518 | if(!(hp->e.exechdr.magic & HDR_MAGIC)) |
| 519 | return 0; |
| 520 | |
| 521 | /* |
| 522 | * There can be more magic here if the |
| 523 | * header ever needs more expansion. |
| 524 | * For now just catch use of any of the |
| 525 | * unused bits. |
| 526 | */ |
| 527 | if((hp->e.exechdr.magic & ~DYN_MAGIC)>>16) |
| 528 | return 0; |
Russ Cox | 219fb02 | 2009-10-22 10:59:27 -0700 | [diff] [blame] | 529 | union { |
| 530 | char *p; |
| 531 | uvlong *v; |
| 532 | } u; |
| 533 | u.p = (char*)&hp->e.exechdr; |
| 534 | entry = beswav(*u.v); |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 535 | |
| 536 | pgsize = mach->pgsize; |
| 537 | settext(fp, entry, pgsize+fp->hdrsz, hp->e.exechdr.text, fp->hdrsz); |
| 538 | setdata(fp, _round(pgsize+fp->txtsz+fp->hdrsz, pgsize), |
| 539 | hp->e.exechdr.data, fp->txtsz+fp->hdrsz, hp->e.exechdr.bss); |
Russ Cox | 19fd5c7 | 2010-10-19 18:07:19 -0400 | [diff] [blame] | 540 | setsym(fp, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz); |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 541 | |
| 542 | if(hp->e.exechdr.magic & DYN_MAGIC) { |
| 543 | fp->txtaddr = 0; |
| 544 | fp->dataddr = fp->txtsz; |
| 545 | return 1; |
| 546 | } |
| 547 | commonboot(fp); |
| 548 | return 1; |
| 549 | } |
| 550 | |
| 551 | /* |
| 552 | * mips bootable image. |
| 553 | */ |
| 554 | static int |
| 555 | mipsboot(int fd, Fhdr *fp, ExecHdr *hp) |
| 556 | { |
Russ Cox | 55db9fe | 2011-08-25 16:08:13 -0400 | [diff] [blame] | 557 | USED(fd); |
| 558 | USED(fp); |
| 559 | USED(hp); |
| 560 | |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 561 | abort(); |
| 562 | #ifdef unused |
| 563 | USED(fd); |
| 564 | fp->type = FMIPSB; |
| 565 | switch(hp->e.exechdr.amagic) { |
| 566 | default: |
| 567 | case 0407: /* some kind of mips */ |
| 568 | settext(fp, (u32int)hp->e.mentry, (u32int)hp->e.text_start, |
| 569 | hp->e.tsize, sizeof(struct mipsexec)+4); |
| 570 | setdata(fp, (u32int)hp->e.data_start, hp->e.dsize, |
| 571 | fp->txtoff+hp->e.tsize, hp->e.bsize); |
| 572 | break; |
| 573 | case 0413: /* some kind of mips */ |
| 574 | settext(fp, (u32int)hp->e.mentry, (u32int)hp->e.text_start, |
| 575 | hp->e.tsize, 0); |
| 576 | setdata(fp, (u32int)hp->e.data_start, hp->e.dsize, |
| 577 | hp->e.tsize, hp->e.bsize); |
| 578 | break; |
| 579 | } |
| 580 | setsym(fp, hp->e.nsyms, 0, hp->e.pcsize, hp->e.symptr); |
| 581 | fp->hdrsz = 0; /* header stripped */ |
| 582 | #endif |
| 583 | return 1; |
| 584 | } |
| 585 | |
| 586 | /* |
| 587 | * mips4k bootable image. |
| 588 | */ |
| 589 | static int |
| 590 | mips4kboot(int fd, Fhdr *fp, ExecHdr *hp) |
| 591 | { |
Russ Cox | 55db9fe | 2011-08-25 16:08:13 -0400 | [diff] [blame] | 592 | USED(fd); |
| 593 | USED(fp); |
| 594 | USED(hp); |
| 595 | |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 596 | abort(); |
| 597 | #ifdef unused |
| 598 | USED(fd); |
| 599 | fp->type = FMIPSB; |
| 600 | switch(hp->e.h.amagic) { |
| 601 | default: |
| 602 | case 0407: /* some kind of mips */ |
| 603 | settext(fp, (u32int)hp->e.h.mentry, (u32int)hp->e.h.text_start, |
| 604 | hp->e.h.tsize, sizeof(struct mips4kexec)); |
| 605 | setdata(fp, (u32int)hp->e.h.data_start, hp->e.h.dsize, |
| 606 | fp->txtoff+hp->e.h.tsize, hp->e.h.bsize); |
| 607 | break; |
| 608 | case 0413: /* some kind of mips */ |
| 609 | settext(fp, (u32int)hp->e.h.mentry, (u32int)hp->e.h.text_start, |
| 610 | hp->e.h.tsize, 0); |
| 611 | setdata(fp, (u32int)hp->e.h.data_start, hp->e.h.dsize, |
| 612 | hp->e.h.tsize, hp->e.h.bsize); |
| 613 | break; |
| 614 | } |
| 615 | setsym(fp, hp->e.h.nsyms, 0, hp->e.h.pcsize, hp->e.h.symptr); |
| 616 | fp->hdrsz = 0; /* header stripped */ |
| 617 | #endif |
| 618 | return 1; |
| 619 | } |
| 620 | |
| 621 | /* |
| 622 | * sparc bootable image |
| 623 | */ |
| 624 | static int |
| 625 | sparcboot(int fd, Fhdr *fp, ExecHdr *hp) |
| 626 | { |
Russ Cox | 55db9fe | 2011-08-25 16:08:13 -0400 | [diff] [blame] | 627 | USED(fd); |
| 628 | USED(fp); |
| 629 | USED(hp); |
| 630 | |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 631 | abort(); |
| 632 | #ifdef unused |
| 633 | USED(fd); |
| 634 | fp->type = FSPARCB; |
| 635 | settext(fp, hp->e.sentry, hp->e.sentry, hp->e.stext, |
| 636 | sizeof(struct sparcexec)); |
| 637 | setdata(fp, hp->e.sentry+hp->e.stext, hp->e.sdata, |
| 638 | fp->txtoff+hp->e.stext, hp->e.sbss); |
| 639 | setsym(fp, hp->e.ssyms, 0, hp->e.sdrsize, fp->datoff+hp->e.sdata); |
| 640 | fp->hdrsz = 0; /* header stripped */ |
| 641 | #endif |
| 642 | return 1; |
| 643 | } |
| 644 | |
| 645 | /* |
| 646 | * next bootable image |
| 647 | */ |
| 648 | static int |
| 649 | nextboot(int fd, Fhdr *fp, ExecHdr *hp) |
| 650 | { |
Russ Cox | 55db9fe | 2011-08-25 16:08:13 -0400 | [diff] [blame] | 651 | USED(fd); |
| 652 | USED(fp); |
| 653 | USED(hp); |
| 654 | |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 655 | abort(); |
| 656 | #ifdef unused |
| 657 | USED(fd); |
| 658 | fp->type = FNEXTB; |
| 659 | settext(fp, hp->e.textc.vmaddr, hp->e.textc.vmaddr, |
| 660 | hp->e.texts.size, hp->e.texts.offset); |
| 661 | setdata(fp, hp->e.datac.vmaddr, hp->e.datas.size, |
| 662 | hp->e.datas.offset, hp->e.bsss.size); |
| 663 | setsym(fp, hp->e.symc.nsyms, hp->e.symc.spoff, hp->e.symc.pcoff, |
| 664 | hp->e.symc.symoff); |
| 665 | fp->hdrsz = 0; /* header stripped */ |
| 666 | #endif |
| 667 | return 1; |
| 668 | } |
| 669 | |
| 670 | /* |
| 671 | * Elf32 and Elf64 binaries. |
| 672 | */ |
| 673 | static int |
| 674 | elf64dotout(int fd, Fhdr *fp, ExecHdr *hp) |
| 675 | { |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 676 | uvlong (*swav)(uvlong); |
Russ Cox | 9aad9fe | 2008-08-03 17:25:15 -0700 | [diff] [blame] | 677 | uint32 (*swal)(uint32); |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 678 | ushort (*swab)(ushort); |
| 679 | Ehdr64 *ep; |
Lucio De Re | 7f417d8 | 2011-11-18 23:11:50 -0500 | [diff] [blame] | 680 | Phdr64 *ph, *pph; |
Rob Pike | 34691cc | 2008-06-13 12:55:37 -0700 | [diff] [blame] | 681 | Shdr64 *sh; |
| 682 | int i, it, id, is, phsz, shsz; |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 683 | |
| 684 | /* bitswap the header according to the DATA format */ |
| 685 | ep = &hp->e.elfhdr64; |
| 686 | if(ep->ident[CLASS] != ELFCLASS64) { |
| 687 | werrstr("bad ELF class - not 32 bit or 64 bit"); |
| 688 | return 0; |
| 689 | } |
| 690 | if(ep->ident[DATA] == ELFDATA2LSB) { |
| 691 | swab = leswab; |
| 692 | swal = leswal; |
| 693 | swav = leswav; |
| 694 | } else if(ep->ident[DATA] == ELFDATA2MSB) { |
| 695 | swab = beswab; |
| 696 | swal = beswal; |
| 697 | swav = beswav; |
| 698 | } else { |
| 699 | werrstr("bad ELF encoding - not big or little endian"); |
| 700 | return 0; |
| 701 | } |
| 702 | |
| 703 | ep->type = swab(ep->type); |
| 704 | ep->machine = swab(ep->machine); |
| 705 | ep->version = swal(ep->version); |
| 706 | ep->elfentry = swal(ep->elfentry); |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 707 | ep->phoff = swav(ep->phoff); |
| 708 | ep->shoff = swav(ep->shoff); |
| 709 | ep->flags = swav(ep->flags); |
| 710 | ep->ehsize = swab(ep->ehsize); |
| 711 | ep->phentsize = swab(ep->phentsize); |
| 712 | ep->phnum = swab(ep->phnum); |
| 713 | ep->shentsize = swab(ep->shentsize); |
| 714 | ep->shnum = swab(ep->shnum); |
| 715 | ep->shstrndx = swab(ep->shstrndx); |
| 716 | if(ep->type != EXEC || ep->version != CURRENT) |
| 717 | return 0; |
| 718 | |
| 719 | /* we could definitely support a lot more machines here */ |
| 720 | fp->magic = ELF_MAG; |
| 721 | fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15; |
| 722 | switch(ep->machine) { |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 723 | case AMD64: |
| 724 | mach = &mamd64; |
| 725 | fp->type = FAMD64; |
| 726 | break; |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 727 | default: |
| 728 | return 0; |
| 729 | } |
| 730 | |
| 731 | if(ep->phentsize != sizeof(Phdr64)) { |
| 732 | werrstr("bad ELF header size"); |
| 733 | return 0; |
| 734 | } |
| 735 | phsz = sizeof(Phdr64)*ep->phnum; |
| 736 | ph = malloc(phsz); |
| 737 | if(!ph) |
| 738 | return 0; |
| 739 | seek(fd, ep->phoff, 0); |
| 740 | if(read(fd, ph, phsz) < 0) { |
| 741 | free(ph); |
| 742 | return 0; |
| 743 | } |
Russ Cox | 9aad9fe | 2008-08-03 17:25:15 -0700 | [diff] [blame] | 744 | hswal(ph, phsz/sizeof(uint32), swal); |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 745 | |
Rob Pike | 34691cc | 2008-06-13 12:55:37 -0700 | [diff] [blame] | 746 | shsz = sizeof(Shdr64)*ep->shnum; |
| 747 | sh = malloc(shsz); |
| 748 | if(sh) { |
| 749 | seek(fd, ep->shoff, 0); |
| 750 | if(read(fd, sh, shsz) < 0) { |
| 751 | free(sh); |
| 752 | sh = 0; |
| 753 | } else |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 754 | hswal(sh, shsz/sizeof(uint32), swal); |
Rob Pike | 34691cc | 2008-06-13 12:55:37 -0700 | [diff] [blame] | 755 | } |
| 756 | |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 757 | /* find text, data and symbols and install them */ |
| 758 | it = id = is = -1; |
| 759 | for(i = 0; i < ep->phnum; i++) { |
| 760 | if(ph[i].type == LOAD |
| 761 | && (ph[i].flags & (R|X)) == (R|X) && it == -1) |
| 762 | it = i; |
| 763 | else if(ph[i].type == LOAD |
| 764 | && (ph[i].flags & (R|W)) == (R|W) && id == -1) |
| 765 | id = i; |
| 766 | else if(ph[i].type == NOPTYPE && is == -1) |
| 767 | is = i; |
| 768 | } |
| 769 | if(it == -1 || id == -1) { |
| 770 | /* |
| 771 | * The SPARC64 boot image is something of an ELF hack. |
| 772 | * Text+Data+BSS are represented by ph[0]. Symbols |
| 773 | * are represented by ph[1]: |
| 774 | * |
| 775 | * filesz, memsz, vaddr, paddr, off |
| 776 | * ph[0] : txtsz+datsz, txtsz+datsz+bsssz, txtaddr-KZERO, datasize, txtoff |
| 777 | * ph[1] : symsz, lcsz, 0, 0, symoff |
| 778 | */ |
| 779 | if(ep->machine == SPARC64 && ep->phnum == 2) { |
Russ Cox | 9aad9fe | 2008-08-03 17:25:15 -0700 | [diff] [blame] | 780 | uint32 txtaddr, txtsz, dataddr, bsssz; |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 781 | |
| 782 | txtaddr = ph[0].vaddr | 0x80000000; |
| 783 | txtsz = ph[0].filesz - ph[0].paddr; |
| 784 | dataddr = txtaddr + txtsz; |
| 785 | bsssz = ph[0].memsz - ph[0].filesz; |
| 786 | settext(fp, ep->elfentry | 0x80000000, txtaddr, txtsz, ph[0].offset); |
| 787 | setdata(fp, dataddr, ph[0].paddr, ph[0].offset + txtsz, bsssz); |
Russ Cox | 19fd5c7 | 2010-10-19 18:07:19 -0400 | [diff] [blame] | 788 | setsym(fp, ph[1].offset, ph[1].filesz, 0, 0, 0, ph[1].memsz); |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 789 | free(ph); |
| 790 | return 1; |
| 791 | } |
| 792 | |
| 793 | werrstr("No TEXT or DATA sections"); |
| 794 | free(ph); |
Rob Pike | 34691cc | 2008-06-13 12:55:37 -0700 | [diff] [blame] | 795 | free(sh); |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 796 | return 0; |
| 797 | } |
| 798 | |
| 799 | settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset); |
Lucio De Re | 7f417d8 | 2011-11-18 23:11:50 -0500 | [diff] [blame] | 800 | pph = ph + id; |
| 801 | setdata(fp, pph->vaddr, pph->filesz, pph->offset, pph->memsz - pph->filesz); |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 802 | if(is != -1) |
Russ Cox | 19fd5c7 | 2010-10-19 18:07:19 -0400 | [diff] [blame] | 803 | setsym(fp, ph[is].offset, ph[is].filesz, 0, 0, 0, ph[is].memsz); |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 804 | else if(sh != 0){ |
Rob Pike | 34691cc | 2008-06-13 12:55:37 -0700 | [diff] [blame] | 805 | char *buf; |
| 806 | uvlong symsize = 0; |
| 807 | uvlong symoff = 0; |
| 808 | uvlong pclnsz = 0; |
Russ Cox | 19fd5c7 | 2010-10-19 18:07:19 -0400 | [diff] [blame] | 809 | uvlong pclnoff = 0; |
Rob Pike | 34691cc | 2008-06-13 12:55:37 -0700 | [diff] [blame] | 810 | |
| 811 | /* load shstrtab names */ |
| 812 | buf = malloc(sh[ep->shstrndx].size); |
| 813 | if (buf == 0) |
| 814 | goto done; |
Dave Cheney | ae502c4 | 2011-09-01 13:43:03 -0400 | [diff] [blame] | 815 | memset(buf, 0, sh[ep->shstrndx].size); |
Rob Pike | 34691cc | 2008-06-13 12:55:37 -0700 | [diff] [blame] | 816 | seek(fd, sh[ep->shstrndx].offset, 0); |
Russ Cox | 05cc83b | 2010-09-28 13:00:13 -0400 | [diff] [blame] | 817 | i = read(fd, buf, sh[ep->shstrndx].size); |
| 818 | USED(i); // shut up ubuntu gcc |
Rob Pike | 34691cc | 2008-06-13 12:55:37 -0700 | [diff] [blame] | 819 | |
| 820 | for(i = 0; i < ep->shnum; i++) { |
Russ Cox | 899c528 | 2008-09-18 15:06:14 -0700 | [diff] [blame] | 821 | if (strcmp(&buf[sh[i].name], ".gosymtab") == 0) { |
Rob Pike | 34691cc | 2008-06-13 12:55:37 -0700 | [diff] [blame] | 822 | symsize = sh[i].size; |
| 823 | symoff = sh[i].offset; |
| 824 | } |
Russ Cox | 899c528 | 2008-09-18 15:06:14 -0700 | [diff] [blame] | 825 | if (strcmp(&buf[sh[i].name], ".gopclntab") == 0) { |
Rob Pike | 34691cc | 2008-06-13 12:55:37 -0700 | [diff] [blame] | 826 | pclnsz = sh[i].size; |
Russ Cox | 19fd5c7 | 2010-10-19 18:07:19 -0400 | [diff] [blame] | 827 | pclnoff = sh[i].offset; |
Rob Pike | 34691cc | 2008-06-13 12:55:37 -0700 | [diff] [blame] | 828 | } |
| 829 | } |
Russ Cox | 19fd5c7 | 2010-10-19 18:07:19 -0400 | [diff] [blame] | 830 | setsym(fp, symoff, symsize, 0, 0, pclnoff, pclnsz); |
Rob Pike | 34691cc | 2008-06-13 12:55:37 -0700 | [diff] [blame] | 831 | free(buf); |
| 832 | } |
| 833 | done: |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 834 | free(ph); |
Rob Pike | 34691cc | 2008-06-13 12:55:37 -0700 | [diff] [blame] | 835 | free(sh); |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 836 | return 1; |
| 837 | } |
| 838 | |
| 839 | static int |
| 840 | elfdotout(int fd, Fhdr *fp, ExecHdr *hp) |
| 841 | { |
| 842 | |
Russ Cox | 9aad9fe | 2008-08-03 17:25:15 -0700 | [diff] [blame] | 843 | uint32 (*swal)(uint32); |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 844 | ushort (*swab)(ushort); |
| 845 | Ehdr32 *ep; |
| 846 | Phdr32 *ph; |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 847 | int i, it, id, is, phsz, shsz; |
| 848 | Shdr32 *sh; |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 849 | |
| 850 | /* bitswap the header according to the DATA format */ |
| 851 | ep = &hp->e.elfhdr32; |
| 852 | if(ep->ident[CLASS] != ELFCLASS32) { |
| 853 | return elf64dotout(fd, fp, hp); |
| 854 | } |
| 855 | if(ep->ident[DATA] == ELFDATA2LSB) { |
| 856 | swab = leswab; |
| 857 | swal = leswal; |
| 858 | } else if(ep->ident[DATA] == ELFDATA2MSB) { |
| 859 | swab = beswab; |
| 860 | swal = beswal; |
| 861 | } else { |
| 862 | werrstr("bad ELF encoding - not big or little endian"); |
| 863 | return 0; |
| 864 | } |
| 865 | |
| 866 | ep->type = swab(ep->type); |
| 867 | ep->machine = swab(ep->machine); |
| 868 | ep->version = swal(ep->version); |
| 869 | ep->elfentry = swal(ep->elfentry); |
| 870 | ep->phoff = swal(ep->phoff); |
| 871 | ep->shoff = swal(ep->shoff); |
| 872 | ep->flags = swal(ep->flags); |
| 873 | ep->ehsize = swab(ep->ehsize); |
| 874 | ep->phentsize = swab(ep->phentsize); |
| 875 | ep->phnum = swab(ep->phnum); |
| 876 | ep->shentsize = swab(ep->shentsize); |
| 877 | ep->shnum = swab(ep->shnum); |
| 878 | ep->shstrndx = swab(ep->shstrndx); |
| 879 | if(ep->type != EXEC || ep->version != CURRENT) |
| 880 | return 0; |
| 881 | |
| 882 | /* we could definitely support a lot more machines here */ |
| 883 | fp->magic = ELF_MAG; |
| 884 | fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15; |
| 885 | switch(ep->machine) { |
| 886 | case I386: |
| 887 | mach = &mi386; |
| 888 | fp->type = FI386; |
| 889 | break; |
| 890 | case MIPS: |
| 891 | mach = &mmips; |
| 892 | fp->type = FMIPS; |
| 893 | break; |
| 894 | case SPARC64: |
| 895 | mach = &msparc64; |
| 896 | fp->type = FSPARC64; |
| 897 | break; |
| 898 | case POWER: |
| 899 | mach = &mpower; |
| 900 | fp->type = FPOWER; |
| 901 | break; |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 902 | case ARM: |
| 903 | mach = &marm; |
| 904 | fp->type = FARM; |
| 905 | break; |
| 906 | default: |
| 907 | return 0; |
| 908 | } |
| 909 | |
| 910 | if(ep->phentsize != sizeof(Phdr32)) { |
| 911 | werrstr("bad ELF header size"); |
| 912 | return 0; |
| 913 | } |
| 914 | phsz = sizeof(Phdr32)*ep->phnum; |
| 915 | ph = malloc(phsz); |
| 916 | if(!ph) |
| 917 | return 0; |
| 918 | seek(fd, ep->phoff, 0); |
| 919 | if(read(fd, ph, phsz) < 0) { |
| 920 | free(ph); |
| 921 | return 0; |
| 922 | } |
Russ Cox | 9aad9fe | 2008-08-03 17:25:15 -0700 | [diff] [blame] | 923 | hswal(ph, phsz/sizeof(uint32), swal); |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 924 | |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 925 | shsz = sizeof(Shdr32)*ep->shnum; |
| 926 | sh = malloc(shsz); |
| 927 | if(sh) { |
| 928 | seek(fd, ep->shoff, 0); |
| 929 | if(read(fd, sh, shsz) < 0) { |
| 930 | free(sh); |
| 931 | sh = 0; |
| 932 | } else |
| 933 | hswal(sh, shsz/sizeof(uint32), swal); |
| 934 | } |
| 935 | |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 936 | /* find text, data and symbols and install them */ |
| 937 | it = id = is = -1; |
| 938 | for(i = 0; i < ep->phnum; i++) { |
| 939 | if(ph[i].type == LOAD |
| 940 | && (ph[i].flags & (R|X)) == (R|X) && it == -1) |
| 941 | it = i; |
| 942 | else if(ph[i].type == LOAD |
| 943 | && (ph[i].flags & (R|W)) == (R|W) && id == -1) |
| 944 | id = i; |
| 945 | else if(ph[i].type == NOPTYPE && is == -1) |
| 946 | is = i; |
| 947 | } |
| 948 | if(it == -1 || id == -1) { |
| 949 | /* |
| 950 | * The SPARC64 boot image is something of an ELF hack. |
| 951 | * Text+Data+BSS are represented by ph[0]. Symbols |
| 952 | * are represented by ph[1]: |
| 953 | * |
| 954 | * filesz, memsz, vaddr, paddr, off |
| 955 | * ph[0] : txtsz+datsz, txtsz+datsz+bsssz, txtaddr-KZERO, datasize, txtoff |
| 956 | * ph[1] : symsz, lcsz, 0, 0, symoff |
| 957 | */ |
| 958 | if(ep->machine == SPARC64 && ep->phnum == 2) { |
Russ Cox | 9aad9fe | 2008-08-03 17:25:15 -0700 | [diff] [blame] | 959 | uint32 txtaddr, txtsz, dataddr, bsssz; |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 960 | |
| 961 | txtaddr = ph[0].vaddr | 0x80000000; |
| 962 | txtsz = ph[0].filesz - ph[0].paddr; |
| 963 | dataddr = txtaddr + txtsz; |
| 964 | bsssz = ph[0].memsz - ph[0].filesz; |
| 965 | settext(fp, ep->elfentry | 0x80000000, txtaddr, txtsz, ph[0].offset); |
| 966 | setdata(fp, dataddr, ph[0].paddr, ph[0].offset + txtsz, bsssz); |
Russ Cox | 19fd5c7 | 2010-10-19 18:07:19 -0400 | [diff] [blame] | 967 | setsym(fp, ph[1].offset, ph[1].filesz, 0, 0, 0, ph[1].memsz); |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 968 | free(ph); |
| 969 | return 1; |
| 970 | } |
| 971 | |
| 972 | werrstr("No TEXT or DATA sections"); |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 973 | free(sh); |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 974 | free(ph); |
| 975 | return 0; |
| 976 | } |
| 977 | |
| 978 | settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset); |
| 979 | setdata(fp, ph[id].vaddr, ph[id].filesz, ph[id].offset, ph[id].memsz - ph[id].filesz); |
| 980 | if(is != -1) |
Russ Cox | 19fd5c7 | 2010-10-19 18:07:19 -0400 | [diff] [blame] | 981 | setsym(fp, ph[is].offset, ph[is].filesz, 0, 0, 0, ph[is].memsz); |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 982 | else if(sh != 0){ |
| 983 | char *buf; |
| 984 | uvlong symsize = 0; |
| 985 | uvlong symoff = 0; |
Russ Cox | 19fd5c7 | 2010-10-19 18:07:19 -0400 | [diff] [blame] | 986 | uvlong pclnsize = 0; |
| 987 | uvlong pclnoff = 0; |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 988 | |
| 989 | /* load shstrtab names */ |
| 990 | buf = malloc(sh[ep->shstrndx].size); |
| 991 | if (buf == 0) |
| 992 | goto done; |
Dave Cheney | ae502c4 | 2011-09-01 13:43:03 -0400 | [diff] [blame] | 993 | memset(buf, 0, sh[ep->shstrndx].size); |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 994 | seek(fd, sh[ep->shstrndx].offset, 0); |
Russ Cox | 05cc83b | 2010-09-28 13:00:13 -0400 | [diff] [blame] | 995 | i = read(fd, buf, sh[ep->shstrndx].size); |
| 996 | USED(i); // shut up ubuntu gcc |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 997 | |
| 998 | for(i = 0; i < ep->shnum; i++) { |
| 999 | if (strcmp(&buf[sh[i].name], ".gosymtab") == 0) { |
| 1000 | symsize = sh[i].size; |
| 1001 | symoff = sh[i].offset; |
| 1002 | } |
| 1003 | if (strcmp(&buf[sh[i].name], ".gopclntab") == 0) { |
Russ Cox | 19fd5c7 | 2010-10-19 18:07:19 -0400 | [diff] [blame] | 1004 | pclnsize = sh[i].size; |
| 1005 | pclnoff = sh[i].offset; |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 1006 | } |
| 1007 | } |
Russ Cox | 19fd5c7 | 2010-10-19 18:07:19 -0400 | [diff] [blame] | 1008 | setsym(fp, symoff, symsize, 0, 0, pclnoff, pclnsize); |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 1009 | free(buf); |
| 1010 | } |
| 1011 | done: |
| 1012 | free(sh); |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 1013 | free(ph); |
| 1014 | return 1; |
| 1015 | } |
| 1016 | |
Rob Pike | 073486c | 2008-06-15 17:22:57 -0700 | [diff] [blame] | 1017 | static int |
| 1018 | machdotout(int fd, Fhdr *fp, ExecHdr *hp) |
| 1019 | { |
| 1020 | uvlong (*swav)(uvlong); |
Russ Cox | 9aad9fe | 2008-08-03 17:25:15 -0700 | [diff] [blame] | 1021 | uint32 (*swal)(uint32); |
Rob Pike | 073486c | 2008-06-15 17:22:57 -0700 | [diff] [blame] | 1022 | Machhdr *mp; |
| 1023 | MachCmd **cmd; |
Rob Pike | 073486c | 2008-06-15 17:22:57 -0700 | [diff] [blame] | 1024 | MachSymSeg *symtab; |
| 1025 | MachSymSeg *pclntab; |
| 1026 | MachSeg64 *seg; |
| 1027 | MachSect64 *sect; |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 1028 | MachSeg32 *seg32; |
| 1029 | MachSect32 *sect32; |
Rob Pike | 073486c | 2008-06-15 17:22:57 -0700 | [diff] [blame] | 1030 | uvlong textsize, datasize, bsssize; |
| 1031 | uchar *cmdbuf; |
| 1032 | uchar *cmdp; |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 1033 | int i, hdrsize; |
| 1034 | uint32 textva, textoff, datava, dataoff; |
Rob Pike | 073486c | 2008-06-15 17:22:57 -0700 | [diff] [blame] | 1035 | |
Rob Pike | 073486c | 2008-06-15 17:22:57 -0700 | [diff] [blame] | 1036 | mp = &hp->e.machhdr; |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 1037 | if (leswal(mp->filetype) != MACH_EXECUTABLE_TYPE) { |
| 1038 | werrstr("bad MACH executable type %#ux", leswal(mp->filetype)); |
Rob Pike | 073486c | 2008-06-15 17:22:57 -0700 | [diff] [blame] | 1039 | return 0; |
| 1040 | } |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 1041 | |
Rob Pike | 073486c | 2008-06-15 17:22:57 -0700 | [diff] [blame] | 1042 | swal = leswal; |
| 1043 | swav = leswav; |
| 1044 | |
| 1045 | mp->magic = swal(mp->magic); |
| 1046 | mp->cputype = swal(mp->cputype); |
| 1047 | mp->cpusubtype = swal(mp->cpusubtype); |
| 1048 | mp->filetype = swal(mp->filetype); |
| 1049 | mp->ncmds = swal(mp->ncmds); |
| 1050 | mp->sizeofcmds = swal(mp->sizeofcmds); |
| 1051 | mp->flags = swal(mp->flags); |
| 1052 | mp->reserved = swal(mp->reserved); |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 1053 | |
| 1054 | switch(mp->magic) { |
| 1055 | case 0xFEEDFACE: // 32-bit mach |
| 1056 | if (mp->cputype != MACH_CPU_TYPE_X86) { |
| 1057 | werrstr("bad MACH cpu type - not 386"); |
| 1058 | return 0; |
| 1059 | } |
| 1060 | if (mp->cpusubtype != MACH_CPU_SUBTYPE_X86) { |
| 1061 | werrstr("bad MACH cpu subtype - not 386"); |
| 1062 | return 0; |
| 1063 | } |
| 1064 | if (mp->filetype != MACH_EXECUTABLE_TYPE) { |
| 1065 | werrstr("bad MACH executable type"); |
| 1066 | return 0; |
| 1067 | } |
| 1068 | mach = &mi386; |
| 1069 | fp->type = FI386; |
| 1070 | hdrsize = 28; |
| 1071 | break; |
| 1072 | |
| 1073 | case 0xFEEDFACF: // 64-bit mach |
| 1074 | if (mp->cputype != MACH_CPU_TYPE_X86_64) { |
| 1075 | werrstr("bad MACH cpu type - not amd64"); |
| 1076 | return 0; |
| 1077 | } |
| 1078 | |
| 1079 | if (mp->cpusubtype != MACH_CPU_SUBTYPE_X86) { |
| 1080 | werrstr("bad MACH cpu subtype - not amd64"); |
| 1081 | return 0; |
| 1082 | } |
| 1083 | mach = &mamd64; |
| 1084 | fp->type = FAMD64; |
| 1085 | hdrsize = 32; |
| 1086 | break; |
| 1087 | |
| 1088 | default: |
| 1089 | werrstr("not mach %#ux", mp->magic); |
Rob Pike | 073486c | 2008-06-15 17:22:57 -0700 | [diff] [blame] | 1090 | return 0; |
| 1091 | } |
Rob Pike | 073486c | 2008-06-15 17:22:57 -0700 | [diff] [blame] | 1092 | |
| 1093 | cmdbuf = malloc(mp->sizeofcmds); |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 1094 | seek(fd, hdrsize, 0); |
Rob Pike | 073486c | 2008-06-15 17:22:57 -0700 | [diff] [blame] | 1095 | if(read(fd, cmdbuf, mp->sizeofcmds) != mp->sizeofcmds) { |
| 1096 | free(cmdbuf); |
| 1097 | return 0; |
| 1098 | } |
| 1099 | cmd = malloc(mp->ncmds * sizeof(MachCmd*)); |
| 1100 | cmdp = cmdbuf; |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 1101 | textva = 0; |
| 1102 | textoff = 0; |
| 1103 | dataoff = 0; |
| 1104 | datava = 0; |
Rob Pike | 073486c | 2008-06-15 17:22:57 -0700 | [diff] [blame] | 1105 | symtab = 0; |
| 1106 | pclntab = 0; |
Lucio De Re | 7f417d8 | 2011-11-18 23:11:50 -0500 | [diff] [blame] | 1107 | textsize = 0; |
| 1108 | datasize = 0; |
| 1109 | bsssize = 0; |
Rob Pike | 073486c | 2008-06-15 17:22:57 -0700 | [diff] [blame] | 1110 | for (i = 0; i < mp->ncmds; i++) { |
| 1111 | MachCmd *c; |
| 1112 | |
| 1113 | cmd[i] = (MachCmd*)cmdp; |
| 1114 | c = cmd[i]; |
| 1115 | c->type = swal(c->type); |
| 1116 | c->size = swal(c->size); |
| 1117 | switch(c->type) { |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 1118 | case MACH_SEGMENT_32: |
| 1119 | if(mp->magic != 0xFEEDFACE) { |
| 1120 | werrstr("segment 32 in mach 64"); |
| 1121 | goto bad; |
| 1122 | } |
| 1123 | seg32 = (MachSeg32*)c; |
| 1124 | seg32->vmaddr = swav(seg32->vmaddr); |
| 1125 | seg32->vmsize = swav(seg32->vmsize); |
| 1126 | seg32->fileoff = swav(seg32->fileoff); |
| 1127 | seg32->filesize = swav(seg32->filesize); |
| 1128 | seg32->maxprot = swal(seg32->maxprot); |
| 1129 | seg32->initprot = swal(seg32->initprot); |
| 1130 | seg32->nsects = swal(seg32->nsects); |
| 1131 | seg32->flags = swal(seg32->flags); |
| 1132 | if (strcmp(seg32->segname, "__TEXT") == 0) { |
| 1133 | textva = seg32->vmaddr; |
| 1134 | textoff = seg32->fileoff; |
| 1135 | sect32 = (MachSect32*)(cmdp + sizeof(MachSeg32)); |
| 1136 | if (strcmp(sect32->sectname, "__text") == 0) { |
| 1137 | textsize = swal(sect32->size); |
| 1138 | } else { |
| 1139 | werrstr("no text section"); |
| 1140 | goto bad; |
| 1141 | } |
| 1142 | } |
| 1143 | if (strcmp(seg32->segname, "__DATA") == 0) { |
| 1144 | datava = seg32->vmaddr; |
| 1145 | dataoff = seg32->fileoff; |
| 1146 | sect32 = (MachSect32*)(cmdp + sizeof(MachSeg32)); |
| 1147 | if (strcmp(sect32->sectname, "__data") == 0) { |
| 1148 | datasize = swal(sect32->size); |
| 1149 | } else { |
| 1150 | werrstr("no data section"); |
| 1151 | goto bad; |
| 1152 | } |
| 1153 | sect32++; |
Russ Cox | 133a158 | 2009-10-03 10:37:12 -0700 | [diff] [blame] | 1154 | if (strcmp(sect32->sectname, "__nl_symbol_ptr") == 0) |
| 1155 | sect32++; |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 1156 | if (strcmp(sect32->sectname, "__bss") == 0) { |
| 1157 | bsssize = swal(sect32->size); |
| 1158 | } else { |
| 1159 | werrstr("no bss section"); |
| 1160 | goto bad; |
| 1161 | } |
| 1162 | } |
| 1163 | break; |
| 1164 | |
Rob Pike | 073486c | 2008-06-15 17:22:57 -0700 | [diff] [blame] | 1165 | case MACH_SEGMENT_64: |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 1166 | if(mp->magic != 0xFEEDFACF) { |
| 1167 | werrstr("segment 32 in mach 64"); |
| 1168 | goto bad; |
| 1169 | } |
Rob Pike | 073486c | 2008-06-15 17:22:57 -0700 | [diff] [blame] | 1170 | seg = (MachSeg64*)c; |
| 1171 | seg->vmaddr = swav(seg->vmaddr); |
| 1172 | seg->vmsize = swav(seg->vmsize); |
| 1173 | seg->fileoff = swav(seg->fileoff); |
| 1174 | seg->filesize = swav(seg->filesize); |
| 1175 | seg->maxprot = swal(seg->maxprot); |
| 1176 | seg->initprot = swal(seg->initprot); |
| 1177 | seg->nsects = swal(seg->nsects); |
| 1178 | seg->flags = swal(seg->flags); |
| 1179 | if (strcmp(seg->segname, "__TEXT") == 0) { |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 1180 | textva = seg->vmaddr; |
| 1181 | textoff = seg->fileoff; |
Rob Pike | 073486c | 2008-06-15 17:22:57 -0700 | [diff] [blame] | 1182 | sect = (MachSect64*)(cmdp + sizeof(MachSeg64)); |
| 1183 | if (strcmp(sect->sectname, "__text") == 0) { |
| 1184 | textsize = swav(sect->size); |
| 1185 | } else { |
| 1186 | werrstr("no text section"); |
| 1187 | goto bad; |
| 1188 | } |
| 1189 | } |
| 1190 | if (strcmp(seg->segname, "__DATA") == 0) { |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 1191 | datava = seg->vmaddr; |
| 1192 | dataoff = seg->fileoff; |
Rob Pike | 073486c | 2008-06-15 17:22:57 -0700 | [diff] [blame] | 1193 | sect = (MachSect64*)(cmdp + sizeof(MachSeg64)); |
| 1194 | if (strcmp(sect->sectname, "__data") == 0) { |
| 1195 | datasize = swav(sect->size); |
| 1196 | } else { |
| 1197 | werrstr("no data section"); |
| 1198 | goto bad; |
| 1199 | } |
| 1200 | sect++; |
Russ Cox | 84edc2e | 2010-05-24 14:30:51 -0700 | [diff] [blame] | 1201 | if (strcmp(sect->sectname, "__nl_symbol_ptr") == 0) |
| 1202 | sect++; |
Rob Pike | 073486c | 2008-06-15 17:22:57 -0700 | [diff] [blame] | 1203 | if (strcmp(sect->sectname, "__bss") == 0) { |
| 1204 | bsssize = swav(sect->size); |
| 1205 | } else { |
| 1206 | werrstr("no bss section"); |
| 1207 | goto bad; |
| 1208 | } |
| 1209 | } |
| 1210 | break; |
| 1211 | case MACH_UNIXTHREAD: |
| 1212 | break; |
| 1213 | case MACH_SYMSEG: |
| 1214 | if (symtab == 0) |
| 1215 | symtab = (MachSymSeg*)c; |
| 1216 | else if (pclntab == 0) |
| 1217 | pclntab = (MachSymSeg*)c; |
| 1218 | break; |
| 1219 | } |
| 1220 | cmdp += c->size; |
| 1221 | } |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 1222 | if (textva == 0 || datava == 0) { |
Rob Pike | 073486c | 2008-06-15 17:22:57 -0700 | [diff] [blame] | 1223 | free(cmd); |
| 1224 | free(cmdbuf); |
| 1225 | return 0; |
| 1226 | } |
| 1227 | /* compute entry by taking address after header - weird - BUG? */ |
Russ Cox | fcd536d | 2009-03-24 18:04:50 -0700 | [diff] [blame] | 1228 | settext(fp, textva+sizeof(Machhdr) + mp->sizeofcmds, textva, textsize, textoff); |
| 1229 | setdata(fp, datava, datasize, dataoff, bsssize); |
Rob Pike | 073486c | 2008-06-15 17:22:57 -0700 | [diff] [blame] | 1230 | if(symtab != 0) |
Russ Cox | 19fd5c7 | 2010-10-19 18:07:19 -0400 | [diff] [blame] | 1231 | setsym(fp, symtab->fileoff, symtab->filesize, 0, 0, 0, pclntab? pclntab->filesize : 0); |
Rob Pike | 073486c | 2008-06-15 17:22:57 -0700 | [diff] [blame] | 1232 | free(cmd); |
| 1233 | free(cmdbuf); |
| 1234 | return 1; |
| 1235 | bad: |
| 1236 | free(cmd); |
| 1237 | free(cmdbuf); |
| 1238 | return 0; |
| 1239 | } |
| 1240 | |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 1241 | /* |
| 1242 | * (Free|Net)BSD ARM header. |
| 1243 | */ |
| 1244 | static int |
| 1245 | armdotout(int fd, Fhdr *fp, ExecHdr *hp) |
| 1246 | { |
| 1247 | uvlong kbase; |
| 1248 | |
| 1249 | USED(fd); |
| 1250 | settext(fp, hp->e.exechdr.entry, sizeof(Exec), hp->e.exechdr.text, sizeof(Exec)); |
| 1251 | setdata(fp, fp->txtsz, hp->e.exechdr.data, fp->txtsz, hp->e.exechdr.bss); |
Russ Cox | 19fd5c7 | 2010-10-19 18:07:19 -0400 | [diff] [blame] | 1252 | setsym(fp, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz); |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 1253 | |
| 1254 | kbase = 0xF0000000; |
| 1255 | if ((fp->entry & kbase) == kbase) { /* Boot image */ |
| 1256 | fp->txtaddr = kbase+sizeof(Exec); |
| 1257 | fp->name = "ARM *BSD boot image"; |
| 1258 | fp->hdrsz = 0; /* header stripped */ |
| 1259 | fp->dataddr = kbase+fp->txtsz; |
| 1260 | } |
| 1261 | return 1; |
| 1262 | } |
| 1263 | |
Mateusz Czapliński | eae0a48 | 2011-08-29 14:25:43 -0400 | [diff] [blame] | 1264 | /* |
| 1265 | * Structures needed to parse PE image. |
| 1266 | */ |
| 1267 | typedef struct { |
| 1268 | uint16 Machine; |
| 1269 | uint16 NumberOfSections; |
| 1270 | uint32 TimeDateStamp; |
| 1271 | uint32 PointerToSymbolTable; |
| 1272 | uint32 NumberOfSymbols; |
| 1273 | uint16 SizeOfOptionalHeader; |
| 1274 | uint16 Characteristics; |
| 1275 | } IMAGE_FILE_HEADER; |
| 1276 | |
| 1277 | typedef struct { |
| 1278 | uint8 Name[8]; |
| 1279 | uint32 VirtualSize; |
| 1280 | uint32 VirtualAddress; |
| 1281 | uint32 SizeOfRawData; |
| 1282 | uint32 PointerToRawData; |
| 1283 | uint32 PointerToRelocations; |
| 1284 | uint32 PointerToLineNumbers; |
| 1285 | uint16 NumberOfRelocations; |
| 1286 | uint16 NumberOfLineNumbers; |
| 1287 | uint32 Characteristics; |
| 1288 | } IMAGE_SECTION_HEADER; |
| 1289 | |
| 1290 | typedef struct { |
| 1291 | uint32 VirtualAddress; |
| 1292 | uint32 Size; |
| 1293 | } IMAGE_DATA_DIRECTORY; |
| 1294 | |
| 1295 | typedef struct { |
| 1296 | uint16 Magic; |
| 1297 | uint8 MajorLinkerVersion; |
| 1298 | uint8 MinorLinkerVersion; |
| 1299 | uint32 SizeOfCode; |
| 1300 | uint32 SizeOfInitializedData; |
| 1301 | uint32 SizeOfUninitializedData; |
| 1302 | uint32 AddressOfEntryPoint; |
| 1303 | uint32 BaseOfCode; |
| 1304 | uint32 BaseOfData; |
| 1305 | uint32 ImageBase; |
| 1306 | uint32 SectionAlignment; |
| 1307 | uint32 FileAlignment; |
| 1308 | uint16 MajorOperatingSystemVersion; |
| 1309 | uint16 MinorOperatingSystemVersion; |
| 1310 | uint16 MajorImageVersion; |
| 1311 | uint16 MinorImageVersion; |
| 1312 | uint16 MajorSubsystemVersion; |
| 1313 | uint16 MinorSubsystemVersion; |
| 1314 | uint32 Win32VersionValue; |
| 1315 | uint32 SizeOfImage; |
| 1316 | uint32 SizeOfHeaders; |
| 1317 | uint32 CheckSum; |
| 1318 | uint16 Subsystem; |
| 1319 | uint16 DllCharacteristics; |
| 1320 | uint32 SizeOfStackReserve; |
| 1321 | uint32 SizeOfStackCommit; |
| 1322 | uint32 SizeOfHeapReserve; |
| 1323 | uint32 SizeOfHeapCommit; |
| 1324 | uint32 LoaderFlags; |
| 1325 | uint32 NumberOfRvaAndSizes; |
| 1326 | IMAGE_DATA_DIRECTORY DataDirectory[16]; |
| 1327 | } IMAGE_OPTIONAL_HEADER; |
| 1328 | |
| 1329 | static int |
| 1330 | match8(void *buf, char *cmp) |
| 1331 | { |
| 1332 | return strncmp((char*)buf, cmp, 8) == 0; |
| 1333 | } |
| 1334 | |
| 1335 | /* TODO(czaplinski): 64b windows? */ |
| 1336 | /* |
| 1337 | * Read from Windows PE/COFF .exe file image. |
| 1338 | */ |
| 1339 | static int |
| 1340 | pedotout(int fd, Fhdr *fp, ExecHdr *hp) |
| 1341 | { |
| 1342 | uint32 start, magic; |
| 1343 | uint32 symtab, esymtab; |
| 1344 | IMAGE_FILE_HEADER fh; |
| 1345 | IMAGE_SECTION_HEADER sh; |
| 1346 | IMAGE_OPTIONAL_HEADER oh; |
| 1347 | uint8 sym[18]; |
| 1348 | uint32 *valp; |
| 1349 | int i; |
| 1350 | |
| 1351 | USED(hp); |
| 1352 | seek(fd, 0x3c, 0); |
| 1353 | if (readn(fd, &start, sizeof(start)) != sizeof(start)) { |
| 1354 | werrstr("crippled PE MSDOS header"); |
| 1355 | return 0; |
| 1356 | } |
| 1357 | start = leswal(start); |
| 1358 | |
| 1359 | seek(fd, start, 0); |
| 1360 | if (readn(fd, &magic, sizeof(magic)) != sizeof(magic)) { |
| 1361 | werrstr("no PE magic number found"); |
| 1362 | return 0; |
| 1363 | } |
| 1364 | if (beswal(magic) != 0x50450000) { /* "PE\0\0" */ |
| 1365 | werrstr("incorrect PE magic number"); |
| 1366 | return 0; |
| 1367 | } |
| 1368 | |
| 1369 | if (readn(fd, &fh, sizeof(fh)) != sizeof(fh)) { |
| 1370 | werrstr("crippled PE File Header"); |
| 1371 | return 0; |
| 1372 | } |
| 1373 | if (fh.PointerToSymbolTable == 0) { |
| 1374 | werrstr("zero pointer to COFF symbol table"); |
| 1375 | return 0; |
| 1376 | } |
| 1377 | |
| 1378 | if (readn(fd, &oh, sizeof(oh)) != sizeof(oh)) { |
| 1379 | werrstr("crippled PE Optional Header"); |
| 1380 | return 0; |
| 1381 | } |
| 1382 | |
| 1383 | seek(fd, start+sizeof(magic)+sizeof(fh)+leswab(fh.SizeOfOptionalHeader), 0); |
Lucio De Re | 7f417d8 | 2011-11-18 23:11:50 -0500 | [diff] [blame] | 1384 | fp->txtaddr = 0; |
| 1385 | fp->dataddr = 0; |
Mateusz Czapliński | eae0a48 | 2011-08-29 14:25:43 -0400 | [diff] [blame] | 1386 | for (i=0; i<leswab(fh.NumberOfSections); i++) { |
| 1387 | if (readn(fd, &sh, sizeof(sh)) != sizeof(sh)) { |
| 1388 | werrstr("could not read Section Header %d", i+1); |
| 1389 | return 0; |
| 1390 | } |
| 1391 | if (match8(sh.Name, ".text")) |
| 1392 | settext(fp, leswal(sh.VirtualAddress), leswal(oh.AddressOfEntryPoint), leswal(sh.VirtualSize), leswal(sh.PointerToRawData)); |
| 1393 | if (match8(sh.Name, ".data")) |
| 1394 | setdata(fp, leswal(sh.VirtualAddress), leswal(sh.SizeOfRawData), leswal(sh.PointerToRawData), leswal(sh.VirtualSize)-leswal(sh.SizeOfRawData)); |
| 1395 | } |
| 1396 | if (fp->txtaddr==0 || fp->dataddr==0) { |
| 1397 | werrstr("no .text or .data"); |
| 1398 | return 0; |
| 1399 | } |
| 1400 | |
| 1401 | seek(fd, leswal(fh.PointerToSymbolTable), 0); |
| 1402 | symtab = esymtab = 0; |
| 1403 | for (i=0; i<leswal(fh.NumberOfSymbols); i++) { |
Lucio De Re | 7f417d8 | 2011-11-18 23:11:50 -0500 | [diff] [blame] | 1404 | if (readn(fd, sym, sizeof(sym)) != sizeof(sym)) { |
Mateusz Czapliński | eae0a48 | 2011-08-29 14:25:43 -0400 | [diff] [blame] | 1405 | werrstr("crippled COFF symbol %d", i); |
| 1406 | return 0; |
| 1407 | } |
| 1408 | valp = (uint32 *)&sym[8]; |
| 1409 | if (match8(sym, "symtab")) |
| 1410 | symtab = leswal(*valp); |
| 1411 | if (match8(sym, "esymtab")) |
| 1412 | esymtab = leswal(*valp); |
| 1413 | } |
| 1414 | if (symtab==0 || esymtab==0) { |
| 1415 | werrstr("no symtab or esymtab in COFF symbol table"); |
| 1416 | return 0; |
| 1417 | } |
| 1418 | setsym(fp, symtab, esymtab-symtab, 0, 0, 0, 0); |
| 1419 | |
| 1420 | return 1; |
| 1421 | } |
| 1422 | |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 1423 | static void |
Russ Cox | 9aad9fe | 2008-08-03 17:25:15 -0700 | [diff] [blame] | 1424 | settext(Fhdr *fp, uvlong e, uvlong a, int32 s, vlong off) |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 1425 | { |
| 1426 | fp->txtaddr = a; |
| 1427 | fp->entry = e; |
| 1428 | fp->txtsz = s; |
| 1429 | fp->txtoff = off; |
| 1430 | } |
| 1431 | |
| 1432 | static void |
Russ Cox | 9aad9fe | 2008-08-03 17:25:15 -0700 | [diff] [blame] | 1433 | setdata(Fhdr *fp, uvlong a, int32 s, vlong off, int32 bss) |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 1434 | { |
| 1435 | fp->dataddr = a; |
| 1436 | fp->datsz = s; |
| 1437 | fp->datoff = off; |
| 1438 | fp->bsssz = bss; |
| 1439 | } |
| 1440 | |
| 1441 | static void |
Russ Cox | 19fd5c7 | 2010-10-19 18:07:19 -0400 | [diff] [blame] | 1442 | setsym(Fhdr *fp, vlong symoff, int32 symsz, vlong sppcoff, int32 sppcsz, vlong lnpcoff, int32 lnpcsz) |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 1443 | { |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 1444 | fp->symoff = symoff; |
Russ Cox | 19fd5c7 | 2010-10-19 18:07:19 -0400 | [diff] [blame] | 1445 | fp->symsz = symsz; |
| 1446 | |
| 1447 | if(sppcoff == 0) |
| 1448 | sppcoff = symoff+symsz; |
| 1449 | fp->sppcoff = symoff; |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 1450 | fp->sppcsz = sppcsz; |
Russ Cox | 19fd5c7 | 2010-10-19 18:07:19 -0400 | [diff] [blame] | 1451 | |
| 1452 | if(lnpcoff == 0) |
| 1453 | lnpcoff = sppcoff + sppcsz; |
| 1454 | fp->lnpcoff = lnpcoff; |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 1455 | fp->lnpcsz = lnpcsz; |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 1456 | } |
| 1457 | |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 1458 | static uvlong |
Russ Cox | 9aad9fe | 2008-08-03 17:25:15 -0700 | [diff] [blame] | 1459 | _round(uvlong a, uint32 b) |
Rob Pike | ed5e39a | 2008-06-12 14:50:25 -0700 | [diff] [blame] | 1460 | { |
| 1461 | uvlong w; |
| 1462 | |
| 1463 | w = (a/b)*b; |
| 1464 | if (a!=w) |
| 1465 | w += b; |
| 1466 | return(w); |
| 1467 | } |