As Vlad Krasnov has said in a comment on the question, the problem comes from the compiler (and/or the assembler) not knowing the size of the arguments in code like add [esp], 7
. This problem wouldn't arise if you were writing, for example, add [esp], eax
.
If you were the compiler, how would you interpret this instruction? You are asked to add 7 to the memory location ESP is pointing to. But neither 7, nor [esp]
specify how large the arguments for the addition are. A byte? Two bytes? Four bytes? Even 8 bytes would have been a possibility if this wasn't inline assembly (isn't allowed in 64-bit code.)
Note that while ESP is 4 bytes, the memory location it points to can be of any size. The same goes for the immediate value 7, which can fit in any number of bytes.
The solution, as again is mentioned by Vlad Krasnov in the comments is to specify the size of the operand explicitly. You can check your favorite assembler's documentation, but in this case, if you want 32-bit addition, you can write add DWORD PTR [esp], 7
. This obviously says that [esp]
points to a DWORD in memory (which is 32 bits for MASM.)
Also note that not all instructions on x86 support a form that have immediate values and memory addresses in them. For each instruction, you could check "Intel Architectures Software Developer Manual", volume 2 (which is the instruction set reference) to make sure the instruction you are trying to use actually exists!
And, you should always inspect the assembly output of the compiler (since you are working with inline assembly) to make sure the code the compiler generated is actually what you intended. It is quite easy to instruct the compiler to generate assembler code, and it's quite readable!