0

Ive been going over the book over and over again and cannot understand why this is giving me "improper operand type". It should work!

This is inline assembly in Visual Studio.

function(unsigned int* a){
unsigned int num;

_asm {

mov eax, a //This stores address (start of the array) in eax
mov num, dword ptr [eax*4] //This is the line I am having issues with.

That last line, I am trying to store the 4 byte value that is in the array. But I get error C2415: improper operand type

What am I doing wrong? How do I copy 4 byte value from an array into a 32 bit register?

Duxa
  • 966
  • 2
  • 14
  • 27
  • 3
    There is no such thing as moving a memory operand to another memory operand in a single MOV operation. You have to use a temporary register. – Michael Petch May 04 '17 at 05:33
  • But I am moving from memory to register then from register to memory, 2 separate operations, no copying memory to memory? – Duxa May 04 '17 at 05:40
  • 4
    `num` is not a register. Both operands of `mov num, dword ptr [eax*4]` are memory – phuclv May 04 '17 at 05:44
  • [This answer I posted to your other question should answer this one as well](http://stackoverflow.com/a/43774644/366904). What makes this confusing is that `a` is actually a pointer. Still, the same logic applies. `mov eax, a` works because it puts the pointer value in `eax`. `mov num, dword ptr [eax*4]` doesn't work because you can't do `mov memory, memory`. When I say "register", I mean just a bare register. With `dword ptr [eax*4]`, it is reading from the memory pointed to by `eax*4` (that's what the brackets mean). Use a temporary register, or clobber `eax`, as I demonstrate in that answer – Cody Gray - on strike May 04 '17 at 08:37
  • 1
    Of course, `eax*4` doesn't make sense. Why would you scale a pointer by 4? You probably want `eax+4`. Honestly, though, it makes very little sense to use inline assembly for this. Just let the compiler generate the code. It will be more efficient than anything you could write in inline assembly. – Cody Gray - on strike May 04 '17 at 08:38
  • 1
    Possible duplicate of [x86 Assembly pointers](http://stackoverflow.com/questions/43769467/x86-assembly-pointers) – David Hoelzer May 04 '17 at 11:23

1 Answers1

2

In Visual C++'s inline assembly, all variables are accessed as memory operands1; in other words, wherever you write num you can think that the compiler will replace dword ptr[ebp - something].

Now, this means that in the last mov you are effectively trying to perform a memory-memory mov, which isn't provided on x86. Use a temporary register instead:

mov eax, dword ptr [a]     ; load value of 'a' (which is an address) in eax
mov eax, dword ptr [eax]   ; dereference address, and load contents in eax
mov dword ptr [num], eax   ; store value in 'num'

Notice that I removed the *4, as it doesn't really make sense to multiply a pointer by four - maybe you meant to use a as base plus some other index?


1 Other compilers, such as gcc, provide means to control way more finely the interaction between inline assembly and compiler generated code, which provides great flexibility and power but has quite a steep learning curve and requires great care to get everything right.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
  • The *4 is supposed to be scale. Am I not using it correctly? Here is what I mean - http://imgur.com/a/AGjxt Its supposed to specify how many bytes to copy – Duxa May 04 '17 at 05:31
  • 2
    In Intel notation the number of bytes to copy is implicit in the source value - `dword ptr` specifies that your source is the dword (=4 bytes) stored at the given location. The index and scale is used when you want to access some particular element of an array given the array start and the element index - if you have an array of dword starting at the address stored in ebx you can access the eax-th element by `mov target, dword ptr[ebx + eax*4]`. – Matteo Italia May 04 '17 at 05:44
  • MASM interprets `mov reg, [mem]` and `mov reg, mem` as being identical. The brackets are implicit for variables and other memory operands. I believe this is what you're trying to say in the first sentence. If you want the normal `mov reg, mem` behavior that you'd get in an assembler like NASM, you use `mov reg, OFFSET mem`. – Cody Gray - on strike May 04 '17 at 08:40
  • @CodyGray: unfortunately I'm not proficient at all with the MASM syntax, most of my assembly knowledge comes from disassembly/reverse engineering and some small-scale fiddling with nasm; anyhow, the correction is fine, that's exactly what I meant. – Matteo Italia May 04 '17 at 09:06
  • @CodyGray Hi, I am trying to read color value from an array pointer to a variable (unsigned int) and then back into a register. Here is what I am doing but it doesnt seem to be working: `function(unsigned int* image){ unsigned into color; _asm{ mov eax, image //Moves address to mem location to eax register mov edx, dword ptr [eax] //Mov the value of the location to edx register (so this is hex for color) mov color , edx //Now the color hex value is in color int mov edi, dword ptr [color] //Moving the color value from int to register mov dword ptr [eax], edi //Wrote color back to mem` – Duxa May 04 '17 at 19:14
  • 2
    Code in comments is not readable; there are no line breaks. This isn't the "Ask a Question" box. Look for that if you have a new question, @duxa. – Cody Gray - on strike May 05 '17 at 13:46