C to x86-64 assembly
Source: CS:APP3e, Bryant and O’Hallaron, homework problem 3.58
For a function with prototype long decode2(long x, long y, long z)
,
gcc
generates the following [x86-64] assembly code:
decode2:
subq %rdx, %rsi
imulq %rsi, %rdi
movq %rsi, %rax
salq $63, %rax
sarq $63, %rax
xorq %rdi, %rax
ret
Parameters x
, y
, and z
are passed in registers %rdi
, %rsi
,
and %rdx
. The code stores the return value in register %rax
.
Write C code for decode2
that will have an effect equivalent to
the assembly code shown.
Solution
1. Annotate the assembly instructions
- Function signature:
long decode2(long x, long y, long z)
- Parameter
x
passed in%rdi
- Parameter
y
passed in%rsi
- Parameter
z
passed in%rdx
- Return value in
%rax
decode2:
subq %rdx, %rsi ; Decrement %rsi by the quad word value in %rdx
; C: y = y - z
imulq %rsi, %rdi ; Multiply %rdi * %rsi and store quad word result
; in %rdi
; C: x = x * y
movq %rsi, %rax ; Move quad word from register %rsi to register
; %rax, which stores the return value.
; C: long result = y
salq $63, %rax ; Left-shift (logical): %rax << $63 and store
; quad word result in %rax
; C: result = result << 63
sarq $63, %rax ; Arithmetic right-shift: %rax >> $63 and store
; quad word result in %rax
; C: result = result >> 63
xorq %rdi, %rax ; Exclusive or: %rax ^ %rdi and store quad word
; result in %rax
; C: result = result ^ x
ret ; Return the value in `%rax`.
; C: return result
2. Write equivalent C
1
2
3
4
5
6
7
8
9
long decode2(long x, long y, long z) {
y -= z;
x *= y;
long result = y;
result <<= 63;
result >>= 63;
result ^= x;
return result;
}
3. Generate x86-64 assembly code
Red Hat Linux 4.4.7-23, gcc 4.4.7:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
% gcc -O1 -S decode2.c && cat decode2.s
.file "decode2.c"
.text
.globl decode2
.type decode2, @function
decode2:
.LFB0:
.cfi_startproc
subq %rdx, %rsi
movq %rsi, %rax
salq $63, %rax
sarq $63, %rax
imulq %rdi, %rsi
xorq %rsi, %rax
ret
.cfi_endproc
.LFE0:
.size decode2, .-decode2
.ident "GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-23)"
.section .note.GNU-stack,"",@progbits
Notes
Compiled on MacOS 10.12.6 with gcc 4.8.1, my C code produces the x86-64 assembly given in the textbook, in EXACTLY that order of instructions. Compiled on Red Hat Linux 4.4.7-23 with gcc 4.4.7, it produces the same instructions in a different order, but the effect is the same:
subq %rdx, %rsi ; y -= z
movq %rsi, %rax ; long result = y
salq $63, %rax ; result <<= 63
sarq $63, %rax ; result >>= 63
imulq %rdi, %rsi ; x *= y
xorq %rsi, %rax ; result ^= x
ret