Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

InvalidOperationException when assembling JMP r/m64 #310

Closed
alexrp opened this issue Jul 11, 2022 · 4 comments
Closed

InvalidOperationException when assembling JMP r/m64 #310

alexrp opened this issue Jul 11, 2022 · 4 comments

Comments

@alexrp
Copy link

alexrp commented Jul 11, 2022

using Iced.Intel;
using static Iced.Intel.AssemblerRegisters;

var asm = new Assembler(64);

using var stream = new MemoryStream();
var writer = new StreamCodeWriter(stream);

asm.jmp(__qword_ptr[0xaabbccddeeffaabb]);

_ = asm.Assemble(writer, 0);

Console.WriteLine(Convert.ToHexString(stream.ToArray()).ToLowerInvariant());

This throws:

Unhandled exception. System.InvalidOperationException: Operand 0: Displacement must fit in an int : 0x0 jmp qword ptr [0AABBCCDDEEFFAABBh]
   at Iced.Intel.Assembler.Assemble(CodeWriter writer, UInt64 rip, BlockEncoderOptions options)
   at Program.<Main>$(String[] args) in C:\Users\alex\source\repos\tests\Program.cs:line 12

This seems odd to me. I would expect this to successfully assemble to a JMP r/m64: https://www.felixcloutier.com/x86/jmp

But it's quite possible I'm missing something, because some other tools also handle this particular instruction weirdly. For example, Binary Ninja's x86-64 assembler turns jmp qword [0xaabbccddeeffaabb] into ff 24 25 bb aa ff ee...

@wtfsck
Copy link
Member

wtfsck commented Jul 12, 2022

Looks like a dupe of #212

@alexrp
Copy link
Author

alexrp commented Jul 12, 2022

Actually, I think this issue is just invalid altogether.

I was under the impression that the FF /4 JMP r/m64 encoding would allow a full 64-bit memory address from which to load the jump address from, but that doesn't seem to be the case? I might have been confusing it with REX.W FF /5 JMP m16:64...

@wtfsck
Copy link
Member

wtfsck commented Jul 12, 2022

jmp qword ptr [mem] reads a 64-bit value from memory (address 'mem') and treats the value as an address in memory and jumps to it. It doesn't jump to the address value of 'mem'.

jmp qword ptr [1234] => target = readmem(1234); set rip = target; execute code from current rip.

If you want to jump to the address 0xaabbccddeeffaabb, you can just do mov rax,0xaabbccddeeffaabb; jmp rax

@alexrp
Copy link
Author

alexrp commented Jul 12, 2022

jmp qword ptr [mem] reads a 64-bit value from memory (address 'mem') and treats the value as an address in memory and jumps to it. It doesn't jump to the address value of 'mem'.

jmp qword ptr [1234] => target = readmem(1234); set rip = target; execute code from current rip.

Right. That's precisely the behavior I wanted.

Where I was mistaken is that I thought mem here could be a full 64-bit displacement value. But apparently the displacement can be 32-bit at most.

If you want to jump to the address 0xaabbccddeeffaabb, you can just do mov rax,0xaabbccddeeffaabb; jmp rax

My hope was to do it in a single instruction without modifying registers, but I see now that that's not going to work - unless I use a far jump, but that's a whole other can of worms.

I ended up going with this trick that I've seen used in a few places:

push rax
mov rax, <addr>
mov rax, qword ptr [rax]
xchg qword ptr [rsp], rax
ret

Since this wasn't actually a bug in Iced, I'll go ahead and close this issue.

@alexrp alexrp closed this as completed Jul 12, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants