使用NASM构建KMP前缀

时间:2015-10-05 12:32:54

标签: c linux assembly nasm

我正在尝试在NASM中实现以下C代码,然后将其链接到C程序并从那里运行。

我正在尝试实施的代码:

   void preKmp(char *x, int m, int kmpNext[]) {
   int i, j;

   i = 0;
   j = kmpNext[0] = -1;
   while (i < m) {
      while (j > -1 && x[i] != x[j])
         j = kmpNext[j];
      i++;
      j++;
      if (x[i] == x[j])
         kmpNext[i] = kmpNext[j];
      else
         kmpNext[i] = j;
   }
}

我的NASM尝试与我的评论:

;nasm -f elf32 table.asm -o table.o

segment .bss
kmpNext resd 256


segment .text
global table

table:
    push ebp          ;save the old base pointer value
    mov  ebp,esp      ;base pointer <- stack pointer

    mov eax,[ebp+8]     ;function argument, eax = search_string
    mov ecx, 0          ;i = 0
    mov edx, -1         ;j = -1
    mov [kmpNext], edx  ;kmpNext[0] = -1
oWhile:
    cmp byte [eax + ecx*4], 0  ;end of array control
    je finished
iWhile:
    cmp edx, -1
    jle pass
    mov edi,[eax + ecx*4] ;edi = x[i]
    mov esi,[eax + edx*4] ;esi = x[j]
    cmp edi, esi
    je pass
    mov edx, [kmpNext +edx*4] ;j = kmpNext[j]
pass:
    inc ecx
    inc edx
    mov edi,[eax + ecx*4] ;edi = x[i]
    mov esi,[eax + edx*4] ;esi = x[j]
    cmp edi, esi
    jne store
    mov edi, [kmpNext + edx*4]  ;edi = kmpNext[j]
    mov [kmpNext + ecx*4], edi  ;kmpNext[i] = edi
store:
    mov [kmpNext + ecx*4], edx  ;kmpNext[i] = j
    jmp oWhile
finished:
    mov eax, kmpNext;

    pop ebp
    ret

我在其中调用NASM功能的C代码:

#include <stdio.h>
#include <string.h>

int* table(char *str);

int main(void)
{
    char str[256];
    int i, n, *pre;

    printf("Enter string: ");
    scanf("%s" , str) ;
    n = strlen(str);
    pre = table(str);
    for (i = 0; i < n; i++){
      printf("%d ", pre[i]);

    }
    printf("\n");
    return 0;
}

所有内容编译并运行正常但输出错误。例如,

对于'cocacola'我应该得到:-1 -1 0 -1 0 1 -1 -1

我得到的地方:-1 0 0 0 0 0 0 0

有人能指出我在NASM代码中的错误吗?

我怀疑问题在于这一行:

mov esi,[eax + ecx * 4]

当我运行调试器时,我看不到esi内容的变化。

2 个答案:

答案 0 :(得分:2)

1)主要错误是str是一个字节数组(8位),但你把它当作一个整数数组(32位)。

2)有两个while循环。 他们两个都需要跳回来重复。

3)storeelse - 案例。如果if - 案例合适,它就不能运行。在这种情况下,适当跳转到oWhile

这是更正后的功能:

table:
    push ebp          ;save the old base pointer value
    mov  ebp,esp      ;base pointer <- stack pointer

    push edi          ; callee saved
    push ebx

    mov eax,[ebp+8]     ;function argument, eax = search_string
    mov ecx, 0          ;i = 0
    mov edx, -1         ;j = -1
    mov [kmpNext], edx  ;kmpNext[0] = -1

oWhile:
    cmp byte [eax + ecx], 0  ;end of array control
    je finished

iWhile:
    cmp edx, -1
    jle pass

    mov bl,[eax + ecx] ; bl = x[i]
    mov bh,[eax + edx] ; bh = x[j]
    cmp bl, bh

    je pass
    mov edx, [kmpNext +edx*4] ;j = kmpNext[j]
    jmp iWhile

pass:
    inc ecx
    inc edx

    mov bl,[eax + ecx] ; bl = x[i]
    mov bh,[eax + edx] ; bh = x[j]
    cmp bl, bh

    jne store
    mov edi, [kmpNext + edx*4]  ;edi = kmpNext[j]
    mov [kmpNext + ecx*4], edi  ;kmpNext[i] = edi

    jmp oWhile

store:
    mov [kmpNext + ecx*4], edx  ;kmpNext[i] = j
    jmp oWhile

finished:
    mov eax, kmpNext;

    pop ebx
    pop edi
    pop ebp
    ret

答案 1 :(得分:1)

routes.MapRoute (
"Default", // Route name
"/{nameofuser}", // URL with parameters
new { controller = "Controller here", action = "Action here" } // Parameter defaults
);

这不等同于oWhile: cmp byte [eax + ecx*4], 0 。它应该是:

while (i < m)

你回来之前不应该oWhile: cmp ecx,[ebp+12] jge finished ;它是一个void函数(虽然没有坏处 - 编译器会忽略返回值)。

此外,您可能需要保存mov eax, [kmpNext]edi以及其他可能的寄存器,否则调用者可能会感到困惑。请查看C编译器手册。