mirror of
https://github.com/golang/go.git
synced 2024-09-22 19:08:30 +00:00
cmd/link: rewrite some code without using reflection
In Mach-O DWARF combining, some code was written using reflection, so it could support both 32-bit and 64-bit Mach-O files without duplicating code. We no longer support 32-bit darwin platforms now. 32-bit support can go. Rewrite it with direct field access, for 64-bit only. Change-Id: If1338c3cd37cecf603f4df0c6eb0c890eaebfe5f Reviewed-on: https://go-review.googlesource.com/c/go/+/253557 Run-TryBot: Cherry Zhang <cherryyz@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Than McIntosh <thanm@google.com>
This commit is contained in:
parent
e8f918535e
commit
ae3680b30b
@ -217,9 +217,9 @@ func machoCombineDwarf(ctxt *Link, exef *os.File, exem *macho.File, dsym, outexe
|
|||||||
linkoffset := uint64(linkstart) - linkseg.Offset
|
linkoffset := uint64(linkstart) - linkseg.Offset
|
||||||
switch cmd.Cmd {
|
switch cmd.Cmd {
|
||||||
case macho.LoadCmdSegment64:
|
case macho.LoadCmdSegment64:
|
||||||
err = machoUpdateSegment(reader, linkseg, linkoffset, &macho.Segment64{}, &macho.Section64{})
|
err = machoUpdateSegment(reader, linkseg, linkoffset)
|
||||||
case macho.LoadCmdSegment:
|
case macho.LoadCmdSegment:
|
||||||
err = machoUpdateSegment(reader, linkseg, linkoffset, &macho.Segment32{}, &macho.Section32{})
|
panic("unexpected 32-bit segment")
|
||||||
case LC_DYLD_INFO, LC_DYLD_INFO_ONLY:
|
case LC_DYLD_INFO, LC_DYLD_INFO_ONLY:
|
||||||
err = machoUpdateLoadCommand(reader, linkseg, linkoffset, &dyldInfoCmd{}, "RebaseOff", "BindOff", "WeakBindOff", "LazyBindOff", "ExportOff")
|
err = machoUpdateLoadCommand(reader, linkseg, linkoffset, &dyldInfoCmd{}, "RebaseOff", "BindOff", "WeakBindOff", "LazyBindOff", "ExportOff")
|
||||||
case macho.LoadCmdSymtab:
|
case macho.LoadCmdSymtab:
|
||||||
@ -313,70 +313,56 @@ func machoCompressSection(sectBytes []byte) (compressed bool, contents []byte, e
|
|||||||
|
|
||||||
// machoUpdateSegment updates the load command for a moved segment.
|
// machoUpdateSegment updates the load command for a moved segment.
|
||||||
// Only the linkedit segment should move, and it should have 0 sections.
|
// Only the linkedit segment should move, and it should have 0 sections.
|
||||||
// seg should be a macho.Segment32 or macho.Segment64 as appropriate.
|
func machoUpdateSegment(r loadCmdReader, linkseg *macho.Segment, linkoffset uint64) error {
|
||||||
// sect should be a macho.Section32 or macho.Section64 as appropriate.
|
var seg macho.Segment64
|
||||||
func machoUpdateSegment(r loadCmdReader, linkseg *macho.Segment, linkoffset uint64, seg, sect interface{}) error {
|
if err := r.ReadAt(0, &seg); err != nil {
|
||||||
if err := r.ReadAt(0, seg); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
segValue := reflect.ValueOf(seg)
|
|
||||||
offset := reflect.Indirect(segValue).FieldByName("Offset")
|
|
||||||
|
|
||||||
// Only the linkedit segment moved, anything before that is fine.
|
// Only the linkedit segment moved, anything before that is fine.
|
||||||
if offset.Uint() < linkseg.Offset {
|
if seg.Offset < linkseg.Offset {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
offset.SetUint(offset.Uint() + linkoffset)
|
seg.Offset += linkoffset
|
||||||
if err := r.WriteAt(0, seg); err != nil {
|
if err := r.WriteAt(0, &seg); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// There shouldn't be any sections, but just to make sure...
|
// There shouldn't be any sections, but just to make sure...
|
||||||
return machoUpdateSections(r, segValue, reflect.ValueOf(sect), linkoffset, nil)
|
return machoUpdateSections(r, &seg, linkoffset, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func machoUpdateSections(r loadCmdReader, seg, sect reflect.Value, deltaOffset uint64, compressedSects []*macho.Section) error {
|
func machoUpdateSections(r loadCmdReader, seg *macho.Segment64, deltaOffset uint64, compressedSects []*macho.Section) error {
|
||||||
iseg := reflect.Indirect(seg)
|
nsect := seg.Nsect
|
||||||
nsect := iseg.FieldByName("Nsect").Uint()
|
|
||||||
if nsect == 0 {
|
if nsect == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
sectOffset := int64(iseg.Type().Size())
|
sectOffset := int64(unsafe.Sizeof(*seg))
|
||||||
|
|
||||||
isect := reflect.Indirect(sect)
|
var sect macho.Section64
|
||||||
offsetField := isect.FieldByName("Offset")
|
sectSize := int64(unsafe.Sizeof(sect))
|
||||||
reloffField := isect.FieldByName("Reloff")
|
for i := uint32(0); i < nsect; i++ {
|
||||||
addrField := isect.FieldByName("Addr")
|
if err := r.ReadAt(sectOffset, §); err != nil {
|
||||||
nameField := isect.FieldByName("Name")
|
|
||||||
sizeField := isect.FieldByName("Size")
|
|
||||||
sectSize := int64(isect.Type().Size())
|
|
||||||
for i := uint64(0); i < nsect; i++ {
|
|
||||||
if err := r.ReadAt(sectOffset, sect.Interface()); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if compressedSects != nil {
|
if compressedSects != nil {
|
||||||
cSect := compressedSects[i]
|
cSect := compressedSects[i]
|
||||||
var name [16]byte
|
copy(sect.Name[:], cSect.Name)
|
||||||
copy(name[:], []byte(cSect.Name))
|
sect.Size = cSect.Size
|
||||||
nameField.Set(reflect.ValueOf(name))
|
|
||||||
sizeField.SetUint(cSect.Size)
|
|
||||||
if cSect.Offset != 0 {
|
if cSect.Offset != 0 {
|
||||||
offsetField.SetUint(uint64(cSect.Offset) + deltaOffset)
|
sect.Offset = cSect.Offset + uint32(deltaOffset)
|
||||||
}
|
}
|
||||||
if cSect.Addr != 0 {
|
if cSect.Addr != 0 {
|
||||||
addrField.SetUint(cSect.Addr)
|
sect.Addr = cSect.Addr
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if offsetField.Uint() != 0 {
|
if sect.Offset != 0 {
|
||||||
offsetField.SetUint(offsetField.Uint() + deltaOffset)
|
sect.Offset += uint32(deltaOffset)
|
||||||
}
|
}
|
||||||
if reloffField.Uint() != 0 {
|
if sect.Reloff != 0 {
|
||||||
reloffField.SetUint(reloffField.Uint() + deltaOffset)
|
sect.Reloff += uint32(deltaOffset)
|
||||||
}
|
|
||||||
if addrField.Uint() != 0 {
|
|
||||||
addrField.SetUint(addrField.Uint())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := r.WriteAt(sectOffset, sect.Interface()); err != nil {
|
if err := r.WriteAt(sectOffset, §); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
sectOffset += sectSize
|
sectOffset += sectSize
|
||||||
@ -386,32 +372,27 @@ func machoUpdateSections(r loadCmdReader, seg, sect reflect.Value, deltaOffset u
|
|||||||
|
|
||||||
// machoUpdateDwarfHeader updates the DWARF segment load command.
|
// machoUpdateDwarfHeader updates the DWARF segment load command.
|
||||||
func machoUpdateDwarfHeader(r *loadCmdReader, compressedSects []*macho.Section, dwarfsize uint64, dwarfstart int64, realdwarf *macho.Segment) error {
|
func machoUpdateDwarfHeader(r *loadCmdReader, compressedSects []*macho.Section, dwarfsize uint64, dwarfstart int64, realdwarf *macho.Segment) error {
|
||||||
var seg, sect interface{}
|
|
||||||
cmd, err := r.Next()
|
cmd, err := r.Next()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if cmd.Cmd == macho.LoadCmdSegment64 {
|
if cmd.Cmd != macho.LoadCmdSegment64 {
|
||||||
seg = new(macho.Segment64)
|
panic("not a Segment64")
|
||||||
sect = new(macho.Section64)
|
|
||||||
} else {
|
|
||||||
seg = new(macho.Segment32)
|
|
||||||
sect = new(macho.Section32)
|
|
||||||
}
|
}
|
||||||
if err := r.ReadAt(0, seg); err != nil {
|
var seg macho.Segment64
|
||||||
|
if err := r.ReadAt(0, &seg); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
segv := reflect.ValueOf(seg).Elem()
|
seg.Offset = uint64(dwarfstart)
|
||||||
segv.FieldByName("Offset").SetUint(uint64(dwarfstart))
|
|
||||||
|
|
||||||
if compressedSects != nil {
|
if compressedSects != nil {
|
||||||
var segSize uint64
|
var segSize uint64
|
||||||
for _, newSect := range compressedSects {
|
for _, newSect := range compressedSects {
|
||||||
segSize += newSect.Size
|
segSize += newSect.Size
|
||||||
}
|
}
|
||||||
segv.FieldByName("Filesz").SetUint(segSize)
|
seg.Filesz = segSize
|
||||||
} else {
|
} else {
|
||||||
segv.FieldByName("Filesz").SetUint(dwarfsize)
|
seg.Filesz = dwarfsize
|
||||||
}
|
}
|
||||||
|
|
||||||
// We want the DWARF segment to be considered non-loadable, so
|
// We want the DWARF segment to be considered non-loadable, so
|
||||||
@ -424,14 +405,14 @@ func machoUpdateDwarfHeader(r *loadCmdReader, compressedSects []*macho.Section,
|
|||||||
// in ImageLoaderMachO.cpp (various versions can be found online, see
|
// in ImageLoaderMachO.cpp (various versions can be found online, see
|
||||||
// https://opensource.apple.com/source/dyld/dyld-519.2.2/src/ImageLoaderMachO.cpp.auto.html
|
// https://opensource.apple.com/source/dyld/dyld-519.2.2/src/ImageLoaderMachO.cpp.auto.html
|
||||||
// as one example).
|
// as one example).
|
||||||
segv.FieldByName("Addr").SetUint(0)
|
seg.Addr = 0
|
||||||
segv.FieldByName("Memsz").SetUint(0)
|
seg.Memsz = 0
|
||||||
segv.FieldByName("Prot").SetUint(0)
|
seg.Prot = 0
|
||||||
|
|
||||||
if err := r.WriteAt(0, seg); err != nil {
|
if err := r.WriteAt(0, &seg); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return machoUpdateSections(*r, segv, reflect.ValueOf(sect), uint64(dwarfstart)-realdwarf.Offset, compressedSects)
|
return machoUpdateSections(*r, &seg, uint64(dwarfstart)-realdwarf.Offset, compressedSects)
|
||||||
}
|
}
|
||||||
|
|
||||||
func machoUpdateLoadCommand(r loadCmdReader, linkseg *macho.Segment, linkoffset uint64, cmd interface{}, fields ...string) error {
|
func machoUpdateLoadCommand(r loadCmdReader, linkseg *macho.Segment, linkoffset uint64, cmd interface{}, fields ...string) error {
|
||||||
|
Loading…
Reference in New Issue
Block a user