Converting 32-bit Linux programs to 64-bit

Here's a quick guide to converting a 32-bit x86 Linux program to 64-bit. This is intended to follow up our CS250 text, Programming from the Ground Up.

Register Changes

64-bit registers are indicated with r, like 32-bit with e. So this extends our sizes:
	al  : 8-bit
	ax  : 16-bit
	eax : 32-bit
	rax : 64-bit
	
For registers that hold an address, like rsp or rbp, use the r versions instead of e. For others, use whatever size matches the value you intend to use.

In addition, there are new registers r8, r9, r10, r11, r12, r13, r14, and r15. These are general purpose.

System Calls

The system call number should be in rax. Arguments go in rdi, rsi, rdx, r10, r8, and r9, in that order. This is the same order as functions except that r10 is used instead of rcx. Return value will be in rax.

Instead of int 0x80, use "syscall".

Note that system calls are numbered differently in 64-bit! A few we've used in class:
	read:    0
	write:   1
	open:    2
	close:   3
	exit:   60
	
These are all listed in syscall_64.tbl Example of how to exit a program with a return value of 0:
	mov $60, %rax
	mov $0, %rdi
	syscall
	

Function Calls

Linux uses the System V ABI. For 32-bit, parameters went on the stack. On 64-bit, the first 6 parameters go in registers.

Integer argument register order: rdi, rsi, rdx, rcx, r8, r9. Any more arguments than this go on the stack. Note that "integer" here includes memory addresses, including strings. Floating point arguments would go in XMM0, XMM1, XMM2, etc.

Return value: rax for integers, xmm0 for floating point

Clobbered (caller-preserved): rax, rcx, rdx, rsi, rdi, r8 through r11
Not clobbered (callee-preserved): rbx, r12 through r15, rsp, rbp

Special Note: When calling a function, rsp must be a multiple of 16 (the 1's place should be 0). If this is not so, your program will probably segfault.

Example of how to call printf and print out some numbers (%ld is the format specifier for a long integer, a 64-bit value):

printf_format:
	.asciz "a = %ld, b = %ld\n"
.global _start
_start:
	mov $printf_format, %rdi
	mov $37, %rsi
	mov $41, %rdx
	call printf
	

Building

If linking with a C library, you'll need -lc and the dynamic linker. This is the same as 32-bit, except you shouldn't specify --32 or -m elf_i386. You also need the 64-bit library from /lib64. Like this:
	as example.s -o example.o -g
	ld example.o -o example -g -lc --dynamic-linker /lib64/ld-linux-x86-64.so.2