9
votes

I have decided to create a simple guessing number game that uses Linux system calls, and some C functions to provide a more simpler interface. I seem to get a segmentation fault when I convert the int to string and print the correct answeron the screen.

Here is the output:

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

Here is the C code:

// 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;

}

Here is the NASM Code:

      ; 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

3
+1 just for the title :)Earlz
Okay, I'm going to resist my first inclination (which is to ask "Why? Seriously, why?" :-) I think you have the right answer but I'm curious as to why the f message is null terminated. That's not required for syscall 4. Perhaps it's left over from a cut and paste?paxdiablo
Daniel, you can use #include <header.h> instead of #include "/usr/include/header.h" for system headers (unless there is some path configuration problem?)Fernando
It's not the cause of your crash, but your stoi function won't work. You need to call atoi(str), not atoi("str").. what you have will try to convert literal "str" to a number.Splat
Gotta love the "The answer is: Segmentation fault" You are like YES ITS GONNA WORK, ohhhh .ChemiCalChems

3 Answers

6
votes

There is a problem with this code:

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

buf is a pointer to readonly memory, and sprintf wants to be able to modify its contents. You should change buf to an array: char buf[20] (or some number other than 20 that is arbitrarily large enough to hold your desired contents)

5
votes
void itos(int n)
{

     char* buf = "5";

In buf you have space for 2 chars (the five and \0)

But here:

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

you insert in it at least 3 chars, at least one digit of the number, the break line \n, and then \0.

Also is incorrect to modify a literal string this way. You can declare a stack copy of a literal string in the next way:

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

Or better just an empty array big enougth for several digits:

char buf[1024];
3
votes

In your function itos(), you are attempting to modify the string literal "5". String literals are non-modifiable (in this case, your OS stores them in memory mapped as read-only).

In this case, your itos() function is needlessly complicated - you could simply replace it with:

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

(..or you could just directly call printf() from your asm code).