github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/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  	Sym* sym;
   106  };
   107  
   108  struct PeSect {
   109  	char* name;
   110  	uchar* base;
   111  	uint64 size;
   112  	Sym* 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 readsym(PeObj *obj, int i, PeSym **sym);
   132  
   133  void
   134  ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
   135  {
   136  	char *name;
   137  	int32 base;
   138  	uint32 l;
   139  	int i, j, numaux;
   140  	PeObj *obj;
   141  	PeSect *sect, *rsect;
   142  	IMAGE_SECTION_HEADER sh;
   143  	uchar symbuf[18];
   144  	Sym *s;
   145  	Reloc *r, *rp;
   146  	PeSym *sym;
   147  
   148  	USED(len);
   149  	if(debug['v'])
   150  		Bprint(&bso, "%5.2f ldpe %s\n", cputime(), pn);
   151  	
   152  	sect = nil;
   153  	version++;
   154  	base = Boffset(f);
   155  	
   156  	obj = mal(sizeof *obj);
   157  	obj->f = f;
   158  	obj->base = base;
   159  	obj->name = pn;
   160  	// read header
   161  	if(Bread(f, &obj->fh, sizeof obj->fh) != sizeof obj->fh)
   162  		goto bad;
   163  	// load section list
   164  	obj->sect = mal(obj->fh.NumberOfSections*sizeof obj->sect[0]);
   165  	obj->nsect = obj->fh.NumberOfSections;
   166  	for(i=0; i < obj->fh.NumberOfSections; i++) {
   167  		if(Bread(f, &obj->sect[i].sh, sizeof sh) != sizeof sh)
   168  			goto bad;
   169  		obj->sect[i].size = obj->sect[i].sh.SizeOfRawData;
   170  		obj->sect[i].name = (char*)obj->sect[i].sh.Name;
   171  		// TODO return error if found .cormeta
   172  	}
   173  	// load string table
   174  	Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*obj->fh.NumberOfSymbols, 0);
   175  	if(Bread(f, symbuf, 4) != 4) 
   176  		goto bad;
   177  	l = le32(symbuf);
   178  	obj->snames = mal(l);
   179  	Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*obj->fh.NumberOfSymbols, 0);
   180  	if(Bread(f, obj->snames, l) != l)
   181  		goto bad;
   182  	// read symbols
   183  	obj->pesym = mal(obj->fh.NumberOfSymbols*sizeof obj->pesym[0]);
   184  	obj->npesym = obj->fh.NumberOfSymbols;
   185  	Bseek(f, base+obj->fh.PointerToSymbolTable, 0);
   186  	for(i=0; i<obj->fh.NumberOfSymbols; i+=numaux+1) {
   187  		Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*i, 0);
   188  		if(Bread(f, symbuf, sizeof symbuf) != sizeof symbuf)
   189  			goto bad;
   190  		
   191  		if((symbuf[0] == 0) && (symbuf[1] == 0) &&
   192  			 (symbuf[2] == 0) && (symbuf[3] == 0)) {
   193  			l = le32(&symbuf[4]);
   194  			obj->pesym[i].name = (char*)&obj->snames[l];
   195  		} else { // sym name length <= 8
   196  			obj->pesym[i].name = mal(9);
   197  			strncpy(obj->pesym[i].name, (char*)symbuf, 8);
   198  			obj->pesym[i].name[8] = 0;
   199  		}
   200  		obj->pesym[i].value = le32(&symbuf[8]);
   201  		obj->pesym[i].sectnum = le16(&symbuf[12]);
   202  		obj->pesym[i].sclass = symbuf[16];
   203  		obj->pesym[i].aux = symbuf[17];
   204  		obj->pesym[i].type = le16(&symbuf[14]);
   205  		numaux = obj->pesym[i].aux; 
   206  		if (numaux < 0) 
   207  			numaux = 0;
   208  	}
   209  	// create symbols for mapped sections
   210  	for(i=0; i<obj->nsect; i++) {
   211  		sect = &obj->sect[i];
   212  		if(sect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE)
   213  			continue;
   214  
   215  		if((sect->sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA)) == 0) {
   216  			// This has been seen for .idata sections, which we
   217  			// want to ignore.  See issues 5106 and 5273.
   218  			continue;
   219  		}
   220  
   221  		if(map(obj, sect) < 0)
   222  			goto bad;
   223  		
   224  		name = smprint("%s(%s)", pkg, sect->name);
   225  		s = lookup(name, version);
   226  		free(name);
   227  		switch(sect->sh.Characteristics&(IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_CNT_INITIALIZED_DATA|
   228  			IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE)) {
   229  			case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ: //.rdata
   230  				s->type = SRODATA;
   231  				break;
   232  			case IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.bss
   233  				s->type = SBSS;
   234  				break;
   235  			case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.data
   236  				s->type = SDATA;
   237  				break;
   238  			case IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ: //.text
   239  				s->type = STEXT;
   240  				break;
   241  			default:
   242  				werrstr("unexpected flags %#08ux for PE section %s", sect->sh.Characteristics, sect->name);
   243  				goto bad;
   244  		}
   245  		s->p = sect->base;
   246  		s->np = sect->size;
   247  		s->size = sect->size;
   248  		sect->sym = s;
   249  		if(strcmp(sect->name, ".rsrc") == 0)
   250  			setpersrc(sect->sym);
   251  	}
   252  	
   253  	// load relocations
   254  	for(i=0; i<obj->nsect; i++) {
   255  		rsect = &obj->sect[i];
   256  		if(rsect->sym == 0 || rsect->sh.NumberOfRelocations == 0)
   257  			continue;
   258  		if(rsect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE)
   259  			continue;
   260  		if((sect->sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA)) == 0) {
   261  			// This has been seen for .idata sections, which we
   262  			// want to ignore.  See issues 5106 and 5273.
   263  			continue;
   264  		}
   265  		r = mal(rsect->sh.NumberOfRelocations*sizeof r[0]);
   266  		Bseek(f, obj->base+rsect->sh.PointerToRelocations, 0);
   267  		for(j=0; j<rsect->sh.NumberOfRelocations; j++) {
   268  			rp = &r[j];
   269  			if(Bread(f, symbuf, 10) != 10)
   270  				goto bad;
   271  			
   272  			uint32 rva, symindex;
   273  			uint16 type;
   274  			rva = le32(&symbuf[0]);
   275  			symindex = le32(&symbuf[4]);
   276  			type = le16(&symbuf[8]);
   277  			if(readsym(obj, symindex, &sym) < 0)
   278  				goto bad;
   279  			if(sym->sym == nil) {
   280  				werrstr("reloc of invalid sym %s idx=%d type=%d", sym->name, symindex, sym->type);
   281  				goto bad;
   282  			}
   283  			rp->sym = sym->sym;
   284  			rp->siz = 4;
   285  			rp->off = rva;
   286  			switch(type) {
   287  				default:
   288  					diag("%s: unknown relocation type %d;", pn, type);
   289  				case IMAGE_REL_I386_REL32:
   290  				case IMAGE_REL_AMD64_REL32:
   291  				case IMAGE_REL_AMD64_ADDR32: // R_X86_64_PC32
   292  				case IMAGE_REL_AMD64_ADDR32NB:
   293  					rp->type = D_PCREL;
   294  					rp->add = (int32)le32(rsect->base+rp->off);
   295  					break;
   296  				case IMAGE_REL_I386_DIR32NB:
   297  				case IMAGE_REL_I386_DIR32:
   298  					rp->type = D_ADDR;
   299  					// load addend from image
   300  					rp->add = le32(rsect->base+rp->off);
   301  					break;
   302  				case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64
   303  					rp->siz = 8;
   304  					rp->type = D_ADDR;
   305  					// load addend from image
   306  					rp->add = le64(rsect->base+rp->off);
   307  					break;
   308  			}
   309  			// ld -r could generate multiple section symbols for the
   310  			// same section but with different values, we have to take
   311  			// that into account
   312  			if (obj->pesym[symindex].name[0] == '.')
   313  					rp->add += obj->pesym[symindex].value;
   314  		}
   315  		qsort(r, rsect->sh.NumberOfRelocations, sizeof r[0], rbyoff);
   316  		
   317  		s = rsect->sym;
   318  		s->r = r;
   319  		s->nr = rsect->sh.NumberOfRelocations;
   320  	}
   321  	
   322  	// enter sub-symbols into symbol table.
   323  	for(i=0; i<obj->npesym; i++) {
   324  		if(obj->pesym[i].name == 0)
   325  			continue;
   326  		if(obj->pesym[i].name[0] == '.') //skip section
   327  			continue;
   328  		if(obj->pesym[i].sectnum > 0) {
   329  			sect = &obj->sect[obj->pesym[i].sectnum-1];
   330  			if(sect->sym == 0)
   331  				continue;
   332  		}
   333  		if(readsym(obj, i, &sym) < 0)
   334  			goto bad;
   335  	
   336  		s = sym->sym;
   337  		if(sym->sectnum == 0) {// extern
   338  			if(s->type == SDYNIMPORT)
   339  				s->plt = -2; // flag for dynimport in PE object files.
   340  			if (s->type == SXREF && sym->value > 0) {// global data
   341  				s->type = SDATA; 
   342  				s->size = sym->value;
   343  			}
   344  			continue;
   345  		} else if (sym->sectnum > 0) {
   346  			sect = &obj->sect[sym->sectnum-1];
   347  			if(sect->sym == 0)
   348  				diag("%s: %s sym == 0!", pn, s->name);
   349  		} else {
   350  			diag("%s: %s sectnum < 0!", pn, s->name);
   351  		}
   352  
   353  		if(sect == nil) 
   354  			return;
   355  
   356  		if(s->outer != S) {
   357  			if(s->dupok)
   358  				continue;
   359  			diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s->name, s->outer->name, sect->sym->name);
   360  			errorexit();
   361  		}
   362  		s->sub = sect->sym->sub;
   363  		sect->sym->sub = s;
   364  		s->type = sect->sym->type | SSUB;
   365  		s->value = sym->value;
   366  		s->size = 4;
   367  		s->outer = sect->sym;
   368  		if(sect->sym->type == STEXT) {
   369  			Prog *p;
   370  	
   371  			if(s->text != P)
   372  				diag("%s: duplicate definition of %s", pn, s->name);
   373  			// build a TEXT instruction with a unique pc
   374  			// just to make the rest of the linker happy.
   375  			p = prg();
   376  			p->as = ATEXT;
   377  			p->from.type = D_EXTERN;
   378  			p->from.sym = s;
   379  			p->textflag = 7;
   380  			p->to.type = D_CONST;
   381  			p->link = nil;
   382  			p->pc = pc++;
   383  			s->text = p;
   384  		}
   385  	}
   386  
   387  	// Sort outer lists by address, adding to textp.
   388  	// This keeps textp in increasing address order.
   389  	for(i=0; i<obj->nsect; i++) {
   390  		s = obj->sect[i].sym;
   391  		if(s == S)
   392  			continue;
   393  		if(s->sub)
   394  			s->sub = listsort(s->sub, valuecmp, offsetof(Sym, sub));
   395  		if(s->type == STEXT) {
   396  			if(etextp)
   397  				etextp->next = s;
   398  			else
   399  				textp = s;
   400  			etextp = s;
   401  			for(s = s->sub; s != S; s = s->sub) {
   402  				etextp->next = s;
   403  				etextp = s;
   404  			}
   405  		}
   406  	}
   407  
   408  	return;
   409  bad:
   410  	diag("%s: malformed pe file: %r", pn);
   411  }
   412  
   413  static int
   414  map(PeObj *obj, PeSect *sect)
   415  {
   416  	if(sect->base != nil)
   417  		return 0;
   418  
   419  	sect->base = mal(sect->sh.SizeOfRawData);
   420  	if(sect->sh.PointerToRawData == 0) // .bss doesn't have data in object file
   421  		return 0;
   422  	werrstr("short read");
   423  	if(Bseek(obj->f, obj->base+sect->sh.PointerToRawData, 0) < 0 || 
   424  			Bread(obj->f, sect->base, sect->sh.SizeOfRawData) != sect->sh.SizeOfRawData)
   425  		return -1;
   426  	
   427  	return 0;
   428  }
   429  
   430  static int
   431  readsym(PeObj *obj, int i, PeSym **y)
   432  {
   433  	Sym *s;
   434  	PeSym *sym;
   435  	char *name, *p;
   436  
   437  	if(i >= obj->npesym || i < 0) {
   438  		werrstr("invalid pe symbol index");
   439  		return -1;
   440  	}
   441  
   442  	sym = &obj->pesym[i];
   443  	*y = sym;
   444  	
   445  	if(sym->name[0] == '.') // .section
   446  		name = obj->sect[sym->sectnum-1].sym->name;
   447  	else {
   448  		name = sym->name;
   449  		if(strncmp(name, "__imp_", 6) == 0)
   450  			name = &name[6]; // __imp_Name => Name
   451  		if(thechar == '8' && name[0] == '_')
   452  			name = &name[1]; // _Name => Name
   453  	}
   454  	// remove last @XXX
   455  	p = strchr(name, '@');
   456  	if(p)
   457  		*p = 0;
   458  	
   459  	switch(sym->type) {
   460  	default:
   461  		werrstr("%s: invalid symbol type %d", sym->name, sym->type);
   462  		return -1;
   463  	case IMAGE_SYM_DTYPE_FUNCTION:
   464  	case IMAGE_SYM_DTYPE_NULL:
   465  		switch(sym->sclass) {
   466  		case IMAGE_SYM_CLASS_EXTERNAL: //global
   467  			s = lookup(name, 0);
   468  			break;
   469  		case IMAGE_SYM_CLASS_NULL:
   470  		case IMAGE_SYM_CLASS_STATIC:
   471  			s = lookup(name, version);
   472  			break;
   473  		default:
   474  			werrstr("%s: invalid symbol binding %d", sym->name, sym->sclass);
   475  			return -1;
   476  		}
   477  		break;
   478  	}
   479  
   480  	if(s != nil && s->type == 0 && !(sym->sclass == IMAGE_SYM_CLASS_STATIC && sym->value == 0))
   481  		s->type = SXREF;
   482  	if(strncmp(sym->name, "__imp_", 6) == 0)
   483  		s->got = -2; // flag for __imp_
   484  	sym->sym = s;
   485  
   486  	return 0;
   487  }