组装中有大量算术运算

时间:2018-10-04 16:20:55

标签: c assembly x86

我有一个任务来编写可从C读取并声明如下的汇编例程:

extern int solve_equation(long int a, long  int b,long  int c, long int *x, long int *y);

找到方程式的解决方案

a * x + b * y = c

-2147483648 <x, y <2147483647中,选中所有选项。

如果找到解决方案,则例程返回的值将为1,而另一个0将会返回。

您必须考虑到以下计算结果:a * x, b * y, a * x + b * y可能超过32位。

.MODEL SMALL
.DATA
C DQ ?
SUM DQ 0
MUL1 DQ ?
MUL2 DQ ?
X DD ?
Y DD ?
.CODE
.386
PUBLIC _solve_equation
_solve_equation PROC NEAR
PUSH BP 
MOV BP,SP
PUSH SI
MOV X,-2147483648 
MOV Y,-2147483648 
MOV ECX,4294967295
FOR1:
        CMP ECX,0
        JE FALSE
        PUSH ECX
        MOV Y,-2147483648 
        MOV ECX,4294967295
FOR2:
        MOV SUM,0
        CMP ECX,0
        JE SET_FOR1

        MOV EAX,DWORD PTR [BP+4]
        IMUL X
        MOV DWORD PTR MUL1,EAX
        MOV DWORD PTR MUL1+4,EDX

        MOV EAX,DWORD PTR [BP+8]
        IMUL Y
        MOV DWORD PTR MUL2,EAX
        MOV DWORD PTR MUL2+4,EDX

        MOV EAX, DWORD PTR MUL1
        ADD DWORD PTR SUM,EAX
        MOV EAX, DWORD PTR MUL2
        ADD DWORD PTR SUM,EAX

        MOV EAX, DWORD PTR MUL1+4
        ADD DWORD PTR SUM+4,EAX
        MOV EAX, DWORD PTR MUL2+4
        ADD DWORD PTR SUM+4,EAX

        CMP SUM,-2147483648
        JL SET_FOR2
        CMP SUM,2147483647
        JG SET_FOR2
        MOV EAX,DWORD PTR [BP+12]
        CMP DWORD PTR SUM,EAX
        JE TRUE
SET_FOR2:       
            DEC ECX
            INC Y
            JMP FOR2
SET_FOR1:
            POP ECX
            DEC ECX
            JMP FOR1
FALSE:
            MOV AX,0
            JMP SOF
TRUE:
            MOV SI,WORD PTR [BP+16]
            MOV EAX,X
            MOV DWORD PTR [SI],EAX
            MOV SI,WORD PTR [BP+18]
            MOV EAX,Y   
            MOV DWORD PTR [SI],EAX
            MOV AX,1
SOF:
        POP SI
        POP BP
        RET
        _solve_equation ENDP
        END 

这是处理大量数字的正确方法吗?

尝试执行操作时,我得到操作或指令has illegal size的参数:

MOV SUM,0
CMP SUM,-2147483648
CMP SUM,2147483647

主要代码:

int main() 
    {
     long int x, y, flag;

     flag = solve_equation(-5,4,2147483647,&x, &y);
    if (flag == 1)
      printf("%ld*%ld + %ld*%ld = %ld\n", -5L,x,4L,y,2147483647);
      return 0;

    } 

输出

-5*-2147483647 + 4*-2147483647 = 2147483647

我使用dosbox 0.74和tcc

1 个答案:

答案 0 :(得分:3)

您使用的是16位代码,因此64位操作数大小不可用。您的汇编器神奇地将大小与sum关联,因为您已将sum dq 0定义为大小。

因此mov sum, 0等效于mov qword ptr [sum], 0,它当然不会以16位或32位模式进行汇编;您只能使用整数运算一次最多处理32位。

(32位操作数大小在386兼容CPU上以16位模式可用,使用的机器编码与在32位模式下允许16位操作数大小的机器编码相同。但是64位操作数大小仅可用在64位模式下运行。与386不同,AMD64出于各种原因未向以前存在的模式添加任何新的前缀或任何内容。)


您可以通过SSE存储将整个64位sum归零,甚至可以与SSE4.2 pcmpgtq进行比较,但这可能不是您想要的。

您似乎想检查64位sum是否适合32位。 (即,如果它是符号扩展的32位整数)。

所以实际上,您只需要检查所有32个高位是否相同并匹配低半部分的第31位即可。

mov  eax, dword ptr [sum]
cdq                              ; sign extend eax into edx:eax
                                 ; i.e. copy bit 31 of EAX to all bits of EDX
cmp  edx, dword ptr [sum+4]
je   small_sum