Exemple #1
0
// 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.
			// look up existing trampolines first. if we found one within the range
			// of direct call, we can reuse it. otherwise create a new one.
			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.Type == obj.SDYNIMPORT {
					// don't reuse trampoline defined in other module
					continue
				}
				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)
				if ctxt.DynlinkingGo() {
					if immrot(uint32(offset)) == 0 {
						ld.Errorf(s, "odd offset in dynlink direct call: %v+%d", r.Sym, offset)
					}
					gentrampdyn(tramp, r.Sym, int64(offset))
				} else if ld.Buildmode == ld.BuildmodeCArchive || ld.Buildmode == ld.BuildmodeCShared || ld.Buildmode == ld.BuildmodePIE {
					gentramppic(tramp, r.Sym, int64(offset))
				} else {
					gentramp(tramp, r.Sym, int64(offset))
				}
			}
			// 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)
	}
}
Exemple #2
0
// 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)
	}
}
Exemple #3
0
// 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)
	}
}