(from Problem4 in https://web.stanford.edu/class/archive/cs/cs107/cs107.1186/exams/f1.pdf)
The below C code:
#include <stdlib.h>
int pinky(char *param1, int *param2) {
char *str = NULL;
int local = strtol(param1, &str, 0x10);
if (local - 7 > 12) {
local += param2[3];
}
return local / 4;
}
int main(int argc, char *argv[]) {
char *param1 = "foo";
int param2 = 17;
pinky("foo", ¶m2);
return 0;
}
generates the below assembly (by gcc -o pinky.s -S -Og pinky.c
).
.file "pinky.c"
.text
.globl pinky
.type pinky, @function
pinky:
.LFB11:
.cfi_startproc
pushq %rbx
.cfi_def_cfa_offset 16
.cfi_offset 3, -16
subq $16, %rsp
.cfi_def_cfa_offset 32
movq %rsi, %rbx
movq %fs:40, %rax
movq %rax, 8(%rsp)
xorl %eax, %eax
movq $0, (%rsp)
movq %rsp, %rsi
movl $16, %edx
call strtol@PLT
movl %eax, %edx
cmpl $19, %eax
jle .L2
addl 12(%rbx), %edx
.L2:
leal 3(%rdx), %eax
testl %edx, %edx
cmovns %edx, %eax
sarl $2, %eax
movq 8(%rsp), %rcx
xorq %fs:40, %rcx
jne .L5
addq $16, %rsp
.cfi_remember_state
.cfi_def_cfa_offset 16
popq %rbx
.cfi_def_cfa_offset 8
ret
.L5:
.cfi_restore_state
call __stack_chk_fail@PLT
.cfi_endproc
.LFE11:
.size pinky, .-pinky
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "foo"
.text
.globl main
.type main, @function
main:
.LFB12:
.cfi_startproc
pushq %rbx
.cfi_def_cfa_offset 16
.cfi_offset 3, -16
subq $16, %rsp
.cfi_def_cfa_offset 32
movl $40, %ebx
movq %fs:(%rbx), %rax
movq %rax, 8(%rsp)
xorl %eax, %eax
movl $17, 4(%rsp)
leaq 4(%rsp), %rsi
leaq .LC0(%rip), %rdi
call pinky
movq 8(%rsp), %rax
xorq %fs:(%rbx), %rax
jne .L9
movl $0, %eax
addq $16, %rsp
.cfi_remember_state
.cfi_def_cfa_offset 16
popq %rbx
.cfi_def_cfa_offset 8
ret
.L9:
.cfi_restore_state
call __stack_chk_fail@PLT
.cfi_endproc
.LFE12:
.size main, .-main
.ident "GCC: (GNU) 9.1.0"
.section .note.GNU-stack,"",@progbits
This shows that local / 4
is performed by the four operations:
leal 3(%rdx), %eax ; this is not for calculating address, but for add and store to a register in a single operation
testl %edx, %edx ; compute logical AND of operands and set SF, ZF, and PF flags
cmovns %edx, %eax ; move if not signed (SF=0)
sarl $2, %eax
The detail is explained here.
The format of assembly gcc generates is AT&T (https://en.wikibooks.org/wiki/X86_Assembly/GAS_Syntax) in default.