Skip to content

Commit 5a31228

Browse files
committed
cmd/objdump: add support for -gnu option on Go objdump
This adds support for the -gnu option on Go objdump. When this option is used, then output will include gnu assembly in comments alongside the Go assembly. The objdump test was updated to test this new option. This option is supported for the arches found in golang.org/x that provide the GNUsyntax function. Updates #34372 Change-Id: I9e60e1691526607dda3c857c4564dcef408b8391 Reviewed-on: https://go-review.googlesource.com/c/go/+/225459 Run-TryBot: Lynn Boger <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Cherry Zhang <[email protected]>
1 parent 89e13c8 commit 5a31228

File tree

4 files changed

+87
-25
lines changed

4 files changed

+87
-25
lines changed

src/cmd/internal/objfile/disasm.go

+27-15
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ func (fc *FileCache) Line(filename string, line int) ([]byte, error) {
187187
// If filter is non-nil, the disassembly only includes functions with names matching filter.
188188
// If printCode is true, the disassembly includs corresponding source lines.
189189
// The disassembly only includes functions that overlap the range [start, end).
190-
func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64, printCode bool) {
190+
func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64, printCode bool, gnuAsm bool) {
191191
if start < d.textStart {
192192
start = d.textStart
193193
}
@@ -229,7 +229,7 @@ func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64, pr
229229
var lastFile string
230230
var lastLine int
231231

232-
d.Decode(symStart, symEnd, relocs, func(pc, size uint64, file string, line int, text string) {
232+
d.Decode(symStart, symEnd, relocs, gnuAsm, func(pc, size uint64, file string, line int, text string) {
233233
i := pc - d.textStart
234234

235235
if printCode {
@@ -266,7 +266,7 @@ func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64, pr
266266
}
267267

268268
// Decode disassembles the text segment range [start, end), calling f for each instruction.
269-
func (d *Disasm) Decode(start, end uint64, relocs []Reloc, f func(pc, size uint64, file string, line int, text string)) {
269+
func (d *Disasm) Decode(start, end uint64, relocs []Reloc, gnuAsm bool, f func(pc, size uint64, file string, line int, text string)) {
270270
if start < d.textStart {
271271
start = d.textStart
272272
}
@@ -277,7 +277,7 @@ func (d *Disasm) Decode(start, end uint64, relocs []Reloc, f func(pc, size uint6
277277
lookup := d.lookup
278278
for pc := start; pc < end; {
279279
i := pc - d.textStart
280-
text, size := d.disasm(code[i:], pc, lookup, d.byteOrder)
280+
text, size := d.disasm(code[i:], pc, lookup, d.byteOrder, gnuAsm)
281281
file, line, _ := d.pcln.PCToLine(pc)
282282
sep := "\t"
283283
for len(relocs) > 0 && relocs[0].Addr < i+uint64(size) {
@@ -291,25 +291,29 @@ func (d *Disasm) Decode(start, end uint64, relocs []Reloc, f func(pc, size uint6
291291
}
292292

293293
type lookupFunc = func(addr uint64) (sym string, base uint64)
294-
type disasmFunc func(code []byte, pc uint64, lookup lookupFunc, ord binary.ByteOrder) (text string, size int)
294+
type disasmFunc func(code []byte, pc uint64, lookup lookupFunc, ord binary.ByteOrder, _ bool) (text string, size int)
295295

296-
func disasm_386(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder) (string, int) {
297-
return disasm_x86(code, pc, lookup, 32)
296+
func disasm_386(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder, gnuAsm bool) (string, int) {
297+
return disasm_x86(code, pc, lookup, 32, gnuAsm)
298298
}
299299

300-
func disasm_amd64(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder) (string, int) {
301-
return disasm_x86(code, pc, lookup, 64)
300+
func disasm_amd64(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder, gnuAsm bool) (string, int) {
301+
return disasm_x86(code, pc, lookup, 64, gnuAsm)
302302
}
303303

304-
func disasm_x86(code []byte, pc uint64, lookup lookupFunc, arch int) (string, int) {
304+
func disasm_x86(code []byte, pc uint64, lookup lookupFunc, arch int, gnuAsm bool) (string, int) {
305305
inst, err := x86asm.Decode(code, arch)
306306
var text string
307307
size := inst.Len
308308
if err != nil || size == 0 || inst.Op == 0 {
309309
size = 1
310310
text = "?"
311311
} else {
312-
text = x86asm.GoSyntax(inst, pc, lookup)
312+
if gnuAsm {
313+
text = fmt.Sprintf("%-36s // %s", x86asm.GoSyntax(inst, pc, lookup), x86asm.GNUSyntax(inst, pc, nil))
314+
} else {
315+
text = x86asm.GoSyntax(inst, pc, lookup)
316+
}
313317
}
314318
return text, size
315319
}
@@ -334,39 +338,47 @@ func (r textReader) ReadAt(data []byte, off int64) (n int, err error) {
334338
return
335339
}
336340

337-
func disasm_arm(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder) (string, int) {
341+
func disasm_arm(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder, gnuAsm bool) (string, int) {
338342
inst, err := armasm.Decode(code, armasm.ModeARM)
339343
var text string
340344
size := inst.Len
341345
if err != nil || size == 0 || inst.Op == 0 {
342346
size = 4
343347
text = "?"
348+
} else if gnuAsm {
349+
text = fmt.Sprintf("%-36s // %s", armasm.GoSyntax(inst, pc, lookup, textReader{code, pc}), armasm.GNUSyntax(inst))
344350
} else {
345351
text = armasm.GoSyntax(inst, pc, lookup, textReader{code, pc})
346352
}
347353
return text, size
348354
}
349355

350-
func disasm_arm64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.ByteOrder) (string, int) {
356+
func disasm_arm64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.ByteOrder, gnuAsm bool) (string, int) {
351357
inst, err := arm64asm.Decode(code)
352358
var text string
353359
if err != nil || inst.Op == 0 {
354360
text = "?"
361+
} else if gnuAsm {
362+
text = fmt.Sprintf("%-36s // %s", arm64asm.GoSyntax(inst, pc, lookup, textReader{code, pc}), arm64asm.GNUSyntax(inst))
355363
} else {
356364
text = arm64asm.GoSyntax(inst, pc, lookup, textReader{code, pc})
357365
}
358366
return text, 4
359367
}
360368

361-
func disasm_ppc64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.ByteOrder) (string, int) {
369+
func disasm_ppc64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.ByteOrder, gnuAsm bool) (string, int) {
362370
inst, err := ppc64asm.Decode(code, byteOrder)
363371
var text string
364372
size := inst.Len
365373
if err != nil || size == 0 {
366374
size = 4
367375
text = "?"
368376
} else {
369-
text = ppc64asm.GoSyntax(inst, pc, lookup)
377+
if gnuAsm {
378+
text = fmt.Sprintf("%-36s // %s", ppc64asm.GoSyntax(inst, pc, lookup), ppc64asm.GNUSyntax(inst, pc))
379+
} else {
380+
text = ppc64asm.GoSyntax(inst, pc, lookup)
381+
}
370382
}
371383
return text, size
372384
}

src/cmd/objdump/main.go

+5-4
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,13 @@ import (
4343
"cmd/internal/objfile"
4444
)
4545

46-
var printCode = flag.Bool("S", false, "print go code alongside assembly")
46+
var printCode = flag.Bool("S", false, "print Go code alongside assembly")
4747
var symregexp = flag.String("s", "", "only dump symbols matching this regexp")
48+
var gnuAsm = flag.Bool("gnu", false, "print GNU assembly next to Go assembly (where supported)")
4849
var symRE *regexp.Regexp
4950

5051
func usage() {
51-
fmt.Fprintf(os.Stderr, "usage: go tool objdump [-S] [-s symregexp] binary [start end]\n\n")
52+
fmt.Fprintf(os.Stderr, "usage: go tool objdump [-S] [-gnu] [-s symregexp] binary [start end]\n\n")
5253
flag.PrintDefaults()
5354
os.Exit(2)
5455
}
@@ -87,7 +88,7 @@ func main() {
8788
usage()
8889
case 1:
8990
// disassembly of entire object
90-
dis.Print(os.Stdout, symRE, 0, ^uint64(0), *printCode)
91+
dis.Print(os.Stdout, symRE, 0, ^uint64(0), *printCode, *gnuAsm)
9192

9293
case 3:
9394
// disassembly of PC range
@@ -99,6 +100,6 @@ func main() {
99100
if err != nil {
100101
log.Fatalf("invalid end PC: %v", err)
101102
}
102-
dis.Print(os.Stdout, symRE, start, end, *printCode)
103+
dis.Print(os.Stdout, symRE, start, end, *printCode, *gnuAsm)
103104
}
104105
}

src/cmd/objdump/objdump_test.go

+54-5
Original file line numberDiff line numberDiff line change
@@ -64,18 +64,42 @@ var x86Need = []string{
6464
"RET",
6565
}
6666

67+
var amd64GnuNeed = []string{
68+
"movq",
69+
"callq",
70+
"cmpb",
71+
}
72+
73+
var i386GnuNeed = []string{
74+
"mov",
75+
"call",
76+
"cmp",
77+
}
78+
6779
var armNeed = []string{
6880
"B main.main(SB)",
6981
"BL main.Println(SB)",
7082
"RET",
7183
}
7284

85+
var arm64GnuNeed = []string{
86+
"ldr",
87+
"bl",
88+
"cmp",
89+
}
90+
7391
var ppcNeed = []string{
7492
"BR main.main(SB)",
7593
"CALL main.Println(SB)",
7694
"RET",
7795
}
7896

97+
var ppcGnuNeed = []string{
98+
"mflr",
99+
"lbz",
100+
"cmpw",
101+
}
102+
79103
var target = flag.String("target", "", "test disassembly of `goos/goarch` binary")
80104

81105
// objdump is fully cross platform: it can handle binaries
@@ -87,7 +111,7 @@ var target = flag.String("target", "", "test disassembly of `goos/goarch` binary
87111
// binary for the current system (only) and test that objdump
88112
// can handle that one.
89113

90-
func testDisasm(t *testing.T, printCode bool, flags ...string) {
114+
func testDisasm(t *testing.T, printCode bool, printGnuAsm bool, flags ...string) {
91115
t.Parallel()
92116
goarch := runtime.GOARCH
93117
if *target != "" {
@@ -102,7 +126,7 @@ func testDisasm(t *testing.T, printCode bool, flags ...string) {
102126
goarch = f[1]
103127
}
104128

105-
hash := md5.Sum([]byte(fmt.Sprintf("%v-%v", flags, printCode)))
129+
hash := md5.Sum([]byte(fmt.Sprintf("%v-%v-%v", flags, printCode, printGnuAsm)))
106130
hello := filepath.Join(tmp, fmt.Sprintf("hello-%x.exe", hash))
107131
args := []string{"build", "-o", hello}
108132
args = append(args, flags...)
@@ -133,6 +157,18 @@ func testDisasm(t *testing.T, printCode bool, flags ...string) {
133157
need = append(need, ppcNeed...)
134158
}
135159

160+
if printGnuAsm {
161+
switch goarch {
162+
case "amd64":
163+
need = append(need, amd64GnuNeed...)
164+
case "386":
165+
need = append(need, i386GnuNeed...)
166+
case "arm64":
167+
need = append(need, arm64GnuNeed...)
168+
case "ppc64", "ppc64le":
169+
need = append(need, ppcGnuNeed...)
170+
}
171+
}
136172
args = []string{
137173
"-s", "main.main",
138174
hello,
@@ -142,6 +178,9 @@ func testDisasm(t *testing.T, printCode bool, flags ...string) {
142178
args = append([]string{"-S"}, args...)
143179
}
144180

181+
if printGnuAsm {
182+
args = append([]string{"-gnu"}, args...)
183+
}
145184
cmd = exec.Command(exe, args...)
146185
cmd.Dir = "testdata" // "Bad line" bug #36683 is sensitive to being run in the source directory
147186
out, err = cmd.CombinedOutput()
@@ -180,15 +219,25 @@ func TestDisasm(t *testing.T) {
180219
case "s390x":
181220
t.Skipf("skipping on %s, issue 15255", runtime.GOARCH)
182221
}
183-
testDisasm(t, false)
222+
testDisasm(t, false, false)
184223
}
185224

186225
func TestDisasmCode(t *testing.T) {
187226
switch runtime.GOARCH {
188227
case "mips", "mipsle", "mips64", "mips64le", "riscv64", "s390x":
189228
t.Skipf("skipping on %s, issue 19160", runtime.GOARCH)
190229
}
191-
testDisasm(t, true)
230+
testDisasm(t, true, false)
231+
}
232+
233+
func TestDisasmGnuAsm(t *testing.T) {
234+
switch runtime.GOARCH {
235+
case "mips", "mipsle", "mips64", "mips64le", "riscv64", "s390x":
236+
t.Skipf("skipping on %s, issue 19160", runtime.GOARCH)
237+
case "arm":
238+
t.Skipf("skipping gnuAsm test on %s", runtime.GOARCH)
239+
}
240+
testDisasm(t, false, true)
192241
}
193242

194243
func TestDisasmExtld(t *testing.T) {
@@ -209,7 +258,7 @@ func TestDisasmExtld(t *testing.T) {
209258
if !build.Default.CgoEnabled {
210259
t.Skip("skipping because cgo is not enabled")
211260
}
212-
testDisasm(t, false, "-ldflags=-linkmode=external")
261+
testDisasm(t, false, false, "-ldflags=-linkmode=external")
213262
}
214263

215264
func TestDisasmGoobj(t *testing.T) {

src/cmd/pprof/pprof.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ func (t *objTool) Disasm(file string, start, end uint64) ([]driver.Inst, error)
177177
return nil, err
178178
}
179179
var asm []driver.Inst
180-
d.Decode(start, end, nil, func(pc, size uint64, file string, line int, text string) {
180+
d.Decode(start, end, nil, false, func(pc, size uint64, file string, line int, text string) {
181181
asm = append(asm, driver.Inst{Addr: pc, File: file, Line: line, Text: text})
182182
})
183183
return asm, nil

0 commit comments

Comments
 (0)