ppc64/ppc64asm: improve PCrel argument decoding
If an object is built for PIE, CALL opcodes will target the symbol's
local entry point. When disassembling, we should print the symbol
name if the target is the symbol+8.
The local entry offset on PPC64 is almost always 0 or 8. For pure go,
it is always 0 or 8 today.
If a call looks like it targets a local entry, print it as
"CALL symbol+8(SB)".
Change-Id: I72a2f1eaafd226ed5466384c63040d2f375a541f
Reviewed-on: https://go-review.googlesource.com/c/arch/+/432166
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Run-TryBot: Paul Murphy <murp@ibm.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
diff --git a/ppc64/ppc64asm/decode_test.go b/ppc64/ppc64asm/decode_test.go
index 3337312..83a3acd 100644
--- a/ppc64/ppc64asm/decode_test.go
+++ b/ppc64/ppc64asm/decode_test.go
@@ -31,6 +31,15 @@
}
}
+// Provide a fake symbol to verify PCrel argument decoding.
+func symlookup(pc uint64) (string, uint64) {
+ foopc := uint64(0x100000)
+ if pc >= foopc && pc < foopc+0x10 {
+ return "foo", foopc
+ }
+ return "", 0
+}
+
func decode(data []byte, t *testing.T, filename string) {
all := string(data)
// Simulate PC based on number of instructions found in the test file.
@@ -68,7 +77,14 @@
case "gnu":
out = GNUSyntax(inst, pc)
case "plan9":
- out = GoSyntax(inst, pc, nil)
+ pc := pc
+ // Hack: Setting PC to 0 effectively transforms the PC relative address
+ // of CALL (bl) into an absolute address when decoding in GoSyntax. This
+ // simplifies the testing of symbol lookups via symlookup above.
+ if inst.Op == BL {
+ pc = 0
+ }
+ out = GoSyntax(inst, pc, symlookup)
default:
t.Errorf("unknown syntax %q", syntax)
continue
diff --git a/ppc64/ppc64asm/objdump_test.go b/ppc64/ppc64asm/objdump_test.go
index e89146e..414fada 100644
--- a/ppc64/ppc64asm/objdump_test.go
+++ b/ppc64/ppc64asm/objdump_test.go
@@ -47,6 +47,10 @@
return true
case SYNC, WAIT, RFEBB: // ISA 3.1 adds more bits and extended mnemonics for these book ii instructions.
return true
+ case BL:
+ // TODO: Ignore these for now. The output format from gnu objdump is dependent on more than the
+ // instruction itself e.g: decode(48100009) = "bl 0x100008", 4, want "bl .+0x100008", 4
+ return true
}
if len(dec.enc) >= 4 {
diff --git a/ppc64/ppc64asm/plan9.go b/ppc64/ppc64asm/plan9.go
index 5fe4077..4bd1c7f 100644
--- a/ppc64/ppc64asm/plan9.go
+++ b/ppc64/ppc64asm/plan9.go
@@ -168,8 +168,9 @@
}
// plan9Arg formats arg (which is the argIndex's arg in inst) according to Plan 9 rules.
+//
// NOTE: because Plan9Syntax is the only caller of this func, and it receives a copy
-// of inst, it's ok to modify inst.Args here.
+// of inst, it's ok to modify inst.Args here.
func plan9Arg(inst *Inst, argIndex int, pc uint64, arg Arg, symname func(uint64) (string, uint64)) string {
// special cases for load/store instructions
if _, ok := arg.(Offset); ok {
@@ -211,9 +212,16 @@
return fmt.Sprintf("SPR(%d)", int(arg))
case PCRel:
addr := pc + uint64(int64(arg))
- if s, base := symname(addr); s != "" && base == addr {
+ s, base := symname(addr)
+ if s != "" && addr == base {
return fmt.Sprintf("%s(SB)", s)
}
+ if inst.Op == BL && s != "" && (addr-base) == 8 {
+ // When decoding an object built for PIE, a CALL targeting
+ // a global entry point will be adjusted to the local entry
+ // if any. For now, assume any symname+8 PC is a local call.
+ return fmt.Sprintf("%s+%d(SB)", s, addr-base)
+ }
return fmt.Sprintf("%#x", addr)
case Label:
return fmt.Sprintf("%#x", int(arg))
diff --git a/ppc64/ppc64asm/testdata/decode.txt b/ppc64/ppc64asm/testdata/decode.txt
index 54fcafd..7bf4355 100644
--- a/ppc64/ppc64asm/testdata/decode.txt
+++ b/ppc64/ppc64asm/testdata/decode.txt
@@ -469,6 +469,9 @@
7c6802a6| plan9 MOVD LR,R3
7c6902a6| plan9 MOVD CTR,R3
4c8c0000| plan9 MOVFL CR3,CR1
+48100001| plan9 CALL foo(SB)
+48100009| plan9 CALL foo+8(SB)
+4810000d| plan9 CALL 0x10000c
7c6803a6| gnu mtlr r3
7c6802a6| gnu mflr r3
7c6903a6| gnu mtctr r3