0

I'm currently trying to write a program in Rust (Windows 32-bits) which will basically extract some specific part machine code from it's own .text section.

Basically, if I define and call a function test1 as:

unsafe fn test1(){
    asm!("
        pushad
        .byte 0x90, 0x90, 0x09, 0xC0, 0x09, 0xDB, 0x09, 0xC9, 0x90

        inc eax
        mov eax, ebx
        xor eax, eax

        .byte 0x90, 0x09, 0xC0, 0x09, 0xDB, 0x09, 0xC9, 0x90, 0x90
        popad
    "
    :
    :
    :
    :"intel");
}

It will output:

inc eax
mov eax, ebx
xor eax, eax

The program uses .byte 0x90, 0x09, 0xC0, 0x09, 0xDB, 0x09, 0xC9, 0x90, 0x90 and .byte 0x90, 0x09, 0xC0, 0x09, 0xDB, 0x09, 0xC9, 0x90, 0x90 to recognize the code to retrieve (those opcode represent some nop and or reg, reg which basically does nothing).

Everything was working fine until I tried to do the following thing:

unsafe fn test2(){
    asm!("
        .byte 0x90, 0x90, 0x09, 0xC0, 0x09, 0xDB, 0x09, 0xC9, 0x90
    "
    :
    :
    :
    :"intel");
    while a < 10{
        a += 1;
    }
    asm!("
        inc eax
        dec eax
        .byte 0x90, 0x09, 0xC0, 0x09, 0xDB, 0x09, 0xC9, 0x90, 0x90
    "
    :
    :
    :
    :"intel");
}

It only detects the inc/dec instructions, which means that I can't see anything which could be the assembly equivalent of the Rust code between the two usage of inline assembly (while loop that increments a).

I don't really know how the Rust compiler process inline assembly, but I logically thought that it would respect the order in which the code has to be executed...

I hope my question was clear enough.

  • Can you put an example on https://godbolt.org/? Is `a` optimized away? Your function doesn't declare it itself so this isn't a [mcve]. If you remove both asm statements, does the Rust compiler emit any instructions for that loop? I'd guess that optimizing that loop is orthogonal to the `asm` statements. – Peter Cordes Jun 01 '20 at 10:16
  • @PeterCordes I just removed all the statement in [profile.dev] in the Cargo.toml file to decrease the size and optimize the executable `opt-level="z"`, `lto = false` etc...and it successfully worked ! I don't really know why doing that solved the issue but thanks :) – Aleister Crowley Jun 01 '20 at 10:24
  • Removing optimization options will result in the default no optimization where code with no visible side effects doesn't get removed. [Why does clang produce inefficient asm with -O0 (for this simple floating point sum)?](https://stackoverflow.com/q/53366394). And BTW, you very rarely want `opt-level="z"`. If you want small but still fast, use `s`. – Peter Cordes Jun 01 '20 at 10:26

1 Answers1

3

In optimized output there are basically no guarantees other than the assembly executed in between will have the same observable effects. This means no guarantees about ordering or that the assembly will look at all like the input. (The compiler is known to convert certain loops calculating series into their equivalent sum functions).

If you want to locate the assembly associated with a piece of code in optimized assembly, put that code in its own function, and mark that function and all functions it calls as no_inline. And make sure that all code you want to see has an observable effect, or use benchmark::black_box to pretend it does.

user1937198
  • 4,987
  • 4
  • 20
  • 31