Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何在汇编语言X86中检测溢出条件_C_Assembly_X86_Integer Overflow - Fatal编程技术网

C 如何在汇编语言X86中检测溢出条件

C 如何在汇编语言X86中检测溢出条件,c,assembly,x86,integer-overflow,C,Assembly,X86,Integer Overflow,我有一个作业,我们必须写两个函数。还必须使用处理器的条件代码检测溢出条件,并返回0,以指示遇到错误。我能够编写函数 .file "formula.c" .text .globl _nCr .def _nCr; .scl 2; .type 32; .endef _nCr: pushl %ebp movl %esp, %ebp subl $56, %esp movl 8

我有一个作业,我们必须写两个函数。还必须使用处理器的条件代码检测溢出条件,并返回
0
,以指示遇到错误。我能够编写函数

 .file  "formula.c"  
    .text
.globl _nCr  
    .def    _nCr;   .scl    2;  .type   32; .endef  
_nCr:  
        pushl   %ebp  
    movl    %esp, %ebp  
    subl    $56, %esp  
    movl    8(%ebp), %eax  
    movl    %eax, (%esp)  
    testl %eax, %eax  
    call    _factorial  
    movl    %eax, -12(%ebp)  
    movl    12(%ebp), %eax  
    addl    $1, %eax  
    movl    %eax, (%esp)  
    call    _factorial  
    movl    %eax, -16(%ebp)  
    movl    12(%ebp), %eax  
    notl    %eax  
    addl    8(%ebp), %eax  
    movl    %eax, (%esp)  
    call    _factorial  
    movl    %eax, -20(%ebp)  
    movl    -16(%ebp), %eax  
    movl    %eax, %edx  
    imull   -20(%ebp), %edx  
    movl    %edx, -28(%ebp)  
    movl    -12(%ebp), %eax  
    movl    %eax, %edx  
    sarl    $31, %edx  
    idivl   -28(%ebp)  
    leave  
    ret  
.globl _factorial   
    .def    _factorial;  .scl    2;     .type   32;     .endef   
_factorial:  
    pushl   %ebp  
    movl    %esp, %ebp  
    subl    $16, %esp  
    movl    $1, -8(%ebp)  
    movl    $1, -4(%ebp)  
    jmp L3  
L4:   
    movl    -8(%ebp), %eax   
    imull   -4(%ebp), %eax  
    movl    %eax, -8(%ebp)  
    addl    $1, -4(%ebp)   
L3:
    movl    -4(%ebp), %eax  
    cmpl    8(%ebp), %eax  
    jle L4  
    movl    -8(%ebp), %eax  
    leave  
    ret  
    .def    ___main;    .scl    2;  .type   32; .endef  
    .section .rdata,"dr"  
    .align 4  
此函数基本上执行
nCr=n!/(r!(n-r)!)
。当数字变大时,溢出发生在阶乘中

我只是不明白如何设置溢出条件

1)算术命令是可能设置溢出位的操作

2) “JO”(溢出时跳转)和“JNO”(非溢出时跳转)允许您进行分支,具体取决于是否发生溢出

3) 您可能只是在“JO”之后将“%eax”设置为0

4) 非常好,非常好的资源,如果您还不熟悉它:


在x86体系结构上,当执行算术指令时,例如执行
addl 8(%ebp),%eax
在CPU状态字中设置条件代码。有些指令的行为取决于条件代码

您可以让代码在给定条件下采用备用路径(执行分支)。x86在
Jxx
助记符下有一系列条件分支指令:
JA,JAE,JB,JBE,JC,JCXZ,…,JZ
。例如,
JZ
表示零跳转:如果指令产生零结果,则执行分支,设置零标志
JO
是溢出时的跳转

条件也可以转换为字节数据并存储到寄存器或内存中。这对于编译C表达式非常有用,例如:

 x = (y != 3); /* if (y != 3) x = 1; else x = 0 */
它是由
SETx
一组指令完成的,这些指令也很多,比如条件分支:
SETA、SETAE、SETB、…、SETZ
。例如,如果零条件为真,SETZ将把给定字节设置为1。例如

 seto %bl  /* set bottom byte of B register to 1 if overflow flag set */

大多数指令集在有符号溢出时,或CF在无符号溢出时。解释add/sub(像and/or/xor这样的位布尔指令不能溢出,所以它们总是清除CF和OF)

当完整结果不是低半结果的符号扩展(与输入宽度相同)时,设置OF和CF。这甚至适用于高效的2操作数形式,即不在任何地方写入高半部;他们仍然根据实际情况设置旗帜。如果要对乘法执行无符号溢出检测,则需要使用笨拙的单操作数
mul

当商不适合AL/AX/EAX/RAX(取决于操作数大小)时,除法会引发#DE异常。不幸的是,没有办法抑制/屏蔽这一点,因此您无法尝试2N/N=>N位除法并在除法后检测溢出,除非您有一个信号处理程序来捕获SIGFPE(在POSIX操作系统上)。或者在裸机上,一个#DE的中断处理程序

特别是对于组合式: 而不是天真地计算
n
,您可以提前取消,只需计算
prod(r+1..n)
。实际使用较大的或
r
n-r
,然后除以另一个

您仍然以除以一个可能较大的数字作为结束,因此这不会消除适合32位整数的所有可能结果的溢出机会。但是它扩展了你可以简单处理的范围,当然更快,因为你做的乘法更少。e、 g.
C(999,1000)
只做
1000/(1000-999)
所以没有乘法,只有一个
div

如果使用
mul
指令对乘积进行最后一次乘法,以在EDX:EAX中生成64位结果,则可以将其用作32位除法的64位红利。(如果您想冒异常风险。)

mul
是NxN=>2N乘法,因此如果您只是在循环中使用它,它会忽略上一个输出的上半部分。如果你按从低到高的顺序进行乘法,那么最后一次乘法就是这个范围的高端,这就给了你最大的可能范围

例如,你可能会这样做

// mix of C pseudocode and AT&T 32-bit.
//  Some real registers, some var names: pick registers for those.

   if (n == r) return 1;
   divisor = factorial(min(r, n-r));   // and save in another register until later
   eax = max(r,n-r) + 1;               // prod

   xor  %edx, %edx        # in case we skip the mul
   cmp  n, %eax
   jae  endprod           # loop might need to run 0 times, but n==r case already handled

   lea  1(%eax), %ecx     # i = low+1.  Not overflow-checked
   jmp  loop_entry

 prod_loop:                  # do{
    imul  %ecx, %eax         # prod *= i for i=[max+2 .. n-1]
     jo  overflow_in_prod    # maybe need mul to avoid spurious signed but not unsigned overflow cases
    inc   %ecx
  loop_entry:
    cmp   n, %ecx
    jb    prod_loop          # }while(i<n)
                           # leave the loop with ECX = n, with one multiply left to do
    mul   %ecx             # EDX:EAX = n * EAX
    # We're keeping the full 64-bit result, therefore this can't overflow
 endprod:

    div   divisor          # prod /= the smaller factorial
    # EDX:EAX / divisor, quotient in EAX.  Or will raise #DE if it didn't fit.
    ret

overflow_in_prod:
   do something
   ret
//C伪码和AT&T 32位的混合。
//一些实寄存器,一些变量名:为它们选择寄存器。
如果(n==r)返回1;
除数=阶乘(最小(r,n-r));//并保存在另一个寄存器中,直到稍后
eax=max(r,n-r)+1;//戳
xor%edx,%edx#以防我们跳过mul
cmp n,%eax
jae endprod#循环可能需要运行0次,但n==r情况已经处理
lea 1(%eax),%ecx#i=低+1。未检查溢出
jmp循环_项
生产循环:#执行{
imul%ecx,%eax#prod*=i代表i=[max+2..n-1]
jo overflow_in_prod#可能需要mul来避免虚假的有符号而非无符号溢出情况
公司%ecx
循环输入:
化学机械抛光n,%ecx

jb prod#U loop#同时(iOverflow条件是由算术指令自动设置的。你只需要知道如何读取它们。谢谢你的回答。我应该输入我自己的条件标志。我只是在如何输入我自己的条件标志方面遇到了问题。根据问题和你的评论,这似乎是家庭作业,所以我添加了homework标记。如果这不是家庭作业,请随意删除标记。@user1282285您通过执行所需的操作来设置条件标志。或者我遗漏了什么?如果您自己编写和理解程序集,而不是使用GCC生成的程序集,您可能会更轻松。非常感谢!JO非常有帮助l、 还有资源。