Skip to content

Commit

Permalink
cmd/internal/obj, cmd/internal/ld, cmd/7l: external linking for darwi…
Browse files Browse the repository at this point in the history
…n/arm64

Change-Id: I3b3f80791a1db4c2b7318f81a115972cd2237f02
Signed-off-by: Shenghou Ma <[email protected]>
Reviewed-on: https://go-review.googlesource.com/8781
Reviewed-by: David Crawshaw <[email protected]>
  • Loading branch information
minux committed Apr 16, 2015
1 parent 909bdf5 commit 4fd9a3f
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 29 deletions.
148 changes: 135 additions & 13 deletions src/cmd/7l/asm.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,82 @@ func elfsetupplt() {
}

func machoreloc1(r *ld.Reloc, sectoff int64) int {
return -1
var v uint32

rs := r.Xsym

// ld64 has a bug handling MACHO_ARM64_RELOC_UNSIGNED with !extern relocation.
// see cmd/internal/ld/data.go for details. The workarond is that don't use !extern
// UNSIGNED relocation at all.
if rs.Type == ld.SHOSTOBJ || r.Type == ld.R_CALLARM64 || r.Type == ld.R_ADDRARM64 || r.Type == ld.R_ADDR {
if rs.Dynid < 0 {
ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
return -1
}

v = uint32(rs.Dynid)
v |= 1 << 27 // external relocation
} else {
v = uint32((rs.Sect.(*ld.Section)).Extnum)
if v == 0 {
ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, (rs.Sect.(*ld.Section)).Name, rs.Type)
return -1
}
}

switch r.Type {
default:
return -1

case ld.R_ADDR:
v |= ld.MACHO_ARM64_RELOC_UNSIGNED << 28

case ld.R_CALLARM64:
if r.Xadd != 0 {
ld.Diag("ld64 doesn't allow BR26 reloc with non-zero addend: %s+%d", rs.Name, r.Xadd)
}

v |= 1 << 24 // pc-relative bit
v |= ld.MACHO_ARM64_RELOC_BRANCH26 << 28

case ld.R_ADDRARM64:
r.Siz = 4
// Two relocation entries: MACHO_ARM64_RELOC_PAGEOFF12 MACHO_ARM64_RELOC_PAGE21
// if r.Xadd is non-zero, add two MACHO_ARM64_RELOC_ADDEND.
if r.Xadd != 0 {
ld.Thearch.Lput(uint32(sectoff + 4))
ld.Thearch.Lput((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(r.Xadd&0xffffff))
}
ld.Thearch.Lput(uint32(sectoff + 4))
ld.Thearch.Lput(v | (ld.MACHO_ARM64_RELOC_PAGEOFF12 << 28) | (2 << 25))
if r.Xadd != 0 {
ld.Thearch.Lput(uint32(sectoff))
ld.Thearch.Lput((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(r.Xadd&0xffffff))
}
v |= 1 << 24 // pc-relative bit
v |= ld.MACHO_ARM64_RELOC_PAGE21 << 28
}

switch r.Siz {
default:
return -1

case 1:
v |= 0 << 25

case 2:
v |= 1 << 25

case 4:
v |= 2 << 25

case 8:
v |= 3 << 25
}

ld.Thearch.Lput(uint32(sectoff))
ld.Thearch.Lput(v)
return 0
}

func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
Expand All @@ -121,18 +196,6 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
case ld.R_ADDRARM64:
r.Done = 0

// the first instruction is always at the lower address, this is endian neutral;
// but note that o0 and o1 should still use the target endian.
o0 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off : r.Off+4])
o1 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off+4 : r.Off+8])

// when laid out, the instruction order must always be o1, o2.
if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
*val = int64(o0)<<32 | int64(o1)
} else {
*val = int64(o1)<<32 | int64(o0)
}

// set up addend for eventual relocation via outer symbol.
rs := r.Sym
r.Xadd = r.Add
Expand All @@ -146,6 +209,34 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
}
r.Xsym = rs

// the first instruction is always at the lower address, this is endian neutral;
// but note that o0 and o1 should still use the target endian.
o0 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off : r.Off+4])
o1 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off+4 : r.Off+8])

// Note: ld64 currently has a bug that any non-zero addend for BR26 relocation
// will make the linking fail because it thinks the code is not PIC even though
// the BR26 relocation should be fully resolved at link time.
// That is the reason why the next if block is disabled. When the bug in ld64
// is fixed, we can enable this block and also enable duff's device in cmd/7g.
if false && ld.HEADTYPE == ld.Hdarwin {
// Mach-O wants the addend to be encoded in the instruction
// Note that although Mach-O supports ARM64_RELOC_ADDEND, it
// can only encode 24-bit of signed addend, but the instructions
// supports 33-bit of signed addend, so we always encode the
// addend in place.
o0 |= (uint32((r.Xadd>>12)&3) << 29) | (uint32((r.Xadd>>12>>2)&0x7ffff) << 5)
o1 |= uint32(r.Xadd&0xfff) << 10
r.Xadd = 0
}

// when laid out, the instruction order must always be o1, o2.
if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
*val = int64(o0)<<32 | int64(o1)
} else {
*val = int64(o1)<<32 | int64(o0)
}

return 0

case ld.R_CALLARM64:
Expand Down Expand Up @@ -217,6 +308,8 @@ func adddynlib(lib string) {
ld.Addstring(s, "")
}
ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib)))
} else if ld.HEADTYPE == ld.Hdarwin {
ld.Machoadddynlib(lib)
} else {
ld.Diag("adddynlib: unsupported binary format")
}
Expand Down Expand Up @@ -258,6 +351,24 @@ func asmb() {
ld.Cseek(int64(ld.Segdata.Fileoff))
ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))

machlink := uint32(0)
if ld.HEADTYPE == ld.Hdarwin {
if ld.Debug['v'] != 0 {
fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
}

if ld.Debug['w'] == 0 { // TODO(minux): enable DWARF Support
dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)))
ld.Cseek(int64(dwarfoff))

ld.Segdwarf.Fileoff = uint64(ld.Cpos())
ld.Dwarfemitdebugsections()
ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff
}

machlink = uint32(ld.Domacholink())
}

/* output symbol table */
ld.Symsize = 0

Expand All @@ -278,6 +389,9 @@ func asmb() {

case ld.Hplan9:
symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)

case ld.Hdarwin:
symo = uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Filelen), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)) + int64(machlink))
}

ld.Cseek(int64(symo))
Expand Down Expand Up @@ -314,6 +428,11 @@ func asmb() {

ld.Cflush()
}

case ld.Hdarwin:
if ld.Linkmode == ld.LinkExternal {
ld.Machoemitreloc()
}
}
}

Expand Down Expand Up @@ -341,6 +460,9 @@ func asmb() {
ld.Hopenbsd,
ld.Hnacl:
ld.Asmbelf(int64(symo))

case ld.Hdarwin:
ld.Asmbmacho()
}

ld.Cflush()
Expand Down
21 changes: 20 additions & 1 deletion src/cmd/7l/obj.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ func archinit() {
ld.Linkmode = ld.LinkInternal
}

// Darwin/arm64 only supports external linking
if ld.HEADTYPE == ld.Hdarwin {
ld.Linkmode = ld.LinkExternal
}

switch ld.HEADTYPE {
default:
if ld.Linkmode == ld.LinkAuto {
Expand All @@ -96,7 +101,7 @@ func archinit() {
if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE)))
}
case ld.Hlinux:
case ld.Hlinux, ld.Hdarwin:
break
}

Expand Down Expand Up @@ -132,6 +137,20 @@ func archinit() {
ld.INITRND = 0x10000
}

case ld.Hdarwin: /* apple MACH */
ld.Debug['w'] = 1 // disable DWARF generation
ld.Machoinit()
ld.HEADR = ld.INITIAL_MACHO_HEADR
if ld.INITTEXT == -1 {
ld.INITTEXT = 4096 + int64(ld.HEADR)
}
if ld.INITDAT == -1 {
ld.INITDAT = 0
}
if ld.INITRND == -1 {
ld.INITRND = 4096
}

case ld.Hnacl:
ld.Elfinit()
ld.HEADR = 0x10000
Expand Down
12 changes: 11 additions & 1 deletion src/cmd/internal/ld/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -451,8 +451,18 @@ func relocsym(s *LSym) {
o = 0
}
} else if HEADTYPE == Hdarwin {
// ld64 for arm64 has a bug where if the address pointed to by o exists in the
// symbol table (dynid >= 0), or is inside a symbol that exists in the symbol
// table, then it will add o twice into the relocated value.
// The workaround is that on arm64 don't ever add symaddr to o and always use
// extern relocation by requiring rs->dynid >= 0.
if rs.Type != SHOSTOBJ {
o += Symaddr(rs)
if Thearch.Thechar == '7' && rs.Dynid < 0 {
Diag("R_ADDR reloc to %s+%d is not supported on darwin/arm64", rs.Name, o)
}
if Thearch.Thechar != '7' {
o += Symaddr(rs)
}
}
} else if HEADTYPE == Hwindows {
// nothing to do
Expand Down
3 changes: 2 additions & 1 deletion src/cmd/internal/ld/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ func loadlib() {
// dependency problems when compiling natively (external linking requires
// runtime/cgo, runtime/cgo requires cmd/cgo, but cmd/cgo needs to be
// compiled using external linking.)
if Thearch.Thechar == '5' && HEADTYPE == Hdarwin && iscgo {
if (Thearch.Thechar == '5' || Thearch.Thechar == '7') && HEADTYPE == Hdarwin && iscgo {
Linkmode = LinkExternal
}
}
Expand Down Expand Up @@ -1599,6 +1599,7 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
STYPE,
SSTRING,
SGOSTRING,
SGOFUNC,
SWINDOWS:
if !s.Reachable {
continue
Expand Down
40 changes: 33 additions & 7 deletions src/cmd/internal/ld/macho.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ const (
MACHO_CPU_ARM = 12
MACHO_SUBCPU_ARM = 0
MACHO_SUBCPU_ARMV7 = 9
MACHO_CPU_ARM64 = 1<<24 | 12
MACHO_SUBCPU_ARM64_ALL = 0
MACHO32SYMSIZE = 12
MACHO64SYMSIZE = 16
MACHO_X86_64_RELOC_UNSIGNED = 0
Expand All @@ -76,6 +78,11 @@ const (
MACHO_X86_64_RELOC_SIGNED_4 = 8
MACHO_ARM_RELOC_VANILLA = 0
MACHO_ARM_RELOC_BR24 = 5
MACHO_ARM64_RELOC_UNSIGNED = 0
MACHO_ARM64_RELOC_BRANCH26 = 2
MACHO_ARM64_RELOC_PAGE21 = 3
MACHO_ARM64_RELOC_PAGEOFF12 = 4
MACHO_ARM64_RELOC_ADDEND = 10
MACHO_GENERIC_RELOC_VANILLA = 0
MACHO_FAKE_GOTPCREL = 100
)
Expand Down Expand Up @@ -125,7 +132,7 @@ var load_budget int = INITIAL_MACHO_HEADR - 2*1024
func Machoinit() {
switch Thearch.Thechar {
// 64-bit architectures
case '6', '9':
case '6', '7', '9':
macho64 = true

// 32-bit architectures
Expand Down Expand Up @@ -349,7 +356,15 @@ func Machoadddynlib(lib string) {
func machoshbits(mseg *MachoSeg, sect *Section, segname string) {
buf := "__" + strings.Replace(sect.Name[1:], ".", "_", -1)

msect := newMachoSect(mseg, buf, segname)
var msect *MachoSect
if Thearch.Thechar == '7' && sect.Rwx&1 == 0 {
// darwin/arm64 forbids absolute relocs in __TEXT, so if
// the section is not executable, put it in __DATA segment.
msect = newMachoSect(mseg, buf, "__DATA")
} else {
msect = newMachoSect(mseg, buf, segname)
}

if sect.Rellen > 0 {
msect.reloc = uint32(sect.Reloff)
msect.nreloc = uint32(sect.Rellen / 8)
Expand Down Expand Up @@ -416,6 +431,10 @@ func Asmbmacho() {
mh.cpu = MACHO_CPU_AMD64
mh.subcpu = MACHO_SUBCPU_X86

case '7':
mh.cpu = MACHO_CPU_ARM64
mh.subcpu = MACHO_SUBCPU_ARM64_ALL

case '8':
mh.cpu = MACHO_CPU_386
mh.subcpu = MACHO_SUBCPU_X86
Expand Down Expand Up @@ -483,11 +502,18 @@ func Asmbmacho() {
ml.data[2+15] = uint32(Entryvalue()) /* start pc */

case '6':
ml := newMachoLoad(5, 42+2) /* unix thread */
ml.data[0] = 4 /* thread type */
ml.data[1] = 42 /* word count */
ml.data[2+32] = uint32(Entryvalue()) /* start pc */
ml.data[2+32+1] = uint32(Entryvalue() >> 16 >> 16) // hide >>32 for 8l
ml := newMachoLoad(5, 42+2) /* unix thread */
ml.data[0] = 4 /* thread type */
ml.data[1] = 42 /* word count */
ml.data[2+32] = uint32(Entryvalue()) /* start pc */
ml.data[2+32+1] = uint32(Entryvalue() >> 32)

case '7':
ml := newMachoLoad(5, 68+2) /* unix thread */
ml.data[0] = 6 /* thread type */
ml.data[1] = 68 /* word count */
ml.data[2+64] = uint32(Entryvalue()) /* start pc */
ml.data[2+64+1] = uint32(Entryvalue() >> 32)

case '8':
ml := newMachoLoad(5, 16+2) /* unix thread */
Expand Down
9 changes: 6 additions & 3 deletions src/cmd/internal/ld/sym.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,17 @@ func linknew(arch *LinkArch) *Link {
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

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

Expand Down
Loading

0 comments on commit 4fd9a3f

Please sign in to comment.