Print and emit redundant Address-Size override prefix if it's set on the
instruction.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
I think this patch is totally wrong. We need address size override prefix only when the instruction has a memory operand.The address-size override prefix (67H) allows programs to switch between 16- and 32-bit addressing. Either size can be the default; the prefix selects the non-default size. Using this prefix and/or other undefined opcodes when operands for the instruction do not reside in memory is reserved; such use may cause unpredictable behavior. Whether a instruction need ASZ should be included in the definition of the instruction in tablgen.
I believe example test case is supported by gas and callq does use address size. What syntax should be used instead?
This test case is misleading. LLVM-MC can pass the test case w/o this patch b/c an expicit prefix is added. However, this callq does not need a ASZ at all.
There is a legimate use for a redundant addr32 on a call instruction. See this code in lld
// Convert call/jmp instructions. if (modRm == 0x15) { // ABI says we can convert "call *foo@GOTPCREL(%rip)" to "nop; call foo". // Instead we convert to "addr32 call foo" where addr32 is an instruction // prefix. That makes result expression to be a single instruction. loc[-2] = 0x67; // addr32 prefix loc[-1] = 0xe8; // call write32le(loc, val); return; }
Thanks craig, I agree that we can add a redundant addr32 prefix on callq.
In addition, and GNU objdump also prints the prefix even if it is illegal, which can help developer find their bug.
cat 1.s
addr32 ret
as 1.s -o 1.o && objdump -d 1.o
0000000000000000 <.text>: 0: 67 c3 addr32 retq
This change looks good to me. But the test case should be moved into MC and covers ATT/Intel assemble syntax.
bolt/test/X86/addr32.s | ||
---|---|---|
3–21 |
bolt/test/X86/addr32.s | ||
---|---|---|
1 | This test should be moved to llvm/test/MC/Disassembler/X86/ |
@skan, @craig.topper
Thank you for the review! I didn't communicate the intent clearly. There's a BOLT bug report (https://github.com/llvm/llvm-project/issues/54066#issuecomment-1050327548) in which BOLT removes addr32 prefix from call imm. I've root caused it to instruction printer and emitter ignoring the explicit (redundant) prefix. The code is produced by g++ (GCC) 9.2.1 20200225, with -O3 -g -std=gnu++17 -Wl,-Bsymbolic-functions -Wl,--dynamic-list-cpp-new. The linker wasn't mentioned.
I didn't apply the patch and rebuild the compiler. But I think the bug can be reproduced w/o BOLT, right?
llvm/test/MC/X86/align-branch-hardcode.s | ||
---|---|---|
20 ↗ | (On Diff #411935) | Why do we got addr32 here w/ hardcode 0x66? |
llvm/test/MC/X86/align-branch-hardcode.s | ||
---|---|---|
20 ↗ | (On Diff #411935) | Looking into it |
llvm/test/MC/X86/code16-32-64.s | ||
---|---|---|
18–20 ↗ | (On Diff #411938) | addr32 should not be printed here b/c 0x67 is not a redundant prefix here. You can check the behaviour of GNU objdump. |
@skan
I moved NeedAddressOverride check out of X86MCCodeEmitter.cpp (along with isXXBitMemOperand) into X86MCTargetDesc in order to use it in printInstFlags to test if addr32 is a redundant prefix.
I belive it's the correct direction. However there is still a bug. (see my inline comments)
llvm/test/MC/Disassembler/X86/prefixes.txt | ||
---|---|---|
54 ↗ | (On Diff #412323) | 0x67 is not redundant here. It changes (%rdi) to (%edi). You can not encode |
llvm/test/MC/X86/addr16-32.s | ||
20–23 ↗ | (On Diff #412323) | 0x67 is not redundant here. |
Moved RawFrmSrc, RawFrmDstSrc, RawFrmDst handling from X86MCCodeEmitter::emitPrefixImpl
to X86_MC::needsAddressSizeOverride. This consolidates all checks controlling
the emission of AddressSize override prefix in needsAddressSizeOverride.
The flipside is a prefix order change but it should be benign.
llvm/test/MC/X86/index-operations.s | ||
---|---|---|
74 ↗ | (On Diff #412565) | You're right. It was a bug before, but it's still there: |
This test should be moved to llvm/test/MC/Disassembler/X86/