2011-02-17 83 views
5

我已经决定创建一个简单的猜数字游戏,它使用Linux系统调用和一些C函数来提供更简单的接口。当我将int转换为字符串并在屏幕上打印正确答案时,我似乎遇到了分段错误。NASM猜数游戏错了

这里是输出:

Enter A Number One Through Ten:" : 
3 
Response did not match! The Answer Is:Segmentation fault 

下面是C语言代码:

// print.c 
#include "/usr/include/stdio.h" 
#include "/usr/include/string.h" 
#include "/usr/include/stdlib.h" 
#include "/usr/include/time.h" 
void print(const char* msg) 
{ 
    printf(msg); 
    return; 
} 
int compare(const char* str, const char* str2) 
{ 
    int i = strcmp(str, str2); 
    if (i == 0) 
    { 
     return 1; 
    } 
    else 
    { 
     return 0; 
    } 
} 
int divide(int num, int dem) 
{ 
    if (dem == 0) 
    { 
     printf("Undefined"); 
     return 0; 
    } 
    else { 
     return (num/dem); 
    } 
} 
int randnum(int maxn) 
{ 

    if (maxn == 0) 
    { 
     maxn = 1; 
    } 
    srand(time(0)); 
    return rand() % maxn; 
} 
int stoi(const char* str) 
{ 
    return atoi("str"); 
} 
void itos(int n) 
{ 

    char* buf = "5"; 
    int ret = sprintf(buf, "%i\n", n); 
    if (ret == -1){ 
    printf("Error!"); 
    return; 
    } 
    else{ 
    printf(buf); 
    } 
    return; 

} 

这里是NASM代码:

 
     ; Declared C functions. 
     extern print 
     extern compare 
     extern divide 
     extern randnum 
     extern stoi 
     extern itos 
     section .data 
      msg: db 'Enter A Number One Through Ten:" : ', 10 
      ml: equ $ - msg 
      t: db 'Response did match!', 10 
      tl: equ $ - t 
      f: db 'Response did not match! The Answer Is:', 0 
      fl: equ $ - f 
      str2: db 'Hello' 
     section .bss 
      ;srnum: resb 255 
      snum: resb 255 
      rnum: resb 255 
      num: resb 255 
     section .text 
      global _start ; Entry point function or label. 
     _start: 
      ; System call sys_write 
      mov eax, 4 
      mov ebx, 1 
      mov ecx, msg 
      mov edx, ml 
      int 80h

; System call sys_read mov eax, 3 mov ebx, 0 mov ecx, snum mov edx, 255 int 80h ; Call stoi which converts string to int (parameter 1: is string to convert). push snum call stoi mov [num], eax mov ecx, esp sub ecx, 4 mov esp, ecx ; Call random push 10 call randnum mov [rnum], eax mov ecx, esp sub ecx, 4 mov esp, ecx ; Compare the two integers. mov eax, num cmp eax, [rnum] je true jne false true: ; Call sys_write mov eax, 4 mov ebx, 1 mov ecx, t mov edx, tl int 80h false: ; Segmentation fault is somewhere in this label mov eax, 4 mov ebx, 1 mov ecx, f mov edx, fl int 80h push rnum call itos ; Calling sys_exit with exit code (0 = ERROR_SUCCESS) mov eax, 1 mov ebx, 0 int 80h

+2

+1只是为了标题:) – Earlz 2011-02-17 01:30:02

+1

好吧,我要抗拒我的第一个倾向(这是问“为什么?认真,为什么?”:-)我认为你有正确的答案,但我是好奇为什么`f`消息是空终止的。这对系统调用4不是必需的。也许它是从剪切和粘贴中遗留下来的? – paxdiablo 2011-02-17 02:07:41

+0

Daniel,你可以使用`#include `而不是`#include“/usr/include/header.h”`作为系统头文件(除非存在一些路径配置问题?) – Fernando 2011-02-17 03:00:01

回答

4

有一个这个问题代码:

char* buf = "5"; 
int ret = sprintf(buf, "%i\n", n); 

buf是只读存储器的指针,和sprintf希望能够修改其内容。 你应该改变buf到一个数组:char buf[20](或大于20的其他一些数字,任意大到足以容纳你所需的内容)

5
void itos(int n) 
{ 

    char* buf = "5"; 

BUF中的你有空间的2个字符(五和\ 0)

但在这里:

int ret = sprintf(buf, "%i\n", n); 

你在其中插入至少3个字符,数字,断裂线\ n的至少一个数字,然后\ 0。

以这种方式修改文字字符串也是不正确的。

char buf[] = "5"; // This sample will fail anyway, use a larger string... 

或者更好的只是一个空数组大enougth了几个数字:

char buf[1024]; 
2

在你的函数itos(),你正试图您可以在接下来的方式声明文本字符串的堆栈副本修改字符串文字"5"。字符串文字是不可修改的(在这种情况下,您的操作系统将它们存储在映射为只读的内存中)。

在这种情况下,您的itos()功能是不必要的复杂 - 你可以简单地将其替换为:

void itos(int n) 
{ 
    printf("%i\n", n); 
} 

(..或者你可以只直接调用printf()从你的汇编代码)。