
This transcript will help you understand the calling conventions
and the ABI. It's taken on a 64 bit system; do the same on a 32bit 
system and observe the differences.

For these exercises, it is important that you learn to read
disassembly and understand the basics of the x86 platform. A gentle
introduction is provided in the "Solaris on x86" book in the course
directory. Read Chapters 2 and 3 and work through examples in Chapter 3
with your own compiler, objdump, and debugger if you are not familiar with x86!
(You should skip SPARC and Solaris-specific examples for now, but look at 
how C code structs and algorithmic structures are compiled.) 

We spoke about privilege rings and memory translation in ia32 and
x86-64 in class. Chapter 4 has more details about those; Gustavo
Duarte's blog makes nice introductory reading, too:
http://duartes.org/gustavo/blog/post/memory-translation-and-segmentation/
http://duartes.org/gustavo/blog/post/cpu-rings-privilege-and-protection/

In case you are already familiar with the 32-bit assembly, then a good if a
bit terse intro to the new things in the 64-bit can be found at
http://www.x86-64.org/documentation/assembly.html

-----[ A system call in 64 bits ]-------

root@ubuntu64:/home/sergey# cat hello.c 
#include <stdio.h>

int main()
{
	printf("Hello!\n");
	return 42;
}


Ignore the .cfi_* parts, understand the rest. Use the Tiny Guide
to x86 assembly, or simply google specific instructions (it works!).
When in doubt, look at the Intel instruction manuals:
http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html

root@ubuntu64:/home/sergey# cat hello.s 
	.file	"hello.c"
	.section	.rodata
.LC0:
	.string	"Hello!"
	.text
	.globl	main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	movl	$.LC0, %edi
	call	puts
	movl	$42, %eax
	popq	%rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1"
	.section	.note.GNU-stack,"",@progbits


root@ubuntu64:/home/sergey# cat exec.c
#include <unistd.h>

int main()
{
  char *const args[] = {"/bin/ls", NULL};   // see execv(3) for arguments
  execv("/bin/ls", args);
} 

In the following code, understand the representation of the args[]:
where and how the pointers are stored?


root@ubuntu64:/home/sergey# gcc -S exec.c
root@ubuntu64:/home/sergey# cat exec.s
	.file	"exec.c"
	.section	.rodata
.LC0:
	.string	"/bin/ls"
	.text
	.globl	main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	subq	$16, %rsp
	movq	$.LC0, -16(%rbp)
	movq	$0, -8(%rbp)
	leaq	-16(%rbp), %rax
	movq	%rax, %rsi
	movl	$.LC0, %edi
	call	execv
	leave
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1"
	.section	.note.GNU-stack,"",@progbits


Now I am going to walk the code to the actual point where the
exec() system call is made. Notice that I am cheating here,
by compiling the executable statically (and with debug info).
Most executables get compiled dynamically these days; static
libraries no longer ship by default on most distributions.
This cheat allows me to bypass an extra layer of indirection
introduced by dynamic linking, though.


root@ubuntu64:/home/sergey# gcc -static -g -o exec exec.c
root@ubuntu64:/home/sergey# gdb ./exec 
GNU gdb (Ubuntu/Linaro 7.3-0ubuntu2) 7.3-2011.08
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /home/sergey/exec...done.
(gdb) b main
Breakpoint 1 at 0x40104c: file exec.c, line 5.
(gdb) r
Starting program: /home/sergey/exec 

Breakpoint 1, main () at exec.c:5
5	  char *const args[] = {"/bin/ls", NULL};
(gdb) disas main
Dump of assembler code for function main:
   0x0000000000401044 <+0>:	push   %rbp
   0x0000000000401045 <+1>:	mov    %rsp,%rbp
   0x0000000000401048 <+4>:	sub    $0x10,%rsp
=> 0x000000000040104c <+8>:	movq   $0x488be4,-0x10(%rbp)
   0x0000000000401054 <+16>:	movq   $0x0,-0x8(%rbp)
   0x000000000040105c <+24>:	lea    -0x10(%rbp),%rax
   0x0000000000401060 <+28>:	mov    %rax,%rsi
   0x0000000000401063 <+31>:	mov    $0x488be4,%edi
   0x0000000000401068 <+36>:	callq  0x40cfc0 <execv>
   0x000000000040106d <+41>:	leaveq 
   0x000000000040106e <+42>:	retq   
End of assembler dump.
(gdb) disas execv
Dump of assembler code for function execv:
   0x000000000040cfc0 <+0>:	mov    0x2a8941(%rip),%rdx        # 0x6b5908 <environ>
   0x000000000040cfc7 <+7>:	jmpq   0x4445b0 <execve>
End of assembler dump.
(gdb) disas execve
Dump of assembler code for function execve:
   0x00000000004445b0 <+0>:	mov    $0x3b,%eax
   0x00000000004445b5 <+5>:	syscall 
   0x00000000004445b7 <+7>:	cmp    $0xfffffffffffff000,%rax
   0x00000000004445bd <+13>:	ja     0x4445c1 <execve+17>
   0x00000000004445bf <+15>:	repz retq 
   0x00000000004445c1 <+17>:	mov    $0xffffffffffffffb0,%rdx
   0x00000000004445c8 <+24>:	neg    %eax
   0x00000000004445ca <+26>:	mov    %eax,%fs:(%rdx)
   0x00000000004445cd <+29>:	or     $0xffffffffffffffff,%rax
   0x00000000004445d1 <+33>:	retq   
End of assembler dump.

Note the 'syscall' instruction. This is a new optimized x86-64 
instruction that causes a software interrupt and jumps to the
system call dispatcher entry in the kernel, at the same time
setting the code privilege level to Ring0. The kernel entry address is
stored in a Model-specific Register (MSR). Recall that in ia32 
the system call used a software interrupt 0x80 ("int 0x80"),
and the entry address was taken from the 0x80-th entry of the 
Interrupt Descriptor Table (IDT), pointed to by the dedicated
IDTR register. So the new 64-bit scheme has less apparent indirection.

More about 64-bit systems calls:
http://blog.rchapman.org/post/36801038863/linux-system-call-table-for-x86-64

Note the hex 3b above. This is the number of the exec system call in
the 64-bit table. The tables and numbers for 32-bit system calls
and 64-bit system calls are completely independent, and all the 
numbers are different.

The sys_call_table used to be a straight-up array of function 
pointers. In newer Linux kernels, it's generated by a shell script
from a table:

http://lxr.linux.no/#linux+v3.12.6/arch/x86/syscalls/syscalltbl.sh
http://lxr.linux.no/#linux+v3.12.6/arch/x86/syscalls/syscall_64.tbl
http://lxr.linux.no/#linux+v3.12.6/arch/x86/syscalls/syscall_32.tbl

If lxr.linux.no seems sluggish, use http://lxr.free-electrons.com/,
e.g., http://lxr.free-electrons.com/source/arch/x86/syscalls/syscall_64.tbl

The generated syscall header file is pulled in by #include near the bottom
of http://lxr.free-electrons.com/source/arch/x86/kernel/syscall_64.c

Exercises:

Find the system call in Linux source code (e.g., at http://lxr.linux.no/) and
convince yourself that it's indeed exec(). Find the kernel
function that implements exec().

Repeat compilation and interpret the results with other GCC options:
-O (optimization level), -fomit-frame-pointer ,  -fPIC etc. See 'man gcc'
if in doubt -- there are many kinds of options.




