1

I have following C++ code in main.cpp file.

int add(int a,int b)
{
    int c = a + b;
    return c;
}


int main()
{
    int a = 2;
    int b = 4;
    int d = add(2,4);
}

when I ran g++ -S main.cpp I got the following assembly code.(after removing all the debug symbols). Also I have changed the code to print the sum of the 2 numbers using sys_write system call.

.text
.globl  _Z3addii
_Z3addii:
pushq   %rbp
movq    %rsp, %rbp
movl    %edi, -20(%rbp)
movl    %esi, -24(%rbp)
movl    -24(%rbp), %eax
movl    -20(%rbp), %edx
addl    %edx, %eax
movl    %eax, -4(%rbp)
movl    -4(%rbp), %eax
popq    %rbp
ret
.globl  main

main:
pushq   %rbp
movq    %rsp, %rbp
subq    $16, %rsp
movl    $2, -12(%rbp)
movl    $4, -8(%rbp)
movl    $4, %esi
movl    $2, %edi
call    _Z3addii
movl    %eax, -4(%rbp)

movl    $4, %edx            #message length
movl    -4(%rbp), %esi      #message to write
movl    $1, %edi            #file descriptor (stdout)
movl    $1, %eax            #system call number (sys_write)
syscall                     #call kernel

movl    $60, %eax           # Invoke the Linux 'exit' syscall
movl    $0, %edi            # With a return value of 0
syscall                     # call kernel
ret

My problem is when I run the above assembly it gives nothing as output. I can't understand what I am missing here? Can someone please tell me what I am missing? Thanks.

commands used: g++ -o main main.s and ./main -->no output

OS: Ubuntu 12.04 64bit and g++ version: 4.8.2

sampath
  • 53
  • 1
  • 7
  • Somewhat surprising it's even calling `add`, I'd have bet it would just write 6 on the stack. Or not compile that path at all. – Blindy Dec 31 '14 at 03:04
  • You're not doing any `printf` or `cout`, so why would you expect to see any kind of output printed? – greatwolf Dec 31 '14 at 03:14
  • @greatwolf Probably because they're executing the `sys_write` system call. Look at the modified assembly code. – Captain Obvlious Dec 31 '14 at 03:17

1 Answers1

3

There are two things you're doing wrong:

Firstly, you're the 64-bit syscall instruction, but initialize only the %e part of the registers. Secondly, this:

movl    -4(%rbp), %esi

loads the value that is at -4(%rbp) (the 6 you just calculated) into %esi, when sys_write expects the memory address of that value there (by which I mean in %rsi). It works with this:

movq    $1, %rax            #system call number (sys_write)
movq    $1, %rdi            #file descriptor (stdout)
leaq    -4(%rbp), %rsi      #message to write
movq    $4, %rdx            #message length
syscall                     #call kernel

Of course, you're not going to get formatted output this way. To see that the 6 is printed, you will have to pipe the output through hexdump or something similar.

Addendum: That you only initialize the %e part of the registers is actually only really critical here in the case of %rsi. %rbp holds, at the time of reading, a value with set high bits, and these are lost if only -4(%ebp) is written to %esi. Technically this also works:

movl    $1, %eax            #system call number (sys_write)
movl    $1, %edi            #file descriptor (stdout)
leaq    -4(%rbp), %rsi      #message to write
movl    $4, %edx            #message length
syscall                     #call kernel

...but I feel that it is rather poor style.

Wintermute
  • 42,983
  • 5
  • 77
  • 80
  • used below command to pipe the output through hexdump. -d option is to convert to decimal. ./main | hexdump -d output: 0000000 00006 0000004 here 4 is the number of bytes written. – sampath Dec 31 '14 at 12:17