From 6a65923eb7420206543da015f2de19bf506b164a Mon Sep 17 00:00:00 2001 From: "Paul E. Murphy" Date: Tue, 20 Sep 2022 16:52:35 -0500 Subject: [PATCH] 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 Reviewed-by: Dmitri Shuralyov Run-TryBot: Paul Murphy TryBot-Result: Gopher Robot --- ppc64/ppc64asm/decode_test.go | 18 +++++++++++++++++- ppc64/ppc64asm/objdump_test.go | 4 ++++ ppc64/ppc64asm/plan9.go | 12 ++++++++++-- ppc64/ppc64asm/testdata/decode.txt | 3 +++ 4 files changed, 34 insertions(+), 3 deletions(-) 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 @@ func TestDecode(t *testing.T) { } } +// 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 @@ func decode(data []byte, t *testing.T, filename string) { 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 @@ func allowedMismatchObjdump(text string, size int, inst *Inst, dec ExtInst) bool 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 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64)) strin } // 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 @@ func plan9Arg(inst *Inst, argIndex int, pc uint64, arg Arg, symname func(uint64) 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 @@ f0400fe0| plan9 XVCVSXDDP VS1,VS2 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