Assembly C开关语句的程序集-它是如何工作的?
我正在读一本关于汇编开关语句的书,当输入n为case:100102103104106时,代码有cases/分支。它通过从n中减去100来简化跳转表,然后如果结果大于6,则转到L2中的默认情况,否则将转到与%eax中的值匹配的相应分支 我的问题是:Assembly C开关语句的程序集-它是如何工作的?,assembly,switch-statement,Assembly,Switch Statement,我正在读一本关于汇编开关语句的书,当输入n为case:100102103104106时,代码有cases/分支。它通过从n中减去100来简化跳转表,然后如果结果大于6,则转到L2中的默认情况,否则将转到与%eax中的值匹配的相应分支 我的问题是: 如果是这样,如果跳转表的索引保存在%eax中,那么第7行不是假定为jmp*.L7(,%eax) 为什么他们在第5行通过执行ja.L2将数字改为无符号 int x位于%ebp+8,int n位于%ebp+12 movl 8(%ebp), %edx
%eax
中,那么第7行不是假定为jmp*.L7(,%eax)
ja.L2
将数字改为无符号int x
位于%ebp+8
,int n
位于%ebp+12
movl 8(%ebp), %edx
movl 12(%ebp), %eax
subl $100, %eax
cmpl $6, %eax
ja .L2
jmp *.L7(,%eax,4)
.L2:
movl $0, %eax
jmp .L8
.L5:
movl %edx, %eax
jmp .L9
.L3:
leal (%edx,%edx,2), %eax
leal (%edx,%eax,4), %eax
jmp .L8
.L4:
leal 10(%edx), %eax
.L9:
addl $11, %eax
jmp .L8
.L6:
movl %edx, %eax
imull %edx, %eax
.L8:
跳转表:
.section .rodata
.align 4 Align
.L7:
.long .L3 //Case 100: loc_A
.long .L2 //Case 101: loc_def
.long .L4 //Case 102: loc_B
.long .L5 //Case 103: loc_C
.long .L6 //Case 104: loc_D
.long .L2 //Case 105: loc_def
.long .L6 //Case 106: loc_D
如果跳转表的索引保存在%eax
中,那么第7行不是假定为jmp*.L7(,%eax)
跳转表中的每个条目都是一个长
,即4个字节。因此,eax
按4缩放
为什么他们在第5行通过执行ja.L2
将数字改为无符号
关键是要排除任何小于100且大于106的数字。我认为很明显,它是如何排除大于106的值的
假设n
小于100,例如99。如果我们从中减去100,我们得到-1,当被视为无符号32位值时,它是4294967295,这显然是“高于”6,并且跳转到.L2
,就像它应该的那样
subl $100, %eax ; eax = 99-100 == -1
cmpl $6, %eax ; set flags based on -1 - 6 == -7 => ZF=0 and CF=0
ja .L2 ; jump if ZF=0 and CF=0
这是因为当我们将有符号整数更改为无符号整数时,无符号整数的值将更改为某个较大的数字,因为有符号整数使用2的补码,而无符号整数不使用2的补码?嗯,没有任何实际的符号“更改”。根据特定标志的状态进行条件跳转。在
ja
的情况下,如果ZF=0且CF=0,将进行跳转。更新标志的最后一个操作是cmp
,这实际上是一个减法。减法运算得到ZF=0意味着操作数不相等,要得到CF=0,第一个操作数(eax
)需要无符号大于或等于第二个操作数(6
)。因此,我建议将eax
的值视为未签名,以便更容易对将发生的情况进行推理。