让我们使用gcc -g -O0 -o prog prog.c
编译以下程序并在其上运行gdb
。如果我们一步一步走,我们会在行后看到
4 switch (c) {
直接行
38 return 0;
这是错误的,因为它首先必须去行
32 break;
适用于使用clang -g -O0 -o prog prog.c
GCC版本: gcc(Debian 6.4.0-1)6.4.0 20170704
clang版本: 3.8.1-24(标签/ RELEASE_381 / final)
int main(void)
{
char c = '\x1a';
switch (c) {
case '\x18': /* C-x */
break;
case '\x12': /* C-r */
break;
case '\x13': /* C-s */
break;
case '\x10': /* C-p */
break;
case '\x0e': /* C-n */
break;
case '\x02': /* C-b */
break;
case '\x06': /* C-f */
break;
case '\x05': /* C-e */
break;
case '\x01': /* C-a */
break;
case '\x04': /* C-d */
break;
case '\x08': /* C-h */
break;
case '\x1d': /* C-] */
break;
case '\x16': /* C-v */
break;
case '\x1a': /* C-z */
break;
case '\x0d': /* C-m */
break;
default:
(void) c;
}
return 0;
}
答案 0 :(得分:3)
gdb不能正常工作,它只会跨越编译器生成的代码。对于这个无效的虚拟示例,gcc会生成this code:
main:
push rbp
mov rbp, rsp
mov BYTE PTR [rbp-1], 26
movsx eax, BYTE PTR [rbp-1]
cmp eax, 29
ja .L2
mov eax, eax
mov rax, QWORD PTR .L4[0+rax*8]
jmp rax
.L4:
.quad .L2
.quad .L2
.quad .L2
.quad .L2
.quad .L2
.quad .L2
.quad .L2
.quad .L2
.quad .L2
.quad .L2
.quad .L2
.quad .L2
.quad .L2
.quad .L2
.quad .L2
.quad .L2
.quad .L2
.quad .L2
.quad .L2
.quad .L2
.quad .L2
.quad .L2
.quad .L2
.quad .L2
.quad .L2
.quad .L2
.quad .L2
.quad .L2
.quad .L2
.quad .L2
.L2:
mov eax, 0
pop rbp
ret
没有为break
语句生成相应的代码,因此gdb无法遍历它们,因为它们不存在。
另一方面,clang为break
语句生成了另一个more verbose code。这就是你可以走过它们的原因:
main: # @main
push rbp
mov rbp, rsp
mov dword ptr [rbp - 4], 0
mov byte ptr [rbp - 5], 26
movsx eax, byte ptr [rbp - 5]
dec eax
mov ecx, eax
sub eax, 28
mov qword ptr [rbp - 16], rcx # 8-byte Spill
mov dword ptr [rbp - 20], eax # 4-byte Spill
ja .LBB0_16
mov rax, qword ptr [rbp - 16] # 8-byte Reload
mov rcx, qword ptr [8*rax + .LJTI0_0]
jmp rcx
.LBB0_1:
jmp .LBB0_17
.LBB0_2:
jmp .LBB0_17
.LBB0_3:
jmp .LBB0_17
.LBB0_4:
jmp .LBB0_17
.LBB0_5:
jmp .LBB0_17
.LBB0_6:
jmp .LBB0_17
.LBB0_7:
jmp .LBB0_17
.LBB0_8:
jmp .LBB0_17
.LBB0_9:
jmp .LBB0_17
.LBB0_10:
jmp .LBB0_17
.LBB0_11:
jmp .LBB0_17
.LBB0_12:
jmp .LBB0_17
.LBB0_13:
jmp .LBB0_17
.LBB0_14:
jmp .LBB0_17
.LBB0_15:
jmp .LBB0_17
.LBB0_16:
jmp .LBB0_17
.LBB0_17:
xor eax, eax
pop rbp
ret
.LJTI0_0:
.quad .LBB0_9
.quad .LBB0_6
.quad .LBB0_16
.quad .LBB0_10
.quad .LBB0_8
.quad .LBB0_7
.quad .LBB0_16
.quad .LBB0_11
.quad .LBB0_16
.quad .LBB0_16
.quad .LBB0_16
.quad .LBB0_16
.quad .LBB0_15
.quad .LBB0_5
.quad .LBB0_16
.quad .LBB0_4
.quad .LBB0_16
.quad .LBB0_2
.quad .LBB0_3
.quad .LBB0_16
.quad .LBB0_16
.quad .LBB0_13
.quad .LBB0_16
.quad .LBB0_1
.quad .LBB0_16
.quad .LBB0_14
.quad .LBB0_16
.quad .LBB0_16
.quad .LBB0_12
如果你想让gcc为break
语句生成代码,你应该改变你的例子来至少在switch
语句中做一些事情。例如,再添加一个变量i
并在switch
语句中更改它的值:
int main(void)
{
int i = 0;
char c = '\x1a';
switch (c) {
case '\x18': /* C-x */
break;
case '\x12': /* C-r */
break;
case '\x13': /* C-s */
break;
case '\x10': /* C-p */
break;
case '\x0e': /* C-n */
break;
case '\x02': /* C-b */
break;
case '\x06': /* C-f */
break;
case '\x05': /* C-e */
break;
case '\x01': /* C-a */
break;
case '\x04': /* C-d */
break;
case '\x08': /* C-h */
break;
case '\x1d': /* C-] */
break;
case '\x16': /* C-v */
break;
case '\x1a': /* C-z */
i = 1;
break;
case '\x0d': /* C-m */
break;
default:
(void) c;
}
return 0;
}