3

I am trying to get my head around some inline ASM but for some reason this isn't behaving as I would have expected. Why isn't this setting the value of x equal to 62?

#include <stdio.h>

int main()
{
    int x = 525;
    int* y = &x;

    _asm
    {
        mov eax, 62
        mov [y], eax
    }

    printf("%i", x);
    getchar();
    return 0;
}

The code results in 525 being output. I expected it to be 62.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
user1727141
  • 133
  • 2
  • 11

2 Answers2

2

There's a perfectly excusable misunderstanding here:

surely [y] would mean [0xCCCCCCCC] (assuming the address of x was 0xCCCCCCCC)

In high-level theory, yes. The trouble is, in actual assembly [0xCCCCCCCC] makes no sense - the CPU can't dereference a memory address directly - it can only load a value from that address into a register, then dereference that.

Similarly, since y is a variable, not a register, it's implicitly treated as an address1 i.e. y inside the asm block is the equivalent of &y in the C code outside2. As you can see by stepping through in a debugger, what happened is the assembler simply ignored the brackets that don't make sense (rather than throwing a helpful error) and assembled the equivalent of mov y, eax.

The way to get what you expect would be something like this:

asm {
    mov eax, 62
    mov edx, y
    mov [edx], eax
}

[1] this clearly isn't GCC. GCC extended asm is a whole different ball game...

[2] somewhat of a simplification - it's an "address" from a C point of view, but in assembly context it's a memory operand, which is really more like the use of an address. When I compiled this, y came out as [ebp-20], which from the high level view is "an address on the stack".

Notlikethat
  • 20,095
  • 3
  • 40
  • 77
  • Thanks, that clears things up a bit and the code works perfectly. However, according to your explanation shouldn't the second instruction, `mov edx, y`, result in the _address_ of `y` being copied to edx and not the _value_? Obviously I can see it is indeed copying `y` by value but if you say inside the `_asm` block it is actually the equivalent of `&y` in C, why is it not copying the address of `y`? Hope that makes sense... – user1727141 Feb 18 '14 at 17:51
  • @user1727141 I say "equivalent" because there's not really a 1:1 correspondence - the way an "address" is used depends on the instruction - `mov` only cares about moving data so uses a memory operand as a pointer to dereference. To put the address itself in a register there's the "load effective address" instruction: `lea edx, y` would would do exactly what you're thinking of. – Notlikethat Feb 18 '14 at 21:08
0

You are loadig the address of x into y. Then you are storing 62 in the address (again!) of the variable y -- that's what the [..] syntax means. So you are not modifying the variable x but rather the value stored at *(*y). (And it's a small wonder that does not crash your program.)

You probably want

mov [&y], eax

(if your compiler accepts that syntax).

Jongware
  • 22,200
  • 8
  • 54
  • 100
  • I already tried that before I asked the question, it doesn't work. error C2400: inline assembler syntax error in 'first operand'; found 'AND' – user1727141 Feb 17 '14 at 23:35
  • Also, surely [y] would mean [0xCCCCCCCC] (assuming the address of x was 0xCCCCCCCC). Therefore [0xCCCCCCCC] == x.. Right? – user1727141 Feb 17 '14 at 23:40