コード例 #1
0
ファイル: asm.go プロジェクト: kuangchanglang/go
// Convert the direct jump relocation r to refer to a trampoline if the target is too far
func trampoline(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol) {
	switch r.Type {
	case obj.R_CALLARM:
		// r.Add is the instruction
		// low 24-bit encodes the target address
		t := (ld.Symaddr(r.Sym) + int64(signext24(r.Add&0xffffff)*4) - (s.Value + int64(r.Off))) / 4
		if t > 0x7fffff || t < -0x800000 || (*ld.FlagDebugTramp > 1 && s.File != r.Sym.File) {
			// direct call too far, need to insert trampoline
			offset := (signext24(r.Add&0xffffff) + 2) * 4
			var tramp *ld.Symbol
			for i := 0; ; i++ {
				name := r.Sym.Name + fmt.Sprintf("%+d-tramp%d", offset, i)
				tramp = ctxt.Syms.Lookup(name, int(r.Sym.Version))
				if tramp.Value == 0 {
					// either the trampoline does not exist -- we need to create one,
					// or found one the address which is not assigned -- this will be
					// laid down immediately after the current function. use this one.
					break
				}

				t = (ld.Symaddr(tramp) - 8 - (s.Value + int64(r.Off))) / 4
				if t >= -0x800000 && t < 0x7fffff {
					// found an existing trampoline that is not too far
					// we can just use it
					break
				}
			}
			if tramp.Type == 0 {
				// trampoline does not exist, create one
				ctxt.AddTramp(tramp)
				tramp.Size = 12 // 3 instructions
				tramp.P = make([]byte, tramp.Size)
				t = ld.Symaddr(r.Sym) + int64(offset)
				o1 := uint32(0xe5900000 | 11<<12 | 15<<16) // MOVW (R15), R11 // R15 is actual pc + 8
				o2 := uint32(0xe12fff10 | 11)              // JMP  (R11)
				o3 := uint32(t)                            // WORD $target
				ld.SysArch.ByteOrder.PutUint32(tramp.P, o1)
				ld.SysArch.ByteOrder.PutUint32(tramp.P[4:], o2)
				ld.SysArch.ByteOrder.PutUint32(tramp.P[8:], o3)
			}
			// modify reloc to point to tramp, which will be resolved later
			r.Sym = tramp
			r.Add = r.Add&0xff000000 | 0xfffffe // clear the offset embedded in the instruction
			r.Done = 0
		}
	default:
		ld.Errorf(s, "trampoline called with non-jump reloc: %v", r.Type)
	}
}
コード例 #2
0
ファイル: asm.go プロジェクト: achanda/go
// generate a trampoline to target+offset in position independent code
func gentramppic(tramp, target *ld.Symbol, offset int64) {
	tramp.Size = 16 // 4 instructions
	tramp.P = make([]byte, tramp.Size)
	o1 := uint32(0xe5900000 | 11<<12 | 15<<16 | 4)  // MOVW 4(R15), R11 // R15 is actual pc + 8
	o2 := uint32(0xe0800000 | 11<<12 | 15<<16 | 11) // ADD R15, R11, R11
	o3 := uint32(0xe12fff10 | 11)                   // JMP  (R11)
	o4 := uint32(0)                                 // WORD $(target-pc) // filled in with relocation
	ld.SysArch.ByteOrder.PutUint32(tramp.P, o1)
	ld.SysArch.ByteOrder.PutUint32(tramp.P[4:], o2)
	ld.SysArch.ByteOrder.PutUint32(tramp.P[8:], o3)
	ld.SysArch.ByteOrder.PutUint32(tramp.P[12:], o4)

	r := ld.Addrel(tramp)
	r.Off = 12
	r.Type = obj.R_PCREL
	r.Siz = 4
	r.Sym = target
	r.Add = offset + 4
}
コード例 #3
0
ファイル: asm.go プロジェクト: achanda/go
// generate a trampoline to target+offset
func gentramp(tramp, target *ld.Symbol, offset int64) {
	tramp.Size = 12 // 3 instructions
	tramp.P = make([]byte, tramp.Size)
	t := ld.Symaddr(target) + int64(offset)
	o1 := uint32(0xe5900000 | 11<<12 | 15<<16) // MOVW (R15), R11 // R15 is actual pc + 8
	o2 := uint32(0xe12fff10 | 11)              // JMP  (R11)
	o3 := uint32(t)                            // WORD $target
	ld.SysArch.ByteOrder.PutUint32(tramp.P, o1)
	ld.SysArch.ByteOrder.PutUint32(tramp.P[4:], o2)
	ld.SysArch.ByteOrder.PutUint32(tramp.P[8:], o3)

	if ld.Linkmode == ld.LinkExternal {
		r := ld.Addrel(tramp)
		r.Off = 8
		r.Type = obj.R_ADDR
		r.Siz = 4
		r.Sym = target
		r.Add = offset
	}
}
コード例 #4
0
ファイル: asm.go プロジェクト: achanda/go
// generate a trampoline to target+offset in dynlink mode (using GOT)
func gentrampdyn(tramp, target *ld.Symbol, offset int64) {
	tramp.Size = 20                                 // 5 instructions
	o1 := uint32(0xe5900000 | 11<<12 | 15<<16 | 8)  // MOVW 8(R15), R11 // R15 is actual pc + 8
	o2 := uint32(0xe0800000 | 11<<12 | 15<<16 | 11) // ADD R15, R11, R11
	o3 := uint32(0xe5900000 | 11<<12 | 11<<16)      // MOVW (R11), R11
	o4 := uint32(0xe12fff10 | 11)                   // JMP  (R11)
	o5 := uint32(0)                                 // WORD $target@GOT // filled in with relocation
	o6 := uint32(0)
	if offset != 0 {
		// insert an instruction to add offset
		tramp.Size = 24 // 6 instructions
		o6 = o5
		o5 = o4
		o4 = uint32(0xe2800000 | 11<<12 | 11<<16 | immrot(uint32(offset))) // ADD $offset, R11, R11
		o1 = uint32(0xe5900000 | 11<<12 | 15<<16 | 12)                     // MOVW 12(R15), R11
	}
	tramp.P = make([]byte, tramp.Size)
	ld.SysArch.ByteOrder.PutUint32(tramp.P, o1)
	ld.SysArch.ByteOrder.PutUint32(tramp.P[4:], o2)
	ld.SysArch.ByteOrder.PutUint32(tramp.P[8:], o3)
	ld.SysArch.ByteOrder.PutUint32(tramp.P[12:], o4)
	ld.SysArch.ByteOrder.PutUint32(tramp.P[16:], o5)
	if offset != 0 {
		ld.SysArch.ByteOrder.PutUint32(tramp.P[20:], o6)
	}

	r := ld.Addrel(tramp)
	r.Off = 16
	r.Type = obj.R_GOTPCREL
	r.Siz = 4
	r.Sym = target
	r.Add = 8
	if offset != 0 {
		// increase reloc offset by 4 as we inserted an ADD instruction
		r.Off = 20
		r.Add = 12
	}
}
コード例 #5
0
ファイル: asm.go プロジェクト: achanda/go
// resolve direct jump relocation r in s, and add trampoline if necessary
func trampoline(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol) {

	t := ld.Symaddr(r.Sym) + r.Add - (s.Value + int64(r.Off))
	switch r.Type {
	case obj.R_CALLPOWER:

		// If branch offset is too far then create a trampoline.

		if int64(int32(t<<6)>>6) != t || (*ld.FlagDebugTramp > 1 && s.File != r.Sym.File) {
			var tramp *ld.Symbol
			for i := 0; ; i++ {

				// Using r.Add as part of the name is significant in functions like duffzero where the call
				// target is at some offset within the function.  Calls to duff+8 and duff+256 must appear as
				// distinct trampolines.

				name := r.Sym.Name
				if r.Add == 0 {
					name = name + fmt.Sprintf("-tramp%d", i)
				} else {
					name = name + fmt.Sprintf("%+x-tramp%d", r.Add, i)
				}

				// Look up the trampoline in case it already exists

				tramp = ctxt.Syms.Lookup(name, int(r.Sym.Version))
				if tramp.Value == 0 {
					break
				}

				t = ld.Symaddr(tramp) + r.Add - (s.Value + int64(r.Off))

				// If the offset of the trampoline that has been found is within range, use it.
				if int64(int32(t<<6)>>6) == t {
					break
				}
			}
			if tramp.Type == 0 {
				ctxt.AddTramp(tramp)
				tramp.Size = 16 // 4 instructions
				tramp.P = make([]byte, tramp.Size)
				t = ld.Symaddr(r.Sym) + r.Add
				f := t & 0xffff0000
				o1 := uint32(0x3fe00000 | (f >> 16)) // lis r31,trampaddr hi (r31 is temp reg)
				f = t & 0xffff
				o2 := uint32(0x63ff0000 | f) // ori r31,trampaddr lo
				o3 := uint32(0x7fe903a6)     // mtctr
				o4 := uint32(0x4e800420)     // bctr
				ld.SysArch.ByteOrder.PutUint32(tramp.P, o1)
				ld.SysArch.ByteOrder.PutUint32(tramp.P[4:], o2)
				ld.SysArch.ByteOrder.PutUint32(tramp.P[8:], o3)
				ld.SysArch.ByteOrder.PutUint32(tramp.P[12:], o4)
			}
			r.Sym = tramp
			r.Add = 0 // This was folded into the trampoline target address
			r.Done = 0
		}
	default:
		ld.Errorf(s, "trampoline called with non-jump reloc: %v", r.Type)
	}
}