// If filter is non-nil, the disassembly only includes functions with names matching filter.
// If printCode is true, the disassembly includs corresponding source lines.
// The disassembly only includes functions that overlap the range [start, end).
-func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64, printCode bool) {
+func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64, printCode bool, gnuAsm bool) {
if start < d.textStart {
start = d.textStart
}
var lastFile string
var lastLine int
- d.Decode(symStart, symEnd, relocs, func(pc, size uint64, file string, line int, text string) {
+ d.Decode(symStart, symEnd, relocs, gnuAsm, func(pc, size uint64, file string, line int, text string) {
i := pc - d.textStart
if printCode {
}
// Decode disassembles the text segment range [start, end), calling f for each instruction.
-func (d *Disasm) Decode(start, end uint64, relocs []Reloc, f func(pc, size uint64, file string, line int, text string)) {
+func (d *Disasm) Decode(start, end uint64, relocs []Reloc, gnuAsm bool, f func(pc, size uint64, file string, line int, text string)) {
if start < d.textStart {
start = d.textStart
}
lookup := d.lookup
for pc := start; pc < end; {
i := pc - d.textStart
- text, size := d.disasm(code[i:], pc, lookup, d.byteOrder)
+ text, size := d.disasm(code[i:], pc, lookup, d.byteOrder, gnuAsm)
file, line, _ := d.pcln.PCToLine(pc)
sep := "\t"
for len(relocs) > 0 && relocs[0].Addr < i+uint64(size) {
}
type lookupFunc = func(addr uint64) (sym string, base uint64)
-type disasmFunc func(code []byte, pc uint64, lookup lookupFunc, ord binary.ByteOrder) (text string, size int)
+type disasmFunc func(code []byte, pc uint64, lookup lookupFunc, ord binary.ByteOrder, _ bool) (text string, size int)
-func disasm_386(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder) (string, int) {
- return disasm_x86(code, pc, lookup, 32)
+func disasm_386(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder, gnuAsm bool) (string, int) {
+ return disasm_x86(code, pc, lookup, 32, gnuAsm)
}
-func disasm_amd64(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder) (string, int) {
- return disasm_x86(code, pc, lookup, 64)
+func disasm_amd64(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder, gnuAsm bool) (string, int) {
+ return disasm_x86(code, pc, lookup, 64, gnuAsm)
}
-func disasm_x86(code []byte, pc uint64, lookup lookupFunc, arch int) (string, int) {
+func disasm_x86(code []byte, pc uint64, lookup lookupFunc, arch int, gnuAsm bool) (string, int) {
inst, err := x86asm.Decode(code, arch)
var text string
size := inst.Len
size = 1
text = "?"
} else {
- text = x86asm.GoSyntax(inst, pc, lookup)
+ if gnuAsm {
+ text = fmt.Sprintf("%-36s // %s", x86asm.GoSyntax(inst, pc, lookup), x86asm.GNUSyntax(inst, pc, nil))
+ } else {
+ text = x86asm.GoSyntax(inst, pc, lookup)
+ }
}
return text, size
}
return
}
-func disasm_arm(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder) (string, int) {
+func disasm_arm(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder, gnuAsm bool) (string, int) {
inst, err := armasm.Decode(code, armasm.ModeARM)
var text string
size := inst.Len
if err != nil || size == 0 || inst.Op == 0 {
size = 4
text = "?"
+ } else if gnuAsm {
+ text = fmt.Sprintf("%-36s // %s", armasm.GoSyntax(inst, pc, lookup, textReader{code, pc}), armasm.GNUSyntax(inst))
} else {
text = armasm.GoSyntax(inst, pc, lookup, textReader{code, pc})
}
return text, size
}
-func disasm_arm64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.ByteOrder) (string, int) {
+func disasm_arm64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.ByteOrder, gnuAsm bool) (string, int) {
inst, err := arm64asm.Decode(code)
var text string
if err != nil || inst.Op == 0 {
text = "?"
+ } else if gnuAsm {
+ text = fmt.Sprintf("%-36s // %s", arm64asm.GoSyntax(inst, pc, lookup, textReader{code, pc}), arm64asm.GNUSyntax(inst))
} else {
text = arm64asm.GoSyntax(inst, pc, lookup, textReader{code, pc})
}
return text, 4
}
-func disasm_ppc64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.ByteOrder) (string, int) {
+func disasm_ppc64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.ByteOrder, gnuAsm bool) (string, int) {
inst, err := ppc64asm.Decode(code, byteOrder)
var text string
size := inst.Len
size = 4
text = "?"
} else {
- text = ppc64asm.GoSyntax(inst, pc, lookup)
+ if gnuAsm {
+ text = fmt.Sprintf("%-36s // %s", ppc64asm.GoSyntax(inst, pc, lookup), ppc64asm.GNUSyntax(inst, pc))
+ } else {
+ text = ppc64asm.GoSyntax(inst, pc, lookup)
+ }
}
return text, size
}
"cmd/internal/objfile"
)
-var printCode = flag.Bool("S", false, "print go code alongside assembly")
+var printCode = flag.Bool("S", false, "print Go code alongside assembly")
var symregexp = flag.String("s", "", "only dump symbols matching this regexp")
+var gnuAsm = flag.Bool("gnu", false, "print GNU assembly next to Go assembly (where supported)")
var symRE *regexp.Regexp
func usage() {
- fmt.Fprintf(os.Stderr, "usage: go tool objdump [-S] [-s symregexp] binary [start end]\n\n")
+ fmt.Fprintf(os.Stderr, "usage: go tool objdump [-S] [-gnu] [-s symregexp] binary [start end]\n\n")
flag.PrintDefaults()
os.Exit(2)
}
usage()
case 1:
// disassembly of entire object
- dis.Print(os.Stdout, symRE, 0, ^uint64(0), *printCode)
+ dis.Print(os.Stdout, symRE, 0, ^uint64(0), *printCode, *gnuAsm)
case 3:
// disassembly of PC range
if err != nil {
log.Fatalf("invalid end PC: %v", err)
}
- dis.Print(os.Stdout, symRE, start, end, *printCode)
+ dis.Print(os.Stdout, symRE, start, end, *printCode, *gnuAsm)
}
}
"RET",
}
+var amd64GnuNeed = []string{
+ "movq",
+ "callq",
+ "cmpb",
+}
+
+var i386GnuNeed = []string{
+ "mov",
+ "call",
+ "cmp",
+}
+
var armNeed = []string{
"B main.main(SB)",
"BL main.Println(SB)",
"RET",
}
+var arm64GnuNeed = []string{
+ "ldr",
+ "bl",
+ "cmp",
+}
+
var ppcNeed = []string{
"BR main.main(SB)",
"CALL main.Println(SB)",
"RET",
}
+var ppcGnuNeed = []string{
+ "mflr",
+ "lbz",
+ "cmpw",
+}
+
var target = flag.String("target", "", "test disassembly of `goos/goarch` binary")
// objdump is fully cross platform: it can handle binaries
// binary for the current system (only) and test that objdump
// can handle that one.
-func testDisasm(t *testing.T, printCode bool, flags ...string) {
+func testDisasm(t *testing.T, printCode bool, printGnuAsm bool, flags ...string) {
t.Parallel()
goarch := runtime.GOARCH
if *target != "" {
goarch = f[1]
}
- hash := md5.Sum([]byte(fmt.Sprintf("%v-%v", flags, printCode)))
+ hash := md5.Sum([]byte(fmt.Sprintf("%v-%v-%v", flags, printCode, printGnuAsm)))
hello := filepath.Join(tmp, fmt.Sprintf("hello-%x.exe", hash))
args := []string{"build", "-o", hello}
args = append(args, flags...)
need = append(need, ppcNeed...)
}
+ if printGnuAsm {
+ switch goarch {
+ case "amd64":
+ need = append(need, amd64GnuNeed...)
+ case "386":
+ need = append(need, i386GnuNeed...)
+ case "arm64":
+ need = append(need, arm64GnuNeed...)
+ case "ppc64", "ppc64le":
+ need = append(need, ppcGnuNeed...)
+ }
+ }
args = []string{
"-s", "main.main",
hello,
args = append([]string{"-S"}, args...)
}
+ if printGnuAsm {
+ args = append([]string{"-gnu"}, args...)
+ }
cmd = exec.Command(exe, args...)
cmd.Dir = "testdata" // "Bad line" bug #36683 is sensitive to being run in the source directory
out, err = cmd.CombinedOutput()
case "s390x":
t.Skipf("skipping on %s, issue 15255", runtime.GOARCH)
}
- testDisasm(t, false)
+ testDisasm(t, false, false)
}
func TestDisasmCode(t *testing.T) {
case "mips", "mipsle", "mips64", "mips64le", "riscv64", "s390x":
t.Skipf("skipping on %s, issue 19160", runtime.GOARCH)
}
- testDisasm(t, true)
+ testDisasm(t, true, false)
+}
+
+func TestDisasmGnuAsm(t *testing.T) {
+ switch runtime.GOARCH {
+ case "mips", "mipsle", "mips64", "mips64le", "riscv64", "s390x":
+ t.Skipf("skipping on %s, issue 19160", runtime.GOARCH)
+ case "arm":
+ t.Skipf("skipping gnuAsm test on %s", runtime.GOARCH)
+ }
+ testDisasm(t, false, true)
}
func TestDisasmExtld(t *testing.T) {
if !build.Default.CgoEnabled {
t.Skip("skipping because cgo is not enabled")
}
- testDisasm(t, false, "-ldflags=-linkmode=external")
+ testDisasm(t, false, false, "-ldflags=-linkmode=external")
}
func TestDisasmGoobj(t *testing.T) {