mirror of https://github.com/golang/go.git
cmd/link: make mach-o dwarf segment properly aligned
Without this, the load fails during kernel exec, which results in the mysterious and completely uninformative "Killed: 9" error. It appears that the stars (or at least the inputs) were properly aligned with earlier versions of Xcode so that this happened accidentally. Make it happen on purpose. Gregory Man bisected the breakage to this change in LLVM, which fits the theory nicely: https://github.com/llvm-mirror/llvm/commit/9a41e59c Fixes #19734. Change-Id: Ice67a09af2de29d3c0d5e3fcde6a769580897c95 Reviewed-on: https://go-review.googlesource.com/38854 Run-TryBot: Russ Cox <rsc@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
23dc3633ca
commit
b28f2f7399
|
|
@ -179,6 +179,13 @@ if test "$output" != "PASS"; then
|
|||
status=1
|
||||
fi
|
||||
|
||||
if test "$libext" = "dylib"; then
|
||||
# make sure dylibs are well-formed
|
||||
if ! otool -l libgo*.dylib >/dev/null; then
|
||||
status=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if test $status = 0; then
|
||||
echo "ok"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import (
|
|||
|
||||
var realdwarf, linkseg *macho.Segment
|
||||
var dwarfstart, linkstart int64
|
||||
var dwarfaddr, linkaddr int64
|
||||
var linkoffset uint32
|
||||
|
||||
const (
|
||||
|
|
@ -41,8 +42,7 @@ const (
|
|||
LC_DYLIB_CODE_SIGN_DRS = 0x2B
|
||||
LC_ENCRYPTION_INFO_64 = 0x2C
|
||||
|
||||
dwarfMinAlign = 6 // 64 = 1 << 6
|
||||
pageAlign = 12 // 4096 = 1 << 12
|
||||
pageAlign = 12 // 4096 = 1 << 12
|
||||
)
|
||||
|
||||
type loadCmd struct {
|
||||
|
|
@ -157,16 +157,13 @@ func machoCombineDwarf(inexe, dsym, outexe string) error {
|
|||
}
|
||||
|
||||
// Now copy the dwarf data into the output.
|
||||
maxalign := uint32(dwarfMinAlign) //
|
||||
for _, sect := range dwarfm.Sections {
|
||||
if sect.Align > maxalign {
|
||||
maxalign = sect.Align
|
||||
}
|
||||
}
|
||||
dwarfstart = machoCalcStart(realdwarf.Offset, linkseg.Offset, maxalign)
|
||||
// Kernel requires all loaded segments to be page-aligned in the file,
|
||||
// even though we mark this one as being 0 bytes of virtual address space.
|
||||
dwarfstart = machoCalcStart(realdwarf.Offset, linkseg.Offset, pageAlign)
|
||||
if _, err = outf.Seek(dwarfstart, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
dwarfaddr = int64((linkseg.Addr + linkseg.Memsz + 1<<pageAlign - 1) &^ (1<<pageAlign - 1))
|
||||
|
||||
if _, err = dwarff.Seek(int64(realdwarf.Offset), 0); err != nil {
|
||||
return err
|
||||
|
|
@ -277,10 +274,10 @@ func machoUpdateSegment(r loadCmdReader, seg, sect interface{}) error {
|
|||
return err
|
||||
}
|
||||
// There shouldn't be any sections, but just to make sure...
|
||||
return machoUpdateSections(r, segValue, reflect.ValueOf(sect), uint64(linkoffset))
|
||||
return machoUpdateSections(r, segValue, reflect.ValueOf(sect), uint64(linkoffset), 0)
|
||||
}
|
||||
|
||||
func machoUpdateSections(r loadCmdReader, seg, sect reflect.Value, delta uint64) error {
|
||||
func machoUpdateSections(r loadCmdReader, seg, sect reflect.Value, deltaOffset, deltaAddr uint64) error {
|
||||
iseg := reflect.Indirect(seg)
|
||||
nsect := iseg.FieldByName("Nsect").Uint()
|
||||
if nsect == 0 {
|
||||
|
|
@ -291,16 +288,20 @@ func machoUpdateSections(r loadCmdReader, seg, sect reflect.Value, delta uint64)
|
|||
isect := reflect.Indirect(sect)
|
||||
offsetField := isect.FieldByName("Offset")
|
||||
reloffField := isect.FieldByName("Reloff")
|
||||
addrField := isect.FieldByName("Addr")
|
||||
sectSize := int64(isect.Type().Size())
|
||||
for i := uint64(0); i < nsect; i++ {
|
||||
if err := r.ReadAt(sectOffset, sect.Interface()); err != nil {
|
||||
return err
|
||||
}
|
||||
if offsetField.Uint() != 0 {
|
||||
offsetField.SetUint(offsetField.Uint() + delta)
|
||||
offsetField.SetUint(offsetField.Uint() + deltaOffset)
|
||||
}
|
||||
if reloffField.Uint() != 0 {
|
||||
reloffField.SetUint(reloffField.Uint() + delta)
|
||||
reloffField.SetUint(reloffField.Uint() + deltaOffset)
|
||||
}
|
||||
if addrField.Uint() != 0 {
|
||||
addrField.SetUint(addrField.Uint() + deltaAddr)
|
||||
}
|
||||
if err := r.WriteAt(sectOffset, sect.Interface()); err != nil {
|
||||
return err
|
||||
|
|
@ -327,15 +328,30 @@ func machoUpdateDwarfHeader(r *loadCmdReader) error {
|
|||
if err := r.ReadAt(0, seg); err != nil {
|
||||
return err
|
||||
}
|
||||
segValue := reflect.ValueOf(seg)
|
||||
offset := reflect.Indirect(segValue).FieldByName("Offset")
|
||||
segv := reflect.ValueOf(seg).Elem()
|
||||
|
||||
segv.FieldByName("Offset").SetUint(uint64(dwarfstart))
|
||||
segv.FieldByName("Addr").SetUint(uint64(dwarfaddr))
|
||||
|
||||
deltaOffset := uint64(dwarfstart) - realdwarf.Offset
|
||||
deltaAddr := uint64(dwarfaddr) - realdwarf.Addr
|
||||
|
||||
// If we set Memsz to 0 (and might as well set Addr too),
|
||||
// then the xnu kernel will bail out halfway through load_segment
|
||||
// and not apply further sanity checks that we might fail in the future.
|
||||
// We don't need the DWARF information actually available in memory.
|
||||
// But if we do this for buildmode=c-shared then the user-space
|
||||
// dynamic loader complains about memsz < filesz. Sigh.
|
||||
if Buildmode != BuildmodeCShared {
|
||||
segv.FieldByName("Addr").SetUint(0)
|
||||
segv.FieldByName("Memsz").SetUint(0)
|
||||
deltaAddr = 0
|
||||
}
|
||||
|
||||
delta := uint64(dwarfstart) - realdwarf.Offset
|
||||
offset.SetUint(offset.Uint() + delta)
|
||||
if err := r.WriteAt(0, seg); err != nil {
|
||||
return err
|
||||
}
|
||||
return machoUpdateSections(*r, segValue, reflect.ValueOf(sect), delta)
|
||||
return machoUpdateSections(*r, segv, reflect.ValueOf(sect), deltaOffset, deltaAddr)
|
||||
}
|
||||
|
||||
func machoUpdateLoadCommand(r loadCmdReader, cmd interface{}, fields ...string) error {
|
||||
|
|
|
|||
Loading…
Reference in New Issue