github.com/bgentry/go@v0.0.0-20150121062915-6cf5a733d54d/src/cmd/ld/ldpe.c (about) 1 // Copyright 2010 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 #include "l.h" 6 #include "lib.h" 7 #include "../ld/pe.h" 8 9 #define IMAGE_SCN_MEM_DISCARDABLE 0x2000000 10 11 #define IMAGE_SYM_UNDEFINED 0 12 #define IMAGE_SYM_ABSOLUTE (-1) 13 #define IMAGE_SYM_DEBUG (-2) 14 #define IMAGE_SYM_TYPE_NULL 0 15 #define IMAGE_SYM_TYPE_VOID 1 16 #define IMAGE_SYM_TYPE_CHAR 2 17 #define IMAGE_SYM_TYPE_SHORT 3 18 #define IMAGE_SYM_TYPE_INT 4 19 #define IMAGE_SYM_TYPE_LONG 5 20 #define IMAGE_SYM_TYPE_FLOAT 6 21 #define IMAGE_SYM_TYPE_DOUBLE 7 22 #define IMAGE_SYM_TYPE_STRUCT 8 23 #define IMAGE_SYM_TYPE_UNION 9 24 #define IMAGE_SYM_TYPE_ENUM 10 25 #define IMAGE_SYM_TYPE_MOE 11 26 #define IMAGE_SYM_TYPE_BYTE 12 27 #define IMAGE_SYM_TYPE_WORD 13 28 #define IMAGE_SYM_TYPE_UINT 14 29 #define IMAGE_SYM_TYPE_DWORD 15 30 #define IMAGE_SYM_TYPE_PCODE 32768 31 #define IMAGE_SYM_DTYPE_NULL 0 32 #define IMAGE_SYM_DTYPE_POINTER 0x10 33 #define IMAGE_SYM_DTYPE_FUNCTION 0x20 34 #define IMAGE_SYM_DTYPE_ARRAY 0x30 35 #define IMAGE_SYM_CLASS_END_OF_FUNCTION (-1) 36 #define IMAGE_SYM_CLASS_NULL 0 37 #define IMAGE_SYM_CLASS_AUTOMATIC 1 38 #define IMAGE_SYM_CLASS_EXTERNAL 2 39 #define IMAGE_SYM_CLASS_STATIC 3 40 #define IMAGE_SYM_CLASS_REGISTER 4 41 #define IMAGE_SYM_CLASS_EXTERNAL_DEF 5 42 #define IMAGE_SYM_CLASS_LABEL 6 43 #define IMAGE_SYM_CLASS_UNDEFINED_LABEL 7 44 #define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8 45 #define IMAGE_SYM_CLASS_ARGUMENT 9 46 #define IMAGE_SYM_CLASS_STRUCT_TAG 10 47 #define IMAGE_SYM_CLASS_MEMBER_OF_UNION 11 48 #define IMAGE_SYM_CLASS_UNION_TAG 12 49 #define IMAGE_SYM_CLASS_TYPE_DEFINITION 13 50 #define IMAGE_SYM_CLASS_UNDEFINED_STATIC 14 51 #define IMAGE_SYM_CLASS_ENUM_TAG 15 52 #define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16 53 #define IMAGE_SYM_CLASS_REGISTER_PARAM 17 54 #define IMAGE_SYM_CLASS_BIT_FIELD 18 55 #define IMAGE_SYM_CLASS_FAR_EXTERNAL 68 /* Not in PECOFF v8 spec */ 56 #define IMAGE_SYM_CLASS_BLOCK 100 57 #define IMAGE_SYM_CLASS_FUNCTION 101 58 #define IMAGE_SYM_CLASS_END_OF_STRUCT 102 59 #define IMAGE_SYM_CLASS_FILE 103 60 #define IMAGE_SYM_CLASS_SECTION 104 61 #define IMAGE_SYM_CLASS_WEAK_EXTERNAL 105 62 #define IMAGE_SYM_CLASS_CLR_TOKEN 107 63 64 #define IMAGE_REL_I386_ABSOLUTE 0x0000 65 #define IMAGE_REL_I386_DIR16 0x0001 66 #define IMAGE_REL_I386_REL16 0x0002 67 #define IMAGE_REL_I386_DIR32 0x0006 68 #define IMAGE_REL_I386_DIR32NB 0x0007 69 #define IMAGE_REL_I386_SEG12 0x0009 70 #define IMAGE_REL_I386_SECTION 0x000A 71 #define IMAGE_REL_I386_SECREL 0x000B 72 #define IMAGE_REL_I386_TOKEN 0x000C 73 #define IMAGE_REL_I386_SECREL7 0x000D 74 #define IMAGE_REL_I386_REL32 0x0014 75 76 #define IMAGE_REL_AMD64_ABSOLUTE 0x0000 77 #define IMAGE_REL_AMD64_ADDR64 0x0001 // R_X86_64_64 78 #define IMAGE_REL_AMD64_ADDR32 0x0002 // R_X86_64_PC32 79 #define IMAGE_REL_AMD64_ADDR32NB 0x0003 80 #define IMAGE_REL_AMD64_REL32 0x0004 81 #define IMAGE_REL_AMD64_REL32_1 0x0005 82 #define IMAGE_REL_AMD64_REL32_2 0x0006 83 #define IMAGE_REL_AMD64_REL32_3 0x0007 84 #define IMAGE_REL_AMD64_REL32_4 0x0008 85 #define IMAGE_REL_AMD64_REL32_5 0x0009 86 #define IMAGE_REL_AMD64_SECTION 0x000A 87 #define IMAGE_REL_AMD64_SECREL 0x000B 88 #define IMAGE_REL_AMD64_SECREL7 0x000C 89 #define IMAGE_REL_AMD64_TOKEN 0x000D 90 #define IMAGE_REL_AMD64_SREL32 0x000E 91 #define IMAGE_REL_AMD64_PAIR 0x000F 92 #define IMAGE_REL_AMD64_SSPAN32 0x0010 93 94 typedef struct PeSym PeSym; 95 typedef struct PeSect PeSect; 96 typedef struct PeObj PeObj; 97 98 struct PeSym { 99 char* name; 100 uint32 value; 101 uint16 sectnum; 102 uint16 type; 103 uint8 sclass; 104 uint8 aux; 105 LSym* sym; 106 }; 107 108 struct PeSect { 109 char* name; 110 uchar* base; 111 uint64 size; 112 LSym* sym; 113 IMAGE_SECTION_HEADER sh; 114 }; 115 116 struct PeObj { 117 Biobuf *f; 118 char *name; 119 uint32 base; 120 121 PeSect *sect; 122 uint nsect; 123 PeSym *pesym; 124 uint npesym; 125 126 IMAGE_FILE_HEADER fh; 127 char* snames; 128 }; 129 130 static int map(PeObj *obj, PeSect *sect); 131 static int issect(PeSym *s); 132 static int readsym(PeObj *obj, int i, PeSym **sym); 133 134 void 135 ldpe(Biobuf *f, char *pkg, int64 len, char *pn) 136 { 137 char *name; 138 int32 base; 139 uint32 l; 140 int i, j, numaux; 141 PeObj *obj; 142 PeSect *sect, *rsect; 143 IMAGE_SECTION_HEADER sh; 144 uchar symbuf[18]; 145 LSym *s; 146 Reloc *r, *rp; 147 PeSym *sym; 148 149 USED(len); 150 if(debug['v']) 151 Bprint(&bso, "%5.2f ldpe %s\n", cputime(), pn); 152 153 sect = nil; 154 ctxt->version++; 155 base = Boffset(f); 156 157 obj = mal(sizeof *obj); 158 obj->f = f; 159 obj->base = base; 160 obj->name = pn; 161 // read header 162 if(Bread(f, &obj->fh, sizeof obj->fh) != sizeof obj->fh) 163 goto bad; 164 // load section list 165 obj->sect = mal(obj->fh.NumberOfSections*sizeof obj->sect[0]); 166 obj->nsect = obj->fh.NumberOfSections; 167 for(i=0; i < obj->fh.NumberOfSections; i++) { 168 if(Bread(f, &obj->sect[i].sh, sizeof sh) != sizeof sh) 169 goto bad; 170 obj->sect[i].size = obj->sect[i].sh.SizeOfRawData; 171 obj->sect[i].name = (char*)obj->sect[i].sh.Name; 172 // TODO return error if found .cormeta 173 } 174 // load string table 175 Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*obj->fh.NumberOfSymbols, 0); 176 if(Bread(f, symbuf, 4) != 4) 177 goto bad; 178 l = le32(symbuf); 179 obj->snames = mal(l); 180 Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*obj->fh.NumberOfSymbols, 0); 181 if(Bread(f, obj->snames, l) != l) 182 goto bad; 183 // rewrite section names if they start with / 184 for(i=0; i < obj->fh.NumberOfSections; i++) { 185 if(obj->sect[i].name == nil) 186 continue; 187 if(obj->sect[i].name[0] != '/') 188 continue; 189 l = atoi(obj->sect[i].name + 1); 190 obj->sect[i].name = (char*)&obj->snames[l]; 191 } 192 // read symbols 193 obj->pesym = mal(obj->fh.NumberOfSymbols*sizeof obj->pesym[0]); 194 obj->npesym = obj->fh.NumberOfSymbols; 195 Bseek(f, base+obj->fh.PointerToSymbolTable, 0); 196 for(i=0; i<obj->fh.NumberOfSymbols; i+=numaux+1) { 197 Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*i, 0); 198 if(Bread(f, symbuf, sizeof symbuf) != sizeof symbuf) 199 goto bad; 200 201 if((symbuf[0] == 0) && (symbuf[1] == 0) && 202 (symbuf[2] == 0) && (symbuf[3] == 0)) { 203 l = le32(&symbuf[4]); 204 obj->pesym[i].name = (char*)&obj->snames[l]; 205 } else { // sym name length <= 8 206 obj->pesym[i].name = mal(9); 207 strncpy(obj->pesym[i].name, (char*)symbuf, 8); 208 obj->pesym[i].name[8] = 0; 209 } 210 obj->pesym[i].value = le32(&symbuf[8]); 211 obj->pesym[i].sectnum = le16(&symbuf[12]); 212 obj->pesym[i].sclass = symbuf[16]; 213 obj->pesym[i].aux = symbuf[17]; 214 obj->pesym[i].type = le16(&symbuf[14]); 215 numaux = obj->pesym[i].aux; 216 if (numaux < 0) 217 numaux = 0; 218 } 219 // create symbols for mapped sections 220 for(i=0; i<obj->nsect; i++) { 221 sect = &obj->sect[i]; 222 if(sect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE) 223 continue; 224 225 if((sect->sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA)) == 0) { 226 // This has been seen for .idata sections, which we 227 // want to ignore. See issues 5106 and 5273. 228 continue; 229 } 230 231 if(map(obj, sect) < 0) 232 goto bad; 233 234 name = smprint("%s(%s)", pkg, sect->name); 235 s = linklookup(ctxt, name, ctxt->version); 236 free(name); 237 switch(sect->sh.Characteristics&(IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_CNT_INITIALIZED_DATA| 238 IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE)) { 239 case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ: //.rdata 240 s->type = SRODATA; 241 break; 242 case IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.bss 243 s->type = SNOPTRBSS; 244 break; 245 case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.data 246 s->type = SNOPTRDATA; 247 break; 248 case IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ: //.text 249 s->type = STEXT; 250 break; 251 default: 252 werrstr("unexpected flags %#08ux for PE section %s", sect->sh.Characteristics, sect->name); 253 goto bad; 254 } 255 s->p = sect->base; 256 s->np = sect->size; 257 s->size = sect->size; 258 sect->sym = s; 259 if(strcmp(sect->name, ".rsrc") == 0) 260 setpersrc(sect->sym); 261 } 262 263 // load relocations 264 for(i=0; i<obj->nsect; i++) { 265 rsect = &obj->sect[i]; 266 if(rsect->sym == 0 || rsect->sh.NumberOfRelocations == 0) 267 continue; 268 if(rsect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE) 269 continue; 270 if((sect->sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA)) == 0) { 271 // This has been seen for .idata sections, which we 272 // want to ignore. See issues 5106 and 5273. 273 continue; 274 } 275 r = mal(rsect->sh.NumberOfRelocations*sizeof r[0]); 276 Bseek(f, obj->base+rsect->sh.PointerToRelocations, 0); 277 for(j=0; j<rsect->sh.NumberOfRelocations; j++) { 278 rp = &r[j]; 279 if(Bread(f, symbuf, 10) != 10) 280 goto bad; 281 282 uint32 rva, symindex; 283 uint16 type; 284 rva = le32(&symbuf[0]); 285 symindex = le32(&symbuf[4]); 286 type = le16(&symbuf[8]); 287 if(readsym(obj, symindex, &sym) < 0) 288 goto bad; 289 if(sym->sym == nil) { 290 werrstr("reloc of invalid sym %s idx=%d type=%d", sym->name, symindex, sym->type); 291 goto bad; 292 } 293 rp->sym = sym->sym; 294 rp->siz = 4; 295 rp->off = rva; 296 switch(type) { 297 default: 298 diag("%s: unknown relocation type %d;", pn, type); 299 case IMAGE_REL_I386_REL32: 300 case IMAGE_REL_AMD64_REL32: 301 case IMAGE_REL_AMD64_ADDR32: // R_X86_64_PC32 302 case IMAGE_REL_AMD64_ADDR32NB: 303 rp->type = R_PCREL; 304 rp->add = (int32)le32(rsect->base+rp->off); 305 break; 306 case IMAGE_REL_I386_DIR32NB: 307 case IMAGE_REL_I386_DIR32: 308 rp->type = R_ADDR; 309 // load addend from image 310 rp->add = (int32)le32(rsect->base+rp->off); 311 break; 312 case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64 313 rp->siz = 8; 314 rp->type = R_ADDR; 315 // load addend from image 316 rp->add = le64(rsect->base+rp->off); 317 break; 318 } 319 // ld -r could generate multiple section symbols for the 320 // same section but with different values, we have to take 321 // that into account 322 if(issect(&obj->pesym[symindex])) 323 rp->add += obj->pesym[symindex].value; 324 } 325 qsort(r, rsect->sh.NumberOfRelocations, sizeof r[0], rbyoff); 326 327 s = rsect->sym; 328 s->r = r; 329 s->nr = rsect->sh.NumberOfRelocations; 330 } 331 332 // enter sub-symbols into symbol table. 333 for(i=0; i<obj->npesym; i++) { 334 if(obj->pesym[i].name == 0) 335 continue; 336 if(issect(&obj->pesym[i])) 337 continue; 338 if(obj->pesym[i].sectnum > 0) { 339 sect = &obj->sect[obj->pesym[i].sectnum-1]; 340 if(sect->sym == 0) 341 continue; 342 } 343 if(readsym(obj, i, &sym) < 0) 344 goto bad; 345 346 s = sym->sym; 347 if(sym->sectnum == 0) {// extern 348 if(s->type == SDYNIMPORT) 349 s->plt = -2; // flag for dynimport in PE object files. 350 if (s->type == SXREF && sym->value > 0) {// global data 351 s->type = SNOPTRDATA; 352 s->size = sym->value; 353 } 354 continue; 355 } else if (sym->sectnum > 0) { 356 sect = &obj->sect[sym->sectnum-1]; 357 if(sect->sym == 0) 358 diag("%s: %s sym == 0!", pn, s->name); 359 } else { 360 diag("%s: %s sectnum < 0!", pn, s->name); 361 } 362 363 if(sect == nil) 364 return; 365 366 if(s->outer != S) { 367 if(s->dupok) 368 continue; 369 diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s->name, s->outer->name, sect->sym->name); 370 errorexit(); 371 } 372 s->sub = sect->sym->sub; 373 sect->sym->sub = s; 374 s->type = sect->sym->type | SSUB; 375 s->value = sym->value; 376 s->size = 4; 377 s->outer = sect->sym; 378 if(sect->sym->type == STEXT) { 379 if(s->external && !s->dupok) 380 diag("%s: duplicate definition of %s", pn, s->name); 381 s->external = 1; 382 } 383 } 384 385 // Sort outer lists by address, adding to textp. 386 // This keeps textp in increasing address order. 387 for(i=0; i<obj->nsect; i++) { 388 s = obj->sect[i].sym; 389 if(s == S) 390 continue; 391 if(s->sub) 392 s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub)); 393 if(s->type == STEXT) { 394 if(s->onlist) 395 sysfatal("symbol %s listed multiple times", s->name); 396 s->onlist = 1; 397 if(ctxt->etextp) 398 ctxt->etextp->next = s; 399 else 400 ctxt->textp = s; 401 ctxt->etextp = s; 402 for(s = s->sub; s != S; s = s->sub) { 403 if(s->onlist) 404 sysfatal("symbol %s listed multiple times", s->name); 405 s->onlist = 1; 406 ctxt->etextp->next = s; 407 ctxt->etextp = s; 408 } 409 } 410 } 411 412 return; 413 bad: 414 diag("%s: malformed pe file: %r", pn); 415 } 416 417 static int 418 map(PeObj *obj, PeSect *sect) 419 { 420 if(sect->base != nil) 421 return 0; 422 423 sect->base = mal(sect->sh.SizeOfRawData); 424 if(sect->sh.PointerToRawData == 0) // .bss doesn't have data in object file 425 return 0; 426 werrstr("short read"); 427 if(Bseek(obj->f, obj->base+sect->sh.PointerToRawData, 0) < 0 || 428 Bread(obj->f, sect->base, sect->sh.SizeOfRawData) != sect->sh.SizeOfRawData) 429 return -1; 430 431 return 0; 432 } 433 434 static int 435 issect(PeSym *s) 436 { 437 return s->sclass == IMAGE_SYM_CLASS_STATIC && s->type == 0 && s->name[0] == '.'; 438 } 439 440 static int 441 readsym(PeObj *obj, int i, PeSym **y) 442 { 443 LSym *s; 444 PeSym *sym; 445 char *name, *p; 446 447 if(i >= obj->npesym || i < 0) { 448 werrstr("invalid pe symbol index"); 449 return -1; 450 } 451 452 sym = &obj->pesym[i]; 453 *y = sym; 454 455 if(issect(sym)) 456 name = obj->sect[sym->sectnum-1].sym->name; 457 else { 458 name = sym->name; 459 if(strncmp(name, "__imp_", 6) == 0) 460 name = &name[6]; // __imp_Name => Name 461 if(thechar == '8' && name[0] == '_') 462 name = &name[1]; // _Name => Name 463 } 464 // remove last @XXX 465 p = strchr(name, '@'); 466 if(p) 467 *p = 0; 468 469 switch(sym->type) { 470 default: 471 werrstr("%s: invalid symbol type %d", sym->name, sym->type); 472 return -1; 473 case IMAGE_SYM_DTYPE_FUNCTION: 474 case IMAGE_SYM_DTYPE_NULL: 475 switch(sym->sclass) { 476 case IMAGE_SYM_CLASS_EXTERNAL: //global 477 s = linklookup(ctxt, name, 0); 478 break; 479 case IMAGE_SYM_CLASS_NULL: 480 case IMAGE_SYM_CLASS_STATIC: 481 case IMAGE_SYM_CLASS_LABEL: 482 s = linklookup(ctxt, name, ctxt->version); 483 s->dupok = 1; 484 break; 485 default: 486 werrstr("%s: invalid symbol binding %d", sym->name, sym->sclass); 487 return -1; 488 } 489 break; 490 } 491 492 if(s != nil && s->type == 0 && !(sym->sclass == IMAGE_SYM_CLASS_STATIC && sym->value == 0)) 493 s->type = SXREF; 494 if(strncmp(sym->name, "__imp_", 6) == 0) 495 s->got = -2; // flag for __imp_ 496 sym->sym = s; 497 498 return 0; 499 }