1

I am trying to write a small program that takes two hard coded character pointers and switches the contents that they point to using an external x86 32bit function located in a .S file. I am using the basic gcc compiler. Here is my C code:

valSwap.c:

#include <stdio.h>

void extern swapMe(char* c, char* d);

int main() {
        char* c = "boi";
        char* d = "bra";
        printf("%s, %s", c, d);

        swapMe(c, d);

        printf("%s, %s", c, d);
        return 0;

}

Before running swapMe(c, d) the strings that c and d point to are quite clear. After running swapMe(c, d) I get a Segmentation Fault. Here is my code for the swapMe external function:

swapMe.S:

.intel_syntax noprefix
.text
.global swapMe

swapMe:
        push edi
        push esi
        mov eax, [esp+4]
        mov ecx, [esp+8]

        mov edi, [eax]
        mov esi, [ecx]
        mov [eax], esi
        mov [ecx], edi

        pop esi
        pop edi

        ret

Now since swapMe(c, d) is taking in 2 parameters using the cdecl calling convention I should find c and d on the stack at $esp+4 and $esp+8. I tried to print these values to confirm that they are what I expect. Either they are not what I expected or I tried to print them incorrectly:

(gdb) p/s $esp+4
$1 = (void *) 0xffffdb08
(gdb) x/s $esp+4
0xffffdb08:     ""
(gdb) p/s *($esp+4)
Attempt to dereference a generic pointer.
(gdb) x/s *($esp+4)
Attempt to dereference a generic pointer.

I also tried printing $eax as a string since I moved the contents of $esp+4 into $eax.

(gdb) p/x $eax
$3 = 0xf7fa0000
(gdb) x/s $eax
0xf7fa0000:     "\260=\033"
(gdb) x/s *$eax
0x1b3db0:       <error: Cannot access memory at address 0x1b3db0>
(gdb) x/x $eax
0xf7fa0000:     0xb0

I also printed the hex values of c and d before entering swapMe to see if I'm at least getting the correct value:

(gdb) p &c
$12 = (char **) 0xffffdb2c
(gdb) p c
$16 = 0x565556c0 "boi"
(gdb) p &d
$14 = (char **) 0xffffdb28
(gdb) p d
$15 = 0x565556c4 "bra"

I printed a few others values that may be relevant as well:

   30x56555621 <swapMe+2>   mov    eax,DWORD PTR [esp+0x4]                                                             3
   30x56555625 <swapMe+6>   mov    ecx,DWORD PTR [esp+0x8]                                                             3
  >30x56555629 <swapMe+10>  mov    edi,DWORD PTR [eax]                                                                 3
   30x5655562b <swapMe+12>  mov    esi,DWORD PTR [ecx]

(gdb) p/x $eax
$8 = 0xf7fa0000



0x56555621 <swapMe+2>   mov    eax,DWORD PTR [esp+0x4]                                                             3
   30x56555625 <swapMe+6>   mov    ecx,DWORD PTR [esp+0x8]                                                             3
   30x56555629 <swapMe+10>  mov    edi,DWORD PTR [eax]                                                                 3
  >30x5655562b <swapMe+12>  mov    esi,DWORD PTR [ecx]                                                                 3
   30x5655562d <swapMe+14>  mov    DWORD PTR [eax],esi                                                                 3
   30x5655562f <swapMe+16>  mov    DWORD PTR [ecx],edi

p/x $edi
$11 = 0x1b3db0


 30x56555621 <swapMe+2>   mov    eax,DWORD PTR [esp+0x4]                                                             3
   30x56555625 <swapMe+6>   mov    ecx,DWORD PTR [esp+0x8]                                                             3
   30x56555629 <swapMe+10>  mov    edi,DWORD PTR [eax]                                                                 3
   30x5655562b <swapMe+12>  mov    esi,DWORD PTR [ecx]                                                                 3
  >30x5655562d <swapMe+14>  mov    DWORD PTR [eax],esi                                                                 3
   30x5655562f <swapMe+16>  mov    DWORD PTR [ecx],edi

(gdb) p/x $ecx
$19 = 0x565555f5
(gdb) p/x $esi
$20 = 0x8310c483

I don't understand why I'm getting different values when I print the values of $eax, $edi, $ecx, and $esp in swapMe vs when I print the values associated with c and d before calling swapMe. Since swapMe takes in c and d as parameters, I expected to see the same values on the stack when calling swapMe but I do not. I did not see 0xffffdb2c or 0x565556c0 once when printing any registers. Please clarify what I did wrong when calling the function, passing in the parameters, or printing the values in the registers. I'm very new to x86 so I probably made a rookie mistake somewhere.

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
Sam K9
  • 99
  • 9
  • 4
    When your function does `push edi` `push esi` each one decrements esp by 4. So by the time you try retireving the paremetrs they are now at [esp+12] and [esp+16] – Michael Petch Dec 12 '17 at 07:01
  • 1
    The other major issue is the way you defined character array `c` and `d`. `char* c = "boi";` will create a **read only** string with boi in it. Modifying read only data will yield a seg fault on Linux. You want to define thee arrays so they end up as local variables (will end up on the stack here). To do that use `char c[] = "boi";` and `char d[] = "bra";` – Michael Petch Dec 12 '17 at 07:36
  • 4
    It's also unclear if you are intending to swap pointers or swap the contents at those pointers. Your current code is attempting to swap the contents and what you are doing would not be correct for that scenario unless the strings were always exactly 4 bytes. – Michael Petch Dec 12 '17 at 07:48
  • why wouldn't swapping contents of different sizes work? Both strings are terminated by a null pointer. So wouldn't they still be terminated properly if the contents were swapped? – Sam K9 Dec 12 '17 at 08:27
  • 2
    I think you might be confused about swapping the actual contents of a string and the pointers to a string. Here is an exercise for you. How would you code your `swapMe` in purely _C_. If you do that you might realize where you have gone wrong. As it stands your code acts more like the function prototype should be `void extern swapMe(char** c, char** d);` where you call the function this way `swapMe(&c, &d);` – Michael Petch Dec 12 '17 at 08:39

0 Answers0