C语言与汇编

  1. 简单赋值运算
  2. 条件语句
  3. 循环语句
  4. 函数

实验环境: x86 GCC 7.4.0

C语言代码:

简单赋值运算

mov指令实现赋值语句

1
2
3
4
5
6
void foo() {
char c = 'a';
short s = 123;
int i = 12345;
long l = 1111111l;
}
1
2
3
4
movb    $97, -15(%rbp)
movw $123, -14(%rbp)
movl $12345, -12(%rbp)
movq $1111111, -8(%rbp)

运算, 按照C语言语法进行类型隐式转换, 这里movsbl将c按符号拓展转化成32位.

1
2
3
4
5
6
7
void foo() {
int a = 1;
int b = 2;
int d = b + a;
char c = 'a';
c = c + 'A' - 'a';
}
1
2
3
4
5
6
7
8
9
10
movl	$1, -12(%rbp)
movl $2, -8(%rbp)
movl -8(%rbp), %edx
movl -12(%rbp), %eax
addl %edx, %eax
movl %eax, -4(%rbp)
movb $97, -13(%rbp)
movzbl -13(%rbp), %eax
subl $32, %eax
movb %al, -13(%rbp)

条件语句

1
2
3
4
5
6
7
8
int foo() {
int a = 1;
int b = 0;
if (a > 0) {
b = 1;
}
return 0;
}
1
2
3
4
5
6
7
	movl	$1, -8(%rbp)
movl $0, -4(%rbp)
cmpl $0, -8(%rbp)
jle .L2
movl $1, -4(%rbp)
.L2:
movl $0, %eax

cmpl 比较两个值

jle跳转等价与C语言的goto语句

1
2
3
4
5
6
7
8
9
int foo() {
int a = 1;
int b = 0;
if (a <= 0)
goto .L2
b = 1;
.L2:
return 0;
}

if-else

1
2
3
4
5
6
7
8
9
10
11
12
int foo() {
int a = 100;
int res = 0;

if (a >= 100) {
res = 1;
} else {
res = 2;
}

return 0;
}
1
2
3
4
5
6
7
8
9
10
	movl	$100, -8(%rbp)
movl $0, -4(%rbp)
cmpl $99, -8(%rbp)
jle .L2
movl $1, -4(%rbp)
jmp .L3
.L2:
movl $2, -4(%rbp)
.L3:
movl $0, %eax

然后试一下更复杂的condition

1
2
3
4
5
6
7
8
9
10
11
int foo() {

int a = 100;
int res = 0;

if ((a > 80 && a < 85) || (a >= 90 && a <= 100)) {
res = 1;
}

return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
	movl	$100, -8(%rbp)
movl $0, -4(%rbp)
cmpl $80, -8(%rbp)
jle .L2
cmpl $84, -8(%rbp)
jle .L3
.L2:
cmpl $89, -8(%rbp)
jle .L4
cmpl $100, -8(%rbp)
jg .L4
.L3:
movl $1, -4(%rbp)
.L4:
movl $0, %eax

可以发现条件循环对应的汇编也就是对条件取反之后一步步的判断.

循环语句

1
2
3
4
5
6
7
8
9
10
int foo() {
int i = 1;
int sum = 0;
while (i <= 100) {
sum += i;
++i;
}

return sum;
}
1
2
3
4
5
6
7
8
9
10
11
	movl	$1, -8(%rbp)
movl $0, -4(%rbp)
jmp .L2
.L3:
movl -8(%rbp), %eax
addl %eax, -4(%rbp)
addl $1, -8(%rbp)
.L2:
cmpl $100, -8(%rbp)
jle .L3
movl -4(%rbp), %eax
1
2
3
4
5
6
7
int foo() {
int sum = 0;
for (int i = 1; i <= 100; ++i) {
sum += i;
}
return sum;
}
1
2
3
4
5
6
7
8
9
10
11
	movl	$0, -8(%rbp)
movl $1, -4(%rbp)
jmp .L2
.L3:
movl -4(%rbp), %eax
addl %eax, -8(%rbp)
addl $1, -4(%rbp)
.L2:
cmpl $100, -4(%rbp)
jle .L3
movl -8(%rbp), %eax

可以看出for循环和while循环的行为效率是一致的.

函数

1
2
pushq	%rbp
movq %rsp, %rbp

每个函数的汇编部分都包含了以上两条代码, 其中第一条 push %rbp 是保存了上一个函数的栈帧指针, movq %rsp, %rbp 使栈顶指针指向 %rbp.

… 未完

script>