github.com/zach-klippenstein/go@v0.0.0-20150108044943-fcfbeb3adf58/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  }