]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/obj, cmd/internal/ld, cmd/7l: external linking for darwin/arm64
authorShenghou Ma <minux@golang.org>
Sat, 11 Apr 2015 01:28:09 +0000 (21:28 -0400)
committerMinux Ma <minux@golang.org>
Thu, 16 Apr 2015 05:13:06 +0000 (05:13 +0000)
Change-Id: I3b3f80791a1db4c2b7318f81a115972cd2237f02
Signed-off-by: Shenghou Ma <minux@golang.org>
Reviewed-on: https://go-review.googlesource.com/8781
Reviewed-by: David Crawshaw <crawshaw@golang.org>
src/cmd/7l/asm.go
src/cmd/7l/obj.go
src/cmd/internal/ld/data.go
src/cmd/internal/ld/lib.go
src/cmd/internal/ld/macho.go
src/cmd/internal/ld/sym.go
src/cmd/internal/obj/sym.go

index 525ccc660bcc81d0820e41dfa24ef84bdbd98dc3..b7ddaa0acb0c1c9eaa143421ecc8da8900be54e0 100644 (file)
@@ -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 {
@@ -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
@@ -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:
@@ -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")
        }
@@ -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
 
@@ -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))
@@ -314,6 +428,11 @@ func asmb() {
 
                                ld.Cflush()
                        }
+
+               case ld.Hdarwin:
+                       if ld.Linkmode == ld.LinkExternal {
+                               ld.Machoemitreloc()
+                       }
                }
        }
 
@@ -341,6 +460,9 @@ func asmb() {
                ld.Hopenbsd,
                ld.Hnacl:
                ld.Asmbelf(int64(symo))
+
+       case ld.Hdarwin:
+               ld.Asmbmacho()
        }
 
        ld.Cflush()
index c6ea541552364acf4f720ac788ed3e053a1ad010..1e03fa8e7521fbba3294d1441b4cc63eda2cc6d5 100644 (file)
@@ -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 {
@@ -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
        }
 
@@ -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
index 4175d4d3a1c8dde3f4481011e29500a53de83273..1b4f319ff95c4c78fb3094e962746b18990b2ad8 100644 (file)
@@ -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
index aa382717fd8d391ce7f7256983c716cea6a27c84..390d320be2b2b5ab7b6dcab120e7a06682fd2c84 100644 (file)
@@ -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
                }
        }
@@ -1599,6 +1599,7 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
                        STYPE,
                        SSTRING,
                        SGOSTRING,
+                       SGOFUNC,
                        SWINDOWS:
                        if !s.Reachable {
                                continue
index 27cdaa67b8b577aaf7d5cf1d1647c04abcebe1a6..e7ad8e2d85177ee7b9dd8fc6ebc8aa194007ffde 100644 (file)
@@ -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
@@ -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
 )
@@ -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
@@ -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)
@@ -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
@@ -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 */
index d0a80e667741eacd06960457064d9063ac0935a1..de983f38c1fc352d8c1a9769f2bbc5c7edab1e9e 100644 (file)
@@ -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
                }
        }
 
index 03584b20b00f47ec710eb4e1436ba4c9bc4ffc97..046b0f19c28e752aba409a79ba607f98dde58898 100644 (file)
@@ -158,14 +158,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
                }
        }