I have some problems when trying to encode the 64bit forms of far call/jump. Like all other far operations in 64bit, lcall/ljmp default to a 32bit operand, and require a rex64 to promote the instruction to having a 64bit operand (specifically, it changes these instructions between having a 6 byte operand and a 10 byte operand). $ cat far-jmps.S .code64 code64: lcalll *(%rsp) rex64 lcall *(%rsp) ljmpl *(%rsp) rex64 ljmp *(%rsp) lretl lretq This version of the file assembles correct: $ /local/bin/bin-2.32/bin/as far-jmps.S -o far-jmps.o $ However, when substituting the rex64 prefix for an l or q suffix, assembly fails with: $ /local/bin/bin-2.32/bin/as far-jmps.S -o far-jmps.o far-jmps.S: Assembler messages: far-jmps.S:4: Error: invalid instruction suffix for `lcall' far-jmps.S:7: Error: invalid instruction suffix for `ljmp' Furthermore (or possibly relatedly), objdump doesn't disassemble the instruction in an expected manner: $ /local/bin/bin-2.32/bin/objdump -d far-jmps.o far-jmps.o: file format elf64-x86-64 Disassembly of section .text: 0000000000000000 <code64>: 0: ff 1c 24 lcall *(%rsp) 3: 48 ff 1c 24 rex.W lcall *(%rsp) 7: ff 2c 24 ljmp *(%rsp) a: 48 ff 2c 24 rex.W ljmp *(%rsp) e: cb lret f: 48 cb lretq The rex.W prefix printed is an accurate representation of the encoding, but an l or q suffix would be the consistent way of rendering the instructions. Observe that throughout all of this, lret and lretq do assemble and disassemble in the expected manner (as do iretl and iretq which I omitted from the example.)
Can far call/jmp take m16:m64 on AMD processors?
Yes. That works on all 64bit capable processors. The encoding which isn't supported in 64bit mode is the ptr:16:{16,32,64} encoding, which stores the segment and offset as immediate data operands in the instruction. ~Andrew
(In reply to Andrew Cooper from comment #2) > Yes. That works on all 64bit capable processors. > > The encoding which isn't supported in 64bit mode is the ptr:16:{16,32,64} > encoding, which stores the segment and offset as immediate data operands in > the instruction. > > ~Andrew AMD64 manual says: CALL FAR pntr16:16 9A cd Far call direct, with the target specified by a far pointer contained in the instruction. (Invalid in 64-bit mode.) CALL FAR pntr16:32 9A cp Far call direct, with the target specified by a far pointer contained in the instruction. (Invalid in 64-bit mode.) CALL FAR mem16:16 FF /3 Far call indirect, with the target specified by a far pointer in memory. CALL FAR mem16:32 FF /3 Far call indirect, with the target specified by a far pointer in memory.
(In reply to H.J. Lu from comment #3) > AMD64 manual says: > > CALL FAR pntr16:16 9A cd Far call direct, with the target specified by a far > pointer > contained in the instruction. (Invalid in 64-bit mode.) > CALL FAR pntr16:32 9A cp Far call direct, with the target specified by a far > pointer > contained in the instruction. (Invalid in 64-bit mode.) > CALL FAR mem16:16 FF /3 Far call indirect, with the target specified by a > far pointer > in memory. > CALL FAR mem16:32 FF /3 Far call indirect, with the target specified by a > far pointer > in memory. After some experimentation, it turns out that it really is only Intel processors which implement the mem16:64 form. AMD processors ignore the REX prefix and use mem16:32 form, even when REX-encoded.
(In reply to Andrew Cooper from comment #4) > > After some experimentation, it turns out that it really is only Intel > processors which implement the mem16:64 form. AMD processors ignore the REX > prefix and use mem16:32 form, even when REX-encoded. That is the reason for the current behavior.
(In reply to H.J. Lu from comment #5) > That is the reason for the current behavior. But you've introduced the Intel64 and AMD64 attributes, which could be used here as well to distinguish the behavior. Also for LFS, LGS, and LSS then. Similarly conditional branches (including LOOP etc) would want handling to match that of near CALL/JMP afaict.
(In reply to Jan Beulich from comment #6) > (In reply to H.J. Lu from comment #5) > > That is the reason for the current behavior. > > But you've introduced the Intel64 and AMD64 attributes, which could be used > here as well to distinguish the behavior. Also for LFS, LGS, and LSS then. > > Similarly conditional branches (including LOOP etc) would want handling to > match that of near CALL/JMP afaict. Care to make a patch?
(In reply to H.J. Lu from comment #7) > Care to make a patch? Well, I've added it to my list of things to look into, but there are various other things higher up that list, so it's not clear at all when I'd fine time. Plus Andrew's and my own observations on the actual behavior appear to disagree, making us suspect for the moment that there might even be model specific behavior (beyond the vendor differences) here. I wouldn't want to pin down one variant in binutils when there potentially are others as well.
The proposed added (AT&T mode) behavior is to allow lcall and ljmp to also have q suffixes in 64-bit Intel mode, paralleling how other insns (including branching ones) work. Similarly the assembler would then print q suffixes in Intel64 mode, rather than rex.W. A patch for this was already posted as part of a larger series: https://sourceware.org/ml/binutils/2019-12/msg00355.html
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commitdiff;h=5990e377e5a339bce715fabfc3e45b24b459a7af I don't see a mechanism in the web interface though how to change a bug's status, so I'm leaving it at "NEW".
Fixed for 2.35.