Xor eax, eax may be still sometimes faster than mov eax, 0 afaik. |
Only if you count the amount of time it takes to load the instruction, since the XOR is two bytes and the MOV EAX is five. (So XOR is still better...)
Going to try to explain my answer a little bit better, but on just one single post because I think you are intelligent enough to notice it without resorting to spamming.
(NB. You are lucky you are getting any response at all. You've just done the internet equivalent of biting the hand that feeds you then adding insult to injury. If you don't think you have got a satifactory answer, don't just turn up the volume and repeat the question. The reason I am responding at all is because of the clear effort you made to explain yourself better --so I assume that the inordinate rudeness was an accidental faux pas.)
Answer 1
If you stick inline assembly in the middle of a function, C and C++ presume that the assembly code is part of that very function, and simply insert the assembly code (assembled to machine code, of course) into the function exactly where your
__asm statement(s) are. There is no magic to it.
But, if I understand your example correctly, you are wondering about the local variables
x,
y, and
z.
Typically, functions have specific
entry and
exit frame code, or (as
jmc referred to it), a
prolog and an
epilog. Basically it means that a set amount of code is inserted at the beginning and end of a function. It works something like this simplified example:
1 2 3 4 5
|
int quux( int x, int y )
{
int z = x + y;
return z / (x - y);
}
| |
The
prolog adjusts the stack's
frame pointer (EBP on Intel architectures) and makes room on the stack for all local variables. A "frame" is simply a reference to a specific position on the program's stack. (For purposes of illustration I will not optimize that local variable out of existence and that we are using the default
cdecl calling convention.)
1 2 3 4 5
|
; when the function is called, the stack looks like this:
(return address) <-- ESP ; (lower addresses)
(x) ; (function arguments were pushed right to left)
(y)
... <-- EBP ; (higher addresses)
| |
1 2 3 4 5
|
_quux:
; The function prolog
push ebp ; preserve the last function's frame
mov ebp, esp ; and set this function's frame
sub esp, 4 ; make room for our local variable: sizeof( z )
| |
1 2 3 4 5 6 7
|
; now the stack looks like this
(z) <-- ESP
(previous EBP) <-- EBP
(return address)
(x) ; (function arguments were pushed right to left)
(y)
...
| |
1 2 3 4 5 6 7 8 9 10
|
; The function body
mov eax, [ebp+8] ; x
add eax, [ebp+12] ; + y
mov [ebp-4], eax ; --> z
mov ecx, [ebp+8] ; x
sub ecx, [ebp+12] ; - y
xor edx, edx ; (high-order word of dividend = 0)
mov eax, [ebp-4] ; z
idiv ecx ; z / (x - y) --> quotient eax, remainder edx
| |
1 2 3 4 5 6
|
; The function epilog
; (eax contains the function's return value)
mov esp, ebp ; restore the top of the stack to what it was before allocating space for local variables
pop ebp ; restore the previous function's frame
ret ; return to previous function (the cdecl calling convention says
; that the caller must remove the arguments x and y from the stack)
| |
So, when the compiler comes across something like
mov eax, [z]
it knows that you want to move the contents of memory at address 'z' into the EAX register. The compiler looks in its current symbol table and discovers that 'z' is a local variable at (in my example) ebp-4. So it replaces [z] with [ebp-4] and assembles that into machine code.
When you call a function, like
call _quux
again the compiler looks in its current symbol table to find the actual address of the function 'quux', and again produces the correct machine code.
Exact details of how the stack frame is constructed and used depend on the function's
calling convention. There are many besides the old
cdecl.
(Hopefully you understand now why I said that you must know basic assembly to use this stuff.)
Answer 2
The registers EAX, ECX, and EDX are typically understood to be "use as you will". Other registers (including EBX) may (or may not) have restrictions on them. Exactly which registers you can clobber and which registers you must preserve depend on your compiler. You will have to read the documentation to know for sure.
Your assumption is wrong: the variables aren't being
declared. They already exist. They are just being
used.
In the example you posted, EAX is used as a temporary value. (It wasn't strictly necessary --the code could have been written as just
1 2 3
|
push [x]
push [y]
push [z]
| |
)
In any case, EAX is changed each time you assign it a value (using the MOV instruction, or any other instruction that modifies it).
Now, if you were using the
__fastcall calling convention (MS VC++), you could just use ECX and EDX as the first two arguments. The function
void __fastcall MovePlayerToXYZCoords( float x, float y, float z )
would be called with:
1 2 3 4 5 6
|
mov ecx, [x]
mov edx, [y]
push [z]
call @MovePlayerToXYZCoords@12
; The function cleaned up its own stack, so we don't need to pop anything here
; Also, the function returns nothing, but if it returned an ordinal value it would be in EAX (not on the stack)
| |
Answer 3
All those things named 'dword_12345' are the names the IDA disassembler gives to things it doesn't know the names of. This is typical of local variables (which you already named in your original program) and temporary values produced by the compiler (which don't have a name to begin with).
You cannot use these IDA names in your inline assembly.
The C++ compiler would have no clue what you are talking about. And, even if you did by some lucky miracle get some name right:
1) it could change the next time you compile and/or disassemble
2) the name wouldn't be listed in the local symbol table the compiler keeps for
user names. (It keeps a separate table for symbols that it makes up.)
Your first task will be to figure out what each of those names are.
1 2 3 4
|
dword_980D84 = player_count (global variable)
dword_7B8440 = ?
sub_658FB0 = adjust_player_hitpoints (function name) [It should be obvious that I am making these names up]
...
| |
The thins with names like 'loc_40A365' are address labels. If there isn't a lable at the given address, you'll have to add one.
1 2 3 4 5 6
|
jz short return_label
...
return_label:
; do your prolog
retn
| |
Make sure you look up the meanings of the instructions you are using. RETN means "near return" --are you using a medium, small, or tiny memory model?
Beyond that I cannot guess much to what the code you posted means or does.
Hopefully this helps you get nearer to understanding your goal.