codetective
codetective

Reputation: 86

Swapping two int pointers in assembly x86

I want to swap two int pointers.

I can do it in C like this

void swap(int* a, int* b)
    int temp = *a;
    *a = *b;
    *b=temp;

Now I'm trying to do it in assembly but, and bear with me, I don't understand why this doesn't work

push %ebp
mov %esp,%ebp   

mov 8(%ebp), %ecx       #a 
mov 12(%ebp), %ebx      #b

mov (%ecx), %eax        #move o a para temp
mov (%ebx), %ecx        #move o b para o a
mov (%eax), %ebx        #move o temp para o b

mov %ebp, %esp
pop %ebp
ret

Can someone explain what I'm doing wrong?

Upvotes: 1

Views: 4627

Answers (2)

Michael Petch
Michael Petch

Reputation: 47573

Your C code is attempting to swap the values pointed to by pointers but your assembly code seems to be treating values as pointers leading to segmentation faults. One way to handle this is to use extra register(s) to hold the pointers and the values they point to.

The 32-bit CDECL allows us to use EAX, ECX, and EDX without worrying about saving their values. We'll need a 4th register and we'll have to preserve it ourselves.

I will also assume you want the frame pointer present (the routine could be written without it):

push   %ebp
mov    %esp,%ebp
push   %ebx              # Preserve non-volatile EBX register
mov    8(%ebp),%eax      # EAX = Pointer to a (arg1)
mov    12(%ebp),%edx     # EDX = Pointer to b (arg2)
mov    (%eax),%ecx       # Temporarily save value at memory address a (*a) to ECX
mov    (%edx),%ebx       # Temporarily save value at memory address b (*b) to EBX
mov    %ebx,(%eax)       # Move value of b (EBX) to memory address of a (*a)
mov    %ecx,(%edx)       # Move value of a (ECX) to memory address of b (*b)
pop    %ebx              # Restore non-volatile EBX register
pop    %ebp
ret

In theory you could remove the stack frame altogether (may make stack traces in the debugger harder to follow). The code could have used ESP to access the arguments rather than EBP:

push   %ebx              # Preserve non-volatile EBX register
mov    8(%esp),%eax      # EAX = Pointer to a
mov    12(%esp),%edx     # EDX = Pointer to b
mov    (%eax),%ecx       # Temporarily save value at memory address a (*a) to ECX
mov    (%edx),%ebx       # Temporarily save value at memory address b (*b) to EBX
mov    %ebx,(%eax)       # Move value of b (EBX) to memory address of a (*a)
mov    %ecx,(%edx)       # Move value of a (ECX) to memory address of b (*b)
pop    %ebx              # Restore non-volatile EBX register
ret

Note: Failing to preserve (per 32-bit CDECL calling convention) non-volatile registers like EBX, EBP, ESI, and EDI is a bug. In simple test code it may appear to work, but in more complex code with optimizations on you may experience undefined behaviour if the calling convention isn't strictly adhered to.

Upvotes: 1

Mike Nakis
Mike Nakis

Reputation: 61986

As Weather Vane said, the C code you have shown is not swapping two int pointers. It is swapping two ints pointed by two int pointers.

But in your assembly you appear to be trying to swap two ints pointed by two int pointers, so your code is not an entirely lost cause.

Study this to understand what it does, and then give it a try:

mov (%ecx), %eax
mov (%ebx), %edx
mov %edx, (%ecx)
mov %eax, (%ebx)

Upvotes: 1

Related Questions