How Do I Convert This ATT assembly to Intel Syntax? Jump to a non-relative address without using registers

888 Views Asked by At

I was reading this article " assembly-challenge-jump-to-a-non-relative-address-without-using-registers ".

I need to do exactly what he suggests here (Jump to a non-relative address without using registers), only I need to do it in intel syntax instead of att.

The solution he found for att syntax was:

jmp *0f(%eip)
0: .int 0x12345678

What would this look like in intel syntax?

2

There are 2 best solutions below

5
On

OK I'll follow the main approach to answer such question by somebody's own.

Created a file with the following contents:

.text
        jmp *0f(%eip)
0:      .int 0x12345678

Compiled it and checked report of the same contents (well, your .int is decoded as a command):

$ gcc -c so_72135694.S 
$ objdump -d so_72135694.o

so_72135694.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <.text>:
   0:   67 ff 25 00 00 00 00    jmpq   *0x0(%eip)        # 0x7
   7:   78 56                   js     0x5f
   9:   34 12                   xor    $0x12,%al

(why gcc and not directly as - well, I was too lazy to recall as options.)

And then, called Intel style decoding:

$ objdump -d -Mintel-syntax so_72135694.o

so_72135694.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <.text>:
   0:   67 ff 25 00 00 00 00    jmp    QWORD PTR [eip+0x0]        # 0x7
   7:   78 56                   js     0x5f
   9:   34 12                   xor    al,0x12

Let's compare it back:

$ cat so_72135694.intel.S
.intel_syntax noprefix
.text
        jmp QWORD PTR [eip+0x0]
0:      .int 0x12345678
$ gcc -c so_72135694.intel.S 
$ objdump -d so_72135694.intel.o

so_72135694.intel.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <.text>:
   0:   67 ff 25 00 00 00 00    jmpq   *0x0(%eip)        # 0x7
   7:   78 56                   js     0x5f
   9:   34 12                   xor    $0x12,%al
$ objdump -d -Mintel-syntax so_72135694.intel.o

so_72135694.intel.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <.text>:
   0:   67 ff 25 00 00 00 00    jmp    QWORD PTR [eip+0x0]        # 0x7
   7:   78 56                   js     0x5f
   9:   34 12                   xor    al,0x12

One can easily see they are identical, and you can follow this method for all similar questions.

NB1: It is crucial to note that Unix binutils interpretation of what is "Intel syntax" will differ in subtle details with what Intel itself thinks (and even in syntax basics, like 0x1234 vs. 1234h), and with wide popular tools like NASM or FASM. Here I assume if you say for AT&T syntax, the most typical Binutils pack (GNU one) is utilized (and my system here is Ubuntu 20.04/x86-64, the nearly most popular one). If Iʼm wrong here, feel free to explore other tools specifics.

NB2: The really confusing thing in your code was using relative addressing over EIP. This addressing can be used only in 64-bit mode, but in that case using EIP is weird. An attempt to compile this in 32-bit mode (using e.g. .code32) naturally fails.

1
On

The blog actually suggests jmp *0f(%eip) for use in 32-bit mode. But that is wrong; there is no EIP-relative addressing available in 32-bit mode, so this is not valid 32-bit assembly. It looks like clang 6.0 and earlier had a bug where it would accept jmp *0f(%eip) anyway, but the output shows that the instruction it actually assembled was jmp *0, i.e. trying to load the jump target from absolute address 0 (not *0f, the address of the local label where you put some data). This won't work and will simply crash, assuming page 0 is unmapped as would be the case under a normal OS.

(More generally, it appears the bug would cause jmp label(%eip) to take the displacement of label from the next instruction, and use it as an absolute address, which would never be useful. i.e. encode as if EIP-relative addressing worked in 32-bit mode; in 64-bit mode the same machine-code would use those 4 byte of machine code as a rel32 relative displacement instead of a disp32 absolute address. But x86-64 couldn't change how 32-bit machine code worked while maintaining backwards compatibility.) So the author is mistaken about this, and must not have actually tested their proposed code.


You tagged this so I assume you are actually interested in 64-bit mode. In that case the blog's suggestion of

    jmp *0f(%rip)
0:
    .quad 0x1234567890

is valid. Note the use of the 64-bit program counter rip and the use of .quad to get a 64-bit address. (Using eip here actually is a valid instruction, corresponding to a 0x67 address size override, but it would cause the load address to be truncated to 32 bits, which is unlikely to be desired.)

The Intel syntax for RIP-relative addressing varies between assemblers. In NASM you would write:

    jmp [rel label]
label:
    dq 0x1234567890

Other assemblers might want some variation, or might assemble jmp [label] as RIP-relative by default. Check the manual of the assembler you want to use.


If you really did want to accomplish this in 32-bit mode, it would be harder. If you know the correct selector for the code segment, which on many operating systems would be a fixed value, you could do a direct far jump and encode the 6-byte segment/offset directly into the instruction. Otherwise, I don't immediately see a way to do this without using either registers or stack.

Of course, it is easy using the stack, temporarily modifying ESP:

push $0xdeadbeef   # push the constant
ret                # pop it into EIP

The blog you linked got that one wrong, too, writing push 0xdeadbeef which is a memory source operand, loading 4 bytes from that absolute address.

The next example is also broken, using mov %eax,0xdeadbeef (store EAX to an absolute address), then jmp %eax (which GAS assembles as jmp *%eax, warning you about the missing * for an indirect jump).

Seems they're used to Intel syntax; .intel_syntax noprefix would avoid having to translate to AT&T. The blog cites an SO question they asked where the same examples appear. @fuz's answer there does correct the AT&T syntax.