Exemplo n.º 1
0
Arquivo: ldpe.go Projeto: rsc/tmp
func ldpe(f *Biobuf, pkg string, length int64, pn string) {
	if Debug['v'] != 0 {
		fmt.Fprintf(&Bso, "%5.2f ldpe %s\n", obj.Cputime(), pn)
	}

	var sect *PeSect
	Ctxt.Version++
	base := int32(Boffset(f))

	peobj := new(PeObj)
	peobj.f = f
	peobj.base = uint32(base)
	peobj.name = pn

	// read header
	var err error
	var j int
	var l uint32
	var name string
	var numaux int
	var r []Reloc
	var rp *Reloc
	var rsect *PeSect
	var s *LSym
	var sym *PeSym
	var symbuf [18]uint8
	if err = binary.Read(f, binary.LittleEndian, &peobj.fh); err != nil {
		goto bad
	}

	// load section list
	peobj.sect = make([]PeSect, peobj.fh.NumberOfSections)

	peobj.nsect = uint(peobj.fh.NumberOfSections)
	for i := 0; i < int(peobj.fh.NumberOfSections); i++ {
		if err = binary.Read(f, binary.LittleEndian, &peobj.sect[i].sh); err != nil {
			goto bad
		}
		peobj.sect[i].size = uint64(peobj.sect[i].sh.SizeOfRawData)
		peobj.sect[i].name = cstring(peobj.sect[i].sh.Name[:])
	}

	// TODO return error if found .cormeta

	// load string table
	Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0)

	if Bread(f, symbuf[:4]) != 4 {
		goto bad
	}
	l = Le32(symbuf[:])
	peobj.snames = make([]byte, l)
	Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0)
	if Bread(f, peobj.snames) != len(peobj.snames) {
		goto bad
	}

	// rewrite section names if they start with /
	for i := 0; i < int(peobj.fh.NumberOfSections); i++ {
		if peobj.sect[i].name == "" {
			continue
		}
		if peobj.sect[i].name[0] != '/' {
			continue
		}
		l = uint32(obj.Atoi(peobj.sect[i].name[1:]))
		peobj.sect[i].name = cstring(peobj.snames[l:])
	}

	// read symbols
	peobj.pesym = make([]PeSym, peobj.fh.NumberOfSymbols)

	peobj.npesym = uint(peobj.fh.NumberOfSymbols)
	Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable), 0)
	for i := 0; uint32(i) < peobj.fh.NumberOfSymbols; i += numaux + 1 {
		Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(i), 0)
		if Bread(f, symbuf[:]) != len(symbuf) {
			goto bad
		}

		if (symbuf[0] == 0) && (symbuf[1] == 0) && (symbuf[2] == 0) && (symbuf[3] == 0) {
			l = Le32(symbuf[4:])
			peobj.pesym[i].name = cstring(peobj.snames[l:]) // sym name length <= 8
		} else {
			peobj.pesym[i].name = cstring(symbuf[:8])
		}

		peobj.pesym[i].value = Le32(symbuf[8:])
		peobj.pesym[i].sectnum = Le16(symbuf[12:])
		peobj.pesym[i].sclass = symbuf[16]
		peobj.pesym[i].aux = symbuf[17]
		peobj.pesym[i].type_ = Le16(symbuf[14:])
		numaux = int(peobj.pesym[i].aux)
		if numaux < 0 {
			numaux = 0
		}
	}

	// create symbols for mapped sections
	for i := 0; uint(i) < peobj.nsect; i++ {
		sect = &peobj.sect[i]
		if sect.sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 {
			continue
		}

		if sect.sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 {
			// This has been seen for .idata sections, which we
			// want to ignore.  See issues 5106 and 5273.
			continue
		}

		if pemap(peobj, sect) < 0 {
			goto bad
		}

		name = fmt.Sprintf("%s(%s)", pkg, sect.name)
		s = Linklookup(Ctxt, name, Ctxt.Version)

		switch sect.sh.Characteristics & (IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE) {
		case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ: //.rdata
			s.Type = obj.SRODATA

		case IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.bss
			s.Type = obj.SNOPTRBSS

		case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.data
			s.Type = obj.SNOPTRDATA

		case IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ: //.text
			s.Type = obj.STEXT

		default:
			err = fmt.Errorf("unexpected flags %#06x for PE section %s", sect.sh.Characteristics, sect.name)
			goto bad
		}

		s.P = sect.base
		s.P = s.P[:sect.size]
		s.Size = int64(sect.size)
		sect.sym = s
		if sect.name == ".rsrc" {
			setpersrc(sect.sym)
		}
	}

	// load relocations
	for i := 0; uint(i) < peobj.nsect; i++ {
		rsect = &peobj.sect[i]
		if rsect.sym == nil || rsect.sh.NumberOfRelocations == 0 {
			continue
		}
		if rsect.sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 {
			continue
		}
		if sect.sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 {
			// This has been seen for .idata sections, which we
			// want to ignore.  See issues 5106 and 5273.
			continue
		}

		r = make([]Reloc, rsect.sh.NumberOfRelocations)
		Bseek(f, int64(peobj.base)+int64(rsect.sh.PointerToRelocations), 0)
		for j = 0; j < int(rsect.sh.NumberOfRelocations); j++ {
			rp = &r[j]
			if Bread(f, symbuf[:10]) != 10 {
				goto bad
			}
			rva := Le32(symbuf[0:])
			symindex := Le32(symbuf[4:])
			type_ := Le16(symbuf[8:])
			if err = readpesym(peobj, int(symindex), &sym); err != nil {
				goto bad
			}
			if sym.sym == nil {
				err = fmt.Errorf("reloc of invalid sym %s idx=%d type=%d", sym.name, symindex, sym.type_)
				goto bad
			}

			rp.Sym = sym.sym
			rp.Siz = 4
			rp.Off = int32(rva)
			switch type_ {
			default:
				Diag("%s: unknown relocation type %d;", pn, type_)
				fallthrough

			case IMAGE_REL_I386_REL32, IMAGE_REL_AMD64_REL32,
				IMAGE_REL_AMD64_ADDR32, // R_X86_64_PC32
				IMAGE_REL_AMD64_ADDR32NB:
				rp.Type = obj.R_PCREL

				rp.Add = int64(int32(Le32(rsect.base[rp.Off:])))

			case IMAGE_REL_I386_DIR32NB, IMAGE_REL_I386_DIR32:
				rp.Type = obj.R_ADDR

				// load addend from image
				rp.Add = int64(int32(Le32(rsect.base[rp.Off:])))

			case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64
				rp.Siz = 8

				rp.Type = obj.R_ADDR

				// load addend from image
				rp.Add = int64(Le64(rsect.base[rp.Off:]))
			}

			// ld -r could generate multiple section symbols for the
			// same section but with different values, we have to take
			// that into account
			if issect(&peobj.pesym[symindex]) {
				rp.Add += int64(peobj.pesym[symindex].value)
			}
		}

		sort.Sort(rbyoff(r[:rsect.sh.NumberOfRelocations]))

		s = rsect.sym
		s.R = r
		s.R = s.R[:rsect.sh.NumberOfRelocations]
	}

	// enter sub-symbols into symbol table.
	for i := 0; uint(i) < peobj.npesym; i++ {
		if peobj.pesym[i].name == "" {
			continue
		}
		if issect(&peobj.pesym[i]) {
			continue
		}
		if uint(peobj.pesym[i].sectnum) > peobj.nsect {
			continue
		}
		if peobj.pesym[i].sectnum > 0 {
			sect = &peobj.sect[peobj.pesym[i].sectnum-1]
			if sect.sym == nil {
				continue
			}
		}

		if err = readpesym(peobj, i, &sym); err != nil {
			goto bad
		}

		s = sym.sym
		if sym.sectnum == 0 { // extern
			if s.Type == obj.SDYNIMPORT {
				s.Plt = -2 // flag for dynimport in PE object files.
			}
			if s.Type == obj.SXREF && sym.value > 0 { // global data
				s.Type = obj.SNOPTRDATA
				s.Size = int64(sym.value)
			}

			continue
		} else if sym.sectnum > 0 && uint(sym.sectnum) <= peobj.nsect {
			sect = &peobj.sect[sym.sectnum-1]
			if sect.sym == nil {
				Diag("%s: %s sym == 0!", pn, s.Name)
			}
		} else {
			Diag("%s: %s sectnum < 0!", pn, s.Name)
		}

		if sect == nil {
			return
		}

		if s.Outer != nil {
			if s.Dupok != 0 {
				continue
			}
			Exitf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
		}

		s.Sub = sect.sym.Sub
		sect.sym.Sub = s
		s.Type = sect.sym.Type | obj.SSUB
		s.Value = int64(sym.value)
		s.Size = 4
		s.Outer = sect.sym
		if sect.sym.Type == obj.STEXT {
			if s.External != 0 && s.Dupok == 0 {
				Diag("%s: duplicate definition of %s", pn, s.Name)
			}
			s.External = 1
		}
	}

	// Sort outer lists by address, adding to textp.
	// This keeps textp in increasing address order.
	for i := 0; uint(i) < peobj.nsect; i++ {
		s = peobj.sect[i].sym
		if s == nil {
			continue
		}
		if s.Sub != nil {
			s.Sub = listsort(s.Sub, valuecmp, listsubp)
		}
		if s.Type == obj.STEXT {
			if s.Onlist != 0 {
				log.Fatalf("symbol %s listed multiple times", s.Name)
			}
			s.Onlist = 1
			if Ctxt.Etextp != nil {
				Ctxt.Etextp.Next = s
			} else {
				Ctxt.Textp = s
			}
			Ctxt.Etextp = s
			for s = s.Sub; s != nil; s = s.Sub {
				if s.Onlist != 0 {
					log.Fatalf("symbol %s listed multiple times", s.Name)
				}
				s.Onlist = 1
				Ctxt.Etextp.Next = s
				Ctxt.Etextp = s
			}
		}
	}

	return

bad:
	Diag("%s: malformed pe file: %v", pn, err)
}
Exemplo n.º 2
0
Arquivo: sym.go Projeto: rsc/tmp
func linknew(arch *LinkArch) *Link {
	ctxt := new(Link)
	ctxt.Hash = make(map[symVer]*LSym)
	ctxt.Arch = arch
	ctxt.Version = obj.HistVersion
	ctxt.Goroot = obj.Getgoroot()

	p := obj.Getgoarch()
	if p != arch.Name {
		log.Fatalf("invalid goarch %s (want %s)", p, arch.Name)
	}

	var buf string
	buf, _ = os.Getwd()
	if buf == "" {
		buf = "/???"
	}
	buf = filepath.ToSlash(buf)

	ctxt.Headtype = headtype(obj.Getgoos())
	if ctxt.Headtype < 0 {
		log.Fatalf("unknown goos %s", obj.Getgoos())
	}

	// Record thread-local storage offset.
	// TODO(rsc): Move tlsoffset back into the linker.
	switch ctxt.Headtype {
	default:
		log.Fatalf("unknown thread-local storage offset for %s", Headstr(ctxt.Headtype))

	case obj.Hplan9, obj.Hwindows:
		break

		/*
		 * ELF uses TLS offset negative from FS.
		 * Translate 0(FS) and 8(FS) into -16(FS) and -8(FS).
		 * Known to low-level assembly in package runtime and runtime/cgo.
		 */
	case obj.Hlinux,
		obj.Hfreebsd,
		obj.Hnetbsd,
		obj.Hopenbsd,
		obj.Hdragonfly,
		obj.Hsolaris:
		ctxt.Tlsoffset = -1 * ctxt.Arch.Ptrsize

	case obj.Hnacl:
		switch ctxt.Arch.Thechar {
		default:
			log.Fatalf("unknown thread-local storage offset for nacl/%s", ctxt.Arch.Name)

		case '5':
			ctxt.Tlsoffset = 0

		case '6':
			ctxt.Tlsoffset = 0

		case '8':
			ctxt.Tlsoffset = -8
		}

		/*
		 * OS X system constants - offset from 0(GS) to our TLS.
		 * Explained in ../../runtime/cgo/gcc_darwin_*.c.
		 */
	case obj.Hdarwin:
		switch ctxt.Arch.Thechar {
		default:
			log.Fatalf("unknown thread-local storage offset for darwin/%s", ctxt.Arch.Name)

		case '5':
			ctxt.Tlsoffset = 0 // dummy value, not needed

		case '6':
			ctxt.Tlsoffset = 0x8a0

		case '7':
			ctxt.Tlsoffset = 0 // dummy value, not needed

		case '8':
			ctxt.Tlsoffset = 0x468
		}
	}

	// On arm, record goarm.
	if ctxt.Arch.Thechar == '5' {
		p := obj.Getgoarm()
		if p != "" {
			ctxt.Goarm = int32(obj.Atoi(p))
		} else {
			ctxt.Goarm = 6
		}
	}

	return ctxt
}