case obj.NAME_EXTERN,
obj.NAME_STATIC:
- if a.Sym != nil && isextern(a.Sym) || p.Mode == 32 {
+ if a.Sym != nil && isextern(a.Sym) || (p.Mode == 32 && ctxt.Flag_shared == 0) {
return Yi32
}
return Yiauto // use pc-relative addressing
if a.Name == obj.NAME_GOTREF {
r.Siz = 4
r.Type = obj.R_GOTPCREL
- } else if isextern(s) || p.Mode != 64 {
+ } else if isextern(s) || (p.Mode != 64 && ctxt.Flag_shared == 0) {
r.Siz = 4
r.Type = obj.R_ADDR
} else {
if !isextern(a.Sym) && p.Mode == 64 {
goto bad
}
- base = REG_NONE
+ if p.Mode == 32 && ctxt.Flag_shared != 0 {
+ base = REG_CX
+ } else {
+ base = REG_NONE
+ }
v = int32(vaddr(ctxt, p, a, &rel))
case obj.NAME_AUTO,
if a.Sym == nil {
ctxt.Diag("bad addr: %v", p)
}
- base = REG_NONE
+ if p.Mode == 32 && ctxt.Flag_shared != 0 {
+ base = REG_CX
+ } else {
+ base = REG_NONE
+ }
v = int32(vaddr(ctxt, p, a, &rel))
case obj.NAME_AUTO,
r.Off++
}
if r.Type == obj.R_PCREL {
- // PC-relative addressing is relative to the end of the instruction,
- // but the relocations applied by the linker are relative to the end
- // of the relocation. Because immediate instruction
- // arguments can follow the PC-relative memory reference in the
- // instruction encoding, the two may not coincide. In this case,
- // adjust addend so that linker can keep relocating relative to the
- // end of the relocation.
- r.Add -= p.Pc + int64(n) - (int64(r.Off) + int64(r.Siz))
+ if p.Mode == 64 || p.As == obj.AJMP || p.As == obj.ACALL {
+ // PC-relative addressing is relative to the end of the instruction,
+ // but the relocations applied by the linker are relative to the end
+ // of the relocation. Because immediate instruction
+ // arguments can follow the PC-relative memory reference in the
+ // instruction encoding, the two may not coincide. In this case,
+ // adjust addend so that linker can keep relocating relative to the
+ // end of the relocation.
+ r.Add -= p.Pc + int64(n) - (int64(r.Off) + int64(r.Siz))
+ } else if p.Mode == 32 {
+ // On 386 PC-relative addressing (for non-call/jmp instructions)
+ // assumes that the previous instruction loaded the PC of the end
+ // of that instruction into CX, so the adjustment is relative to
+ // that.
+ r.Add += int64(r.Off) - p.Pc + int64(r.Siz)
+ }
}
}
if ctxt.Flag_dynlink {
rewriteToUseGot(ctxt, p)
}
+
+ if ctxt.Flag_shared != 0 && p.Mode == 32 {
+ rewriteToPcrel(ctxt, p)
+ }
}
// Rewrite p, if necessary, to access global data via the global offset table.
obj.Nopout(p)
}
+func rewriteToPcrel(ctxt *obj.Link, p *obj.Prog) {
+ // RegTo2 is set on the instructions we insert here so they don't get
+ // processed twice.
+ if p.RegTo2 != 0 {
+ return
+ }
+ if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
+ return
+ }
+ // Any Prog (aside from the above special cases) with an Addr with Name ==
+ // NAME_EXTERN, NAME_STATIC or NAME_GOTREF has a CALL __x86.get_pc_thunk.cx
+ // inserted before it.
+ isName := func(a *obj.Addr) bool {
+ if a.Sym == nil || (a.Type != obj.TYPE_MEM && a.Type != obj.TYPE_ADDR) || a.Reg != 0 {
+ return false
+ }
+ if a.Sym.Type == obj.STLSBSS {
+ return false
+ }
+ return a.Name == obj.NAME_EXTERN || a.Name == obj.NAME_STATIC || a.Name == obj.NAME_GOTREF
+ }
+
+ if isName(&p.From) && p.From.Type == obj.TYPE_ADDR {
+ // Handle things like "MOVL $sym, (SP)" or "PUSHL $sym" by rewriting
+ // to "MOVL $sym, CX; MOVL CX, (SP)" or "MOVL $sym, CX; PUSHL CX"
+ // respectively.
+ if p.To.Type != obj.TYPE_REG {
+ q := obj.Appendp(ctxt, p)
+ q.As = p.As
+ q.From.Type = obj.TYPE_REG
+ q.From.Reg = REG_CX
+ q.To = p.To
+ p.As = AMOVL
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = REG_CX
+ p.To.Sym = nil
+ p.To.Name = obj.NAME_NONE
+ }
+ }
+
+ if !isName(&p.From) && !isName(&p.To) && (p.From3 == nil || !isName(p.From3)) {
+ return
+ }
+ q := obj.Appendp(ctxt, p)
+ q.RegTo2 = 1
+ r := obj.Appendp(ctxt, q)
+ r.RegTo2 = 1
+ q.As = obj.ACALL
+ q.To.Sym = obj.Linklookup(ctxt, "__x86.get_pc_thunk.cx", 0)
+ q.To.Type = obj.TYPE_MEM
+ q.To.Name = obj.NAME_EXTERN
+ q.To.Sym.Local = true
+ r.As = p.As
+ r.Scond = p.Scond
+ r.From = p.From
+ r.From3 = p.From3
+ r.Reg = p.Reg
+ r.To = p.To
+ obj.Nopout(p)
+}
+
func nacladdr(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
if p.As == ALEAL || p.As == ALEAQ {
return