2

I try to better understand assembly and currently playing around with some compiled c snippets. I have the following snippet:

#include <stdio.h>
#include <string.h>

int main() {
    char b[] = " a nice nice long string";

    char c[100];
    strcpy(c, b);
    printf("Hello World %s\n", c);
    strcpy(c, " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
}

After compiling it with gcc hello_world.c -o hello_world and opening it in gdb the assembly code of the main function looks like this:

   0x00000000000006fa <+0>:     push   rbp
   0x00000000000006fb <+1>:     mov    rbp,rsp
   0x00000000000006fe <+4>:     sub    rsp,0x90
   0x0000000000000705 <+11>:    mov    rax,QWORD PTR fs:0x28
   0x000000000000070e <+20>:    mov    QWORD PTR [rbp-0x8],rax
   0x0000000000000712 <+24>:    xor    eax,eax
   0x0000000000000714 <+26>:    movabs rax,0x206563696e206120
   0x000000000000071e <+36>:    movabs rdx,0x6e6f6c206563696e
   0x0000000000000728 <+46>:    mov    QWORD PTR [rbp-0x90],rax
   0x000000000000072f <+53>:    mov    QWORD PTR [rbp-0x88],rdx
   0x0000000000000736 <+60>:    movabs rax,0x676e697274732067
   0x0000000000000740 <+70>:    mov    QWORD PTR [rbp-0x80],rax
   0x0000000000000744 <+74>:    mov    BYTE PTR [rbp-0x78],0x0
   0x0000000000000748 <+78>:    lea    rdx,[rbp-0x90]
   0x000000000000074f <+85>:    lea    rax,[rbp-0x70]
   0x0000000000000753 <+89>:    mov    rsi,rdx
   0x0000000000000756 <+92>:    mov    rdi,rax
   0x0000000000000759 <+95>:    call   0x5b0 <strcpy@plt>
   0x000000000000075e <+100>:   lea    rax,[rbp-0x70]
   0x0000000000000762 <+104>:   mov    rsi,rax
   0x0000000000000765 <+107>:   lea    rdi,[rip+0xe8]        # 0x854
   0x000000000000076c <+114>:   mov    eax,0x0
   0x0000000000000771 <+119>:   call   0x5d0 <printf@plt>
   0x0000000000000776 <+124>:   lea    rax,[rbp-0x70]
   0x000000000000077a <+128>:   movabs rsi,0x4141414141414120
   0x0000000000000784 <+138>:   movabs rdi,0x4141414141414141
   0x000000000000078e <+148>:   mov    QWORD PTR [rax],rsi
   0x0000000000000791 <+151>:   mov    QWORD PTR [rax+0x8],rdi
   0x0000000000000795 <+155>:   movabs rdx,0x4141414141414141
   0x000000000000079f <+165>:   movabs rcx,0x4141414141414141
   0x00000000000007a9 <+175>:   mov    QWORD PTR [rax+0x10],rdx
   0x00000000000007ad <+179>:   mov    QWORD PTR [rax+0x18],rcx
   0x00000000000007b1 <+183>:   mov    BYTE PTR [rax+0x20],0x0
   0x00000000000007b5 <+187>:   mov    eax,0x0
   0x00000000000007ba <+192>:   mov    rcx,QWORD PTR [rbp-0x8]
   0x00000000000007be <+196>:   xor    rcx,QWORD PTR fs:0x28
   0x00000000000007c7 <+205>:   je     0x7ce <main+212>
   0x00000000000007c9 <+207>:   call   0x5c0 <__stack_chk_fail@plt>
   0x00000000000007ce <+212>:   leave
   0x00000000000007cf <+213>:   ret

I think i understand which part is doing what. But some things are not clear to me.

  1. strcpy is only called once and only when the second argument is a variable. Why is ther no call for the second strcopy?
  2. printf is called with a string and a second arg. The string is loaded from rip+0xe8. Why is the string provided to the second strcopy not loaded in the same fashion? It is "hardcoded" with in the moveabs instructions.

Is this due to some compiler optimization? Can someone elaborate?

4
import binascii
print(binascii.hexlify(b" a nice nice long string"))
print(binascii.hexlify(b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"))

you can find both the string in your listing

b'2061206e696365206e696365206c6f6e6720737472696e67'
b'41414141414141414141414141414141414141414141414141414141414141'

first string

0x0000000000000714 <+26>:    movabs rax,0x206563696e206120
0x000000000000071e <+36>:    movabs rdx,0x6e6f6c206563696e
0x0000000000000736 <+60>:    movabs rax,0x676e697274732067

second string

 0x000000000000077a <+128>:   movabs rsi,0x4141414141414120
 0x0000000000000784 <+138>:   movabs rdi,0x4141414141414141
 0x000000000000078e <+148>:   mov    QWORD PTR [rax],rsi
 0x0000000000000791 <+151>:   mov    QWORD PTR [rax+0x8],rdi
 0x0000000000000795 <+155>:   movabs rdx,0x4141414141414141
 0x000000000000079f <+165>:   movabs rcx,0x4141414141414141

first time you give it an address which is unknown at compile time so compiler is forced to use the function (dynamic arguments)

second time you give a CONSTANT String which can be split and put into the c
(static argument)

or if you provide a very very big string it can take the address and do a repmovsq

strcpy(d, " lshdgfdghsdfghsdfghsdfhgsdfhgsdfhgshsfur4tye36346asdgxzcvgaewt34t sg afeaerwbhtyhswrtwqee5t6e67redhfdxbw45bh hhjljuhlfjsdhlksjdghsdlkjfhgsldkjfghlskjdghlkjsdhggkjsdhgksdjhgskdjhglsdkjhgfskjdhfgsdkjhfgkjsdfhgskdjhfgsdk;ljhg;djkgsjhg;dsljkhf;ljg;dljg;jh");
}

using repmovsq

mov     eax, OFFSET FLAT:.LC1
mov     ecx, 31
mov     rdi, rdx
mov     rsi, rax
rep movsq

.LC1:
        .string " lshd

just to confirm remove the b[] = line and put strcpy(c,const string ); you will see the compiler has eliminated the .plt entry also and will convert the strcpy to __builtin_memcpy()

 __builtin_memcpy (&c, " a nice nice long string", 25);
  printf ("Hello World %s\n", &c);
  __builtin_memcpy (&c, " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 33);

compile with -fno-builtin and you will get both strcpy

.LC0:
        .string "Hello World %s\n"
.LC1:
        .string " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 144
        movabs  rax, 2334381286331801888
        movabs  rdx, 7957697952982722926
        mov     QWORD PTR [rbp-32], rax
        mov     QWORD PTR [rbp-24], rdx
        movabs  rax, 7453010373645639783
        mov     QWORD PTR [rbp-16], rax
        mov     BYTE PTR [rbp-8], 0
        lea     rdx, [rbp-32]
        lea     rax, [rbp-144]
        mov     rsi, rdx
        mov     rdi, rax
        call    strcpy
        lea     rax, [rbp-144]
        mov     rsi, rax
        mov     edi, OFFSET FLAT:.LC0
        mov     eax, 0
        call    printf
        lea     rax, [rbp-144]
        mov     esi, OFFSET FLAT:.LC1
        mov     rdi, rax
        call    strcpy
        mov     eax, 0
        leave
        ret

you can read about various other __builtins here

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.