NASM Modulo操作

时间:2018-07-27 19:21:33

标签: assembly x86 nasm modulo

我刚刚开始与NASM组装商进行组装。使用C驱动程序使用gcc进行编译。据我所知,可以很容易地以两种方式实现模函数(假设size_t a中的eaxsize_t b中的ebx for { {1}}):

第一个选项:

mod(a, b)

第二个选项:

minus:
  sub eax, ebx
modulo:
  CMP eax, ebx
  JGE minus
  leave   ; else result is already saved in eax
  ret

以下是必需的文件:

diver.c:

 modulo:         ; calcs eax mod ebx, returns eax
    mov edx, 0  ; clear higher 32-bits as edx:eax / ebx is calced
    div ebx     
    mov eax, edx ; the remainder was stored in edx
    leave      
    ret

modulo.asm:

#include "cdecl.h"
#include "stdio.h"

int PRE_CDECL asm_main( size_t, size_t ) POST_CDECL;

int main() {
    size_t a;
    size_t b;
    int result;
    a = 15;
    b = 5;
    result = asm_main(a, b);
    printf("%d", result);
    return 0;
}

编译正常:

segment .data
buffer: times 1 dd 0    ; define a 32-bit buffer

segment.text
global asm_main

modulo:
  ; one of above options implemented here

asm_main:
    enter 0, 0
    push ebp
    mov ebp, esp    ; save the stack pointer on ebp
    pusha

    ; dump_regs 0 ,requires %include "asm_io.inc"
    mov eax, [ebp + 12]    ; move first argument to eax
    mov ebx, [ebp + 16]    ; move second argument to ebx
    ; dump_regs 1

    call modulo                ; result is saved in eax now
    ; dump_regs 2

    mov ecx, buffer        ; get buffer's address into the register
    mov [ecx], eax           ; save the modulo result into the buffer

    popa
    pop ebp

    mov eax, [buffer]        ; move the saved result back into eax
    leave
    ret

使用两个选项执行时,都会以某种方式收到分段错误:

$ nasm -f elf modulo.asm
$ gcc -m32 -c driver.c
$ gcc -m32 -o modulo driver.o modulo.o

我不知道在哪里可以尝试访问环境外部的地址,因此我仍无法弄清错误在哪里。

如果有人可以帮助我找到麻烦制造者或建议我在Assembler中使用有效的模函数(如果可能,最好使用intel语法),我将不胜感激。谢谢!

PS:this link中可以找到$ ./modulo Register Dump # 0 EAX = 00000001 EBX = F76D0000 ECX = FFF987F0 EDX = FFF98814 ESI = 00000000 EDI = 00000000 EBP = FFF987A4 ESP = FFF98784 EIP = 080484EE FLAGS = 0296 SF AF PF Register Dump # 1 EAX = 0000000F EBX = 00000005 ECX = FFF987F0 EDX = FFF98814 ESI = 00000000 EDI = 00000000 EBP = FFF987A4 ESP = FFF98784 EIP = 080484FB FLAGS = 0296 SF AF PF Segmentation fault asm_io.asmasm_io.inc

1 个答案:

答案 0 :(得分:0)

谢谢@fuz,@harold的评论。我想您的评论实际上可以成为答案:)

更改第二个选项

modulo:         ; calcs eax mod ebx, returns eax
    mov edx, 0  ; clear higher 32-bits as edx:eax / ebx is calced
    div ebx     
    mov eax, edx ; the remainder was stored in edx     
    ret

解决了整个问题。

警告:即使删除leave,第一个选项也会返回错误的值。


附录:

正如彼得·科德斯(Peter Cordes)所说,使用asm_main实际上不是一个好习惯。所以我修改了C约定中的两个选项,如下所示:

第一个选项:

modulo:    ; Function size_t modulo(a, b)
        mov     eax, dword [esp+4H]    ; a in EAX
        mov     edx, dword [esp+8H]    ; b in EDX
        cmp     eax, edx               ; if (a < b) -> return
        JL      return

minus:  sub     eax, edx               ; else: a = a-b
        cmp     eax, edx               ; if (a >= b) -> minus
        JGE     minus
return:                                ; else: return
        ret

第二个选项:

modulo:
        mov     eax, dword [esp+4H]   ; a in EAX
        mov     edx, 0                ; EDX should be zero
        div     dword [esp+8H]        ; a / b
        mov     eax, edx              ; move a % b to eax
        ret

modulo.asm

global modulo

segment .text

modulo:    ; insert one of the options above here

modulodriver.c

#include "cdecl.h"
#include "stdio.h"

unsigned int PRE_CDECL modulo( unsigned int, unsigned int ) POST_CDECL;

int main() {
    unsigned int a = 25;
    unsigned int b = 5;
    unsigned int result = modulo(a, b);
    printf("%d", result);
    return 0;
}

我已经测试了两个选项,并且工作正常:)

注意:如果使用-m32选项进行编译,则可以使用size_t代替unsigned int,但是size_t将是64位整数,大于不过,在64位系统上使用的寄存器。