I'm very new to Assembly and the code below is supposed to swap two integers via two different functions: first using swap_c
and then using swap_asm
.
However, I doubt, whether I need to push
(I mean save) each value of registers before assembly code and pop
them later (just before returning to main
). In other words, will the CPU get mad at me if I return different register content (not the crucial ones like ebp
or esp
; but, just eax
, ebx
, ecx
& edx
) after running swap_asm
function? Is it better to uncomment the lines in the assembly part?
This code runs OK for me and I managed to reduce the 27 lines of assembled C
code down to 7 Assembly lines.
p.s.: System is Windows 10, VS-2013 Express.
main.c
part
#include <stdio.h>
extern void swap_asm(int *x, int *y);
void swap_c(int *a, int *b) {
int t = *a;
*a = *b;
*b = t;
}
int main(int argc, char *argv[]) {
int x = 3, y = 5;
printf("before swap => x = %d y = %d\n\n", x, y);
swap_c(&x, &y);
printf("after swap_c => x = %d y = %d\n\n", x, y);
swap_asm(&x, &y);
printf("after swap_asm => x = %d y = %d\n\n", x, y);
getchar();
return (0);
}
assembly.asm
part
.686
.model flat, c
.stack 100h
.data
.code
swap_asm proc
; push eax
; push ebx
; push ecx
; push edx
mov eax, [esp] + 4 ; get address of "x" stored in stack into eax
mov ebx, [esp] + 8 ; get address of "y" stored in stack into ebx
mov ecx, [eax] ; get value of "x" from address stored in [eax] into ecx
mov edx, [ebx] ; get value of "y" from address stored in [ebx] into edx
mov [eax], edx ; store value in edx into address stored in [eax]
mov [ebx], ecx ; store value in ecx into address stored in [ebx]
; pop edx
; pop ecx
; pop ebx
; pop eax
ret
swap_asm endp
end
pushing a value (not necessarily stored in a register) means writing it to the stack. popping means restoring whatever is on top of the stack into a register.
Registers are popped in order (smallest number first) so if you push a list of registers and then pop the same list, the values end up in the same locations.
The register keeps its value after push instruction.
The PUSH instruction increments the stack pointer and stores the value of the specified byte operand at the internal RAM address indirectly referenced by the stack pointer. No flags are affected by this instruction.
Generally, this depends on the calling convention of the system you are working on. The calling convention specifies how to call functions. Generally, it says where to put the arguments and what registers must be preserved by the called function.
On i386 Windows with the cdecl calling convention (which is the one you probably use), you can freely overwrite the eax
, ecx
, and edx
registers. The ebx
register must be preserved. While your code appears to work, it mysteriously fails when a function starts to depend on ebx
being preserved, so better save and restore it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With