mavix
mavix

Reputation: 2552

NASM - segmentation fault and other problems

this is my first ever post here. I'm not sure if I've done the formatting correctly, so forgive me if I've messed up.

Anyway, this is supposed to take two inputs, halve one and double the other, and then print them. It's not supposed to work properly, as the input data is in characters, but the output is nonetheless confusing:

[poise] [/home/a/a_mccr/terminal] > ./assignment2
Please enter a four-digit number, negative or positive
1234
The number you entered is
Half the entered value is
ÞH
Double the entered value is
x#      ÞH
Segmentation fault

It doesn't print out my input (which is 1234), and then every time the output is PH and then X# PH. All this indicates to me that the input is not being stored, but I can't figure out why. Also I get a mysterious segmentation fault at the end of my program... Help! Here's the code:

segment .data                   ;to compile use:        nasm -f elf assignment2.asm
                            ;                       ld -o assignment2 assignment2.o

    msg1 db 'Please enter a four-digit number, negative or positive', 0xA
    len1 equ $-msg1         ;length of 1st message
    msg2 db 'The number you entered is', 0xA
    len2 equ $-msg2         ;length of 2nd message
    msg3 db 'Half the entered value is', 0xA
    len3 equ $-msg3         ;length of 3rd message
    msg4 db 'Double the entered value is', 0xA
    len4 equ $-msg4         ;length of 4th message

segment .bss

    input2 resb 3           ;reserve 5 bytes for the entered number
    input resb 3            ;reserve 5 bytes for the entered number

segment .text
    global _start

_start:
    mov eax, 4      ;select kernel call 4, the write function
    mov ebx, 1      ;use the default output device (print in terminal)
    mov ecx, msg1   ;set the pointer to msg
    mov edx, len1   ;set the length to len
    int 0x80        ;call write function

    mov eax, 3      ;select the kernel read function
    mov ebx, 0      ;use the default input device (user txt input)
    mov ecx, input  ;pointer to input variable
    int 0x80        ;invoke kernel read function

    mov eax, 4      ;select kernel call 4, the write function
    mov ebx, 1      ;use the default output device (print in terminal)
    mov ecx, msg2   ;set the pointer to msg2
    mov edx, len2   ;set the length to len2
    int 0x80        ;call write function

    mov eax, 4      ;select kernel call 4, the write function
    mov ebx, 1      ;use the default output device (print in terminal)
    mov ecx, input  ;set the pointer to input
    int 0x80        ;call write function

    mov eax, [input]        ;move input to eax register
    mov ebx, [input]        ;move input to ebx register

    shr eax, 1      ;shift eax 1 place to the right
    shl ebx, 1      ;shift ebx 1 place to the left

    mov [input], eax        ;move contents of eax to input
    mov [input2], ebx       ;move contents of ebx to input2

    mov eax, 4      ;Write message about half
    mov ebx, 1      ;use the default output device (print in terminal)
    mov ecx, msg3   ;set the pointer to msg3
    mov edx, len3   ;set the length to len3
    int 0x80        ;call write function

    mov eax, 4      ;write contents of input
    mov ebx, 1      ;use the default output device (print in terminal)
    mov ecx, input  ;set the pointer to input
    int 0x80        ;call write function

    mov eax, 4      ;write message about double
    mov ebx, 1      ;use the default output device (print in terminal)
    mov ecx, msg4   ;set the pointer to msg4
    mov edx, len4   ;set the length to len4
    int 0x80        ;call write function

    mov eax, 4      ;write contents of input2
    mov ebx, 1      ;use the default output device (print in terminal)
    mov ecx, input2 ;set the pointer to input2
    int 0x80        ;call write function

_exit:
    mov eax, 1      ;standard exit
    mov ebx, 0      ;0 is normal
    int 0x80

Upvotes: 1

Views: 2544

Answers (2)

Gunther Piez
Gunther Piez

Reputation: 30419

Let me get that right:

  1. You read a string as input
  2. You put it in a register (actually a 32 bit register is just wide enough to hold a 4 char string)
  3. You reinterpret the string a integer (here you actually need to convert it from decimal to binary)
  4. You halve/double it
  5. You send the meaningless stream of halved chars to the output
  6. You receive garbage on the screen.

You need to convert the ASCII string you receive from decimal to binary and back before input and output. If you don't to use atoi() or similar, you can write your own version, it isn't actually that hard.

You need to reserve more bytes for the strings, a 32 bit number may be up to 10 chars long. Would you have done that, you probably have seen there error by yourself, because you might have find it difficult to squeeze a 10 byte string into a 32 bit register.

Upvotes: 0

sarnold
sarnold

Reputation: 104020

When you're reading input, it appears that you forgot to specify a length to read:

mov eax, 3      ;select the kernel read function
mov ebx, 0      ;use the default input device (user txt input)
mov ecx, input  ;pointer to input variable
int 0x80        ;invoke kernel read function

I presume that the old value of edx will be the length of read(2) -- which will be far longer than your input space. (And five bytes? Sure seems odd. Also, the comment doesn't seem to match the code, but that could be my ignorance more than your code.)

Upvotes: 1

Related Questions